mirror of
https://github.com/syncthing/syncthing-android.git
synced 2025-02-03 15:51:37 +00:00
Add "Uptime" to status tab (#30)
This commit is contained in:
parent
b666ada7d2
commit
bbeecc8777
7 changed files with 91 additions and 46 deletions
|
@ -340,8 +340,8 @@ public class SettingsActivity extends SyncthingActivity {
|
||||||
mGlobalAnnounceServers.setText(joiner.join(mOptions.globalAnnounceServers));
|
mGlobalAnnounceServers.setText(joiner.join(mOptions.globalAnnounceServers));
|
||||||
mAddress.setText(mGui.address);
|
mAddress.setText(mGui.address);
|
||||||
mRestartOnWakeup.setChecked(mOptions.restartOnWakeup);
|
mRestartOnWakeup.setChecked(mOptions.restartOnWakeup);
|
||||||
mApi.getSystemInfo(systemInfo ->
|
mApi.getSystemStatus(systemStatus ->
|
||||||
mUrAccepted.setChecked(mOptions.isUsageReportingAccepted(systemInfo.urVersionMax)));
|
mUrAccepted.setChecked(mOptions.isUsageReportingAccepted(systemStatus.urVersionMax)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -439,9 +439,9 @@ public class SettingsActivity extends SyncthingActivity {
|
||||||
mOptions.restartOnWakeup = (boolean) o;
|
mOptions.restartOnWakeup = (boolean) o;
|
||||||
break;
|
break;
|
||||||
case "urAccepted":
|
case "urAccepted":
|
||||||
mApi.getSystemInfo(systemInfo -> {
|
mApi.getSystemStatus(systemStatus -> {
|
||||||
mOptions.urAccepted = ((boolean) o)
|
mOptions.urAccepted = ((boolean) o)
|
||||||
? systemInfo.urVersionMax
|
? systemStatus.urVersionMax
|
||||||
: Options.USAGE_REPORTING_DENIED;
|
: Options.USAGE_REPORTING_DENIED;
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -36,7 +36,7 @@ public class DrawerFragment extends Fragment implements SyncthingService.OnServi
|
||||||
|
|
||||||
private static final String TAG = "DrawerFragment";
|
private static final String TAG = "DrawerFragment";
|
||||||
|
|
||||||
private TextView mVersion;
|
private TextView mVersion = null;
|
||||||
private TextView mDrawerActionShowQrCode;
|
private TextView mDrawerActionShowQrCode;
|
||||||
private TextView mDrawerActionWebGui;
|
private TextView mDrawerActionWebGui;
|
||||||
private TextView mDrawerActionRestart;
|
private TextView mDrawerActionRestart;
|
||||||
|
@ -44,7 +44,7 @@ public class DrawerFragment extends Fragment implements SyncthingService.OnServi
|
||||||
private TextView mExitButton;
|
private TextView mExitButton;
|
||||||
|
|
||||||
private MainActivity mActivity;
|
private MainActivity mActivity;
|
||||||
private SharedPreferences sharedPreferences;
|
private SharedPreferences sharedPreferences = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServiceStateChange(SyncthingService.State currentState) {
|
public void onServiceStateChange(SyncthingService.State currentState) {
|
||||||
|
@ -55,6 +55,7 @@ public class DrawerFragment extends Fragment implements SyncthingService.OnServi
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
updateLabels();
|
||||||
updateButtons();
|
updateButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,9 +84,6 @@ public class DrawerFragment extends Fragment implements SyncthingService.OnServi
|
||||||
mDrawerActionSettings = view.findViewById(R.id.drawerActionSettings);
|
mDrawerActionSettings = view.findViewById(R.id.drawerActionSettings);
|
||||||
mExitButton = view.findViewById(R.id.drawerActionExit);
|
mExitButton = view.findViewById(R.id.drawerActionExit);
|
||||||
|
|
||||||
// Show static content.
|
|
||||||
mVersion.setText(sharedPreferences.getString(Constants.PREF_LAST_BINARY_VERSION, ""));
|
|
||||||
|
|
||||||
// Add listeners to buttons.
|
// Add listeners to buttons.
|
||||||
mDrawerActionShowQrCode.setOnClickListener(this);
|
mDrawerActionShowQrCode.setOnClickListener(this);
|
||||||
mDrawerActionWebGui.setOnClickListener(this);
|
mDrawerActionWebGui.setOnClickListener(this);
|
||||||
|
@ -93,6 +91,7 @@ public class DrawerFragment extends Fragment implements SyncthingService.OnServi
|
||||||
mDrawerActionSettings.setOnClickListener(this);
|
mDrawerActionSettings.setOnClickListener(this);
|
||||||
mExitButton.setOnClickListener(this);
|
mExitButton.setOnClickListener(this);
|
||||||
|
|
||||||
|
updateLabels();
|
||||||
updateButtons();
|
updateButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +100,15 @@ public class DrawerFragment extends Fragment implements SyncthingService.OnServi
|
||||||
super.onActivityCreated(savedInstanceState);
|
super.onActivityCreated(savedInstanceState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update static info labels.
|
||||||
|
*/
|
||||||
|
private void updateLabels() {
|
||||||
|
if (sharedPreferences != null && mVersion != null) {
|
||||||
|
mVersion.setText(sharedPreferences.getString(Constants.PREF_LAST_BINARY_VERSION, ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update action button availability.
|
* Update action button availability.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -21,13 +21,14 @@ import com.nutomic.syncthingandroid.activities.MainActivity;
|
||||||
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.Connections;
|
import com.nutomic.syncthingandroid.model.Connections;
|
||||||
import com.nutomic.syncthingandroid.model.SystemInfo;
|
import com.nutomic.syncthingandroid.model.SystemStatus;
|
||||||
import com.nutomic.syncthingandroid.model.SystemVersion;
|
import com.nutomic.syncthingandroid.model.SystemVersion;
|
||||||
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;
|
||||||
import com.nutomic.syncthingandroid.util.Util;
|
import com.nutomic.syncthingandroid.util.Util;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -67,6 +68,7 @@ public class StatusFragment extends ListFragment implements SyncthingService.OnS
|
||||||
private String mDownload = "";
|
private String mDownload = "";
|
||||||
private String mUpload = "";
|
private String mUpload = "";
|
||||||
private String mAnnounceServer = "";
|
private String mAnnounceServer = "";
|
||||||
|
private String mUptime = "";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUserVisibleHint(boolean isVisibleToUser)
|
public void setUserVisibleHint(boolean isVisibleToUser)
|
||||||
|
@ -173,12 +175,15 @@ public class StatusFragment extends ListFragment implements SyncthingService.OnS
|
||||||
// Add status holders refreshed by callbacks to the list.
|
// Add status holders refreshed by callbacks to the list.
|
||||||
if (mServiceState == SyncthingService.State.ACTIVE) {
|
if (mServiceState == SyncthingService.State.ACTIVE) {
|
||||||
synchronized (mStatusHolderLock) {
|
synchronized (mStatusHolderLock) {
|
||||||
if (!TextUtils.isEmpty(mCpuUsage)) {
|
if (!TextUtils.isEmpty(mUptime)) {
|
||||||
statusItems.add(getString(R.string.cpu_usage) + ": " + mCpuUsage);
|
statusItems.add(getString(R.string.uptime) + ": " + mUptime);
|
||||||
}
|
}
|
||||||
if (!TextUtils.isEmpty(mRamUsage)) {
|
if (!TextUtils.isEmpty(mRamUsage)) {
|
||||||
statusItems.add(getString(R.string.ram_usage) + ": " + mRamUsage);
|
statusItems.add(getString(R.string.ram_usage) + ": " + mRamUsage);
|
||||||
}
|
}
|
||||||
|
if (!TextUtils.isEmpty(mCpuUsage)) {
|
||||||
|
statusItems.add(getString(R.string.cpu_usage) + ": " + mCpuUsage);
|
||||||
|
}
|
||||||
if (!TextUtils.isEmpty(mDownload)) {
|
if (!TextUtils.isEmpty(mDownload)) {
|
||||||
statusItems.add(getString(R.string.download_title) + ": " + mDownload);
|
statusItems.add(getString(R.string.download_title) + ": " + mDownload);
|
||||||
}
|
}
|
||||||
|
@ -218,26 +223,42 @@ public class StatusFragment extends ListFragment implements SyncthingService.OnS
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log.v(TAG, "Invoking REST status queries");
|
Log.v(TAG, "Invoking REST status queries");
|
||||||
restApi.getSystemInfo(this::onReceiveSystemInfo);
|
restApi.getSystemStatus(this::onReceiveSystemStatus);
|
||||||
restApi.getConnections(this::onReceiveConnections);
|
restApi.getConnections(this::onReceiveConnections);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populates status holders with status received via {@link RestApi#getSystemInfo}.
|
* Populates status holders with status received via {@link RestApi#getSystemStatus}.
|
||||||
*/
|
*/
|
||||||
private void onReceiveSystemInfo(SystemInfo info) {
|
private void onReceiveSystemStatus(SystemStatus systemStatus) {
|
||||||
if (getActivity() == null) {
|
if (getActivity() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NumberFormat percentFormat = NumberFormat.getPercentInstance();
|
NumberFormat percentFormat = NumberFormat.getPercentInstance();
|
||||||
percentFormat.setMaximumFractionDigits(2);
|
percentFormat.setMaximumFractionDigits(2);
|
||||||
int announceTotal = info.discoveryMethods;
|
int announceTotal = systemStatus.discoveryMethods;
|
||||||
int announceConnected =
|
int announceConnected =
|
||||||
announceTotal - Optional.fromNullable(info.discoveryErrors).transform(Map::size).or(0);
|
announceTotal - Optional.fromNullable(systemStatus.discoveryErrors).transform(Map::size).or(0);
|
||||||
synchronized (mStatusHolderLock) {
|
synchronized (mStatusHolderLock) {
|
||||||
mCpuUsage = percentFormat.format(info.cpuPercent / 100);
|
mCpuUsage = (systemStatus.cpuPercent / 100 < 1) ? "" : percentFormat.format(systemStatus.cpuPercent / 100);
|
||||||
mRamUsage = Util.readableFileSize(mActivity, info.sys);
|
mRamUsage = Util.readableFileSize(mActivity, systemStatus.sys);
|
||||||
mAnnounceServer = String.format(Locale.getDefault(), "%1$d/%2$d", announceConnected, announceTotal);
|
mAnnounceServer = (announceTotal == 0) ?
|
||||||
|
"" :
|
||||||
|
String.format(Locale.getDefault(), "%1$d/%2$d", announceConnected, announceTotal);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate readable uptime.
|
||||||
|
*/
|
||||||
|
long uptimeDays = TimeUnit.SECONDS.toDays(systemStatus.uptime);
|
||||||
|
long uptimeHours = TimeUnit.SECONDS.toHours(systemStatus.uptime) - TimeUnit.DAYS.toHours(uptimeDays);
|
||||||
|
long uptimeMinutes = TimeUnit.SECONDS.toMinutes(systemStatus.uptime) - TimeUnit.HOURS.toMinutes(uptimeHours) - TimeUnit.DAYS.toMinutes(uptimeDays);
|
||||||
|
if (uptimeDays > 0) {
|
||||||
|
mUptime = String.format(Locale.getDefault(), "%dd %02dh %02dm", uptimeDays, uptimeHours, uptimeMinutes);
|
||||||
|
} else if (uptimeHours > 0) {
|
||||||
|
mUptime = String.format(Locale.getDefault(), "%dh %02dm", uptimeHours, uptimeMinutes);
|
||||||
|
} else {
|
||||||
|
mUptime = String.format(Locale.getDefault(), "%dm", uptimeMinutes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
updateStatus();
|
updateStatus();
|
||||||
}
|
}
|
||||||
|
@ -251,8 +272,12 @@ public class StatusFragment extends ListFragment implements SyncthingService.OnS
|
||||||
}
|
}
|
||||||
Connections.Connection c = connections.total;
|
Connections.Connection c = connections.total;
|
||||||
synchronized (mStatusHolderLock) {
|
synchronized (mStatusHolderLock) {
|
||||||
mDownload = Util.readableTransferRate(mActivity, c.inBits);
|
/**
|
||||||
mUpload = Util.readableTransferRate(mActivity, c.outBits);
|
* Hide the rates on the UI if they are lower than 1 KByte/sec. We don't like to
|
||||||
|
* bother the user looking at discovery or index exchange traffic.
|
||||||
|
*/
|
||||||
|
mDownload = (c.inBits / 8 < 1024) ? "" : Util.readableTransferRate(mActivity, c.inBits);
|
||||||
|
mUpload = (c.outBits / 8 < 1024) ? "" : Util.readableTransferRate(mActivity, c.outBits);
|
||||||
}
|
}
|
||||||
updateStatus();
|
updateStatus();
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,9 @@ 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_VERSION = "/rest/system/version";
|
public static final String URI_VERSION = "/rest/system/version";
|
||||||
public static final String URI_SYSTEM = "/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";
|
||||||
public static final String URI_STATUS = "/rest/db/status";
|
public static final String URI_DB_STATUS = "/rest/db/status";
|
||||||
public static final String URI_DEVICEID = "/rest/svc/deviceid";
|
public static final String URI_DEVICEID = "/rest/svc/deviceid";
|
||||||
public static final String URI_REPORT = "/rest/svc/report";
|
public static final String URI_REPORT = "/rest/svc/report";
|
||||||
public static final String URI_EVENTS = "/rest/events";
|
public static final String URI_EVENTS = "/rest/events";
|
||||||
|
|
|
@ -1,15 +1,24 @@
|
||||||
package com.nutomic.syncthingandroid.model;
|
package com.nutomic.syncthingandroid.model;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class SystemInfo {
|
/**
|
||||||
|
* REST API endpoint "/rest/system/status"
|
||||||
|
*/
|
||||||
|
public class SystemStatus {
|
||||||
public long alloc;
|
public long alloc;
|
||||||
public double cpuPercent;
|
public double cpuPercent;
|
||||||
|
public Map<String, Map<String, List<String>>> connectionServiceStatus;
|
||||||
|
public boolean discoveryEnabled;
|
||||||
|
public Map<String, String> discoveryErrors;
|
||||||
|
public int discoveryMethods;
|
||||||
public int goroutines;
|
public int goroutines;
|
||||||
public String myID;
|
public String myID;
|
||||||
|
public String pathSeparator;
|
||||||
|
public String startTime;
|
||||||
public long sys;
|
public long sys;
|
||||||
public boolean discoveryEnabled;
|
public String tilde;
|
||||||
public int discoveryMethods;
|
public long uptime;
|
||||||
public Map<String, String> discoveryErrors;
|
|
||||||
public int urVersionMax;
|
public int urVersionMax;
|
||||||
}
|
}
|
|
@ -31,7 +31,7 @@ import com.nutomic.syncthingandroid.model.Event;
|
||||||
import com.nutomic.syncthingandroid.model.Folder;
|
import com.nutomic.syncthingandroid.model.Folder;
|
||||||
import com.nutomic.syncthingandroid.model.FolderStatus;
|
import com.nutomic.syncthingandroid.model.FolderStatus;
|
||||||
import com.nutomic.syncthingandroid.model.Options;
|
import com.nutomic.syncthingandroid.model.Options;
|
||||||
import com.nutomic.syncthingandroid.model.SystemInfo;
|
import com.nutomic.syncthingandroid.model.SystemStatus;
|
||||||
import com.nutomic.syncthingandroid.model.SystemVersion;
|
import com.nutomic.syncthingandroid.model.SystemVersion;
|
||||||
import com.nutomic.syncthingandroid.service.Constants;
|
import com.nutomic.syncthingandroid.service.Constants;
|
||||||
|
|
||||||
|
@ -112,11 +112,11 @@ public class RestApi {
|
||||||
*/
|
*/
|
||||||
private Boolean asyncQueryConfigComplete = false;
|
private Boolean asyncQueryConfigComplete = false;
|
||||||
private Boolean asyncQueryVersionComplete = false;
|
private Boolean asyncQueryVersionComplete = false;
|
||||||
private Boolean asyncQuerySystemInfoComplete = false;
|
private Boolean asyncQuerySystemStatusComplete = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object that must be locked upon accessing the following variables:
|
* Object that must be locked upon accessing the following variables:
|
||||||
* asyncQueryConfigComplete, asyncQueryVersionComplete, asyncQuerySystemInfoComplete
|
* asyncQueryConfigComplete, asyncQueryVersionComplete, asyncQuerySystemStatusComplete
|
||||||
*/
|
*/
|
||||||
private final Object mAsyncQueryCompleteLock = new Object();
|
private final Object mAsyncQueryCompleteLock = new Object();
|
||||||
|
|
||||||
|
@ -163,7 +163,7 @@ public class RestApi {
|
||||||
synchronized (mAsyncQueryCompleteLock) {
|
synchronized (mAsyncQueryCompleteLock) {
|
||||||
asyncQueryVersionComplete = false;
|
asyncQueryVersionComplete = false;
|
||||||
asyncQueryConfigComplete = false;
|
asyncQueryConfigComplete = false;
|
||||||
asyncQuerySystemInfoComplete = false;
|
asyncQuerySystemStatusComplete = false;
|
||||||
}
|
}
|
||||||
new GetRequest(mContext, mUrl, GetRequest.URI_VERSION, mApiKey, null, result -> {
|
new GetRequest(mContext, mUrl, GetRequest.URI_VERSION, mApiKey, null, result -> {
|
||||||
JsonObject json = new JsonParser().parse(result).getAsJsonObject();
|
JsonObject json = new JsonParser().parse(result).getAsJsonObject();
|
||||||
|
@ -182,18 +182,18 @@ public class RestApi {
|
||||||
checkReadConfigFromRestApiCompleted();
|
checkReadConfigFromRestApiCompleted();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
getSystemInfo(info -> {
|
getSystemStatus(info -> {
|
||||||
mLocalDeviceId = info.myID;
|
mLocalDeviceId = info.myID;
|
||||||
mUrVersionMax = info.urVersionMax;
|
mUrVersionMax = info.urVersionMax;
|
||||||
synchronized (mAsyncQueryCompleteLock) {
|
synchronized (mAsyncQueryCompleteLock) {
|
||||||
asyncQuerySystemInfoComplete = true;
|
asyncQuerySystemStatusComplete = true;
|
||||||
checkReadConfigFromRestApiCompleted();
|
checkReadConfigFromRestApiCompleted();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkReadConfigFromRestApiCompleted() {
|
private void checkReadConfigFromRestApiCompleted() {
|
||||||
if (asyncQueryVersionComplete && asyncQueryConfigComplete && asyncQuerySystemInfoComplete) {
|
if (asyncQueryVersionComplete && asyncQueryConfigComplete && asyncQuerySystemStatusComplete) {
|
||||||
Log.v(TAG, "Reading config from REST completed.");
|
Log.v(TAG, "Reading config from REST completed.");
|
||||||
mOnApiAvailableListener.onApiAvailable();
|
mOnApiAvailableListener.onApiAvailable();
|
||||||
}
|
}
|
||||||
|
@ -502,9 +502,9 @@ public class RestApi {
|
||||||
/**
|
/**
|
||||||
* Requests and parses information about current system status and resource usage.
|
* Requests and parses information about current system status and resource usage.
|
||||||
*/
|
*/
|
||||||
public void getSystemInfo(OnResultListener1<SystemInfo> listener) {
|
public void getSystemStatus(OnResultListener1<SystemStatus> listener) {
|
||||||
new GetRequest(mContext, mUrl, GetRequest.URI_SYSTEM, mApiKey, null, result ->
|
new GetRequest(mContext, mUrl, GetRequest.URI_SYSTEM_STATUS, mApiKey, null, result ->
|
||||||
listener.onResult(new Gson().fromJson(result, SystemInfo.class)));
|
listener.onResult(new Gson().fromJson(result, SystemStatus.class)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isConfigLoaded() {
|
public boolean isConfigLoaded() {
|
||||||
|
@ -558,7 +558,7 @@ public class RestApi {
|
||||||
* Returns status information about the folder with the given id.
|
* Returns status information about the folder with the given id.
|
||||||
*/
|
*/
|
||||||
public void getFolderStatus(final String folderId, final OnResultListener2<String, FolderStatus> listener) {
|
public void getFolderStatus(final String folderId, final OnResultListener2<String, FolderStatus> listener) {
|
||||||
new GetRequest(mContext, mUrl, GetRequest.URI_STATUS, mApiKey,
|
new GetRequest(mContext, mUrl, GetRequest.URI_DB_STATUS, mApiKey,
|
||||||
ImmutableMap.of("folder", folderId), result -> {
|
ImmutableMap.of("folder", folderId), result -> {
|
||||||
FolderStatus m = new Gson().fromJson(result, FolderStatus.class);
|
FolderStatus m = new Gson().fromJson(result, FolderStatus.class);
|
||||||
mCachedFolderStatuses.put(folderId, m);
|
mCachedFolderStatuses.put(folderId, m);
|
||||||
|
|
|
@ -158,6 +158,9 @@ Please report any problems you encounter via Github.</string>
|
||||||
<!-- Title for announce server status -->
|
<!-- Title for announce server status -->
|
||||||
<string name="announce_server">Configured Announce Server</string>
|
<string name="announce_server">Configured Announce Server</string>
|
||||||
|
|
||||||
|
<!-- Title for uptime status -->
|
||||||
|
<string name="uptime">Uptime</string>
|
||||||
|
|
||||||
<string name="restart">Restart</string>
|
<string name="restart">Restart</string>
|
||||||
|
|
||||||
<string name="dialog_confirm_restart">Do you want to restart Syncthing?</string>
|
<string name="dialog_confirm_restart">Do you want to restart Syncthing?</string>
|
||||||
|
|
Loading…
Reference in a new issue