mirror of
https://github.com/syncthing/syncthing-android.git
synced 2024-11-29 15:51:17 +00:00
* ENABLE_TEST_DATA * http/GetRequest: Add URI_SYSTEM_DISCOVERY * Add model/DiscoveredDevice * Add RestApi#getDiscoveredDevices (fixes #305) * Add DeviceActivity#asyncQueryDiscoveredDevices in onServiceConnected (fixes #305) * Add strings * Add layout: item_discovered_device_form * Add discoveredDevicesTitle, discoveredDevicesContainer to "add device" dialog (fixes #305) * Revert "ENABLE_TEST_DATA" This reverts commit b2efe73b9b4f7e9d4db8cc50cb48a5422f78c084. * Fix lint error * Updated de translation
This commit is contained in:
parent
f5bb5473e6
commit
1163b1ec83
8 changed files with 189 additions and 0 deletions
|
@ -14,11 +14,15 @@ 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.util.TypedValue;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
import android.widget.CompoundButton;
|
import android.widget.CompoundButton;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
@ -29,6 +33,7 @@ import com.google.zxing.integration.android.IntentResult;
|
||||||
import com.nutomic.syncthingandroid.R;
|
import com.nutomic.syncthingandroid.R;
|
||||||
import com.nutomic.syncthingandroid.model.Connections;
|
import com.nutomic.syncthingandroid.model.Connections;
|
||||||
import com.nutomic.syncthingandroid.model.Device;
|
import com.nutomic.syncthingandroid.model.Device;
|
||||||
|
import com.nutomic.syncthingandroid.model.DiscoveredDevice;
|
||||||
import com.nutomic.syncthingandroid.service.Constants;
|
import com.nutomic.syncthingandroid.service.Constants;
|
||||||
import com.nutomic.syncthingandroid.service.RestApi;
|
import com.nutomic.syncthingandroid.service.RestApi;
|
||||||
import com.nutomic.syncthingandroid.service.SyncthingService;
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
|
@ -42,12 +47,19 @@ import com.nutomic.syncthingandroid.util.Util;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static android.support.v4.view.MarginLayoutParamsCompat.setMarginEnd;
|
||||||
|
import static android.support.v4.view.MarginLayoutParamsCompat.setMarginStart;
|
||||||
import static android.text.TextUtils.isEmpty;
|
import static android.text.TextUtils.isEmpty;
|
||||||
|
import static android.util.TypedValue.COMPLEX_UNIT_DIP;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN;
|
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN;
|
||||||
|
import static android.view.Gravity.CENTER_VERTICAL;
|
||||||
|
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||||
|
|
||||||
import static com.nutomic.syncthingandroid.util.Compression.METADATA;
|
import static com.nutomic.syncthingandroid.util.Compression.METADATA;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,6 +87,8 @@ public class DeviceActivity extends SyncthingActivity {
|
||||||
|
|
||||||
private Device mDevice;
|
private Device mDevice;
|
||||||
private EditText mEditDeviceId;
|
private EditText mEditDeviceId;
|
||||||
|
private TextView mDiscoveredDevicesTitle;
|
||||||
|
private ViewGroup mDiscoveredDevicesContainer;
|
||||||
private View mShowDeviceIdContainer;
|
private View mShowDeviceIdContainer;
|
||||||
private EditText mShowDeviceId;
|
private EditText mShowDeviceId;
|
||||||
private View mQrButton;
|
private View mQrButton;
|
||||||
|
@ -182,6 +196,8 @@ public class DeviceActivity extends SyncthingActivity {
|
||||||
setTitle(mIsCreateMode ? R.string.add_device : R.string.edit_device);
|
setTitle(mIsCreateMode ? R.string.add_device : R.string.edit_device);
|
||||||
|
|
||||||
mEditDeviceId = findViewById(R.id.editDeviceId);
|
mEditDeviceId = findViewById(R.id.editDeviceId);
|
||||||
|
mDiscoveredDevicesTitle = findViewById(R.id.discoveredDevicesTitle);
|
||||||
|
mDiscoveredDevicesContainer = findViewById(R.id.discoveredDevicesContainer);
|
||||||
mShowDeviceIdContainer = findViewById(R.id.showDeviceIdContainer);
|
mShowDeviceIdContainer = findViewById(R.id.showDeviceIdContainer);
|
||||||
mShowDeviceId = findViewById(R.id.showDeviceId);
|
mShowDeviceId = findViewById(R.id.showDeviceId);
|
||||||
mQrButton = findViewById(R.id.qrButton);
|
mQrButton = findViewById(R.id.qrButton);
|
||||||
|
@ -276,6 +292,9 @@ public class DeviceActivity extends SyncthingActivity {
|
||||||
RestApi restApi = syncthingService.getApi();
|
RestApi restApi = syncthingService.getApi();
|
||||||
if (restApi != null) {
|
if (restApi != null) {
|
||||||
restApi.getConnections(this::onReceiveConnections);
|
restApi.getConnections(this::onReceiveConnections);
|
||||||
|
if (mIsCreateMode) {
|
||||||
|
asyncQueryDiscoveredDevices(restApi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -615,4 +634,83 @@ public class DeviceActivity extends SyncthingActivity {
|
||||||
.create();
|
.create();
|
||||||
mDiscardDialog.show();
|
mDiscardDialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform asynchronous query via REST to retrieve locally discovered devices.
|
||||||
|
* Precondition:
|
||||||
|
* restApi != null
|
||||||
|
* mIsCreateMode == true
|
||||||
|
*/
|
||||||
|
private void asyncQueryDiscoveredDevices(RestApi restApi) {
|
||||||
|
if (!restApi.isConfigLoaded()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
restApi.getDiscoveredDevices(this::onReceiveDiscoveredDevices);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback after {@link asyncQueryDiscoveredDevices}.
|
||||||
|
* Precondition:
|
||||||
|
* mIsCreateMode == true
|
||||||
|
*/
|
||||||
|
private void onReceiveDiscoveredDevices(Map<String, DiscoveredDevice> discoveredDevices) {
|
||||||
|
if (discoveredDevices == null) {
|
||||||
|
Log.e(TAG, "onReceiveDiscoveredDevices: discoveredDevices == null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mDiscoveredDevicesContainer.removeAllViews();
|
||||||
|
if (discoveredDevices.size() == 0) {
|
||||||
|
// No discovered devices.
|
||||||
|
int height = (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, 48, getResources().getDisplayMetrics());
|
||||||
|
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(WRAP_CONTENT, height);
|
||||||
|
int dividerInset = getResources().getDimensionPixelOffset(R.dimen.material_divider_inset);
|
||||||
|
int contentInset = getResources().getDimensionPixelOffset(R.dimen.abc_action_bar_content_inset_material);
|
||||||
|
setMarginStart(params, dividerInset);
|
||||||
|
setMarginEnd(params, contentInset);
|
||||||
|
TextView emptyView = new TextView(mDiscoveredDevicesContainer.getContext());
|
||||||
|
emptyView.setGravity(CENTER_VERTICAL);
|
||||||
|
emptyView.setText(R.string.discovered_device_list_empty);
|
||||||
|
mDiscoveredDevicesContainer.addView(emptyView, params);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String deviceId : discoveredDevices.keySet()) {
|
||||||
|
if (deviceId != null) {
|
||||||
|
// Get device address.
|
||||||
|
String readableAddresses = "";
|
||||||
|
DiscoveredDevice discoveredDevice = discoveredDevices.get(deviceId);
|
||||||
|
if (discoveredDevice != null && discoveredDevice.addresses != null) {
|
||||||
|
readableAddresses = TextUtils.join(", ", discoveredDevice.addresses);
|
||||||
|
// Log.v(TAG, "onReceiveDiscoveredDevices: deviceID = '" + deviceId + "' has addresses '" + readableAddresses + "'");
|
||||||
|
}
|
||||||
|
String caption = deviceId + (TextUtils.isEmpty(readableAddresses) ? "" : " (" + readableAddresses + ")");
|
||||||
|
LayoutInflater inflater = getLayoutInflater();
|
||||||
|
inflater.inflate(R.layout.item_discovered_device_form, mDiscoveredDevicesContainer);
|
||||||
|
TextView deviceIdView = (TextView) mDiscoveredDevicesContainer.getChildAt(mDiscoveredDevicesContainer.getChildCount()-1);
|
||||||
|
deviceIdView.setOnClickListener(null);
|
||||||
|
deviceIdView.setText(caption);
|
||||||
|
deviceIdView.setTag(deviceId);
|
||||||
|
deviceIdView.setOnClickListener(v -> onDeviceIdViewClick(v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If "mEditDeviceId" already contains content, don't show local discovery results.
|
||||||
|
* This also suppresses the results being shown a second time after the user chose a
|
||||||
|
* deviceId from the list and rotated the screen.
|
||||||
|
*/
|
||||||
|
mDiscoveredDevicesTitle.setVisibility(TextUtils.isEmpty(mEditDeviceId.getText()) ? View.VISIBLE : View.GONE);
|
||||||
|
mDiscoveredDevicesContainer.setVisibility(TextUtils.isEmpty(mEditDeviceId.getText()) ? View.VISIBLE : View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the deviceId from TextView to "device_id" EditText.
|
||||||
|
* Hides the "mDiscoveredDevicesContainer" view afterwards.
|
||||||
|
*/
|
||||||
|
private void onDeviceIdViewClick(View view) {
|
||||||
|
mEditDeviceId.setText((String) view.getTag());
|
||||||
|
mDiscoveredDevicesTitle.setVisibility(View.GONE);
|
||||||
|
mDiscoveredDevicesContainer.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ public class GetRequest extends ApiRequest {
|
||||||
|
|
||||||
public static final String URI_CONFIG = "/rest/system/config";
|
public static final String URI_CONFIG = "/rest/system/config";
|
||||||
public static final String URI_DEBUG = "/rest/system/debug";
|
public static final String URI_DEBUG = "/rest/system/debug";
|
||||||
|
public static final String URI_SYSTEM_DISCOVERY = "/rest/system/discovery";
|
||||||
public static final String URI_VERSION = "/rest/system/version";
|
public static final String URI_VERSION = "/rest/system/version";
|
||||||
public static final String URI_SYSTEM_STATUS = "/rest/system/status";
|
public static final String URI_SYSTEM_STATUS = "/rest/system/status";
|
||||||
public static final String URI_CONNECTIONS = "/rest/system/connections";
|
public static final String URI_CONNECTIONS = "/rest/system/connections";
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.nutomic.syncthingandroid.model;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This receives the deserialization result of the URI_SYSTEM_DISCOVERY query.
|
||||||
|
*
|
||||||
|
* JSON result example
|
||||||
|
* {
|
||||||
|
* "2MY7NNQ-IRBZIFP-B2V574Y-AX6FNIP-55VGH5H-GUD3RFV-K2RXX6P-XXXXXX":
|
||||||
|
* {
|
||||||
|
* "addresses":
|
||||||
|
* [
|
||||||
|
* "tcp4://192.168.178.10:40001"
|
||||||
|
* ]
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DiscoveredDevice {
|
||||||
|
public String[] addresses;
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ import com.nutomic.syncthingandroid.model.Completion;
|
||||||
import com.nutomic.syncthingandroid.model.CompletionInfo;
|
import com.nutomic.syncthingandroid.model.CompletionInfo;
|
||||||
import com.nutomic.syncthingandroid.model.Connections;
|
import com.nutomic.syncthingandroid.model.Connections;
|
||||||
import com.nutomic.syncthingandroid.model.Device;
|
import com.nutomic.syncthingandroid.model.Device;
|
||||||
|
import com.nutomic.syncthingandroid.model.DiscoveredDevice;
|
||||||
import com.nutomic.syncthingandroid.model.DiskEvent;
|
import com.nutomic.syncthingandroid.model.DiskEvent;
|
||||||
import com.nutomic.syncthingandroid.model.Event;
|
import com.nutomic.syncthingandroid.model.Event;
|
||||||
import com.nutomic.syncthingandroid.model.Folder;
|
import com.nutomic.syncthingandroid.model.Folder;
|
||||||
|
@ -618,6 +619,23 @@ public class RestApi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests locally discovered devices.
|
||||||
|
*/
|
||||||
|
public void getDiscoveredDevices(OnResultListener1<Map<String, DiscoveredDevice>> listener) {
|
||||||
|
new GetRequest(mContext, mUrl, GetRequest.URI_SYSTEM_DISCOVERY, mApiKey,
|
||||||
|
null, result -> {
|
||||||
|
Map<String, DiscoveredDevice> discoveredDevices = mGson.fromJson(result, new TypeToken<Map<String, DiscoveredDevice>>(){}.getType());
|
||||||
|
if (ENABLE_TEST_DATA) {
|
||||||
|
DiscoveredDevice fakeDiscoveredDevice = new DiscoveredDevice();
|
||||||
|
fakeDiscoveredDevice.addresses = new String[]{"tcp4://192.168.178.10:40004"};
|
||||||
|
discoveredDevices.put("ZOK75WR-W3XWWUZ-NNLXV7V-DUYKVWA-SSPD7OH-3QYOZBY-SBH3N2Y-IAVJ4QH", fakeDiscoveredDevice);
|
||||||
|
discoveredDevices.put("ZPUZOWC-SUCJILE-ITNLBLL-MHBWJG5-46QM47Y-CDTQT3M-IA4RSJV-7BYA7QA", fakeDiscoveredDevice);
|
||||||
|
}
|
||||||
|
listener.onResult(discoveredDevices);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests ignore list for given folder.
|
* Requests ignore list for given folder.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -56,6 +56,26 @@
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/Widget.Syncthing.TextView.Label.Details"
|
||||||
|
android:id="@+id/discoveredDevicesTitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:drawableLeft="@drawable/ic_device_hub_black_24dp_active"
|
||||||
|
android:drawableStart="@drawable/ic_device_hub_black_24dp_active"
|
||||||
|
android:focusable="false"
|
||||||
|
android:text="@string/discovered_devices_title"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/discoveredDevicesContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:focusable="false"
|
||||||
|
android:visibility="gone">
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- Option 2: Show or copy device ID -->
|
<!-- Option 2: Show or copy device ID -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/showDeviceIdContainer"
|
android:id="@+id/showDeviceIdContainer"
|
||||||
|
|
18
app/src/main/res/layout/item_discovered_device_form.xml
Normal file
18
app/src/main/res/layout/item_discovered_device_form.xml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/device_button"
|
||||||
|
style="@style/Widget.Syncthing.TextView.Label.Details.DeviceList"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="@dimen/material_divider_inset"
|
||||||
|
android:layout_marginStart="@dimen/material_divider_inset"
|
||||||
|
android:layout_marginEnd="@dimen/abc_action_bar_content_inset_material"
|
||||||
|
android:layout_marginRight="@dimen/abc_action_bar_content_inset_material"
|
||||||
|
android:clickable="true"
|
||||||
|
android:drawableEnd="@drawable/ic_content_copy_black_24dp"
|
||||||
|
android:drawableRight="@drawable/ic_content_copy_black_24dp"
|
||||||
|
android:focusable="true"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Caption"
|
||||||
|
tools:ignore="RtlHardcoded,RtlSymmetry"
|
||||||
|
tools:text="ASD1ASD-ASD1ASD-ASD1ASD-ASD1ASD-ASD1ASD-ASD1ASD-ASD1ASD-ASD1ASD" />
|
|
@ -257,6 +257,12 @@ Bitte melden Sie auftretende Probleme via GitHub.</string>
|
||||||
<!-- Setting title -->
|
<!-- Setting title -->
|
||||||
<string name="device_id">Geräte-ID</string>
|
<string name="device_id">Geräte-ID</string>
|
||||||
|
|
||||||
|
<!-- Status title -->
|
||||||
|
<string name="discovered_devices_title">Gefundene Geräte - Tippe zur Auswahl</string>
|
||||||
|
|
||||||
|
<!-- Status text -->
|
||||||
|
<string name="discovered_device_list_empty">Die lokale Geräteerkennung hat im lokalen Netzwerk keine Geräte gefunden.</string>
|
||||||
|
|
||||||
<!-- Setting title -->
|
<!-- Setting title -->
|
||||||
<string name="name">Name</string>
|
<string name="name">Name</string>
|
||||||
|
|
||||||
|
|
|
@ -260,6 +260,12 @@ Please report any problems you encounter via Github.</string>
|
||||||
<!-- Setting title -->
|
<!-- Setting title -->
|
||||||
<string name="device_id">Device ID</string>
|
<string name="device_id">Device ID</string>
|
||||||
|
|
||||||
|
<!-- Status title -->
|
||||||
|
<string name="discovered_devices_title">Discovered devices - Tap to select</string>
|
||||||
|
|
||||||
|
<!-- Status text -->
|
||||||
|
<string name="discovered_device_list_empty">Local discovery didn\'t find any devices on the local network.</string>
|
||||||
|
|
||||||
<!-- Setting title -->
|
<!-- Setting title -->
|
||||||
<string name="name">Name</string>
|
<string name="name">Name</string>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue