mirror of
https://github.com/syncthing/syncthing-android.git
synced 2024-12-26 12:51:28 +00:00
Avoid the same node being added multiple times (fixes #65).
When trying to add a node that already exists, the existing node is edited instead.
This commit is contained in:
parent
6a85fae8ca
commit
64bad6d0fe
9 changed files with 112 additions and 47 deletions
|
@ -11,13 +11,11 @@ import android.os.Bundle;
|
|||
import android.os.Environment;
|
||||
import android.os.IBinder;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
|
@ -31,9 +29,7 @@ import com.nutomic.syncthingandroid.syncthing.SyncthingServiceBinder;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* Activity that allows selecting a directory in the local file system.
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
package com.nutomic.syncthingandroid.gui;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.ActionBarDrawerToggle;
|
||||
import android.support.v4.app.Fragment;
|
||||
|
@ -15,7 +11,6 @@ import android.view.MotionEvent;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.nutomic.syncthingandroid.R;
|
||||
import com.nutomic.syncthingandroid.syncthing.RestApi;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package com.nutomic.syncthingandroid.gui;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.ActivityNotFoundException;
|
||||
|
@ -34,7 +33,8 @@ import java.util.Map;
|
|||
*/
|
||||
public class NodeSettingsActivity extends PreferenceActivity implements
|
||||
Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener,
|
||||
RestApi.OnReceiveConnectionsListener, SyncthingService.OnApiChangeListener {
|
||||
RestApi.OnReceiveConnectionsListener, SyncthingService.OnApiChangeListener,
|
||||
RestApi.OnNodeIdNormalizedListener {
|
||||
|
||||
public static final String ACTION_CREATE = "create";
|
||||
|
||||
|
@ -161,15 +161,16 @@ public class NodeSettingsActivity extends PreferenceActivity implements
|
|||
switch (item.getItemId()) {
|
||||
case R.id.create:
|
||||
if (mNode.NodeID.equals("")) {
|
||||
Toast.makeText(this, R.string.node_id_required, Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this, R.string.node_id_required, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
return true;
|
||||
}
|
||||
if (mNode.Name.equals("")) {
|
||||
Toast.makeText(this, R.string.node_name_required, Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this, R.string.node_name_required, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
return true;
|
||||
}
|
||||
mSyncthingService.getApi().editNode(mNode, true, this);
|
||||
finish();
|
||||
mSyncthingService.getApi().editNode(mNode, this);
|
||||
return true;
|
||||
case R.id.share_node_id:
|
||||
RestApi.shareNodeId(this, mNode.NodeID);
|
||||
|
@ -255,7 +256,7 @@ public class NodeSettingsActivity extends PreferenceActivity implements
|
|||
*/
|
||||
private void nodeUpdated() {
|
||||
if (getIntent().getAction().equals(ACTION_EDIT)) {
|
||||
mSyncthingService.getApi().editNode(mNode, false, this);
|
||||
mSyncthingService.getApi().editNode(mNode, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -287,4 +288,22 @@ public class NodeSettingsActivity extends PreferenceActivity implements
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for {@link RestApi#editNode(RestApi.Node, RestApi.OnNodeIdNormalizedListener)}.
|
||||
* Displays an error message if present, or finishes the Activity on success in edit mode.
|
||||
*
|
||||
* @param normalizedId The normalized node ID, or null on error.
|
||||
* @param error An error message, or null on success.
|
||||
*/
|
||||
@Override
|
||||
public void onNodeIdNormalized(String normalizedId, String error) {
|
||||
if (error != null) {
|
||||
Toast.makeText(NodeSettingsActivity.this, error,
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
else if (getIntent().getAction().equals(ACTION_CREATE)) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,9 +3,7 @@ package com.nutomic.syncthingandroid.gui;
|
|||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.ListFragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
|
||||
|
|
|
@ -3,9 +3,7 @@ package com.nutomic.syncthingandroid.gui;
|
|||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.ListFragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
|
||||
import com.nutomic.syncthingandroid.R;
|
||||
|
|
|
@ -12,7 +12,6 @@ import android.view.View;
|
|||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.nutomic.syncthingandroid.R;
|
||||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
||||
|
|
|
@ -37,6 +37,8 @@ public class GetTask extends AsyncTask<String, Void, String> {
|
|||
|
||||
public static final String URI_MODEL = "/rest/model";
|
||||
|
||||
public static final String URI_NODEID = "/rest/nodeid";
|
||||
|
||||
/**
|
||||
* params[0] Syncthing hostname
|
||||
* params[1] URI to call
|
||||
|
|
|
@ -647,33 +647,56 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener {
|
|||
}
|
||||
|
||||
/**
|
||||
* Updates or creates the given node.
|
||||
* Updates or creates the given node, depending on whether it already exists.
|
||||
*
|
||||
* @param node Settings of the node to edit. To create a node, pass a non-existant node ID.
|
||||
* @param listener {@link OnNodeIdNormalizedListener} for the normalized node ID.
|
||||
*/
|
||||
public void editNode(Node node, boolean create, Activity activity) {
|
||||
try {
|
||||
JSONArray nodes = mConfig.getJSONArray("Nodes");
|
||||
JSONObject n = null;
|
||||
if (create) {
|
||||
n = new JSONObject();
|
||||
nodes.put(n);
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < nodes.length(); i++) {
|
||||
JSONObject json = nodes.getJSONObject(i);
|
||||
if (node.NodeID.equals(json.getString("NodeID"))) {
|
||||
n = nodes.getJSONObject(i);
|
||||
break;
|
||||
public void editNode(final Node node,
|
||||
final OnNodeIdNormalizedListener listener) {
|
||||
mSyncthingService.getApi().normalizeNodeId(node.NodeID,
|
||||
new RestApi.OnNodeIdNormalizedListener() {
|
||||
@Override
|
||||
public void onNodeIdNormalized(String normalizedId, String error) {
|
||||
listener.onNodeIdNormalized(normalizedId, error);
|
||||
if (normalizedId == null)
|
||||
return;
|
||||
|
||||
node.NodeID = normalizedId;
|
||||
// If the node already exists, just update it.
|
||||
boolean create = true;
|
||||
for (RestApi.Node n : getNodes()) {
|
||||
if (n.NodeID.equals(node.NodeID)) {
|
||||
create = false;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
JSONArray nodes = mConfig.getJSONArray("Nodes");
|
||||
JSONObject n = null;
|
||||
if (create) {
|
||||
n = new JSONObject();
|
||||
nodes.put(n);
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < nodes.length(); i++) {
|
||||
JSONObject json = nodes.getJSONObject(i);
|
||||
if (node.NodeID.equals(json.getString("NodeID"))) {
|
||||
n = nodes.getJSONObject(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
n.put("NodeID", node.NodeID);
|
||||
n.put("Name", node.Name);
|
||||
n.put("Addresses", listToJson(node.Addresses.split(" ")));
|
||||
configUpdated(mSyncthingService);
|
||||
}
|
||||
catch (JSONException e) {
|
||||
Log.w(TAG, "Failed to read nodes", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
n.put("NodeID", node.NodeID);
|
||||
n.put("Name", node.Name);
|
||||
n.put("Addresses", listToJson(node.Addresses.split(" ")));
|
||||
configUpdated(activity);
|
||||
}
|
||||
catch (JSONException e) {
|
||||
Log.w(TAG, "Failed to read nodes", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -781,6 +804,42 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener {
|
|||
return newArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Result listener for {@link #normalizeNodeId(String, OnNodeIdNormalizedListener)}.
|
||||
*/
|
||||
public interface OnNodeIdNormalizedListener {
|
||||
/**
|
||||
* On any call, exactly one parameter will be null.
|
||||
*
|
||||
* @param normalizedId The normalized node ID, or null on error.
|
||||
* @param error An error message, or null on success.
|
||||
*/
|
||||
public void onNodeIdNormalized(String normalizedId, String error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a given node ID.
|
||||
*/
|
||||
public void normalizeNodeId(String id, final OnNodeIdNormalizedListener listener) {
|
||||
new GetTask() {
|
||||
@Override
|
||||
protected void onPostExecute(String s) {
|
||||
super.onPostExecute(s);
|
||||
String normalized = null;
|
||||
String error = null;
|
||||
try {
|
||||
JSONObject json = new JSONObject(s);
|
||||
normalized = json.optString("id", null);
|
||||
error = json.optString("error", null);
|
||||
}
|
||||
catch (JSONException e) {
|
||||
Log.d(TAG, "Failed to parse normalized node ID JSON", e);
|
||||
}
|
||||
listener.onNodeIdNormalized(normalized, error);
|
||||
}
|
||||
}.execute(mUrl, GetTask.URI_NODEID, mApiKey, "id", id);
|
||||
}
|
||||
|
||||
public boolean isApiAvailable() {
|
||||
return mAvailableCount.get() == TOTAL_STARTUP_CALLS;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@ import java.io.InputStreamReader;
|
|||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Holds the native syncthing instance and provides an API to access it.
|
||||
|
|
Loading…
Reference in a new issue