mirror of
https://github.com/syncthing/syncthing-android.git
synced 2024-11-23 04:41:16 +00:00
* Wip adding dialog. * Wip adding ImageRequest functionality. * Got a text converted to a QrCode using the syncthing Api. * Dialog now shows device ID and QRCode. The dialog also keeps it state when the device rotates and the copy ID functionality has been moved to the dialog, from the drawer. * Moved share device ID functionality to the Device ID dialog. * Addressed code change requests and added improved dialog layout by @nutomic.
This commit is contained in:
parent
825a62b902
commit
ab88ca252b
8 changed files with 225 additions and 56 deletions
|
@ -12,6 +12,11 @@ import android.content.Intent;
|
|||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.media.Image;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
@ -36,7 +41,9 @@ import android.view.LayoutInflater;
|
|||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.nutomic.syncthingandroid.R;
|
||||
import com.nutomic.syncthingandroid.fragments.DeviceListFragment;
|
||||
|
@ -44,7 +51,13 @@ import com.nutomic.syncthingandroid.fragments.DrawerFragment;
|
|||
import com.nutomic.syncthingandroid.fragments.FolderListFragment;
|
||||
import com.nutomic.syncthingandroid.model.Options;
|
||||
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||
import com.nutomic.syncthingandroid.util.Util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -61,6 +74,9 @@ public class MainActivity extends SyncthingActivity
|
|||
private static final String TAG = "MainActivity";
|
||||
private static final String IS_SHOWING_RESTART_DIALOG = "RESTART_DIALOG_STATE";
|
||||
private static final String BATTERY_DIALOG_DISMISSED = "BATTERY_DIALOG_STATE";
|
||||
private static final String IS_QRCODE_DIALOG_DISPLAYED = "QRCODE_DIALOG_STATE";
|
||||
private static final String QRCODE_BITMAP_KEY = "QRCODE_BITMAP";
|
||||
private static final String DEVICEID_KEY = "DEVICEID";
|
||||
|
||||
/**
|
||||
* Time after first start when usage reporting dialog should be shown.
|
||||
|
@ -71,6 +87,7 @@ public class MainActivity extends SyncthingActivity
|
|||
|
||||
private AlertDialog mDisabledDialog;
|
||||
private AlertDialog mBatteryOptimizationsDialog;
|
||||
private AlertDialog mQrCodeDialog;
|
||||
private Dialog mRestartDialog;
|
||||
|
||||
private boolean mBatteryOptimizationDialogDismissed;
|
||||
|
@ -224,6 +241,9 @@ public class MainActivity extends SyncthingActivity
|
|||
showRestartDialog();
|
||||
}
|
||||
mBatteryOptimizationDialogDismissed = savedInstanceState.getBoolean(BATTERY_DIALOG_DISMISSED);
|
||||
if(savedInstanceState.getBoolean(IS_QRCODE_DIALOG_DISPLAYED)) {
|
||||
showQrCodeDialog(savedInstanceState.getString(DEVICEID_KEY), savedInstanceState.getParcelable(QRCODE_BITMAP_KEY));
|
||||
}
|
||||
} else {
|
||||
mFolderListFragment = new FolderListFragment();
|
||||
mDeviceListFragment = new DeviceListFragment();
|
||||
|
@ -276,6 +296,13 @@ public class MainActivity extends SyncthingActivity
|
|||
outState.putInt("currentTab", mViewPager.getCurrentItem());
|
||||
outState.putBoolean(BATTERY_DIALOG_DISMISSED, mBatteryOptimizationsDialog == null || !mBatteryOptimizationsDialog.isShowing());
|
||||
outState.putBoolean(IS_SHOWING_RESTART_DIALOG, mRestartDialog != null && mRestartDialog.isShowing());
|
||||
if(mQrCodeDialog != null && mQrCodeDialog.isShowing()) {
|
||||
outState.putBoolean(IS_QRCODE_DIALOG_DISPLAYED, true);
|
||||
ImageView qrCode = (ImageView) mQrCodeDialog.findViewById(R.id.qrcode_image_view);
|
||||
TextView deviceID = (TextView) mQrCodeDialog.findViewById(R.id.device_id);
|
||||
outState.putParcelable(QRCODE_BITMAP_KEY, ((BitmapDrawable) qrCode.getDrawable()).getBitmap());
|
||||
outState.putString(DEVICEID_KEY, deviceID.getText().toString());
|
||||
}
|
||||
if (mRestartDialog != null){
|
||||
mRestartDialog.cancel();
|
||||
}
|
||||
|
@ -332,6 +359,33 @@ public class MainActivity extends SyncthingActivity
|
|||
.create();
|
||||
}
|
||||
|
||||
public void showQrCodeDialog(String deviceId, Bitmap qrCode) {
|
||||
View qrCodeDialogView = this.getLayoutInflater().inflate(R.layout.dialog_qrcode, null);
|
||||
TextView deviceIdTextView = (TextView) qrCodeDialogView.findViewById(R.id.device_id);
|
||||
TextView shareDeviceIdTextView = (TextView) qrCodeDialogView.findViewById(R.id.actionShareId);
|
||||
ImageView qrCodeImageView = (ImageView) qrCodeDialogView.findViewById(R.id.qrcode_image_view);
|
||||
|
||||
deviceIdTextView.setText(deviceId);
|
||||
deviceIdTextView.setOnClickListener(v -> Util.copyDeviceId(this, deviceIdTextView.getText().toString()));
|
||||
shareDeviceIdTextView.setOnClickListener(v -> shareDeviceId(deviceId));
|
||||
qrCodeImageView.setImageBitmap(qrCode);
|
||||
|
||||
mQrCodeDialog = new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.device_id)
|
||||
.setView(qrCodeDialogView)
|
||||
.setPositiveButton(R.string.finish, null)
|
||||
.create();
|
||||
|
||||
mQrCodeDialog.show();
|
||||
}
|
||||
|
||||
private void shareDeviceId(String deviceId) {
|
||||
Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND);
|
||||
shareIntent.setType("text/plain");
|
||||
shareIntent.putExtra(android.content.Intent.EXTRA_TEXT, deviceId);
|
||||
startActivity(Intent.createChooser(shareIntent, "Share device ID with"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
return mDrawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
package com.nutomic.syncthingandroid.fragments;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.util.ArrayMap;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.nutomic.syncthingandroid.R;
|
||||
import com.nutomic.syncthingandroid.activities.MainActivity;
|
||||
import com.nutomic.syncthingandroid.activities.SettingsActivity;
|
||||
import com.nutomic.syncthingandroid.activities.WebGuiActivity;
|
||||
import com.nutomic.syncthingandroid.http.ImageGetRequest;
|
||||
import com.nutomic.syncthingandroid.model.Connections;
|
||||
import com.nutomic.syncthingandroid.model.SystemInfo;
|
||||
import com.nutomic.syncthingandroid.model.SystemVersion;
|
||||
|
@ -23,6 +25,8 @@ import com.nutomic.syncthingandroid.service.RestApi;
|
|||
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||
import com.nutomic.syncthingandroid.util.Util;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
@ -34,7 +38,6 @@ import java.util.TimerTask;
|
|||
*/
|
||||
public class DrawerFragment extends Fragment implements View.OnClickListener {
|
||||
|
||||
private TextView mDeviceId;
|
||||
private TextView mCpuUsage;
|
||||
private TextView mRamUsage;
|
||||
private TextView mDownload;
|
||||
|
@ -43,6 +46,8 @@ public class DrawerFragment extends Fragment implements View.OnClickListener {
|
|||
private TextView mVersion;
|
||||
private TextView mExitButton;
|
||||
|
||||
private String mDeviceId;
|
||||
|
||||
private Timer mTimer;
|
||||
|
||||
private MainActivity mActivity;
|
||||
|
@ -87,7 +92,6 @@ public class DrawerFragment extends Fragment implements View.OnClickListener {
|
|||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
mDeviceId = (TextView) view.findViewById(R.id.device_id);
|
||||
mCpuUsage = (TextView) view.findViewById(R.id.cpu_usage);
|
||||
mRamUsage = (TextView) view.findViewById(R.id.ram_usage);
|
||||
mDownload = (TextView) view.findViewById(R.id.download);
|
||||
|
@ -98,12 +102,12 @@ public class DrawerFragment extends Fragment implements View.OnClickListener {
|
|||
|
||||
view.findViewById(R.id.drawerActionWebGui)
|
||||
.setOnClickListener(this);
|
||||
view.findViewById(R.id.drawerActionShareId)
|
||||
.setOnClickListener(this);
|
||||
view.findViewById(R.id.drawerActionRestart)
|
||||
.setOnClickListener(this);
|
||||
view.findViewById(R.id.drawerActionSettings)
|
||||
.setOnClickListener(this);
|
||||
view.findViewById(R.id.drawerActionShowQrCode)
|
||||
.setOnClickListener(this);
|
||||
mExitButton.setOnClickListener(this);
|
||||
|
||||
updateExitButtonVisibility();
|
||||
|
@ -156,9 +160,7 @@ public class DrawerFragment extends Fragment implements View.OnClickListener {
|
|||
public void onReceiveSystemInfo(SystemInfo info) {
|
||||
if (getActivity() == null)
|
||||
return;
|
||||
|
||||
mDeviceId.setText(info.myID);
|
||||
mDeviceId.setOnClickListener(v -> Util.copyDeviceId(getActivity(), mDeviceId.getText().toString()));
|
||||
mDeviceId = info.myID;
|
||||
NumberFormat percentFormat = NumberFormat.getPercentInstance();
|
||||
percentFormat.setMaximumFractionDigits(2);
|
||||
mCpuUsage.setText(percentFormat.format(info.cpuPercent / 100));
|
||||
|
@ -193,6 +195,22 @@ public class DrawerFragment extends Fragment implements View.OnClickListener {
|
|||
mUpload.setText(Util.readableTransferRate(mActivity, c.outBits));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets QRCode and displays it in a Dialog.
|
||||
*/
|
||||
|
||||
private void showQrCode() {
|
||||
//The QRCode request takes one paramteer called "text", which is the text to be converted to a QRCode.
|
||||
String httpsCertPath = mActivity.getFilesDir() + "/" + SyncthingService.HTTPS_CERT_FILE;
|
||||
String apiKey = mActivity.getApi().getGui().apiKey;
|
||||
URL url = mActivity.getApi().getUrl();
|
||||
new ImageGetRequest(mActivity, url, ImageGetRequest.QR_CODE_GENERATOR, httpsCertPath,
|
||||
apiKey, ImmutableMap.of("text", mDeviceId),qrCodeBitmap -> {
|
||||
mActivity.showQrCodeDialog(mDeviceId, qrCodeBitmap);
|
||||
mActivity.closeDrawer();
|
||||
}, error -> Toast.makeText(mActivity, R.string.could_not_access_deviceid, Toast.LENGTH_SHORT).show());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
switch (v.getId()) {
|
||||
|
@ -200,13 +218,6 @@ public class DrawerFragment extends Fragment implements View.OnClickListener {
|
|||
startActivity(new Intent(mActivity, WebGuiActivity.class));
|
||||
mActivity.closeDrawer();
|
||||
break;
|
||||
case R.id.drawerActionShareId:
|
||||
Intent i = new Intent(android.content.Intent.ACTION_SEND);
|
||||
i.setType("text/plain");
|
||||
i.putExtra(android.content.Intent.EXTRA_TEXT, mDeviceId.getText());
|
||||
startActivity(Intent.createChooser(i, "Share device ID with"));
|
||||
mActivity.closeDrawer();
|
||||
break;
|
||||
case R.id.drawerActionSettings:
|
||||
startActivity(new Intent(mActivity, SettingsActivity.class));
|
||||
mActivity.closeDrawer();
|
||||
|
@ -220,6 +231,9 @@ public class DrawerFragment extends Fragment implements View.OnClickListener {
|
|||
mActivity.finish();
|
||||
mActivity.closeDrawer();
|
||||
break;
|
||||
case R.id.drawerActionShowQrCode:
|
||||
showQrCode();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,19 +3,27 @@ package com.nutomic.syncthingandroid.http;
|
|||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.android.volley.AuthFailureError;
|
||||
import com.android.volley.Request;
|
||||
import com.android.volley.RequestQueue;
|
||||
import com.android.volley.Response;
|
||||
import com.android.volley.VolleyError;
|
||||
import com.android.volley.toolbox.HurlStack;
|
||||
import com.android.volley.toolbox.ImageRequest;
|
||||
import com.android.volley.toolbox.JsonObjectRequest;
|
||||
import com.android.volley.toolbox.StringRequest;
|
||||
import com.android.volley.toolbox.Volley;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
@ -54,6 +62,10 @@ public abstract class ApiRequest {
|
|||
public void onSuccess(String result);
|
||||
}
|
||||
|
||||
public interface OnImageSuccessListener {
|
||||
public void onImageSuccess(Bitmap result);
|
||||
}
|
||||
|
||||
public interface OnErrorListener {
|
||||
public void onError(VolleyError error);
|
||||
}
|
||||
|
@ -119,6 +131,30 @@ public abstract class ApiRequest {
|
|||
getVolleyQueue().add(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the connection, then returns success status and response bitmap.
|
||||
*/
|
||||
protected void makeImageRequest(Uri uri, @Nullable OnImageSuccessListener imageListener,
|
||||
@Nullable OnErrorListener errorListener) {
|
||||
ImageRequest imageRequest = new ImageRequest(uri.toString(), bitmap -> {
|
||||
if (imageListener != null) {
|
||||
imageListener.onImageSuccess(bitmap);
|
||||
}
|
||||
}, 0, 0, ImageView.ScaleType.CENTER, Bitmap.Config.RGB_565, volleyError -> {
|
||||
if(errorListener != null) {
|
||||
errorListener.onError(volleyError);
|
||||
}
|
||||
Log.d(TAG, "onErrorResponse: " + volleyError);
|
||||
}) {
|
||||
@Override
|
||||
public Map<String, String> getHeaders() throws AuthFailureError {
|
||||
return ImmutableMap.of(HEADER_API_KEY, mApiKey);
|
||||
}
|
||||
};
|
||||
|
||||
getVolleyQueue().add(imageRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends {@link HurlStack}, uses {@link #getSslSocketFactory()} and disables hostname
|
||||
* verification.
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package com.nutomic.syncthingandroid.http;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.android.volley.Request;
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by jmintb on 27-06-17.
|
||||
*/
|
||||
|
||||
public class ImageGetRequest extends ApiRequest {
|
||||
|
||||
public static String QR_CODE_GENERATOR = "/qr/";
|
||||
|
||||
public ImageGetRequest(Context context, URL url, String path, String httpsCertPath, String apiKey,
|
||||
@Nullable Map<String, String> params, OnImageSuccessListener onSuccessListener, OnErrorListener onErrorListener) {
|
||||
super(context, url, path, httpsCertPath, apiKey);
|
||||
Map<String, String> safeParams = Optional.fromNullable(params).or(Collections.emptyMap());
|
||||
Uri uri = buildUri(safeParams);
|
||||
makeImageRequest(uri, onSuccessListener, onErrorListener);
|
||||
}
|
||||
}
|
|
@ -501,4 +501,8 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener,
|
|||
public void setRestartPostponed() {
|
||||
mRestartPostponed = true;
|
||||
}
|
||||
|
||||
public URL getUrl() {
|
||||
return mUrl;
|
||||
}
|
||||
}
|
||||
|
|
56
src/main/res/layout/dialog_qrcode.xml
Normal file
56
src/main/res/layout/dialog_qrcode.xml
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="12dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/device_id"
|
||||
style="@style/Widget.Syncthing.TextView.Label"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:padding="8dp"
|
||||
android:clickable="true"
|
||||
android:drawableEnd="@drawable/ic_content_copy_black_24dp"
|
||||
android:drawableRight="@drawable/ic_content_copy_black_24dp"
|
||||
android:focusable="true"
|
||||
android:fontFamily="monospace"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Caption"
|
||||
tools:text="ASD1ASD-ASD1ASD-ASD1ASD-ASD1ASD-ASD1ASD-ASD1ASD-ASD1ASD-ASD1ASD"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/actionShareId"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:padding="8dp"
|
||||
android:drawableRight="@drawable/ic_share_black_24dp"
|
||||
android:drawableEnd="@drawable/ic_share_black_24dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/qrcode_image_view"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="200dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
tools:src="@drawable/ic_launcher"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
|
@ -53,35 +53,6 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
style="@style/Widget.Syncthing.TextView.Label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="48dp"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="6dp"
|
||||
android:paddingTop="4dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/device_id"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
|
||||
|
||||
<TextView
|
||||
style="@style/Widget.Syncthing.TextView.Label"
|
||||
android:id="@+id/device_id"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="monospace"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Caption"
|
||||
android:drawableRight="@drawable/ic_content_copy_black_24dp"
|
||||
android:drawableEnd="@drawable/ic_content_copy_black_24dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true" />
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
|
@ -238,6 +209,17 @@
|
|||
android:layout_marginBottom="4dp"
|
||||
android:background="@drawable/list_divider" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/drawerActionShowQrCode"
|
||||
style="@style/Widget.Syncthing.TextView.Label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:clickable="true"
|
||||
android:drawableLeft="@drawable/ic_qrcode_black_24dp_active"
|
||||
android:drawableStart="@drawable/ic_qrcode_black_24dp_active"
|
||||
android:focusable="true"
|
||||
android:text="@string/show_device_id" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/drawerActionWebGui"
|
||||
style="@style/Widget.Syncthing.TextView.Label"
|
||||
|
@ -249,17 +231,6 @@
|
|||
android:clickable="true"
|
||||
android:focusable="true" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/drawerActionShareId"
|
||||
style="@style/Widget.Syncthing.TextView.Label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:drawableLeft="@drawable/ic_share_black_24dp"
|
||||
android:drawableStart="@drawable/ic_share_black_24dp"
|
||||
android:text="@string/share_device_id"
|
||||
android:clickable="true"
|
||||
android:focusable="true" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/drawerActionRestart"
|
||||
style="@style/Widget.Syncthing.TextView.Label"
|
||||
|
|
|
@ -595,4 +595,9 @@ Please report any problems you encounter via Github.</string>
|
|||
<string name="staggered_versioning_info">Maximum Age: %1$d \nVersions Path: %2$s</string>
|
||||
<string name="external_versioning_info">Command: %1$s</string>
|
||||
<string name="simple_versioning_info">Keep versions: %1$s</string>
|
||||
<string name="show_device_id">Show device ID</string>
|
||||
|
||||
<!-- error message if the deviceID/QRCode dialog for some reason cannot be displayed.-->
|
||||
<string name="could_not_access_deviceid">Could not access device ID.</string>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue