1
0
Fork 0
mirror of https://github.com/syncthing/syncthing-android.git synced 2024-11-23 04:41:16 +00:00

Use Gson for folder parsing

This commit is contained in:
Felix Ableitner 2016-10-15 16:07:58 +09:00
parent b9266ce6a9
commit 3dffc4c900
9 changed files with 175 additions and 211 deletions

View file

@ -161,9 +161,11 @@ public class DrawerFragment extends Fragment implements RestApi.OnReceiveSystemI
percentFormat.setMaximumFractionDigits(2); percentFormat.setMaximumFractionDigits(2);
mCpuUsage.setText(percentFormat.format(info.cpuPercent / 100)); mCpuUsage.setText(percentFormat.format(info.cpuPercent / 100));
mRamUsage.setText(RestApi.readableFileSize(mActivity, info.sys)); mRamUsage.setText(RestApi.readableFileSize(mActivity, info.sys));
int announceTotal = info.discoveryMethods;
int announceConnected = announceTotal - info.discoveryErrors.size();
mAnnounceServer.setText(String.format(Locale.getDefault(), "%1$d/%2$d", mAnnounceServer.setText(String.format(Locale.getDefault(), "%1$d/%2$d",
info.extAnnounceConnected, info.extAnnounceTotal)); announceConnected, announceTotal));
int color = (info.extAnnounceConnected > 0) int color = (announceConnected > 0)
? R.color.text_green ? R.color.text_green
: R.color.text_red; : R.color.text_red;
mAnnounceServer.setTextColor(ContextCompat.getColor(getContext(), color)); mAnnounceServer.setTextColor(ContextCompat.getColor(getContext(), color));

View file

@ -11,16 +11,25 @@ import android.text.Editable;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.util.Log; import android.util.Log;
import android.view.*; import android.view.LayoutInflater;
import android.widget.*; import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.nutomic.syncthingandroid.R; import com.nutomic.syncthingandroid.R;
import com.nutomic.syncthingandroid.activities.FolderPickerActivity; import com.nutomic.syncthingandroid.activities.FolderPickerActivity;
import com.nutomic.syncthingandroid.activities.SettingsActivity; import com.nutomic.syncthingandroid.activities.SettingsActivity;
import com.nutomic.syncthingandroid.activities.SyncthingActivity; import com.nutomic.syncthingandroid.activities.SyncthingActivity;
import com.nutomic.syncthingandroid.fragments.dialog.KeepVersionsDialogFragment; import com.nutomic.syncthingandroid.fragments.dialog.KeepVersionsDialogFragment;
import com.nutomic.syncthingandroid.model.Folder;
import com.nutomic.syncthingandroid.syncthing.RestApi; import com.nutomic.syncthingandroid.syncthing.RestApi;
import com.nutomic.syncthingandroid.syncthing.RestApi.SimpleVersioning;
import com.nutomic.syncthingandroid.syncthing.RestApi.Versioning;
import com.nutomic.syncthingandroid.syncthing.SyncthingService; import com.nutomic.syncthingandroid.syncthing.SyncthingService;
import com.nutomic.syncthingandroid.util.TextWatcherAdapter; import com.nutomic.syncthingandroid.util.TextWatcherAdapter;
@ -58,7 +67,7 @@ public class FolderFragment extends Fragment
private SyncthingService mSyncthingService; private SyncthingService mSyncthingService;
private RestApi.Folder mFolder; private Folder mFolder;
private EditText mLabelView; private EditText mLabelView;
private EditText mIdView; private EditText mIdView;
@ -88,16 +97,18 @@ public class FolderFragment extends Fragment
public void onCheckedChanged(CompoundButton view, boolean isChecked) { public void onCheckedChanged(CompoundButton view, boolean isChecked) {
switch (view.getId()) { switch (view.getId()) {
case R.id.master: case R.id.master:
mFolder.readOnly = isChecked; mFolder.type = (isChecked) ? "readonly" : "readwrite";
mFolderNeedsToUpdate = true; mFolderNeedsToUpdate = true;
break; break;
case R.id.device_toggle: case R.id.device_toggle:
List<String> devicesList = mFolder.getDevices();
RestApi.Device device = (RestApi.Device) view.getTag(); RestApi.Device device = (RestApi.Device) view.getTag();
if (isChecked) { if (isChecked) {
mFolder.deviceIds.add(device.deviceID); devicesList.add(device.deviceID);
} else { } else {
mFolder.deviceIds.remove(device.deviceID); devicesList.remove(device.deviceID);
} }
mFolder.setDevices(devicesList);
mFolderNeedsToUpdate = true; mFolderNeedsToUpdate = true;
break; break;
} }
@ -109,11 +120,10 @@ public class FolderFragment extends Fragment
@Override @Override
public void onValueChange(int intValue) { public void onValueChange(int intValue) {
if (intValue == 0) { if (intValue == 0) {
mFolder.versioning = new Versioning(); mFolder.versioning = new Folder.Versioning();
mVersioningKeepView.setText(R.string.off); mVersioningKeepView.setText(R.string.off);
} else { } else {
mFolder.versioning = new SimpleVersioning(); mFolder.versioning.params.put("keep", valueOf(intValue));
((SimpleVersioning) mFolder.versioning).setParams(intValue);
mVersioningKeepView.setText(valueOf(intValue)); mVersioningKeepView.setText(valueOf(intValue));
} }
mFolderNeedsToUpdate = true; mFolderNeedsToUpdate = true;
@ -143,7 +153,7 @@ public class FolderFragment extends Fragment
if (mIsCreateMode) { if (mIsCreateMode) {
if (savedInstanceState != null) { if (savedInstanceState != null) {
mFolder = (RestApi.Folder) savedInstanceState.getSerializable("folder"); mFolder = (Folder) savedInstanceState.getSerializable("folder");
} }
if (mFolder == null) { if (mFolder == null) {
initFolder(); initFolder();
@ -228,10 +238,10 @@ public class FolderFragment extends Fragment
} }
if (!mIsCreateMode) { if (!mIsCreateMode) {
List<RestApi.Folder> folders = mSyncthingService.getApi().getFolders(); List<Folder> folders = mSyncthingService.getApi().getFolders();
String passedId = getActivity().getIntent().getStringExtra(EXTRA_FOLDER_ID); String passedId = getActivity().getIntent().getStringExtra(EXTRA_FOLDER_ID);
mFolder = null; mFolder = null;
for (RestApi.Folder currentFolder : folders) { for (Folder currentFolder : folders) {
if (currentFolder.id.equals(passedId)) { if (currentFolder.id.equals(passedId)) {
mFolder = currentFolder; mFolder = currentFolder;
break; break;
@ -258,7 +268,7 @@ public class FolderFragment extends Fragment
mLabelView.setText(mFolder.label); mLabelView.setText(mFolder.label);
mIdView.setText(mFolder.id); mIdView.setText(mFolder.id);
mPathView.setText(mFolder.path); mPathView.setText(mFolder.path);
mFolderMasterView.setChecked(mFolder.readOnly); mFolderMasterView.setChecked(mFolder.type.equals("readonly"));
List<RestApi.Device> devicesList = mSyncthingService.getApi().getDevices(false); List<RestApi.Device> devicesList = mSyncthingService.getApi().getDevices(false);
mDevicesContainer.removeAllViews(); mDevicesContainer.removeAllViews();
@ -270,10 +280,10 @@ public class FolderFragment extends Fragment
} }
} }
boolean versioningEnabled = mFolder.versioning instanceof SimpleVersioning; boolean versioningEnabled = mFolder.versioning.type.equals("simple");
int versions = 0; int versions = 0;
if (versioningEnabled) { if (versioningEnabled) {
versions = Integer.valueOf(mFolder.versioning.getParams().get("keep")); versions = Integer.valueOf(mFolder.versioning.params.get("keep"));
mVersioningKeepView.setText(valueOf(versions)); mVersioningKeepView.setText(valueOf(versions));
} else { } else {
mVersioningKeepView.setText(R.string.off); mVersioningKeepView.setText(R.string.off);
@ -342,16 +352,16 @@ public class FolderFragment extends Fragment
} }
private void initFolder() { private void initFolder() {
mFolder = new RestApi.Folder(); mFolder = new Folder();
mFolder.id = getActivity().getIntent().getStringExtra(EXTRA_FOLDER_ID); mFolder.id = getActivity().getIntent().getStringExtra(EXTRA_FOLDER_ID);
mFolder.label = getActivity().getIntent().getStringExtra(EXTRA_FOLDER_LABEL); mFolder.label = getActivity().getIntent().getStringExtra(EXTRA_FOLDER_LABEL);
mFolder.path = ""; mFolder.path = "";
mFolder.rescanIntervalS = 259200; // Scan every 3 days (in case inotify dropped some changes) mFolder.rescanIntervalS = 259200; // Scan every 3 days (in case inotify dropped some changes)
mFolder.deviceIds = new ArrayList<>(); mFolder.setDevices(new ArrayList<>());
mFolder.versioning = new Versioning(); mFolder.versioning = new Folder.Versioning();
String deviceId = getActivity().getIntent().getStringExtra(EXTRA_DEVICE_ID); String deviceId = getActivity().getIntent().getStringExtra(EXTRA_DEVICE_ID);
if (deviceId != null) //if (deviceId != null)
mFolder.deviceIds.add(deviceId); // TODO mFolder.devices.add(deviceId);
} }
private void prepareEditMode() { private void prepareEditMode() {
@ -376,7 +386,7 @@ public class FolderFragment extends Fragment
private void addDeviceViewAndSetListener(RestApi.Device device, LayoutInflater inflater) { private void addDeviceViewAndSetListener(RestApi.Device device, LayoutInflater inflater) {
inflater.inflate(R.layout.item_device_form, mDevicesContainer); inflater.inflate(R.layout.item_device_form, mDevicesContainer);
SwitchCompat deviceView = (SwitchCompat) mDevicesContainer.getChildAt(mDevicesContainer.getChildCount()-1); SwitchCompat deviceView = (SwitchCompat) mDevicesContainer.getChildAt(mDevicesContainer.getChildCount()-1);
deviceView.setChecked(mFolder.deviceIds.contains(device.deviceID)); deviceView.setChecked(mFolder.getDevices().contains(device.deviceID));
deviceView.setText(RestApi.getDeviceDisplayName(device)); deviceView.setText(RestApi.getDeviceDisplayName(device));
deviceView.setTag(device); deviceView.setTag(device);
deviceView.setOnCheckedChangeListener(mCheckedListener); deviceView.setOnCheckedChangeListener(mCheckedListener);

View file

@ -13,6 +13,7 @@ import android.widget.AdapterView;
import com.nutomic.syncthingandroid.R; import com.nutomic.syncthingandroid.R;
import com.nutomic.syncthingandroid.activities.SettingsActivity; import com.nutomic.syncthingandroid.activities.SettingsActivity;
import com.nutomic.syncthingandroid.activities.SyncthingActivity; import com.nutomic.syncthingandroid.activities.SyncthingActivity;
import com.nutomic.syncthingandroid.model.Folder;
import com.nutomic.syncthingandroid.syncthing.RestApi; import com.nutomic.syncthingandroid.syncthing.RestApi;
import com.nutomic.syncthingandroid.syncthing.SyncthingService; import com.nutomic.syncthingandroid.syncthing.SyncthingService;
import com.nutomic.syncthingandroid.util.FoldersAdapter; import com.nutomic.syncthingandroid.util.FoldersAdapter;
@ -32,7 +33,7 @@ public class FolderListFragment extends ListFragment implements SyncthingService
/** /**
* Compares folders by labels, uses the folder ID as fallback if the label is empty * Compares folders by labels, uses the folder ID as fallback if the label is empty
*/ */
private final static Comparator<RestApi.Folder> FOLDERS_COMPARATOR = (lhs, rhs) -> { private final static Comparator<Folder> FOLDERS_COMPARATOR = (lhs, rhs) -> {
String lhsLabel = lhs.label != null && !lhs.label.isEmpty() ? lhs.label : lhs.id; String lhsLabel = lhs.label != null && !lhs.label.isEmpty() ? lhs.label : lhs.id;
String rhsLabel = rhs.label != null && !rhs.label.isEmpty() ? rhs.label : rhs.id; String rhsLabel = rhs.label != null && !rhs.label.isEmpty() ? rhs.label : rhs.id;
@ -106,7 +107,7 @@ public class FolderListFragment extends ListFragment implements SyncthingService
// Prevent scroll position reset due to list update from clear(). // Prevent scroll position reset due to list update from clear().
mAdapter.setNotifyOnChange(false); mAdapter.setNotifyOnChange(false);
mAdapter.clear(); mAdapter.clear();
List<RestApi.Folder> folders = activity.getApi().getFolders(); List<Folder> folders = activity.getApi().getFolders();
Collections.sort(folders, FOLDERS_COMPARATOR); Collections.sort(folders, FOLDERS_COMPARATOR);
mAdapter.addAll(folders); mAdapter.addAll(folders);
mAdapter.updateModel(activity.getApi()); mAdapter.updateModel(activity.getApi());

View file

@ -0,0 +1,58 @@
package com.nutomic.syncthingandroid.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Folder implements Serializable {
public String id;
public String label;
public String path;
public String type;
private transient List<Map<String, String>> devices;
public int rescanIntervalS;
public boolean ignorePerms;
public boolean autoNormalize;
public int minDiskFreePct;
public Versioning versioning;
public int copiers;
public int pullers;
public int hashers;
public String order;
public boolean ignoreDelete;
public int scanProgressIntervalS;
public int pullerSleepS;
public int pullerPauseS;
public int maxConflicts;
public boolean disableSparseFiles;
public boolean disableTempIndexes;
public String invalid;
public static class Versioning implements Serializable {
public String type;
public Map<String, String> params;
}
public List<String> getDevices() {
if (devices == null)
return new ArrayList<>();
List<String> devicesList = new ArrayList<>();
for (Map<String, String> map : devices) {
devicesList.addAll(map.values());
}
return devicesList;
}
public void setDevices(List<String> newDvices) {
devices.clear();
for (String d : newDvices) {
Map<String, String> map = new HashMap<>();
map.put("deviceID", d);
devices.add(map);
}
}
}

View file

@ -13,14 +13,12 @@ import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat;
import android.util.Log; import android.util.Log;
import com.google.gson.JsonObject;
import com.nutomic.syncthingandroid.R; import com.nutomic.syncthingandroid.R;
import com.nutomic.syncthingandroid.activities.SettingsActivity; import com.nutomic.syncthingandroid.activities.SettingsActivity;
import com.nutomic.syncthingandroid.fragments.DeviceFragment; import com.nutomic.syncthingandroid.fragments.DeviceFragment;
import com.nutomic.syncthingandroid.fragments.FolderFragment; import com.nutomic.syncthingandroid.fragments.FolderFragment;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File; import java.io.File;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -70,7 +68,7 @@ public class EventProcessor implements SyncthingService.OnWebGuiAvailableListene
// If that's the case we've to start at zero because syncthing was restarted. // If that's the case we've to start at zero because syncthing was restarted.
mApi.getEvents(0, 1, new RestApi.OnReceiveEventListener() { mApi.getEvents(0, 1, new RestApi.OnReceiveEventListener() {
@Override @Override
public void onEvent(String eventType, JSONObject data) throws JSONException { public void onEvent(String eventType, JsonObject data) {
} }
@ -89,10 +87,10 @@ public class EventProcessor implements SyncthingService.OnWebGuiAvailableListene
* Performs the actual event handling. * Performs the actual event handling.
*/ */
@Override @Override
public void onEvent(String type, JSONObject data) throws JSONException { public void onEvent(String type, JsonObject data) {
switch (type) { switch (type) {
case "DeviceRejected": case "DeviceRejected":
String deviceId = data.getString("device"); String deviceId = data.get("device").getAsString();
Log.d(TAG, "Unknwon device " + deviceId + " wants to connect"); Log.d(TAG, "Unknwon device " + deviceId + " wants to connect");
Intent intent = new Intent(mContext, SettingsActivity.class) Intent intent = new Intent(mContext, SettingsActivity.class)
@ -110,9 +108,9 @@ public class EventProcessor implements SyncthingService.OnWebGuiAvailableListene
notify(title, pi); notify(title, pi);
break; break;
case "FolderRejected": case "FolderRejected":
deviceId = data.getString("device"); deviceId = data.get("device").getAsString();
String folderId = data.getString("folder"); String folderId = data.get("folder").getAsString();
String folderLabel = data.getString("folderLabel"); String folderLabel = data.get("folderLabel").getAsString();
Log.d(TAG, "Device " + deviceId + " wants to share folder " + folderId); Log.d(TAG, "Device " + deviceId + " wants to share folder " + folderId);
intent = new Intent(mContext, SettingsActivity.class) intent = new Intent(mContext, SettingsActivity.class)
@ -137,7 +135,8 @@ public class EventProcessor implements SyncthingService.OnWebGuiAvailableListene
notify(title, pi); notify(title, pi);
break; break;
case "ItemFinished": case "ItemFinished":
File updatedFile = new File(data.getString("folderpath"), data.getString("item")); File updatedFile = new File(data.get("folderpath").getAsString(),
data.get("item").getAsString());
Log.i(TAG, "Notified media scanner about " + updatedFile.toString()); Log.i(TAG, "Notified media scanner about " + updatedFile.toString());
mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
Uri.fromFile(updatedFile))); Uri.fromFile(updatedFile)));

View file

@ -11,15 +11,21 @@ import android.support.annotation.NonNull;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import com.google.gson.annotations.SerializedName;
import com.nutomic.syncthingandroid.BuildConfig; import com.nutomic.syncthingandroid.BuildConfig;
import com.nutomic.syncthingandroid.R; import com.nutomic.syncthingandroid.R;
import com.nutomic.syncthingandroid.activities.RestartActivity; import com.nutomic.syncthingandroid.activities.RestartActivity;
import com.nutomic.syncthingandroid.http.GetTask; import com.nutomic.syncthingandroid.http.GetTask;
import com.nutomic.syncthingandroid.http.PostTask; import com.nutomic.syncthingandroid.http.PostTask;
import com.nutomic.syncthingandroid.model.Folder;
import com.nutomic.syncthingandroid.util.FolderObserver; import com.nutomic.syncthingandroid.util.FolderObserver;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@ -27,7 +33,11 @@ import org.json.JSONObject;
import java.io.Serializable; import java.io.Serializable;
import java.net.URL; import java.net.URL;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.*; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
/** /**
@ -76,60 +86,22 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener,
public static class SystemInfo { public static class SystemInfo {
public long alloc; public long alloc;
public double cpuPercent; public double cpuPercent;
public int extAnnounceConnected; // Number of connected announce servers.
public int extAnnounceTotal; // Total number of configured announce servers.
public int goroutines; public int goroutines;
public String myID; public String myID;
public long sys; public long sys;
public boolean discoveryEnabled;
public int discoveryMethods;
public Map<String, String> discoveryErrors;
} }
public static class SystemVersion { public static class SystemVersion {
@SerializedName("arch") public String arch;
public String architecture;
@SerializedName("codename")
public String codename; public String codename;
@SerializedName("longVersion")
public String longVersion; public String longVersion;
@SerializedName("os")
public String os; public String os;
@SerializedName("version")
public String version; public String version;
} }
public static class Folder implements Serializable {
public String path;
public String label;
public String id;
public String invalid;
public List<String> deviceIds;
public boolean readOnly;
public int rescanIntervalS;
public Versioning versioning;
}
public static class Versioning implements Serializable {
protected final Map<String, String> mParams = new HashMap<>();
public String getType() {
return "";
}
public Map<String, String> getParams() {
return mParams;
}
}
public static class SimpleVersioning extends Versioning {
@Override
public String getType() {
return "simple";
}
public void setParams(int keep) {
mParams.put("keep", Integer.toString(keep));
}
}
public static class Connection { public static class Connection {
public String at; public String at;
public long inBytesTotal; public long inBytesTotal;
@ -240,15 +212,10 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener,
if (s == null) if (s == null)
return; return;
try { JsonObject json = new JsonParser().parse(s).getAsJsonObject();
JSONObject json = new JSONObject(s); mVersion = json.get("version").getAsString();
mVersion = json.getString("version"); Log.i(TAG, "Syncthing version is " + mVersion);
Log.i(TAG, "Syncthing version is " + mVersion); tryIsAvailable();
tryIsAvailable();
}
catch (JSONException e) {
Log.w(TAG, "Failed to parse config", e);
}
} }
}.execute(); }.execute();
new GetTask(mUrl, GetTask.URI_CONFIG, mHttpsCertPath, mApiKey) { new GetTask(mUrl, GetTask.URI_CONFIG, mHttpsCertPath, mApiKey) {
@ -448,26 +415,7 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener,
if (s == null) if (s == null)
return; return;
try { listener.onReceiveSystemInfo(new Gson().fromJson(s, SystemInfo.class));
JSONObject system = new JSONObject(s);
SystemInfo si = new SystemInfo();
si.alloc = system.getLong("alloc");
si.cpuPercent = system.getDouble("cpuPercent");
if (system.has("discoveryEnabled")) {
si.extAnnounceTotal = system.getInt("discoveryMethods");
si.extAnnounceConnected =
si.extAnnounceTotal - system.getJSONObject("discoveryErrors").length();
} else {
si.extAnnounceTotal = 0;
si.extAnnounceConnected = 0;
}
si.goroutines = system.getInt("goroutines");
si.myID = system.getString("myID");
si.sys = system.getLong("sys");
listener.onReceiveSystemInfo(si);
} catch (JSONException e) {
Log.w(TAG, "Failed to read system info", e);
}
} }
}.execute(); }.execute();
} }
@ -502,45 +450,13 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener,
if (mConfig == null) if (mConfig == null)
return new ArrayList<>(); return new ArrayList<>();
List<Folder> ret;
try { try {
JSONArray folders = mConfig.getJSONArray("folders"); String foldersJson = mConfig.getJSONArray("folders").toString();
ret = new ArrayList<>(folders.length()); return Arrays.asList(new Gson().fromJson(foldersJson, Folder[].class));
for (int i = 0; i < folders.length(); i++) {
JSONObject json = folders.getJSONObject(i);
Folder r = new Folder();
r.path = json.getString("path");
r.label = json.getString("label");
r.id = json.getString("id");
// TODO: Field seems to be missing sometimes.
// https://github.com/syncthing/syncthing-android/issues/291
r.invalid = json.optString("invalid");
r.deviceIds = new ArrayList<>();
JSONArray devices = json.getJSONArray("devices");
for (int j = 0; j < devices.length(); j++) {
JSONObject n = devices.getJSONObject(j);
r.deviceIds.add(n.getString("deviceID"));
}
r.readOnly = json.getString("type").equals("readonly");
r.rescanIntervalS = json.getInt("rescanIntervalS");
JSONObject versioning = json.getJSONObject("versioning");
if (versioning.getString("type").equals("simple")) {
SimpleVersioning sv = new SimpleVersioning();
JSONObject params = versioning.getJSONObject("params");
sv.setParams(params.getInt("keep"));
r.versioning = sv;
} else {
r.versioning = new Versioning();
}
ret.add(r);
}
} catch (JSONException e) { } catch (JSONException e) {
Log.w(TAG, "Failed to read devices", e); Log.w(TAG, "Failed to read devices", e);
return new ArrayList<>(); return new ArrayList<>();
} }
return ret;
} }
/** /**
@ -662,12 +578,11 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener,
boolean isShared = false; boolean isShared = false;
outerloop: outerloop:
for (Folder r : getFolders()) { for (Folder r : getFolders()) {
for (String n : r.deviceIds) { for (String n : r.getDevices()) {
if (n.equals(deviceId)) { if (n.equals(deviceId)) {
isShared = true; isShared = true;
break outerloop; break outerloop;
} }
} }
} }
if (isShared) { if (isShared) {
@ -704,7 +619,7 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener,
* @param eventType Name of the event. (See Syncthing documentation) * @param eventType Name of the event. (See Syncthing documentation)
* @param data Contains the data fields of the event. * @param data Contains the data fields of the event.
*/ */
void onEvent(String eventType, JSONObject data) throws JSONException; void onEvent(String eventType, JsonObject data);
/** /**
* Called after all available events have been processed. * Called after all available events have been processed.
@ -723,27 +638,9 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener,
if (s == null) if (s == null)
return; return;
try { Model m = new Gson().fromJson(s, Model.class);
JSONObject json = new JSONObject(s); mCachedModelInfo.put(folderId, m);
Model m = new Model(); listener.onReceiveModel(folderId, m);
m.globalBytes = json.getLong("globalBytes");
m.globalDeleted = json.getLong("globalDeleted");
m.globalFiles = json.getLong("globalFiles");
m.localBytes = json.getLong("localBytes");
m.localDeleted = json.getLong("localDeleted");
m.localFiles = json.getLong("localFiles");
m.inSyncBytes = json.getLong("inSyncBytes");
m.inSyncFiles = json.getLong("inSyncFiles");
m.needBytes = json.getLong("needBytes");
m.needFiles = json.getLong("needFiles");
m.needDeletes = json.getLong("needDeletes");
m.state = json.getString("state");
m.invalid = json.optString("invalid");
mCachedModelInfo.put(folderId, m);
listener.onReceiveModel(folderId, m);
} catch (JSONException e) {
Log.w(TAG, "Failed to read folder info", e);
}
} }
}.execute("folder", folderId); }.execute("folder", folderId);
} }
@ -782,35 +679,32 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener,
if (s == null) if (s == null)
return; return;
try { JsonArray jsonEvents = new JsonParser().parse(s).getAsJsonArray();
JSONArray jsonEvents = new JSONArray(s); long lastId = 0;
long lastId = 0;
for (int i = 0; i < jsonEvents.length(); i++) { for (int i = 0; i < jsonEvents.size(); i++) {
JSONObject json = jsonEvents.getJSONObject(i); JsonObject json = jsonEvents.get(i).getAsJsonObject();
String type = json.getString("type"); String type = json.get("type").getAsString();
long id = json.getLong("id"); long id = json.get("id").getAsLong();
if (lastId < id) if (lastId < id)
lastId = id; lastId = id;
JSONObject data = json.optJSONObject("data"); JsonObject data = null;
if (json.has("data"))
data = json.get("data").getAsJsonObject();
// Add folder path to data. // Add folder path to data.
if (data != null && data.has("folder")) { if (data != null && data.has("folder")) {
String folder = data.getString("folder"); String folder = data.get("folder").getAsString();
String folderPath = getPathForFolder(folder); String folderPath = getPathForFolder(folder);
data.put("folderpath", folderPath); data.addProperty("folderpath", folderPath);
}
listener.onEvent(type, data);
} }
listener.onDone(lastId); listener.onEvent(type, data);
}
catch (JSONException e) {
Log.w(TAG, "Failed to read events", e);
} }
listener.onDone(lastId);
} }
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
"since", String.valueOf(sinceId), "limit", String.valueOf(limit)); "since", String.valueOf(sinceId), "limit", String.valueOf(limit));
@ -913,21 +807,21 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener,
r.put("label", folder.label); r.put("label", folder.label);
r.put("id", folder.id); r.put("id", folder.id);
r.put("ignorePerms", true); r.put("ignorePerms", true);
r.put("type", (folder.readOnly) ? "readonly" : "readwrite"); r.put("type", folder.type);
JSONArray devices = new JSONArray(); JSONArray devices = new JSONArray();
for (String n : folder.deviceIds) { for (String n : folder.getDevices()) {
JSONObject element = new JSONObject(); JSONObject element = new JSONObject();
element.put("deviceID", n); element.put("deviceID", n);
devices.put(element); devices.put(element);
} }
r.put("devices", devices); r.put("devices", devices);
JSONObject versioning = new JSONObject(); JSONObject versioning = new JSONObject();
versioning.put("type", folder.versioning.getType()); versioning.put("type", folder.versioning.type);
JSONObject params = new JSONObject(); JSONObject params = new JSONObject();
versioning.put("params", params); versioning.put("params", params);
for (String key : folder.versioning.getParams().keySet()) { for (String key : folder.versioning.params.keySet()) {
params.put(key, folder.versioning.getParams().get(key)); params.put(key, folder.versioning.params.get(key));
} }
r.put("rescanIntervalS", folder.rescanIntervalS); r.put("rescanIntervalS", folder.rescanIntervalS);
r.put("versioning", versioning); r.put("versioning", versioning);
@ -1002,16 +896,13 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener,
if (s == null) if (s == null)
return; return;
String normalized = null; JsonObject json = new JsonParser().parse(s).getAsJsonObject();
String error = null; JsonElement id = json.get("id");
try { JsonElement error = json.get("error");
JSONObject json = new JSONObject(s); if (id != null)
normalized = json.optString("id", null); listener.onDeviceIdNormalized(id.getAsString(), null);
error = json.optString("error", null); if (error != null)
} catch (JSONException e) { listener.onDeviceIdNormalized(null, error.getAsString());
Log.w(TAG, "Failed to parse normalized device ID JSON", e);
}
listener.onDeviceIdNormalized(normalized, error);
} }
}.execute("id", id); }.execute("id", id);
} }

View file

@ -23,6 +23,7 @@ import android.widget.Toast;
import com.nutomic.syncthingandroid.R; import com.nutomic.syncthingandroid.R;
import com.nutomic.syncthingandroid.activities.MainActivity; import com.nutomic.syncthingandroid.activities.MainActivity;
import com.nutomic.syncthingandroid.http.PollWebGuiAvailableTask; import com.nutomic.syncthingandroid.http.PollWebGuiAvailableTask;
import com.nutomic.syncthingandroid.model.Folder;
import com.nutomic.syncthingandroid.util.ConfigXml; import com.nutomic.syncthingandroid.util.ConfigXml;
import com.nutomic.syncthingandroid.util.FolderObserver; import com.nutomic.syncthingandroid.util.FolderObserver;
import com.android.PRNGFixes; import com.android.PRNGFixes;
@ -350,7 +351,7 @@ public class SyncthingService extends Service implements
mCurrentState = State.ACTIVE; mCurrentState = State.ACTIVE;
onApiChange(); onApiChange();
new Thread(() -> { new Thread(() -> {
for (RestApi.Folder r : mApi.getFolders()) { for (Folder r : mApi.getFolders()) {
try { try {
mObservers.add(new FolderObserver(mApi, r)); mObservers.add(new FolderObserver(mApi, r));
} catch (FolderObserver.FolderNotExistingException e) { } catch (FolderObserver.FolderNotExistingException e) {

View file

@ -3,6 +3,7 @@ package com.nutomic.syncthingandroid.util;
import android.os.FileObserver; import android.os.FileObserver;
import android.util.Log; import android.util.Log;
import com.nutomic.syncthingandroid.model.Folder;
import com.nutomic.syncthingandroid.syncthing.RestApi; import com.nutomic.syncthingandroid.syncthing.RestApi;
import java.io.File; import java.io.File;
@ -17,7 +18,7 @@ public class FolderObserver extends FileObserver {
private final OnFolderFileChangeListener mListener; private final OnFolderFileChangeListener mListener;
private final RestApi.Folder mFolder; private final Folder mFolder;
private final String mPath; private final String mPath;
@ -27,7 +28,7 @@ public class FolderObserver extends FileObserver {
public void onFolderFileChange(String folderId, String relativePath); public void onFolderFileChange(String folderId, String relativePath);
} }
public FolderObserver(OnFolderFileChangeListener listener, RestApi.Folder folder) public FolderObserver(OnFolderFileChangeListener listener, Folder folder)
throws FolderNotExistingException { throws FolderNotExistingException {
this(listener, folder, ""); this(listener, folder, "");
} }
@ -53,7 +54,7 @@ public class FolderObserver extends FileObserver {
* @param folder The folder where this folder belongs to. * @param folder The folder where this folder belongs to.
* @param path path to the monitored folder, relative to folder root. * @param path path to the monitored folder, relative to folder root.
*/ */
private FolderObserver(OnFolderFileChangeListener listener, RestApi.Folder folder, String path) private FolderObserver(OnFolderFileChangeListener listener, Folder folder, String path)
throws FolderNotExistingException { throws FolderNotExistingException {
super(folder.path + "/" + path, super(folder.path + "/" + path,
ATTRIB | CLOSE_WRITE | CREATE | DELETE | DELETE_SELF | MOVED_FROM | ATTRIB | CLOSE_WRITE | CREATE | DELETE | DELETE_SELF | MOVED_FROM |

View file

@ -12,6 +12,7 @@ import android.widget.TextView;
import com.nutomic.syncthingandroid.BuildConfig; import com.nutomic.syncthingandroid.BuildConfig;
import com.nutomic.syncthingandroid.R; import com.nutomic.syncthingandroid.R;
import com.nutomic.syncthingandroid.model.Folder;
import com.nutomic.syncthingandroid.syncthing.RestApi; import com.nutomic.syncthingandroid.syncthing.RestApi;
import java.util.HashMap; import java.util.HashMap;
@ -23,7 +24,7 @@ import static com.nutomic.syncthingandroid.syncthing.RestApi.readableFileSize;
/** /**
* Generates item views for folder items. * Generates item views for folder items.
*/ */
public class FoldersAdapter extends ArrayAdapter<RestApi.Folder> public class FoldersAdapter extends ArrayAdapter<Folder>
implements RestApi.OnReceiveModelListener { implements RestApi.OnReceiveModelListener {
private final HashMap<String, RestApi.Model> mModels = new HashMap<>(); private final HashMap<String, RestApi.Model> mModels = new HashMap<>();
@ -47,7 +48,7 @@ public class FoldersAdapter extends ArrayAdapter<RestApi.Folder>
TextView size = (TextView) convertView.findViewById(R.id.size); TextView size = (TextView) convertView.findViewById(R.id.size);
TextView invalid = (TextView) convertView.findViewById(R.id.invalid); TextView invalid = (TextView) convertView.findViewById(R.id.invalid);
RestApi.Folder folder = getItem(position); Folder folder = getItem(position);
RestApi.Model model = mModels.get(folder.id); RestApi.Model model = mModels.get(folder.id);
label.setText(TextUtils.isEmpty(folder.label) ? folder.id : folder.label); label.setText(TextUtils.isEmpty(folder.label) ? folder.id : folder.label);
state.setTextColor(ContextCompat.getColor(getContext(), R.color.text_green)); state.setTextColor(ContextCompat.getColor(getContext(), R.color.text_green));