mirror of
https://github.com/syncthing/syncthing-android.git
synced 2024-12-01 16:51:16 +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.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
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;
|
||||
|
||||
|
@ -29,6 +33,7 @@ import com.google.zxing.integration.android.IntentResult;
|
|||
import com.nutomic.syncthingandroid.R;
|
||||
import com.nutomic.syncthingandroid.model.Connections;
|
||||
import com.nutomic.syncthingandroid.model.Device;
|
||||
import com.nutomic.syncthingandroid.model.DiscoveredDevice;
|
||||
import com.nutomic.syncthingandroid.service.Constants;
|
||||
import com.nutomic.syncthingandroid.service.RestApi;
|
||||
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||
|
@ -42,12 +47,19 @@ import com.nutomic.syncthingandroid.util.Util;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
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.util.TypedValue.COMPLEX_UNIT_DIP;
|
||||
import static android.view.View.VISIBLE;
|
||||
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;
|
||||
|
||||
/**
|
||||
|
@ -75,6 +87,8 @@ public class DeviceActivity extends SyncthingActivity {
|
|||
|
||||
private Device mDevice;
|
||||
private EditText mEditDeviceId;
|
||||
private TextView mDiscoveredDevicesTitle;
|
||||
private ViewGroup mDiscoveredDevicesContainer;
|
||||
private View mShowDeviceIdContainer;
|
||||
private EditText mShowDeviceId;
|
||||
private View mQrButton;
|
||||
|
@ -182,6 +196,8 @@ public class DeviceActivity extends SyncthingActivity {
|
|||
setTitle(mIsCreateMode ? R.string.add_device : R.string.edit_device);
|
||||
|
||||
mEditDeviceId = findViewById(R.id.editDeviceId);
|
||||
mDiscoveredDevicesTitle = findViewById(R.id.discoveredDevicesTitle);
|
||||
mDiscoveredDevicesContainer = findViewById(R.id.discoveredDevicesContainer);
|
||||
mShowDeviceIdContainer = findViewById(R.id.showDeviceIdContainer);
|
||||
mShowDeviceId = findViewById(R.id.showDeviceId);
|
||||
mQrButton = findViewById(R.id.qrButton);
|
||||
|
@ -276,6 +292,9 @@ public class DeviceActivity extends SyncthingActivity {
|
|||
RestApi restApi = syncthingService.getApi();
|
||||
if (restApi != null) {
|
||||
restApi.getConnections(this::onReceiveConnections);
|
||||
if (mIsCreateMode) {
|
||||
asyncQueryDiscoveredDevices(restApi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -615,4 +634,83 @@ public class DeviceActivity extends SyncthingActivity {
|
|||
.create();
|
||||
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_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_SYSTEM_STATUS = "/rest/system/status";
|
||||
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.Connections;
|
||||
import com.nutomic.syncthingandroid.model.Device;
|
||||
import com.nutomic.syncthingandroid.model.DiscoveredDevice;
|
||||
import com.nutomic.syncthingandroid.model.DiskEvent;
|
||||
import com.nutomic.syncthingandroid.model.Event;
|
||||
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.
|
||||
*/
|
||||
|
|
|
@ -56,6 +56,26 @@
|
|||
|
||||
</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 -->
|
||||
<LinearLayout
|
||||
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 -->
|
||||
<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 -->
|
||||
<string name="name">Name</string>
|
||||
|
||||
|
|
|
@ -260,6 +260,12 @@ Please report any problems you encounter via Github.</string>
|
|||
<!-- Setting title -->
|
||||
<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 -->
|
||||
<string name="name">Name</string>
|
||||
|
||||
|
|
Loading…
Reference in a new issue