mirror of
https://github.com/syncthing/syncthing-android.git
synced 2024-11-23 04:41:16 +00:00
Merge branch 'use-gson'
This commit is contained in:
commit
51df459401
88 changed files with 1732 additions and 2050 deletions
|
@ -4,7 +4,7 @@ import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.syncthing.RestApi;
|
import com.nutomic.syncthingandroid.service.RestApi;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
|
@ -3,8 +3,8 @@ package com.nutomic.syncthingandroid.test;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.syncthing.RestApi;
|
import com.nutomic.syncthingandroid.service.RestApi;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
|
|
@ -5,7 +5,7 @@ import android.support.test.rule.ActivityTestRule;
|
||||||
import com.nutomic.syncthingandroid.activities.MainActivity;
|
import com.nutomic.syncthingandroid.activities.MainActivity;
|
||||||
import com.nutomic.syncthingandroid.fragments.DeviceListFragment;
|
import com.nutomic.syncthingandroid.fragments.DeviceListFragment;
|
||||||
import com.nutomic.syncthingandroid.fragments.FolderListFragment;
|
import com.nutomic.syncthingandroid.fragments.FolderListFragment;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingServiceBinder;
|
import com.nutomic.syncthingandroid.service.SyncthingServiceBinder;
|
||||||
import com.nutomic.syncthingandroid.test.MockSyncthingService;
|
import com.nutomic.syncthingandroid.test.MockSyncthingService;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
|
|
@ -5,8 +5,8 @@ import android.preference.PreferenceManager;
|
||||||
import android.support.test.InstrumentationRegistry;
|
import android.support.test.InstrumentationRegistry;
|
||||||
import android.support.test.rule.ServiceTestRule;
|
import android.support.test.rule.ServiceTestRule;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.syncthing.AppConfigReceiver;
|
import com.nutomic.syncthingandroid.receiver.AppConfigReceiver;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
import com.nutomic.syncthingandroid.test.MockContext;
|
import com.nutomic.syncthingandroid.test.MockContext;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
|
|
@ -5,9 +5,9 @@ import android.preference.PreferenceManager;
|
||||||
import android.support.test.InstrumentationRegistry;
|
import android.support.test.InstrumentationRegistry;
|
||||||
import android.support.test.rule.ServiceTestRule;
|
import android.support.test.rule.ServiceTestRule;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.syncthing.BatteryReceiver;
|
import com.nutomic.syncthingandroid.receiver.BatteryReceiver;
|
||||||
import com.nutomic.syncthingandroid.syncthing.DeviceStateHolder;
|
import com.nutomic.syncthingandroid.service.DeviceStateHolder;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
import com.nutomic.syncthingandroid.test.MockContext;
|
import com.nutomic.syncthingandroid.test.MockContext;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
|
|
@ -5,8 +5,8 @@ import android.preference.PreferenceManager;
|
||||||
import android.support.test.InstrumentationRegistry;
|
import android.support.test.InstrumentationRegistry;
|
||||||
import android.support.test.rule.ServiceTestRule;
|
import android.support.test.rule.ServiceTestRule;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.syncthing.BootReceiver;
|
import com.nutomic.syncthingandroid.receiver.BootReceiver;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
import com.nutomic.syncthingandroid.test.MockContext;
|
import com.nutomic.syncthingandroid.test.MockContext;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
@ -16,8 +16,8 @@ import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that {@link com.nutomic.syncthingandroid.syncthing.BootReceiver} starts the right service
|
* Tests that {@link BootReceiver} starts the right service
|
||||||
* ({@link com.nutomic.syncthingandroid.syncthing.SyncthingService}.
|
* ({@link com.nutomic.syncthingandroid.service.SyncthingService}.
|
||||||
*/
|
*/
|
||||||
public class BootReceiverTest {
|
public class BootReceiverTest {
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import android.os.BatteryManager;
|
||||||
import android.support.test.InstrumentationRegistry;
|
import android.support.test.InstrumentationRegistry;
|
||||||
import android.support.test.rule.ServiceTestRule;
|
import android.support.test.rule.ServiceTestRule;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.syncthing.DeviceStateHolder;
|
import com.nutomic.syncthingandroid.service.DeviceStateHolder;
|
||||||
import com.nutomic.syncthingandroid.test.MockContext;
|
import com.nutomic.syncthingandroid.test.MockContext;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
|
|
@ -6,9 +6,9 @@ import android.preference.PreferenceManager;
|
||||||
import android.support.test.InstrumentationRegistry;
|
import android.support.test.InstrumentationRegistry;
|
||||||
import android.support.test.rule.ServiceTestRule;
|
import android.support.test.rule.ServiceTestRule;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.syncthing.DeviceStateHolder;
|
import com.nutomic.syncthingandroid.service.DeviceStateHolder;
|
||||||
import com.nutomic.syncthingandroid.syncthing.NetworkReceiver;
|
import com.nutomic.syncthingandroid.receiver.NetworkReceiver;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
import com.nutomic.syncthingandroid.test.MockContext;
|
import com.nutomic.syncthingandroid.test.MockContext;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
@ -19,7 +19,7 @@ import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for correct extras on the Intent sent by
|
* Tests for correct extras on the Intent sent by
|
||||||
* {@link com.nutomic.syncthingandroid.syncthing.NetworkReceiver}.
|
* {@link NetworkReceiver}.
|
||||||
*
|
*
|
||||||
* Does not test for correct result value, as that would require mocking
|
* Does not test for correct result value, as that would require mocking
|
||||||
* {@link android.net.ConnectivityManager} (or replacing it with an interface).
|
* {@link android.net.ConnectivityManager} (or replacing it with an interface).
|
||||||
|
|
|
@ -5,11 +5,12 @@ import android.support.test.InstrumentationRegistry;
|
||||||
import android.support.test.rule.ServiceTestRule;
|
import android.support.test.rule.ServiceTestRule;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.http.PollWebGuiAvailableTask;
|
import com.nutomic.syncthingandroid.http.PollWebGuiAvailableTask;
|
||||||
import com.nutomic.syncthingandroid.syncthing.RestApi;
|
import com.nutomic.syncthingandroid.service.RestApi;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingRunnable;
|
import com.nutomic.syncthingandroid.service.SyncthingRunnable;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
import com.nutomic.syncthingandroid.test.MockContext;
|
import com.nutomic.syncthingandroid.test.MockContext;
|
||||||
import com.nutomic.syncthingandroid.util.ConfigXml;
|
import com.nutomic.syncthingandroid.util.ConfigXml;
|
||||||
|
import com.nutomic.syncthingandroid.util.Util;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
@ -38,13 +39,10 @@ public class RestApiTest {
|
||||||
String httpsCertPath = context.getFilesDir() + "/" + SyncthingService.HTTPS_CERT_FILE;
|
String httpsCertPath = context.getFilesDir() + "/" + SyncthingService.HTTPS_CERT_FILE;
|
||||||
|
|
||||||
final CountDownLatch latch = new CountDownLatch(2);
|
final CountDownLatch latch = new CountDownLatch(2);
|
||||||
new PollWebGuiAvailableTask(config.getWebGuiUrl(), httpsCertPath, config.getApiKey()) {
|
new PollWebGuiAvailableTask(config.getWebGuiUrl(), httpsCertPath, config.getApiKey(), result -> {
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Void aVoid) {
|
|
||||||
mApi.onWebGuiAvailable();
|
mApi.onWebGuiAvailable();
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
}
|
}).execute();
|
||||||
}.execute();
|
|
||||||
mApi = new RestApi(context, config.getWebGuiUrl(), config.getApiKey(),
|
mApi = new RestApi(context, config.getWebGuiUrl(), config.getApiKey(),
|
||||||
new RestApi.OnApiAvailableListener() {
|
new RestApi.OnApiAvailableListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -97,8 +95,8 @@ public class RestApiTest {
|
||||||
public void testConvertNotCrashing() {
|
public void testConvertNotCrashing() {
|
||||||
long[] values = new long[]{-1, 0, 1, 2, 4, 8, 16, 1024, 2^10, 2^15, 2^20, 2^25, 2^30};
|
long[] values = new long[]{-1, 0, 1, 2, 4, 8, 16, 1024, 2^10, 2^15, 2^20, 2^25, 2^30};
|
||||||
for (long l : values) {
|
for (long l : values) {
|
||||||
Assert.assertNotSame("", RestApi.readableFileSize(InstrumentationRegistry.getTargetContext(), l));
|
Assert.assertNotSame("", Util.readableFileSize(InstrumentationRegistry.getTargetContext(), l));
|
||||||
Assert.assertNotSame("", RestApi.readableTransferRate(InstrumentationRegistry.getTargetContext(), l));
|
Assert.assertNotSame("", Util.readableTransferRate(InstrumentationRegistry.getTargetContext(), l));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ package com.nutomic.syncthingandroid.test.syncthing;
|
||||||
import android.support.test.InstrumentationRegistry;
|
import android.support.test.InstrumentationRegistry;
|
||||||
import android.support.test.rule.ServiceTestRule;
|
import android.support.test.rule.ServiceTestRule;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingRunnable;
|
import com.nutomic.syncthingandroid.service.SyncthingRunnable;
|
||||||
import com.nutomic.syncthingandroid.test.MockContext;
|
import com.nutomic.syncthingandroid.test.MockContext;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
|
|
@ -2,8 +2,8 @@ package com.nutomic.syncthingandroid.test.syncthing;
|
||||||
|
|
||||||
import android.support.test.rule.ServiceTestRule;
|
import android.support.test.rule.ServiceTestRule;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingServiceBinder;
|
import com.nutomic.syncthingandroid.service.SyncthingServiceBinder;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
|
|
|
@ -9,8 +9,8 @@ import android.preference.PreferenceManager;
|
||||||
import android.support.test.InstrumentationRegistry;
|
import android.support.test.InstrumentationRegistry;
|
||||||
import android.support.test.rule.ServiceTestRule;
|
import android.support.test.rule.ServiceTestRule;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingServiceBinder;
|
import com.nutomic.syncthingandroid.service.SyncthingServiceBinder;
|
||||||
import com.nutomic.syncthingandroid.util.ConfigXml;
|
import com.nutomic.syncthingandroid.util.ConfigXml;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
@ -21,8 +21,6 @@ import org.junit.Test;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -3,7 +3,7 @@ package com.nutomic.syncthingandroid.test.util;
|
||||||
import android.support.test.InstrumentationRegistry;
|
import android.support.test.InstrumentationRegistry;
|
||||||
import android.support.test.rule.ServiceTestRule;
|
import android.support.test.rule.ServiceTestRule;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.syncthing.RestApi;
|
import com.nutomic.syncthingandroid.service.RestApi;
|
||||||
import com.nutomic.syncthingandroid.test.MockContext;
|
import com.nutomic.syncthingandroid.test.MockContext;
|
||||||
import com.nutomic.syncthingandroid.test.Util;
|
import com.nutomic.syncthingandroid.test.Util;
|
||||||
import com.nutomic.syncthingandroid.util.FolderObserver;
|
import com.nutomic.syncthingandroid.util.FolderObserver;
|
||||||
|
|
|
@ -79,25 +79,25 @@
|
||||||
android:theme="@style/Theme.Syncthing.Translucent"
|
android:theme="@style/Theme.Syncthing.Translucent"
|
||||||
android:launchMode="singleTop"/>
|
android:launchMode="singleTop"/>
|
||||||
|
|
||||||
<service android:name=".syncthing.SyncthingService" />
|
<service android:name=".service.SyncthingService" />
|
||||||
|
|
||||||
<receiver android:name=".syncthing.NetworkReceiver">
|
<receiver android:name=".receiver.NetworkReceiver">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
|
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
<receiver android:name=".syncthing.BatteryReceiver">
|
<receiver android:name=".receiver.BatteryReceiver">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
|
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
|
||||||
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
|
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
<receiver android:name=".syncthing.BootReceiver">
|
<receiver android:name=".receiver.BootReceiver">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
<receiver android:name=".syncthing.AppConfigReceiver"
|
<receiver android:name=".receiver.AppConfigReceiver"
|
||||||
tools:ignore="ExportedReceiver">
|
tools:ignore="ExportedReceiver">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="com.nutomic.syncthingandroid.action.START" />
|
<action android:name="com.nutomic.syncthingandroid.action.START" />
|
||||||
|
|
|
@ -28,7 +28,7 @@ import android.widget.Toast;
|
||||||
|
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.nutomic.syncthingandroid.R;
|
import com.nutomic.syncthingandroid.R;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
|
@ -29,8 +29,8 @@ import com.nutomic.syncthingandroid.R;
|
||||||
import com.nutomic.syncthingandroid.fragments.DeviceListFragment;
|
import com.nutomic.syncthingandroid.fragments.DeviceListFragment;
|
||||||
import com.nutomic.syncthingandroid.fragments.DrawerFragment;
|
import com.nutomic.syncthingandroid.fragments.DrawerFragment;
|
||||||
import com.nutomic.syncthingandroid.fragments.FolderListFragment;
|
import com.nutomic.syncthingandroid.fragments.FolderListFragment;
|
||||||
import com.nutomic.syncthingandroid.syncthing.RestApi;
|
import com.nutomic.syncthingandroid.model.Options;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
@ -87,7 +87,7 @@ public class MainActivity extends SyncthingActivity
|
||||||
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
|
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
|
||||||
mDrawerFragment.requestGuiUpdate();
|
mDrawerFragment.requestGuiUpdate();
|
||||||
if (new Date().getTime() > getFirstStartTime() + USAGE_REPORTING_DIALOG_DELAY &&
|
if (new Date().getTime() > getFirstStartTime() + USAGE_REPORTING_DIALOG_DELAY &&
|
||||||
getApi().getUsageReportAccepted() == RestApi.USAGE_REPORTING_UNDECIDED) {
|
getApi().getOptions().getUsageReportValue() == Options.USAGE_REPORTING_UNDECIDED) {
|
||||||
showUsageReportingDialog();
|
showUsageReportingDialog();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -390,21 +390,20 @@ public class MainActivity extends SyncthingActivity
|
||||||
*/
|
*/
|
||||||
private void showUsageReportingDialog() {
|
private void showUsageReportingDialog() {
|
||||||
final DialogInterface.OnClickListener listener = (dialog, which) -> {
|
final DialogInterface.OnClickListener listener = (dialog, which) -> {
|
||||||
|
Options options = getApi().getOptions();
|
||||||
switch (which) {
|
switch (which) {
|
||||||
case DialogInterface.BUTTON_POSITIVE:
|
case DialogInterface.BUTTON_POSITIVE:
|
||||||
getApi().setUsageReportAccepted(RestApi.USAGE_REPORTING_ACCEPTED,
|
options.urAccepted = Options.USAGE_REPORTING_ACCEPTED;
|
||||||
MainActivity.this);
|
|
||||||
break;
|
break;
|
||||||
case DialogInterface.BUTTON_NEGATIVE:
|
case DialogInterface.BUTTON_NEGATIVE:
|
||||||
getApi().setUsageReportAccepted(RestApi.USAGE_REPORTING_DENIED,
|
options.urAccepted = Options.USAGE_REPORTING_DENIED;
|
||||||
MainActivity.this);
|
|
||||||
break;
|
break;
|
||||||
case DialogInterface.BUTTON_NEUTRAL:
|
case DialogInterface.BUTTON_NEUTRAL:
|
||||||
Uri uri = Uri.parse("https://data.syncthing.net");
|
Uri uri = Uri.parse("https://data.syncthing.net");
|
||||||
startActivity(new Intent(Intent.ACTION_VIEW, uri));
|
startActivity(new Intent(Intent.ACTION_VIEW, uri));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
getApi().editSettings(getApi().getGui(), options, this);
|
||||||
};
|
};
|
||||||
|
|
||||||
getApi().getUsageReport(report -> {
|
getApi().getUsageReport(report -> {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import android.os.Bundle;
|
||||||
import android.support.v4.app.NotificationCompat;
|
import android.support.v4.app.NotificationCompat;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.R;
|
import com.nutomic.syncthingandroid.R;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows restart dialog.
|
* Shows restart dialog.
|
||||||
|
@ -30,7 +30,7 @@ public class RestartActivity extends SyncthingActivity {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
builder.setMessage(R.string.restart_title)
|
builder.setMessage(R.string.restart_title)
|
||||||
.setPositiveButton(R.string.restart_now, (dialogInterface, i) -> {
|
.setPositiveButton(R.string.restart_now, (dialogInterface, i) -> {
|
||||||
getService().getApi().updateConfig();
|
getService().getApi().restart();
|
||||||
finish();
|
finish();
|
||||||
})
|
})
|
||||||
.setNegativeButton(R.string.restart_later, (dialogInterface, i) -> {
|
.setNegativeButton(R.string.restart_later, (dialogInterface, i) -> {
|
||||||
|
|
|
@ -7,9 +7,9 @@ import android.content.ServiceConnection;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.syncthing.RestApi;
|
import com.nutomic.syncthingandroid.service.RestApi;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingServiceBinder;
|
import com.nutomic.syncthingandroid.service.SyncthingServiceBinder;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ import android.webkit.WebView;
|
||||||
import android.webkit.WebViewClient;
|
import android.webkit.WebViewClient;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.R;
|
import com.nutomic.syncthingandroid.R;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
import com.nutomic.syncthingandroid.util.ConfigXml;
|
import com.nutomic.syncthingandroid.util.ConfigXml;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.nutomic.syncthingandroid.fragments;
|
package com.nutomic.syncthingandroid.fragments;
|
||||||
|
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
@ -18,15 +19,19 @@ import android.widget.CompoundButton;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
import com.google.zxing.integration.android.IntentIntegrator;
|
import com.google.zxing.integration.android.IntentIntegrator;
|
||||||
import com.google.zxing.integration.android.IntentResult;
|
import com.google.zxing.integration.android.IntentResult;
|
||||||
import com.nutomic.syncthingandroid.R;
|
import com.nutomic.syncthingandroid.R;
|
||||||
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.syncthing.RestApi;
|
import com.nutomic.syncthingandroid.model.Connection;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
import com.nutomic.syncthingandroid.model.Device;
|
||||||
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
import com.nutomic.syncthingandroid.util.Compression;
|
import com.nutomic.syncthingandroid.util.Compression;
|
||||||
import com.nutomic.syncthingandroid.util.TextWatcherAdapter;
|
import com.nutomic.syncthingandroid.util.TextWatcherAdapter;
|
||||||
|
import com.nutomic.syncthingandroid.util.Util;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -37,16 +42,13 @@ import static android.text.TextUtils.isEmpty;
|
||||||
import static android.view.View.GONE;
|
import static android.view.View.GONE;
|
||||||
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 com.nutomic.syncthingandroid.syncthing.SyncthingService.State.ACTIVE;
|
import static com.nutomic.syncthingandroid.service.SyncthingService.State.ACTIVE;
|
||||||
import static com.nutomic.syncthingandroid.util.Compression.METADATA;
|
import static com.nutomic.syncthingandroid.util.Compression.METADATA;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows device details and allows changing them.
|
* Shows device details and allows changing them.
|
||||||
*/
|
*/
|
||||||
public class DeviceFragment extends Fragment implements
|
public class DeviceFragment extends Fragment implements View.OnClickListener {
|
||||||
SyncthingActivity.OnServiceConnectedListener, RestApi.OnReceiveConnectionsListener,
|
|
||||||
SyncthingService.OnApiChangeListener, RestApi.OnDeviceIdNormalizedListener,
|
|
||||||
View.OnClickListener {
|
|
||||||
|
|
||||||
public static final String EXTRA_DEVICE_ID =
|
public static final String EXTRA_DEVICE_ID =
|
||||||
"com.nutomic.syncthingandroid.fragments.DeviceFragment.DEVICE_ID";
|
"com.nutomic.syncthingandroid.fragments.DeviceFragment.DEVICE_ID";
|
||||||
|
@ -57,7 +59,7 @@ public class DeviceFragment extends Fragment implements
|
||||||
|
|
||||||
private SyncthingService mSyncthingService;
|
private SyncthingService mSyncthingService;
|
||||||
|
|
||||||
private RestApi.Device mDevice;
|
private Device mDevice;
|
||||||
|
|
||||||
private View mIdContainer;
|
private View mIdContainer;
|
||||||
|
|
||||||
|
@ -149,13 +151,13 @@ public class DeviceFragment extends Fragment implements
|
||||||
|
|
||||||
SettingsActivity activity = (SettingsActivity) getActivity();
|
SettingsActivity activity = (SettingsActivity) getActivity();
|
||||||
mIsCreateMode = activity.getIsCreate();
|
mIsCreateMode = activity.getIsCreate();
|
||||||
activity.registerOnServiceConnectedListener(this);
|
activity.registerOnServiceConnectedListener(this::onServiceConnected);
|
||||||
activity.setTitle(mIsCreateMode ? R.string.add_device : R.string.edit_device);
|
activity.setTitle(mIsCreateMode ? R.string.add_device : R.string.edit_device);
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
|
|
||||||
if (mIsCreateMode) {
|
if (mIsCreateMode) {
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
mDevice = (RestApi.Device) savedInstanceState.getSerializable("device");
|
mDevice = new Gson().fromJson(savedInstanceState.getString("device"), Device.class);
|
||||||
}
|
}
|
||||||
if (mDevice == null) {
|
if (mDevice == null) {
|
||||||
initDevice();
|
initDevice();
|
||||||
|
@ -167,7 +169,7 @@ public class DeviceFragment extends Fragment implements
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
if (mSyncthingService != null) {
|
if (mSyncthingService != null) {
|
||||||
mSyncthingService.unregisterOnApiChangeListener(this);
|
mSyncthingService.unregisterOnApiChangeListener(this::onApiChange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +190,7 @@ public class DeviceFragment extends Fragment implements
|
||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(Bundle outState) {
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
outState.putSerializable("device", mDevice);
|
outState.putString("device", new Gson().toJson(mDevice));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -229,10 +231,9 @@ public class DeviceFragment extends Fragment implements
|
||||||
mAddressesView.removeTextChangedListener(mAddressesTextWatcher);
|
mAddressesView.removeTextChangedListener(mAddressesTextWatcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onServiceConnected() {
|
public void onServiceConnected() {
|
||||||
mSyncthingService = ((SyncthingActivity) getActivity()).getService();
|
mSyncthingService = ((SyncthingActivity) getActivity()).getService();
|
||||||
mSyncthingService.registerOnApiChangeListener(this);
|
mSyncthingService.registerOnApiChangeListener(this::onApiChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -241,8 +242,7 @@ public class DeviceFragment extends Fragment implements
|
||||||
* NOTE: This is only called once on startup, should be called more often to properly display
|
* NOTE: This is only called once on startup, should be called more often to properly display
|
||||||
* version/address changes.
|
* version/address changes.
|
||||||
*/
|
*/
|
||||||
@Override
|
public void onReceiveConnections(Map<String, Connection> connections) {
|
||||||
public void onReceiveConnections(Map<String, RestApi.Connection> connections) {
|
|
||||||
boolean viewsExist = mSyncthingVersionView != null && mCurrentAddressView != null;
|
boolean viewsExist = mSyncthingVersionView != null && mCurrentAddressView != null;
|
||||||
if (viewsExist && connections.containsKey(mDevice.deviceID)) {
|
if (viewsExist && connections.containsKey(mDevice.deviceID)) {
|
||||||
mCurrentAddressView.setVisibility(VISIBLE);
|
mCurrentAddressView.setVisibility(VISIBLE);
|
||||||
|
@ -252,7 +252,6 @@ public class DeviceFragment extends Fragment implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onApiChange(SyncthingService.State currentState) {
|
public void onApiChange(SyncthingService.State currentState) {
|
||||||
if (currentState != ACTIVE) {
|
if (currentState != ACTIVE) {
|
||||||
getActivity().finish();
|
getActivity().finish();
|
||||||
|
@ -260,9 +259,9 @@ public class DeviceFragment extends Fragment implements
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mIsCreateMode) {
|
if (!mIsCreateMode) {
|
||||||
List<RestApi.Device> devices = mSyncthingService.getApi().getDevices(false);
|
List<Device> devices = mSyncthingService.getApi().getDevices(false);
|
||||||
mDevice = null;
|
mDevice = null;
|
||||||
for (RestApi.Device device : devices) {
|
for (Device device : devices) {
|
||||||
if (device.deviceID.equals(
|
if (device.deviceID.equals(
|
||||||
getActivity().getIntent().getStringExtra(EXTRA_DEVICE_ID))) {
|
getActivity().getIntent().getStringExtra(EXTRA_DEVICE_ID))) {
|
||||||
mDevice = device;
|
mDevice = device;
|
||||||
|
@ -276,7 +275,7 @@ public class DeviceFragment extends Fragment implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mSyncthingService.getApi().getConnections(this);
|
mSyncthingService.getApi().getConnections(this::onReceiveConnections);
|
||||||
|
|
||||||
updateViewsAndSetListeners();
|
updateViewsAndSetListeners();
|
||||||
}
|
}
|
||||||
|
@ -318,16 +317,18 @@ public class DeviceFragment extends Fragment implements
|
||||||
.show();
|
.show();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
mSyncthingService.getApi().editDevice(mDevice, getActivity(), this);
|
mSyncthingService.getApi().addDevice(mDevice, error ->
|
||||||
|
Toast.makeText(getActivity(), error, Toast.LENGTH_LONG).show());
|
||||||
getActivity().finish();
|
getActivity().finish();
|
||||||
return true;
|
return true;
|
||||||
case R.id.share_device_id:
|
case R.id.share_device_id:
|
||||||
RestApi.shareDeviceId(getActivity(), mDevice.deviceID);
|
shareDeviceId(getActivity(), mDevice.deviceID);
|
||||||
return true;
|
return true;
|
||||||
case R.id.remove:
|
case R.id.remove:
|
||||||
new AlertDialog.Builder(getActivity())
|
new AlertDialog.Builder(getActivity())
|
||||||
.setMessage(R.string.remove_device_confirm)
|
.setMessage(R.string.remove_device_confirm)
|
||||||
.setPositiveButton(android.R.string.yes, (dialogInterface, i) -> mSyncthingService.getApi().deleteDevice(mDevice, getActivity()))
|
.setPositiveButton(android.R.string.yes, (dialogInterface, i) ->
|
||||||
|
mSyncthingService.getApi().removeDevice(mDevice.deviceID))
|
||||||
.setNegativeButton(android.R.string.no, null)
|
.setNegativeButton(android.R.string.no, null)
|
||||||
.show();
|
.show();
|
||||||
return true;
|
return true;
|
||||||
|
@ -351,19 +352,8 @@ public class DeviceFragment extends Fragment implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback for {@link RestApi#editDevice}.
|
|
||||||
* Displays an error toast if error message present.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onDeviceIdNormalized(String normalizedId, String error) {
|
|
||||||
if (error != null) {
|
|
||||||
Toast.makeText(getActivity(), error, Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initDevice() {
|
private void initDevice() {
|
||||||
mDevice = new RestApi.Device();
|
mDevice = new Device();
|
||||||
mDevice.name = "";
|
mDevice.name = "";
|
||||||
mDevice.deviceID = getActivity().getIntent().getStringExtra(EXTRA_DEVICE_ID);
|
mDevice.deviceID = getActivity().getIntent().getStringExtra(EXTRA_DEVICE_ID);
|
||||||
mDevice.addresses = DYNAMIC_ADDRESS;
|
mDevice.addresses = DYNAMIC_ADDRESS;
|
||||||
|
@ -387,7 +377,7 @@ public class DeviceFragment extends Fragment implements
|
||||||
*/
|
*/
|
||||||
private void updateDevice() {
|
private void updateDevice() {
|
||||||
if (!mIsCreateMode && mDeviceNeedsToUpdate && mDevice != null) {
|
if (!mIsCreateMode && mDeviceNeedsToUpdate && mDevice != null) {
|
||||||
mSyncthingService.getApi().editDevice(mDevice, getActivity(), this);
|
mSyncthingService.getApi().editDevice(mDevice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,7 +407,19 @@ public class DeviceFragment extends Fragment implements
|
||||||
IntentIntegrator integrator = new IntentIntegrator(DeviceFragment.this);
|
IntentIntegrator integrator = new IntentIntegrator(DeviceFragment.this);
|
||||||
integrator.initiateScan();
|
integrator.initiateScan();
|
||||||
} else if (v.equals(mIdContainer)) {
|
} else if (v.equals(mIdContainer)) {
|
||||||
mSyncthingService.getApi().copyDeviceId(mDevice.deviceID);
|
Util.copyDeviceId(getActivity(), mDevice.deviceID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shares the given device ID via Intent. Must be called from an Activity.
|
||||||
|
*/
|
||||||
|
private void shareDeviceId(Context context, String id) {
|
||||||
|
Intent shareIntent = new Intent();
|
||||||
|
shareIntent.setAction(Intent.ACTION_SEND);
|
||||||
|
shareIntent.setType("text/plain");
|
||||||
|
shareIntent.putExtra(android.content.Intent.EXTRA_TEXT, id);
|
||||||
|
context.startActivity(Intent.createChooser(
|
||||||
|
shareIntent, context.getString(R.string.send_device_id_to)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,9 @@ import android.widget.ListView;
|
||||||
import com.nutomic.syncthingandroid.R;
|
import com.nutomic.syncthingandroid.R;
|
||||||
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.syncthing.RestApi;
|
import com.nutomic.syncthingandroid.model.Device;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
import com.nutomic.syncthingandroid.util.DevicesAdapter;
|
import com.nutomic.syncthingandroid.views.DevicesAdapter;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
@ -29,25 +29,12 @@ import java.util.TimerTask;
|
||||||
public class DeviceListFragment extends ListFragment implements SyncthingService.OnApiChangeListener,
|
public class DeviceListFragment extends ListFragment implements SyncthingService.OnApiChangeListener,
|
||||||
ListView.OnItemClickListener {
|
ListView.OnItemClickListener {
|
||||||
|
|
||||||
private final static Comparator<RestApi.Device> DEVICES_COMPARATOR = (lhs, rhs) -> lhs.name.compareTo(rhs.name);
|
private final static Comparator<Device> DEVICES_COMPARATOR = (lhs, rhs) -> lhs.name.compareTo(rhs.name);
|
||||||
|
|
||||||
private DevicesAdapter mAdapter;
|
private DevicesAdapter mAdapter;
|
||||||
|
|
||||||
private Timer mTimer;
|
private Timer mTimer;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
mTimer = new Timer();
|
|
||||||
mTimer.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
getActivity().runOnUiThread(DeviceListFragment.this::updateList);
|
|
||||||
}
|
|
||||||
|
|
||||||
}, 0, SyncthingService.GUI_UPDATE_INTERVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
|
@ -59,25 +46,28 @@ public class DeviceListFragment extends ListFragment implements SyncthingService
|
||||||
if (currentState != SyncthingService.State.ACTIVE)
|
if (currentState != SyncthingService.State.ACTIVE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
updateList();
|
mTimer = new Timer();
|
||||||
|
mTimer.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (getActivity() == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
getActivity().runOnUiThread(DeviceListFragment.this::updateList);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, 0, SyncthingService.GUI_UPDATE_INTERVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
|
setHasOptionsMenu(true);
|
||||||
setEmptyText(getString(R.string.devices_list_empty));
|
setEmptyText(getString(R.string.devices_list_empty));
|
||||||
getListView().setOnItemClickListener(this);
|
getListView().setOnItemClickListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onActivityCreated(Bundle savedInstanceState) {
|
|
||||||
super.onActivityCreated(savedInstanceState);
|
|
||||||
|
|
||||||
updateList();
|
|
||||||
setHasOptionsMenu(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refreshes ListView by updating devices and info.
|
* Refreshes ListView by updating devices and info.
|
||||||
*
|
*
|
||||||
|
@ -85,8 +75,7 @@ public class DeviceListFragment extends ListFragment implements SyncthingService
|
||||||
*/
|
*/
|
||||||
private void updateList() {
|
private void updateList() {
|
||||||
SyncthingActivity activity = (SyncthingActivity) getActivity();
|
SyncthingActivity activity = (SyncthingActivity) getActivity();
|
||||||
if (activity == null || activity.getApi() == null || getView() == null ||
|
if (activity.getApi() == null || getView() == null || activity.isFinishing())
|
||||||
activity.isFinishing())
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mAdapter == null) {
|
if (mAdapter == null) {
|
||||||
|
@ -97,7 +86,7 @@ public class DeviceListFragment extends ListFragment implements SyncthingService
|
||||||
// Prevent scroll position reset due to list update from clear().
|
// Prevent scroll position reset due to list update from clear().
|
||||||
mAdapter.setNotifyOnChange(false);
|
mAdapter.setNotifyOnChange(false);
|
||||||
mAdapter.clear();
|
mAdapter.clear();
|
||||||
List<RestApi.Device> devices = activity.getApi().getDevices(false);
|
List<Device> devices = activity.getApi().getDevices(false);
|
||||||
Collections.sort(devices, DEVICES_COMPARATOR);
|
Collections.sort(devices, DEVICES_COMPARATOR);
|
||||||
mAdapter.addAll(devices);
|
mAdapter.addAll(devices);
|
||||||
mAdapter.updateConnections(activity.getApi());
|
mAdapter.updateConnections(activity.getApi());
|
||||||
|
|
|
@ -9,12 +9,18 @@ import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.google.common.base.Optional;
|
||||||
import com.nutomic.syncthingandroid.R;
|
import com.nutomic.syncthingandroid.R;
|
||||||
import com.nutomic.syncthingandroid.activities.MainActivity;
|
import com.nutomic.syncthingandroid.activities.MainActivity;
|
||||||
import com.nutomic.syncthingandroid.activities.SettingsActivity;
|
import com.nutomic.syncthingandroid.activities.SettingsActivity;
|
||||||
import com.nutomic.syncthingandroid.activities.WebGuiActivity;
|
import com.nutomic.syncthingandroid.activities.WebGuiActivity;
|
||||||
import com.nutomic.syncthingandroid.syncthing.RestApi;
|
import com.nutomic.syncthingandroid.model.Connection;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
import com.nutomic.syncthingandroid.model.SystemInfo;
|
||||||
|
import com.nutomic.syncthingandroid.model.SystemVersion;
|
||||||
|
import com.nutomic.syncthingandroid.service.RestApi;
|
||||||
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
|
import com.nutomic.syncthingandroid.util.Util;
|
||||||
|
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
@ -25,10 +31,7 @@ import java.util.TimerTask;
|
||||||
/**
|
/**
|
||||||
* Displays information about the local device.
|
* Displays information about the local device.
|
||||||
*/
|
*/
|
||||||
public class DrawerFragment extends Fragment implements RestApi.OnReceiveSystemInfoListener,
|
public class DrawerFragment extends Fragment implements View.OnClickListener {
|
||||||
RestApi.OnReceiveConnectionsListener,
|
|
||||||
RestApi.OnReceiveSystemVersionListener,
|
|
||||||
View.OnClickListener {
|
|
||||||
|
|
||||||
private TextView mDeviceId;
|
private TextView mDeviceId;
|
||||||
private TextView mCpuUsage;
|
private TextView mCpuUsage;
|
||||||
|
@ -133,9 +136,9 @@ public class DrawerFragment extends Fragment implements RestApi.OnReceiveSystemI
|
||||||
private void updateGui() {
|
private void updateGui() {
|
||||||
if (mActivity.getApi() == null || getActivity() == null || getActivity().isFinishing())
|
if (mActivity.getApi() == null || getActivity() == null || getActivity().isFinishing())
|
||||||
return;
|
return;
|
||||||
mActivity.getApi().getSystemInfo(this);
|
mActivity.getApi().getSystemInfo(this::onReceiveSystemInfo);
|
||||||
mActivity.getApi().getSystemVersion(this);
|
mActivity.getApi().getSystemVersion(this::onReceiveSystemVersion);
|
||||||
mActivity.getApi().getConnections(this);
|
mActivity.getApi().getConnections(this::onReceiveConnections);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -150,20 +153,22 @@ public class DrawerFragment extends Fragment implements RestApi.OnReceiveSystemI
|
||||||
/**
|
/**
|
||||||
* Populates views with status received via {@link RestApi#getSystemInfo}.
|
* Populates views with status received via {@link RestApi#getSystemInfo}.
|
||||||
*/
|
*/
|
||||||
@Override
|
public void onReceiveSystemInfo(SystemInfo info) {
|
||||||
public void onReceiveSystemInfo(RestApi.SystemInfo info) {
|
|
||||||
if (getActivity() == null)
|
if (getActivity() == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mDeviceId.setText(info.myID);
|
mDeviceId.setText(info.myID);
|
||||||
mDeviceId.setOnClickListener(v -> mActivity.getApi().copyDeviceId(mDeviceId.getText().toString()));
|
mDeviceId.setOnClickListener(v -> Util.copyDeviceId(getActivity(), mDeviceId.getText().toString()));
|
||||||
NumberFormat percentFormat = NumberFormat.getPercentInstance();
|
NumberFormat percentFormat = NumberFormat.getPercentInstance();
|
||||||
percentFormat.setMaximumFractionDigits(2);
|
percentFormat.setMaximumFractionDigits(2);
|
||||||
mCpuUsage.setText(percentFormat.format(info.cpuPercent / 100));
|
mCpuUsage.setText(percentFormat.format(info.cpuPercent / 100));
|
||||||
mRamUsage.setText(RestApi.readableFileSize(mActivity, info.sys));
|
mRamUsage.setText(Util.readableFileSize(mActivity, info.sys));
|
||||||
|
int announceTotal = info.discoveryMethods;
|
||||||
|
int announceConnected =
|
||||||
|
announceTotal - Optional.fromNullable(info.discoveryErrors).transform(Map::size).or(0);
|
||||||
mAnnounceServer.setText(String.format(Locale.getDefault(), "%1$d/%2$d",
|
mAnnounceServer.setText(String.format(Locale.getDefault(), "%1$d/%2$d",
|
||||||
info.extAnnounceConnected, info.extAnnounceTotal));
|
announceConnected, announceTotal));
|
||||||
int color = (info.extAnnounceConnected > 0)
|
int color = (announceConnected > 0)
|
||||||
? R.color.text_green
|
? R.color.text_green
|
||||||
: R.color.text_red;
|
: R.color.text_red;
|
||||||
mAnnounceServer.setTextColor(ContextCompat.getColor(getContext(), color));
|
mAnnounceServer.setTextColor(ContextCompat.getColor(getContext(), color));
|
||||||
|
@ -172,8 +177,7 @@ public class DrawerFragment extends Fragment implements RestApi.OnReceiveSystemI
|
||||||
/**
|
/**
|
||||||
* Populates views with status received via {@link RestApi#getSystemInfo}.
|
* Populates views with status received via {@link RestApi#getSystemInfo}.
|
||||||
*/
|
*/
|
||||||
@Override
|
public void onReceiveSystemVersion(SystemVersion info) {
|
||||||
public void onReceiveSystemVersion(RestApi.SystemVersion info) {
|
|
||||||
if (getActivity() == null)
|
if (getActivity() == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -183,11 +187,10 @@ public class DrawerFragment extends Fragment implements RestApi.OnReceiveSystemI
|
||||||
/**
|
/**
|
||||||
* Populates views with status received via {@link RestApi#getConnections}.
|
* Populates views with status received via {@link RestApi#getConnections}.
|
||||||
*/
|
*/
|
||||||
@Override
|
private void onReceiveConnections(Map<String, Connection> connections) {
|
||||||
public void onReceiveConnections(Map<String, RestApi.Connection> connections) {
|
Connection c = connections.get(RestApi.TOTAL_STATS);
|
||||||
RestApi.Connection c = connections.get(RestApi.TOTAL_STATS);
|
mDownload.setText(Util.readableTransferRate(mActivity, c.inBits));
|
||||||
mDownload.setText(RestApi.readableTransferRate(mActivity, c.inBits));
|
mUpload.setText(Util.readableTransferRate(mActivity, c.outBits));
|
||||||
mUpload.setText(RestApi.readableTransferRate(mActivity, c.outBits));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -11,28 +11,40 @@ 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.view.*;
|
import android.util.TypedValue;
|
||||||
import android.widget.*;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
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;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.gson.Gson;
|
||||||
import com.nutomic.syncthingandroid.R;
|
import com.nutomic.syncthingandroid.R;
|
||||||
import com.nutomic.syncthingandroid.activities.FolderPickerActivity;
|
import com.nutomic.syncthingandroid.activities.FolderPickerActivity;
|
||||||
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.fragments.dialog.KeepVersionsDialogFragment;
|
import com.nutomic.syncthingandroid.fragments.dialog.KeepVersionsDialogFragment;
|
||||||
import com.nutomic.syncthingandroid.syncthing.RestApi;
|
import com.nutomic.syncthingandroid.model.Device;
|
||||||
import com.nutomic.syncthingandroid.syncthing.RestApi.SimpleVersioning;
|
import com.nutomic.syncthingandroid.model.Folder;
|
||||||
import com.nutomic.syncthingandroid.syncthing.RestApi.Versioning;
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
|
||||||
import com.nutomic.syncthingandroid.util.TextWatcherAdapter;
|
import com.nutomic.syncthingandroid.util.TextWatcherAdapter;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static android.support.v4.view.MarginLayoutParamsCompat.setMarginEnd;
|
import static android.support.v4.view.MarginLayoutParamsCompat.setMarginEnd;
|
||||||
import static android.support.v4.view.MarginLayoutParamsCompat.setMarginStart;
|
import static android.support.v4.view.MarginLayoutParamsCompat.setMarginStart;
|
||||||
|
import static android.util.TypedValue.COMPLEX_UNIT_DIP;
|
||||||
import static android.view.Gravity.CENTER_VERTICAL;
|
import static android.view.Gravity.CENTER_VERTICAL;
|
||||||
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||||
import static com.nutomic.syncthingandroid.syncthing.SyncthingService.State.ACTIVE;
|
import static com.nutomic.syncthingandroid.service.SyncthingService.State.ACTIVE;
|
||||||
import static com.nutomic.syncthingandroid.util.DpConverter.dp;
|
|
||||||
import static java.lang.String.valueOf;
|
import static java.lang.String.valueOf;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -58,7 +70,7 @@ public class FolderFragment extends Fragment
|
||||||
|
|
||||||
private SyncthingService mSyncthingService;
|
private SyncthingService mSyncthingService;
|
||||||
|
|
||||||
private RestApi.Folder mFolder;
|
private Folder mFolder;
|
||||||
|
|
||||||
private EditText mLabelView;
|
private EditText mLabelView;
|
||||||
private EditText mIdView;
|
private EditText mIdView;
|
||||||
|
@ -88,16 +100,18 @@ public class FolderFragment extends Fragment
|
||||||
public void onCheckedChanged(CompoundButton view, boolean isChecked) {
|
public void onCheckedChanged(CompoundButton view, boolean isChecked) {
|
||||||
switch (view.getId()) {
|
switch (view.getId()) {
|
||||||
case R.id.master:
|
case R.id.master:
|
||||||
mFolder.readOnly = isChecked;
|
mFolder.type = (isChecked) ? "readonly" : "readwrite";
|
||||||
mFolderNeedsToUpdate = true;
|
mFolderNeedsToUpdate = true;
|
||||||
break;
|
break;
|
||||||
case R.id.device_toggle:
|
case R.id.device_toggle:
|
||||||
RestApi.Device device = (RestApi.Device) view.getTag();
|
List<String> devicesList = mFolder.getDevices();
|
||||||
|
Device device = (Device) view.getTag();
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
mFolder.deviceIds.add(device.deviceID);
|
devicesList.add(device.deviceID);
|
||||||
} else {
|
} else {
|
||||||
mFolder.deviceIds.remove(device.deviceID);
|
devicesList.remove(device.deviceID);
|
||||||
}
|
}
|
||||||
|
mFolder.setDevices(devicesList);
|
||||||
mFolderNeedsToUpdate = true;
|
mFolderNeedsToUpdate = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -109,11 +123,11 @@ public class FolderFragment extends Fragment
|
||||||
@Override
|
@Override
|
||||||
public void onValueChange(int intValue) {
|
public void onValueChange(int intValue) {
|
||||||
if (intValue == 0) {
|
if (intValue == 0) {
|
||||||
mFolder.versioning = new Versioning();
|
mFolder.versioning = new Folder.Versioning();
|
||||||
mVersioningKeepView.setText(R.string.off);
|
mVersioningKeepView.setText(R.string.off);
|
||||||
} else {
|
} else {
|
||||||
mFolder.versioning = new SimpleVersioning();
|
mFolder.versioning.type = "simple";
|
||||||
((SimpleVersioning) mFolder.versioning).setParams(intValue);
|
mFolder.versioning.params.put("keep", valueOf(intValue));
|
||||||
mVersioningKeepView.setText(valueOf(intValue));
|
mVersioningKeepView.setText(valueOf(intValue));
|
||||||
}
|
}
|
||||||
mFolderNeedsToUpdate = true;
|
mFolderNeedsToUpdate = true;
|
||||||
|
@ -143,7 +157,7 @@ public class FolderFragment extends Fragment
|
||||||
|
|
||||||
if (mIsCreateMode) {
|
if (mIsCreateMode) {
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
mFolder = (RestApi.Folder) savedInstanceState.getSerializable("folder");
|
mFolder = new Gson().fromJson(savedInstanceState.getString("folder"), Folder.class);
|
||||||
}
|
}
|
||||||
if (mFolder == null) {
|
if (mFolder == null) {
|
||||||
initFolder();
|
initFolder();
|
||||||
|
@ -176,7 +190,7 @@ public class FolderFragment extends Fragment
|
||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(Bundle outState) {
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
outState.putSerializable("folder", mFolder);
|
outState.putString("folder", new Gson().toJson(mFolder));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -228,10 +242,10 @@ public class FolderFragment extends Fragment
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mIsCreateMode) {
|
if (!mIsCreateMode) {
|
||||||
List<RestApi.Folder> folders = mSyncthingService.getApi().getFolders();
|
List<Folder> folders = mSyncthingService.getApi().getFolders();
|
||||||
String passedId = getActivity().getIntent().getStringExtra(EXTRA_FOLDER_ID);
|
String passedId = getActivity().getIntent().getStringExtra(EXTRA_FOLDER_ID);
|
||||||
mFolder = null;
|
mFolder = null;
|
||||||
for (RestApi.Folder currentFolder : folders) {
|
for (Folder currentFolder : folders) {
|
||||||
if (currentFolder.id.equals(passedId)) {
|
if (currentFolder.id.equals(passedId)) {
|
||||||
mFolder = currentFolder;
|
mFolder = currentFolder;
|
||||||
break;
|
break;
|
||||||
|
@ -258,22 +272,22 @@ public class FolderFragment extends Fragment
|
||||||
mLabelView.setText(mFolder.label);
|
mLabelView.setText(mFolder.label);
|
||||||
mIdView.setText(mFolder.id);
|
mIdView.setText(mFolder.id);
|
||||||
mPathView.setText(mFolder.path);
|
mPathView.setText(mFolder.path);
|
||||||
mFolderMasterView.setChecked(mFolder.readOnly);
|
mFolderMasterView.setChecked(Objects.equal(mFolder.type, "readonly"));
|
||||||
List<RestApi.Device> devicesList = mSyncthingService.getApi().getDevices(false);
|
List<Device> devicesList = mSyncthingService.getApi().getDevices(false);
|
||||||
|
|
||||||
mDevicesContainer.removeAllViews();
|
mDevicesContainer.removeAllViews();
|
||||||
if (devicesList.isEmpty()) {
|
if (devicesList.isEmpty()) {
|
||||||
addEmptyDeviceListView();
|
addEmptyDeviceListView();
|
||||||
} else {
|
} else {
|
||||||
for (RestApi.Device n : devicesList) {
|
for (Device n : devicesList) {
|
||||||
addDeviceViewAndSetListener(n, LayoutInflater.from(getActivity()));
|
addDeviceViewAndSetListener(n, LayoutInflater.from(getActivity()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean versioningEnabled = mFolder.versioning instanceof SimpleVersioning;
|
boolean versioningEnabled = Objects.equal(mFolder.versioning.type, "simple");
|
||||||
int versions = 0;
|
int versions = 0;
|
||||||
if (versioningEnabled) {
|
if (versioningEnabled) {
|
||||||
versions = Integer.valueOf(mFolder.versioning.getParams().get("keep"));
|
versions = Integer.valueOf(mFolder.versioning.params.get("keep"));
|
||||||
mVersioningKeepView.setText(valueOf(versions));
|
mVersioningKeepView.setText(valueOf(versions));
|
||||||
} else {
|
} else {
|
||||||
mVersioningKeepView.setText(R.string.off);
|
mVersioningKeepView.setText(R.string.off);
|
||||||
|
@ -314,13 +328,14 @@ public class FolderFragment extends Fragment
|
||||||
.show();
|
.show();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
mSyncthingService.getApi().editFolder(mFolder, true, getActivity());
|
mSyncthingService.getApi().addFolder(mFolder);
|
||||||
getActivity().finish();
|
getActivity().finish();
|
||||||
return true;
|
return true;
|
||||||
case R.id.remove:
|
case R.id.remove:
|
||||||
new AlertDialog.Builder(getActivity())
|
new AlertDialog.Builder(getActivity())
|
||||||
.setMessage(R.string.remove_folder_confirm)
|
.setMessage(R.string.remove_folder_confirm)
|
||||||
.setPositiveButton(android.R.string.yes, (dialogInterface, i) -> mSyncthingService.getApi().deleteFolder(mFolder, getActivity()))
|
.setPositiveButton(android.R.string.yes, (dialogInterface, i) ->
|
||||||
|
mSyncthingService.getApi().removeFolder(mFolder.id))
|
||||||
.setNegativeButton(android.R.string.no, null)
|
.setNegativeButton(android.R.string.no, null)
|
||||||
.show();
|
.show();
|
||||||
return true;
|
return true;
|
||||||
|
@ -342,16 +357,19 @@ public class FolderFragment extends Fragment
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initFolder() {
|
private void initFolder() {
|
||||||
mFolder = new RestApi.Folder();
|
mFolder = new Folder();
|
||||||
mFolder.id = getActivity().getIntent().getStringExtra(EXTRA_FOLDER_ID);
|
mFolder.id = getActivity().getIntent().getStringExtra(EXTRA_FOLDER_ID);
|
||||||
mFolder.label = getActivity().getIntent().getStringExtra(EXTRA_FOLDER_LABEL);
|
mFolder.label = getActivity().getIntent().getStringExtra(EXTRA_FOLDER_LABEL);
|
||||||
mFolder.path = "";
|
|
||||||
mFolder.rescanIntervalS = 259200; // Scan every 3 days (in case inotify dropped some changes)
|
mFolder.rescanIntervalS = 259200; // Scan every 3 days (in case inotify dropped some changes)
|
||||||
mFolder.deviceIds = new ArrayList<>();
|
mFolder.versioning = new Folder.Versioning();
|
||||||
mFolder.versioning = new Versioning();
|
|
||||||
String deviceId = getActivity().getIntent().getStringExtra(EXTRA_DEVICE_ID);
|
String deviceId = getActivity().getIntent().getStringExtra(EXTRA_DEVICE_ID);
|
||||||
if (deviceId != null)
|
if (deviceId != null) {
|
||||||
mFolder.deviceIds.add(deviceId);
|
List<String> devices = ImmutableList.<String>builder()
|
||||||
|
.addAll(mFolder.getDevices())
|
||||||
|
.add(deviceId)
|
||||||
|
.build();
|
||||||
|
mFolder.setDevices(devices);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void prepareEditMode() {
|
private void prepareEditMode() {
|
||||||
|
@ -362,7 +380,8 @@ public class FolderFragment extends Fragment
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addEmptyDeviceListView() {
|
private void addEmptyDeviceListView() {
|
||||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(WRAP_CONTENT, dp(48, getActivity()));
|
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 dividerInset = getResources().getDimensionPixelOffset(R.dimen.material_divider_inset);
|
||||||
int contentInset = getResources().getDimensionPixelOffset(R.dimen.abc_action_bar_content_inset_material);
|
int contentInset = getResources().getDimensionPixelOffset(R.dimen.abc_action_bar_content_inset_material);
|
||||||
setMarginStart(params, dividerInset);
|
setMarginStart(params, dividerInset);
|
||||||
|
@ -373,18 +392,18 @@ public class FolderFragment extends Fragment
|
||||||
mDevicesContainer.addView(emptyView, params);
|
mDevicesContainer.addView(emptyView, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addDeviceViewAndSetListener(RestApi.Device device, LayoutInflater inflater) {
|
private void addDeviceViewAndSetListener(Device device, LayoutInflater inflater) {
|
||||||
inflater.inflate(R.layout.item_device_form, mDevicesContainer);
|
inflater.inflate(R.layout.item_device_form, mDevicesContainer);
|
||||||
SwitchCompat deviceView = (SwitchCompat) mDevicesContainer.getChildAt(mDevicesContainer.getChildCount()-1);
|
SwitchCompat deviceView = (SwitchCompat) mDevicesContainer.getChildAt(mDevicesContainer.getChildCount()-1);
|
||||||
deviceView.setChecked(mFolder.deviceIds.contains(device.deviceID));
|
deviceView.setChecked(mFolder.getDevices().contains(device.deviceID));
|
||||||
deviceView.setText(RestApi.getDeviceDisplayName(device));
|
deviceView.setText(device.getDisplayName());
|
||||||
deviceView.setTag(device);
|
deviceView.setTag(device);
|
||||||
deviceView.setOnCheckedChangeListener(mCheckedListener);
|
deviceView.setOnCheckedChangeListener(mCheckedListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateFolder() {
|
private void updateFolder() {
|
||||||
if (!mIsCreateMode) {
|
if (!mIsCreateMode) {
|
||||||
mSyncthingService.getApi().editFolder(mFolder, false, getActivity());
|
mSyncthingService.getApi().editFolder(mFolder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,9 @@ import android.widget.AdapterView;
|
||||||
import com.nutomic.syncthingandroid.R;
|
import com.nutomic.syncthingandroid.R;
|
||||||
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.syncthing.RestApi;
|
import com.nutomic.syncthingandroid.model.Folder;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
import com.nutomic.syncthingandroid.util.FoldersAdapter;
|
import com.nutomic.syncthingandroid.views.FoldersAdapter;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
@ -32,7 +32,7 @@ public class FolderListFragment extends ListFragment implements SyncthingService
|
||||||
/**
|
/**
|
||||||
* Compares folders by labels, uses the folder ID as fallback if the label is empty
|
* Compares folders by labels, uses the folder ID as fallback if the label is empty
|
||||||
*/
|
*/
|
||||||
private final static Comparator<RestApi.Folder> FOLDERS_COMPARATOR = (lhs, rhs) -> {
|
private final static Comparator<Folder> FOLDERS_COMPARATOR = (lhs, rhs) -> {
|
||||||
String lhsLabel = lhs.label != null && !lhs.label.isEmpty() ? lhs.label : lhs.id;
|
String lhsLabel = lhs.label != null && !lhs.label.isEmpty() ? lhs.label : lhs.id;
|
||||||
String rhsLabel = rhs.label != null && !rhs.label.isEmpty() ? rhs.label : rhs.id;
|
String rhsLabel = rhs.label != null && !rhs.label.isEmpty() ? rhs.label : rhs.id;
|
||||||
|
|
||||||
|
@ -43,19 +43,6 @@ public class FolderListFragment extends ListFragment implements SyncthingService
|
||||||
|
|
||||||
private Timer mTimer;
|
private Timer mTimer;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
mTimer = new Timer();
|
|
||||||
mTimer.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
getActivity().runOnUiThread(FolderListFragment.this::updateList);
|
|
||||||
}
|
|
||||||
|
|
||||||
}, 0, SyncthingService.GUI_UPDATE_INTERVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
|
@ -67,26 +54,29 @@ public class FolderListFragment extends ListFragment implements SyncthingService
|
||||||
if (currentState != SyncthingService.State.ACTIVE)
|
if (currentState != SyncthingService.State.ACTIVE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
updateList();
|
mTimer = new Timer();
|
||||||
|
mTimer.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (getActivity() == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
getActivity().runOnUiThread(FolderListFragment.this::updateList);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, 0, SyncthingService.GUI_UPDATE_INTERVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
|
setHasOptionsMenu(true);
|
||||||
setEmptyText(getString(R.string.folder_list_empty));
|
setEmptyText(getString(R.string.folder_list_empty));
|
||||||
getListView().setOnItemClickListener(this);
|
getListView().setOnItemClickListener(this);
|
||||||
getListView().setOnItemLongClickListener(this);
|
getListView().setOnItemLongClickListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onActivityCreated(Bundle savedInstanceState) {
|
|
||||||
super.onActivityCreated(savedInstanceState);
|
|
||||||
|
|
||||||
updateList();
|
|
||||||
setHasOptionsMenu(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refreshes ListView by updating folders and info.
|
* Refreshes ListView by updating folders and info.
|
||||||
*
|
*
|
||||||
|
@ -94,8 +84,7 @@ public class FolderListFragment extends ListFragment implements SyncthingService
|
||||||
*/
|
*/
|
||||||
private void updateList() {
|
private void updateList() {
|
||||||
SyncthingActivity activity = (SyncthingActivity) getActivity();
|
SyncthingActivity activity = (SyncthingActivity) getActivity();
|
||||||
if (activity == null || activity.getApi() == null || getView() == null ||
|
if (activity.getApi() == null || getView() == null || activity.isFinishing())
|
||||||
activity.isFinishing())
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mAdapter == null) {
|
if (mAdapter == null) {
|
||||||
|
@ -106,7 +95,7 @@ public class FolderListFragment extends ListFragment implements SyncthingService
|
||||||
// Prevent scroll position reset due to list update from clear().
|
// Prevent scroll position reset due to list update from clear().
|
||||||
mAdapter.setNotifyOnChange(false);
|
mAdapter.setNotifyOnChange(false);
|
||||||
mAdapter.clear();
|
mAdapter.clear();
|
||||||
List<RestApi.Folder> folders = activity.getApi().getFolders();
|
List<Folder> folders = activity.getApi().getFolders();
|
||||||
Collections.sort(folders, FOLDERS_COMPARATOR);
|
Collections.sort(folders, FOLDERS_COMPARATOR);
|
||||||
mAdapter.addAll(folders);
|
mAdapter.addAll(folders);
|
||||||
mAdapter.updateModel(activity.getApi());
|
mAdapter.updateModel(activity.getApi());
|
||||||
|
|
|
@ -10,19 +10,23 @@ import android.preference.EditTextPreference;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.PreferenceFragment;
|
import android.preference.PreferenceFragment;
|
||||||
import android.preference.PreferenceScreen;
|
import android.preference.PreferenceScreen;
|
||||||
import android.support.v4.app.NavUtils;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.google.common.base.Joiner;
|
||||||
|
import com.google.common.base.Splitter;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
import com.nutomic.syncthingandroid.R;
|
import com.nutomic.syncthingandroid.R;
|
||||||
import com.nutomic.syncthingandroid.activities.SyncthingActivity;
|
import com.nutomic.syncthingandroid.activities.SyncthingActivity;
|
||||||
import com.nutomic.syncthingandroid.preferences.WifiSsidPreference;
|
import com.nutomic.syncthingandroid.model.Config;
|
||||||
import com.nutomic.syncthingandroid.syncthing.RestApi;
|
import com.nutomic.syncthingandroid.model.Device;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
import com.nutomic.syncthingandroid.model.Options;
|
||||||
|
import com.nutomic.syncthingandroid.views.WifiSsidPreference;
|
||||||
|
import com.nutomic.syncthingandroid.service.RestApi;
|
||||||
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
|
|
||||||
|
import java.security.InvalidParameterException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.TreeSet;
|
|
||||||
|
|
||||||
import eu.chainfire.libsuperuser.Shell;
|
import eu.chainfire.libsuperuser.Shell;
|
||||||
|
|
||||||
|
@ -32,89 +36,39 @@ public class SettingsFragment extends PreferenceFragment
|
||||||
Preference.OnPreferenceClickListener {
|
Preference.OnPreferenceClickListener {
|
||||||
|
|
||||||
private static final String TAG = "SettingsFragment";
|
private static final String TAG = "SettingsFragment";
|
||||||
|
private static final String KEY_STTRACE = "sttrace";
|
||||||
private static final String SYNCTHING_OPTIONS_KEY = "syncthing_options";
|
private static final String KEY_EXPORT_CONFIG = "export_config";
|
||||||
private static final String SYNCTHING_GUI_KEY = "syncthing_gui";
|
private static final String KEY_IMPORT_CONFIG = "import_config";
|
||||||
private static final String DEVICE_NAME_KEY = "deviceName";
|
private static final String KEY_STRESET = "streset";
|
||||||
private static final String USAGE_REPORT_ACCEPTED = "urAccepted";
|
|
||||||
private static final String ADDRESS = "address";
|
|
||||||
private static final String USER = "user";
|
|
||||||
// Note that this preference is seperate from the syncthing config value. While Syncthing
|
|
||||||
// stores a password hash, we store the plaintext password in the Android preferences.
|
|
||||||
private static final String PASSWORD = "web_gui_password";
|
|
||||||
private static final String EXPORT_CONFIG = "export_config";
|
|
||||||
private static final String IMPORT_CONFIG = "import_config";
|
|
||||||
private static final String STTRACE = "sttrace";
|
|
||||||
private static final String SYNCTHING_RESET = "streset";
|
|
||||||
private static final String SYNCTHING_VERSION_KEY = "syncthing_version";
|
|
||||||
private static final String APP_VERSION_KEY = "app_version";
|
|
||||||
|
|
||||||
private CheckBoxPreference mAlwaysRunInBackground;
|
private CheckBoxPreference mAlwaysRunInBackground;
|
||||||
private CheckBoxPreference mSyncOnlyCharging;
|
private CheckBoxPreference mSyncOnlyCharging;
|
||||||
private CheckBoxPreference mSyncOnlyWifi;
|
private CheckBoxPreference mSyncOnlyWifi;
|
||||||
private WifiSsidPreference mSyncOnlyOnSSIDs;
|
private WifiSsidPreference mSyncOnlyOnSSIDs;
|
||||||
|
|
||||||
|
private EditTextPreference mDeviceName;
|
||||||
|
private EditTextPreference mListenAddresses;
|
||||||
|
private EditTextPreference mMaxRecvKbps;
|
||||||
|
private EditTextPreference mMaxSendKbps;
|
||||||
|
private CheckBoxPreference mNatEnabled;
|
||||||
|
private CheckBoxPreference mLocalAnnounceEnabled;
|
||||||
|
private CheckBoxPreference mGlobalAnnounceEnabled;
|
||||||
|
private CheckBoxPreference mRelaysEnabled;
|
||||||
|
private EditTextPreference mGlobalAnnounceServers;
|
||||||
|
private EditTextPreference mAddress;
|
||||||
|
private EditTextPreference mUser;
|
||||||
|
private EditTextPreference mPassword;
|
||||||
|
private CheckBoxPreference mUrAccepted;
|
||||||
|
|
||||||
private CheckBoxPreference mUseRoot;
|
private CheckBoxPreference mUseRoot;
|
||||||
private CheckBoxPreference mKeepWakelock;
|
|
||||||
private PreferenceScreen mOptionsScreen;
|
private Preference mSyncthingVersion;
|
||||||
private PreferenceScreen mGuiScreen;
|
|
||||||
private SyncthingService mSyncthingService;
|
private SyncthingService mSyncthingService;
|
||||||
|
private RestApi mApi;
|
||||||
|
|
||||||
@Override
|
private Options mOptions;
|
||||||
public void onApiChange(SyncthingService.State currentState) {
|
private Config.Gui mGui;
|
||||||
boolean enabled = currentState == SyncthingService.State.ACTIVE;
|
|
||||||
mOptionsScreen.setEnabled(enabled);
|
|
||||||
mGuiScreen.setEnabled(enabled);
|
|
||||||
mUseRoot.setEnabled(enabled);
|
|
||||||
mKeepWakelock.setEnabled(enabled);
|
|
||||||
|
|
||||||
if (currentState == SyncthingService.State.ACTIVE) {
|
|
||||||
Preference syncthingVersion = getPreferenceScreen().findPreference(SYNCTHING_VERSION_KEY);
|
|
||||||
syncthingVersion.setSummary(mSyncthingService.getApi().getVersion());
|
|
||||||
RestApi api = mSyncthingService.getApi();
|
|
||||||
for (int i = 0; i < mOptionsScreen.getPreferenceCount(); i++) {
|
|
||||||
final Preference pref = mOptionsScreen.getPreference(i);
|
|
||||||
pref.setOnPreferenceChangeListener(SettingsFragment.this);
|
|
||||||
String value;
|
|
||||||
switch (pref.getKey()) {
|
|
||||||
case DEVICE_NAME_KEY:
|
|
||||||
value = api.getLocalDevice().name;
|
|
||||||
break;
|
|
||||||
case USAGE_REPORT_ACCEPTED:
|
|
||||||
int setting = api.getUsageReportAccepted();
|
|
||||||
value = Boolean.toString(setting == RestApi.USAGE_REPORTING_ACCEPTED);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
value = api.getValue(RestApi.TYPE_OPTIONS, pref.getKey());
|
|
||||||
}
|
|
||||||
applyPreference(pref, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
Preference address = mGuiScreen.findPreference(ADDRESS);
|
|
||||||
address.setOnPreferenceChangeListener(this);
|
|
||||||
applyPreference(address, api.getValue(RestApi.TYPE_GUI, ADDRESS));
|
|
||||||
|
|
||||||
Preference user = mGuiScreen.findPreference(USER);
|
|
||||||
user.setOnPreferenceChangeListener(this);
|
|
||||||
applyPreference(user, api.getValue(RestApi.TYPE_GUI, USER));
|
|
||||||
|
|
||||||
Preference password = mGuiScreen.findPreference(PASSWORD);
|
|
||||||
password.setOnPreferenceChangeListener(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies the given value to the preference.
|
|
||||||
*
|
|
||||||
* If pref is an EditTextPreference, setText is used and the value shown as summary. If pref is
|
|
||||||
* a CheckBoxPreference, setChecked is used (by parsing value as Boolean).
|
|
||||||
*/
|
|
||||||
private void applyPreference(Preference pref, String value) {
|
|
||||||
if (pref instanceof EditTextPreference) {
|
|
||||||
((EditTextPreference) pref).setText(value);
|
|
||||||
} else if (pref instanceof CheckBoxPreference) {
|
|
||||||
((CheckBoxPreference) pref).setChecked(Boolean.parseBoolean(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads layout, sets version from Rest API.
|
* Loads layout, sets version from Rest API.
|
||||||
|
@ -128,20 +82,60 @@ public class SettingsFragment extends PreferenceFragment
|
||||||
((SyncthingActivity) getActivity()).registerOnServiceConnectedListener(this);
|
((SyncthingActivity) getActivity()).registerOnServiceConnectedListener(this);
|
||||||
|
|
||||||
addPreferencesFromResource(R.xml.app_settings);
|
addPreferencesFromResource(R.xml.app_settings);
|
||||||
final PreferenceScreen screen = getPreferenceScreen();
|
PreferenceScreen screen = getPreferenceScreen();
|
||||||
mAlwaysRunInBackground = (CheckBoxPreference)
|
mAlwaysRunInBackground =
|
||||||
findPreference(SyncthingService.PREF_ALWAYS_RUN_IN_BACKGROUND);
|
(CheckBoxPreference) findPreference(SyncthingService.PREF_ALWAYS_RUN_IN_BACKGROUND);
|
||||||
mSyncOnlyCharging = (CheckBoxPreference)
|
mSyncOnlyCharging =
|
||||||
findPreference(SyncthingService.PREF_SYNC_ONLY_CHARGING);
|
(CheckBoxPreference) findPreference(SyncthingService.PREF_SYNC_ONLY_CHARGING);
|
||||||
mSyncOnlyWifi = (CheckBoxPreference) findPreference(SyncthingService.PREF_SYNC_ONLY_WIFI);
|
mSyncOnlyWifi =
|
||||||
mSyncOnlyOnSSIDs = (WifiSsidPreference) findPreference(SyncthingService.PREF_SYNC_ONLY_WIFI_SSIDS);
|
(CheckBoxPreference) findPreference(SyncthingService.PREF_SYNC_ONLY_WIFI);
|
||||||
mSyncOnlyOnSSIDs.setDefaultValue(new TreeSet<String>()); // default to empty list
|
mSyncOnlyOnSSIDs =
|
||||||
|
(WifiSsidPreference) findPreference(SyncthingService.PREF_SYNC_ONLY_WIFI_SSIDS);
|
||||||
|
|
||||||
|
mDeviceName = (EditTextPreference) findPreference("deviceName");
|
||||||
|
mListenAddresses = (EditTextPreference) findPreference("listenAddresses");
|
||||||
|
mMaxRecvKbps = (EditTextPreference) findPreference("maxRecvKbps");
|
||||||
|
mMaxSendKbps = (EditTextPreference) findPreference("maxSendKbps");
|
||||||
|
mNatEnabled = (CheckBoxPreference) findPreference("natEnabled");
|
||||||
|
mLocalAnnounceEnabled = (CheckBoxPreference) findPreference("localAnnounceEnabled");
|
||||||
|
mGlobalAnnounceEnabled = (CheckBoxPreference) findPreference("globalAnnounceEnabled");
|
||||||
|
mRelaysEnabled = (CheckBoxPreference) findPreference("relaysEnabled");
|
||||||
|
mGlobalAnnounceServers = (EditTextPreference) findPreference("globalAnnounceServers");
|
||||||
|
mAddress = (EditTextPreference) findPreference("address");
|
||||||
|
mUser = (EditTextPreference) findPreference("user");
|
||||||
|
mPassword = (EditTextPreference) findPreference("password");
|
||||||
|
mUrAccepted = (CheckBoxPreference) findPreference("urAccepted");
|
||||||
|
|
||||||
|
Preference exportConfig = findPreference("export_config");
|
||||||
|
Preference importConfig = findPreference("import_config");
|
||||||
|
|
||||||
|
Preference stTrace = findPreference("sttrace");
|
||||||
|
Preference stReset = findPreference("streset");
|
||||||
|
|
||||||
mUseRoot = (CheckBoxPreference) findPreference(SyncthingService.PREF_USE_ROOT);
|
mUseRoot = (CheckBoxPreference) findPreference(SyncthingService.PREF_USE_ROOT);
|
||||||
mKeepWakelock = (CheckBoxPreference) findPreference(SyncthingService.PREF_USE_WAKE_LOCK);
|
Preference useWakelock = findPreference(SyncthingService.PREF_USE_WAKE_LOCK);
|
||||||
Preference appVersion = screen.findPreference(APP_VERSION_KEY);
|
Preference foregroundService = findPreference("run_as_foreground_service");
|
||||||
mOptionsScreen = (PreferenceScreen) screen.findPreference(SYNCTHING_OPTIONS_KEY);
|
Preference useTor = findPreference("use_tor");
|
||||||
mGuiScreen = (PreferenceScreen) screen.findPreference(SYNCTHING_GUI_KEY);
|
|
||||||
Preference sttrace = findPreference(STTRACE);
|
mSyncthingVersion = findPreference("syncthing_version");
|
||||||
|
Preference appVersion = screen.findPreference("app_version");
|
||||||
|
|
||||||
|
mSyncOnlyOnSSIDs.setEnabled(mSyncOnlyWifi.isChecked());
|
||||||
|
setPreferenceCategoryChangeListener(findPreference("category_run_conditions"), this);
|
||||||
|
|
||||||
|
setPreferenceCategoryChangeListener(
|
||||||
|
findPreference("category_syncthing_options"), this::onSyncthingPreferenceChange);
|
||||||
|
|
||||||
|
exportConfig.setOnPreferenceClickListener(this);
|
||||||
|
importConfig.setOnPreferenceClickListener(this);
|
||||||
|
|
||||||
|
stTrace.setOnPreferenceChangeListener(this);
|
||||||
|
stReset.setOnPreferenceClickListener(this);
|
||||||
|
|
||||||
|
mUseRoot.setOnPreferenceChangeListener(this);
|
||||||
|
useWakelock.setOnPreferenceChangeListener(this::onRequireRestart);
|
||||||
|
foregroundService.setOnPreferenceChangeListener(this::onRequireRestart);
|
||||||
|
useTor.setOnPreferenceChangeListener(this::onRequireRestart);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
appVersion.setSummary(getActivity().getPackageManager()
|
appVersion.setSummary(getActivity().getPackageManager()
|
||||||
|
@ -149,44 +143,42 @@ public class SettingsFragment extends PreferenceFragment
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
Log.d(TAG, "Failed to get app version name");
|
Log.d(TAG, "Failed to get app version name");
|
||||||
}
|
}
|
||||||
|
|
||||||
mAlwaysRunInBackground.setOnPreferenceChangeListener(this);
|
|
||||||
mSyncOnlyCharging.setOnPreferenceChangeListener(this);
|
|
||||||
mSyncOnlyWifi.setOnPreferenceChangeListener(this);
|
|
||||||
mSyncOnlyOnSSIDs.setOnPreferenceChangeListener(this);
|
|
||||||
mUseRoot.setOnPreferenceClickListener(this);
|
|
||||||
mKeepWakelock.setOnPreferenceClickListener(this);
|
|
||||||
screen.findPreference(EXPORT_CONFIG).setOnPreferenceClickListener(this);
|
|
||||||
screen.findPreference(IMPORT_CONFIG).setOnPreferenceClickListener(this);
|
|
||||||
screen.findPreference(SYNCTHING_RESET).setOnPreferenceClickListener(this);
|
|
||||||
sttrace.setOnPreferenceChangeListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables or disables {@link #mUseRoot} preference depending whether root is available.
|
|
||||||
*/
|
|
||||||
private class TestRootTask extends AsyncTask<Void, Void, Boolean> {
|
|
||||||
@Override
|
|
||||||
protected Boolean doInBackground(Void... params) {
|
|
||||||
return Shell.SU.available();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Boolean haveRoot) {
|
|
||||||
if (haveRoot) {
|
|
||||||
mSyncthingService.getApi().requireRestart(getActivity());
|
|
||||||
mUseRoot.setChecked(true);
|
|
||||||
} else {
|
|
||||||
Toast.makeText(getActivity(), R.string.toast_root_denied, Toast.LENGTH_SHORT)
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServiceConnected() {
|
public void onServiceConnected() {
|
||||||
mSyncthingService = ((SyncthingActivity) getActivity()).getService();
|
mSyncthingService = ((SyncthingActivity) getActivity()).getService();
|
||||||
mSyncthingService.registerOnApiChangeListener(this);
|
mSyncthingService.registerOnApiChangeListener(this);
|
||||||
|
mGui = mSyncthingService.getApi().getGui();
|
||||||
|
mOptions = mSyncthingService.getApi().getOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onApiChange(SyncthingService.State currentState) {
|
||||||
|
boolean enabled = currentState == SyncthingService.State.ACTIVE;
|
||||||
|
getPreferenceScreen().setEnabled(enabled);
|
||||||
|
if (!enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mApi = mSyncthingService.getApi();
|
||||||
|
mSyncthingVersion.setSummary(mApi.getVersion());
|
||||||
|
mOptions = mApi.getOptions();
|
||||||
|
mGui = mApi.getGui();
|
||||||
|
|
||||||
|
Joiner joiner = Joiner.on(", ");
|
||||||
|
mDeviceName.setText(mApi.getLocalDevice().name);
|
||||||
|
mListenAddresses.setText(joiner.join(mOptions.listenAddresses));
|
||||||
|
mMaxRecvKbps.setText(Integer.toString(mOptions.maxRecvKbps));
|
||||||
|
mMaxSendKbps.setText(Integer.toString(mOptions.maxSendKbps));
|
||||||
|
mNatEnabled.setChecked(mOptions.natEnabled);
|
||||||
|
mLocalAnnounceEnabled.setChecked(mOptions.localAnnounceEnabled);
|
||||||
|
mGlobalAnnounceEnabled.setChecked(mOptions.globalAnnounceEnabled);
|
||||||
|
mRelaysEnabled.setChecked(mOptions.relaysEnabled);
|
||||||
|
mGlobalAnnounceServers.setText(joiner.join(mOptions.globalAnnounceServers));
|
||||||
|
mAddress.setText(mGui.address);
|
||||||
|
mUser.setText(mGui.user);
|
||||||
|
mPassword.setText(mGui.password);
|
||||||
|
mUrAccepted.setChecked(mOptions.getUsageReportValue() == Options.USAGE_REPORTING_ACCEPTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -195,31 +187,65 @@ public class SettingsFragment extends PreferenceFragment
|
||||||
mSyncthingService.unregisterOnApiChangeListener(this);
|
mSyncthingService.unregisterOnApiChangeListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void setPreferenceCategoryChangeListener(
|
||||||
* Handles ActionBar back selected.
|
Preference category, Preference.OnPreferenceChangeListener listener) {
|
||||||
*/
|
PreferenceScreen ps = (PreferenceScreen) category;
|
||||||
@Override
|
for (int i = 0; i < ps.getPreferenceCount(); i++) {
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
Preference p = ps.getPreference(i);
|
||||||
switch (item.getItemId()) {
|
p.setOnPreferenceChangeListener(listener);
|
||||||
case android.R.id.home:
|
|
||||||
NavUtils.navigateUpFromSameTask(getActivity());
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean onSyncthingPreferenceChange(Preference preference, Object o) {
|
||||||
|
Splitter splitter = Splitter.on(",").trimResults().omitEmptyStrings();
|
||||||
|
switch (preference.getKey()) {
|
||||||
|
case "deviceName":
|
||||||
|
Device localDevice = mApi.getLocalDevice();
|
||||||
|
localDevice.name = (String) o;
|
||||||
|
mApi.editDevice(localDevice);
|
||||||
|
break;
|
||||||
|
case "listenAddresses":
|
||||||
|
mOptions.listenAddresses = Iterables.toArray(splitter.split((String) o), String.class);
|
||||||
|
break;
|
||||||
|
case "maxRecvKbps": mOptions.maxRecvKbps = (int) o; break;
|
||||||
|
case "maxSendKbps": mOptions.maxRecvKbps = (int) o; break;
|
||||||
|
case "natEnabled": mOptions.natEnabled = (boolean) o; break;
|
||||||
|
case "localAnnounceEnabled": mOptions.localAnnounceEnabled = (boolean) o; break;
|
||||||
|
case "globalAnnounceEnabled": mOptions.globalAnnounceEnabled = (boolean) o; break;
|
||||||
|
case "relaysEnabled": mOptions.relaysEnabled = (boolean) o; break;
|
||||||
|
case "globalAnnounceServers":
|
||||||
|
mOptions.globalAnnounceServers = Iterables.toArray(splitter.split((String) o), String.class);
|
||||||
|
break;
|
||||||
|
case "address": mGui.address = (String) o; break;
|
||||||
|
case "user": mGui.user = (String) o; break;
|
||||||
|
case "password": mGui.password = (String) o; break;
|
||||||
|
case "urAccepted":
|
||||||
|
mOptions.urAccepted = ((boolean) o)
|
||||||
|
? Options.USAGE_REPORTING_ACCEPTED
|
||||||
|
: Options.USAGE_REPORTING_DENIED;
|
||||||
|
break;
|
||||||
|
default: throw new InvalidParameterException();
|
||||||
|
}
|
||||||
|
|
||||||
|
mApi.editSettings(mGui, mOptions, getActivity());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onRequireRestart(Preference preference, Object o) {
|
||||||
|
mSyncthingService.getApi().showRestartDialog(getActivity());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends the updated value to {@link }RestApi}, and sets it as the summary
|
* Sends the updated value to {@link }RestApi}, and sets it as the summary
|
||||||
* for EditTextPreference.
|
* for EditTextPreference.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceChange(Preference preference, Object o) {
|
public boolean onPreferenceChange(Preference preference, Object o) {
|
||||||
boolean requireRestart = false;
|
switch (preference.getKey()) {
|
||||||
|
case SyncthingService.PREF_ALWAYS_RUN_IN_BACKGROUND:
|
||||||
if (preference.equals(mAlwaysRunInBackground)) {
|
|
||||||
boolean value = (Boolean) o;
|
boolean value = (Boolean) o;
|
||||||
preference.setSummary((value)
|
mAlwaysRunInBackground.setSummary((value)
|
||||||
? R.string.always_run_in_background_enabled
|
? R.string.always_run_in_background_enabled
|
||||||
: R.string.always_run_in_background_disabled);
|
: R.string.always_run_in_background_disabled);
|
||||||
mSyncOnlyCharging.setEnabled(value);
|
mSyncOnlyCharging.setEnabled(value);
|
||||||
|
@ -230,66 +256,24 @@ public class SettingsFragment extends PreferenceFragment
|
||||||
mSyncOnlyCharging.setChecked(false);
|
mSyncOnlyCharging.setChecked(false);
|
||||||
mSyncOnlyWifi.setChecked(false);
|
mSyncOnlyWifi.setChecked(false);
|
||||||
}
|
}
|
||||||
} else if (preference.equals(mSyncOnlyWifi)) {
|
break;
|
||||||
|
case SyncthingService.PREF_SYNC_ONLY_WIFI:
|
||||||
mSyncOnlyOnSSIDs.setEnabled((Boolean) o);
|
mSyncOnlyOnSSIDs.setEnabled((Boolean) o);
|
||||||
} else if (preference.getKey().equals(DEVICE_NAME_KEY)) {
|
break;
|
||||||
RestApi.Device old = mSyncthingService.getApi().getLocalDevice();
|
case KEY_STTRACE:
|
||||||
RestApi.Device updated = new RestApi.Device();
|
|
||||||
updated.addresses = old.addresses;
|
|
||||||
updated.compression = old.compression;
|
|
||||||
updated.deviceID = old.deviceID;
|
|
||||||
updated.introducer = old.introducer;
|
|
||||||
updated.name = (String) o;
|
|
||||||
mSyncthingService.getApi().editDevice(updated, getActivity(), null);
|
|
||||||
} else if (preference.getKey().equals(USAGE_REPORT_ACCEPTED)) {
|
|
||||||
int setting = ((Boolean) o)
|
|
||||||
? RestApi.USAGE_REPORTING_ACCEPTED
|
|
||||||
: RestApi.USAGE_REPORTING_DENIED;
|
|
||||||
mSyncthingService.getApi().setUsageReportAccepted(setting, getActivity());
|
|
||||||
} else if (mOptionsScreen.findPreference(preference.getKey()) != null) {
|
|
||||||
boolean isArray = preference.getKey().equals("listenAddress") ||
|
|
||||||
preference.getKey().equals("globalAnnounceServers");
|
|
||||||
mSyncthingService.getApi().setValue(RestApi.TYPE_OPTIONS, preference.getKey(), o,
|
|
||||||
isArray, getActivity());
|
|
||||||
} else if (preference.getKey().equals(ADDRESS)) {
|
|
||||||
mSyncthingService.getApi().setValue(
|
|
||||||
RestApi.TYPE_GUI, preference.getKey(), o, false, getActivity());
|
|
||||||
} else if (preference.getKey().equals(USER)) {
|
|
||||||
mSyncthingService.getApi().setValue(
|
|
||||||
RestApi.TYPE_GUI, preference.getKey(), o, false, getActivity());
|
|
||||||
} else if (preference.getKey().equals(PASSWORD)) {
|
|
||||||
mSyncthingService.getApi().setValue(
|
|
||||||
RestApi.TYPE_GUI, "password", o, false, getActivity());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Avoid any code injection.
|
|
||||||
if (preference.getKey().equals(STTRACE)) {
|
|
||||||
if (((String) o).matches("[0-9a-z, ]*"))
|
if (((String) o).matches("[0-9a-z, ]*"))
|
||||||
requireRestart = true;
|
mSyncthingService.getApi().showRestartDialog(getActivity());
|
||||||
else {
|
else {
|
||||||
Toast.makeText(getActivity(), R.string.toast_invalid_sttrace, Toast.LENGTH_SHORT).show();
|
Toast.makeText(getActivity(), R.string.toast_invalid_sttrace, Toast.LENGTH_SHORT)
|
||||||
|
.show();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requireRestart)
|
|
||||||
mSyncthingService.getApi().requireRestart(getActivity());
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the owner of syncthing files so they can be accessed without root.
|
|
||||||
*/
|
|
||||||
private class ChownFilesRunnable implements Runnable {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
String f = getActivity().getFilesDir().getAbsolutePath();
|
|
||||||
List<String> out = Shell.SU.run("chown -R --reference=" + f + " " + f);
|
|
||||||
Log.i(TAG, "Changed owner of syncthing files, output: " + out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceClick(Preference preference) {
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
switch (preference.getKey()) {
|
switch (preference.getKey()) {
|
||||||
|
@ -300,17 +284,13 @@ public class SettingsFragment extends PreferenceFragment
|
||||||
new TestRootTask().execute();
|
new TestRootTask().execute();
|
||||||
} else {
|
} else {
|
||||||
new Thread(new ChownFilesRunnable()).start();
|
new Thread(new ChownFilesRunnable()).start();
|
||||||
mSyncthingService.getApi().requireRestart(getActivity());
|
mSyncthingService.getApi().showRestartDialog(getActivity());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case SyncthingService.PREF_USE_WAKE_LOCK:
|
case KEY_EXPORT_CONFIG:
|
||||||
mSyncthingService.getApi().requireRestart(getActivity());
|
|
||||||
return true;
|
|
||||||
case EXPORT_CONFIG:
|
|
||||||
new AlertDialog.Builder(getActivity())
|
new AlertDialog.Builder(getActivity())
|
||||||
.setMessage(R.string.dialog_confirm_export)
|
.setMessage(R.string.dialog_confirm_export)
|
||||||
.setPositiveButton(android.R.string.yes,
|
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
|
||||||
(dialog, which) -> {
|
|
||||||
mSyncthingService.exportConfig();
|
mSyncthingService.exportConfig();
|
||||||
Toast.makeText(getActivity(),
|
Toast.makeText(getActivity(),
|
||||||
getString(R.string.config_export_successful,
|
getString(R.string.config_export_successful,
|
||||||
|
@ -319,11 +299,10 @@ public class SettingsFragment extends PreferenceFragment
|
||||||
.setNegativeButton(android.R.string.no, null)
|
.setNegativeButton(android.R.string.no, null)
|
||||||
.show();
|
.show();
|
||||||
return true;
|
return true;
|
||||||
case IMPORT_CONFIG:
|
case KEY_IMPORT_CONFIG:
|
||||||
new AlertDialog.Builder(getActivity())
|
new AlertDialog.Builder(getActivity())
|
||||||
.setMessage(R.string.dialog_confirm_import)
|
.setMessage(R.string.dialog_confirm_import)
|
||||||
.setPositiveButton(android.R.string.yes,
|
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
|
||||||
(dialog, which) -> {
|
|
||||||
if (mSyncthingService.importConfig()) {
|
if (mSyncthingService.importConfig()) {
|
||||||
Toast.makeText(getActivity(),
|
Toast.makeText(getActivity(),
|
||||||
getString(R.string.config_imported_successful),
|
getString(R.string.config_imported_successful),
|
||||||
|
@ -339,7 +318,7 @@ public class SettingsFragment extends PreferenceFragment
|
||||||
.setNegativeButton(android.R.string.no, null)
|
.setNegativeButton(android.R.string.no, null)
|
||||||
.show();
|
.show();
|
||||||
return true;
|
return true;
|
||||||
case SYNCTHING_RESET:
|
case KEY_STRESET:
|
||||||
final Intent intent = new Intent(getActivity(), SyncthingService.class)
|
final Intent intent = new Intent(getActivity(), SyncthingService.class)
|
||||||
.setAction(SyncthingService.ACTION_RESET);
|
.setAction(SyncthingService.ACTION_RESET);
|
||||||
|
|
||||||
|
@ -359,4 +338,37 @@ public class SettingsFragment extends PreferenceFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables or disables {@link #mUseRoot} preference depending whether root is available.
|
||||||
|
*/
|
||||||
|
private class TestRootTask extends AsyncTask<Void, Void, Boolean> {
|
||||||
|
@Override
|
||||||
|
protected Boolean doInBackground(Void... params) {
|
||||||
|
return Shell.SU.available();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Boolean haveRoot) {
|
||||||
|
if (haveRoot) {
|
||||||
|
mSyncthingService.getApi().showRestartDialog(getActivity());
|
||||||
|
mUseRoot.setChecked(true);
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getActivity(), R.string.toast_root_denied, Toast.LENGTH_SHORT)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the owner of syncthing files so they can be accessed without root.
|
||||||
|
*/
|
||||||
|
private class ChownFilesRunnable implements Runnable {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
String f = getActivity().getFilesDir().getAbsolutePath();
|
||||||
|
List<String> out = Shell.SU.run("chown -R --reference=" + f + " " + f);
|
||||||
|
Log.i(TAG, "Changed owner of syncthing files, output: " + out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,24 @@
|
||||||
package com.nutomic.syncthingandroid.http;
|
package com.nutomic.syncthingandroid.http;
|
||||||
|
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.net.URL;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a GET request to the Syncthing API
|
* Performs a GET request to the Syncthing API
|
||||||
* Performs a GET request with no parameters to the URL in uri[0] with the path in uri[1] and
|
* Performs a GET request with no parameters to the URL in uri[0] with the path in uri[1] and
|
||||||
* returns the result as a String.
|
* returns the result as a String.
|
||||||
*/
|
*/
|
||||||
public class GetTask extends RestTask<String, Void, String> {
|
public class GetTask extends RestTask {
|
||||||
|
|
||||||
private static final String TAG = "GetTask";
|
private static final String TAG = "GetTask";
|
||||||
|
|
||||||
|
@ -26,31 +31,23 @@ public class GetTask extends RestTask<String, Void, String> {
|
||||||
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";
|
||||||
|
|
||||||
public GetTask(URL url, String path, String httpsCertPath, String apiKey) {
|
private final Map<String, String> mParams;
|
||||||
super(url, path, httpsCertPath, apiKey);
|
|
||||||
|
public GetTask(URL url, String path, String httpsCertPath, String apiKey,
|
||||||
|
@Nullable Map<String, String> params, OnSuccessListener listener) {
|
||||||
|
super(url, path, httpsCertPath, apiKey, listener);
|
||||||
|
mParams = Optional.fromNullable(params).or(Collections.emptyMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param params Keys and values for the query string.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
protected String doInBackground(String... params) {
|
protected Pair<Boolean, String> doInBackground(Void... aVoid) {
|
||||||
try {
|
try {
|
||||||
HttpsURLConnection connection = openConnection(params);
|
HttpsURLConnection connection = openConnection(mParams);
|
||||||
Log.v(TAG, "Calling Rest API at " + connection.getURL());
|
Log.v(TAG, "Calling Rest API at " + connection.getURL());
|
||||||
connection.connect();
|
return connect(connection);
|
||||||
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
|
|
||||||
String line;
|
|
||||||
String result = "";
|
|
||||||
while ((line = br.readLine()) != null) {
|
|
||||||
result += line;
|
|
||||||
}
|
|
||||||
br.close();
|
|
||||||
Log.v(TAG, "API call result: " + result);
|
|
||||||
return result;
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w(TAG, "Failed to call rest api", e);
|
Log.w(TAG, "Failed to call rest api", e);
|
||||||
return null;
|
return new Pair<>(false, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,15 +2,20 @@ package com.nutomic.syncthingandroid.http;
|
||||||
|
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Polls to load the web interface, until we receive http status 200.
|
* Polls to load the web interface, until we receive http status 200.
|
||||||
*/
|
*/
|
||||||
public abstract class PollWebGuiAvailableTask extends RestTask<Void, Void, Void> {
|
public class PollWebGuiAvailableTask extends RestTask {
|
||||||
|
|
||||||
private static final String TAG = "PollWebGuiAvailableTask";
|
private static final String TAG = "PollWebGuiAvailableTask";
|
||||||
|
|
||||||
|
@ -20,16 +25,17 @@ public abstract class PollWebGuiAvailableTask extends RestTask<Void, Void, Void>
|
||||||
*/
|
*/
|
||||||
private static final long WEB_GUI_POLL_INTERVAL = 100;
|
private static final long WEB_GUI_POLL_INTERVAL = 100;
|
||||||
|
|
||||||
public PollWebGuiAvailableTask(URL url, String httpsCertPath, String apiKey) {
|
public PollWebGuiAvailableTask(URL url, String httpsCertPath, String apiKey,
|
||||||
super(url, "", httpsCertPath, apiKey);
|
OnSuccessListener listener) {
|
||||||
|
super(url, "", httpsCertPath, apiKey, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... aVoid) {
|
protected Pair<Boolean, String> doInBackground(Void... aVoid) {
|
||||||
int status = 0;
|
int status = 0;
|
||||||
do {
|
do {
|
||||||
try {
|
try {
|
||||||
HttpsURLConnection connection = openConnection();
|
HttpsURLConnection connection = openConnection(Collections.emptyMap());
|
||||||
connection.connect();
|
connection.connect();
|
||||||
status = connection.getResponseCode();
|
status = connection.getResponseCode();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -41,7 +47,7 @@ public abstract class PollWebGuiAvailableTask extends RestTask<Void, Void, Void>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (status != HttpsURLConnection.HTTP_OK);
|
} while (status != HttpsURLConnection.HTTP_OK);
|
||||||
return null;
|
return new Pair<>(true, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
package com.nutomic.syncthingandroid.http;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
|
||||||
|
public class PostConfigTask extends RestTask {
|
||||||
|
|
||||||
|
private static final String TAG = "PostConfigTask";
|
||||||
|
|
||||||
|
private static final String URI_CONFIG = "/rest/system/config";
|
||||||
|
|
||||||
|
private final String mConfig;
|
||||||
|
|
||||||
|
public PostConfigTask(URL url, String httpsCertPath, String apiKey, String config,
|
||||||
|
OnSuccessListener listener) {
|
||||||
|
super(url, URI_CONFIG, httpsCertPath, apiKey, listener);
|
||||||
|
mConfig = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Pair<Boolean, String> doInBackground(Void... params) {
|
||||||
|
try {
|
||||||
|
HttpsURLConnection connection = openConnection(Collections.emptyMap());
|
||||||
|
connection.setRequestMethod("POST");
|
||||||
|
Log.v(TAG, "Calling Rest API at " + connection.getURL());
|
||||||
|
|
||||||
|
OutputStream os = connection.getOutputStream();
|
||||||
|
os.write(mConfig.getBytes("UTF-8"));
|
||||||
|
return connect(connection);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, "Failed to call rest api", e);
|
||||||
|
return new Pair<>(false, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package com.nutomic.syncthingandroid.http;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
|
||||||
|
public class PostScanTask extends RestTask {
|
||||||
|
|
||||||
|
private static final String TAG = "PostScanTask";
|
||||||
|
|
||||||
|
private static final String URI_SCAN = "/rest/db/scan";
|
||||||
|
|
||||||
|
private final String mFolder;
|
||||||
|
private final String mSub;
|
||||||
|
|
||||||
|
public PostScanTask(URL url, String httpsCertPath, String apiKey, String folder, String sub) {
|
||||||
|
super(url, URI_SCAN, httpsCertPath, apiKey, null);
|
||||||
|
mFolder = folder;
|
||||||
|
mSub = sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Pair<Boolean, String> doInBackground(Void... params) {
|
||||||
|
try {
|
||||||
|
HttpsURLConnection connection = openConnection(ImmutableMap.of("folder", mFolder, "sub", mSub));
|
||||||
|
connection.setRequestMethod("POST");
|
||||||
|
return connect(connection);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, "Failed to call rest api", e);
|
||||||
|
return new Pair<>(false, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,60 +0,0 @@
|
||||||
package com.nutomic.syncthingandroid.http;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.net.URL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a POST request to the Syncthing API.
|
|
||||||
*/
|
|
||||||
public class PostTask extends RestTask<String, Void, Boolean> {
|
|
||||||
|
|
||||||
private static final String TAG = "PostTask";
|
|
||||||
|
|
||||||
public static final String URI_CONFIG = "/rest/system/config";
|
|
||||||
public static final String URI_SCAN = "/rest/db/scan";
|
|
||||||
|
|
||||||
public PostTask(URL url, String path, String httpsCertPath, String apiKey) {
|
|
||||||
super(url, path, httpsCertPath, apiKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For {@link #URI_CONFIG}, params[0] must contain the config.
|
|
||||||
*
|
|
||||||
* For {@link #URI_SCAN}, params[0] must contain the folder, and params[1] the subfolder.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected Boolean doInBackground(String... params) {
|
|
||||||
try {
|
|
||||||
HttpsURLConnection connection = (mPath.equals(URI_SCAN))
|
|
||||||
? openConnection("folder", params[0], "sub", params[1])
|
|
||||||
: openConnection();
|
|
||||||
connection.setRequestMethod("POST");
|
|
||||||
Log.v(TAG, "Calling Rest API at " + connection.getURL());
|
|
||||||
|
|
||||||
if (mPath.equals(URI_CONFIG)) {
|
|
||||||
OutputStream os = connection.getOutputStream();
|
|
||||||
os.write(params[0].getBytes("UTF-8"));
|
|
||||||
}
|
|
||||||
connection.connect();
|
|
||||||
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
|
|
||||||
String line;
|
|
||||||
String result = "";
|
|
||||||
while ((line = br.readLine()) != null) {
|
|
||||||
result += line;
|
|
||||||
}
|
|
||||||
br.close();
|
|
||||||
Log.v(TAG, "API call result: " + result);
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.w(TAG, "Failed to call rest api", e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -5,51 +5,122 @@ import android.annotation.SuppressLint;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import com.nutomic.syncthingandroid.syncthing.RestApi;
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import com.google.common.base.Charsets;
|
||||||
|
import com.google.common.io.ByteSource;
|
||||||
|
|
||||||
import javax.net.ssl.*;
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.security.*;
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.KeyManagementException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.NoSuchProviderException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.SignatureException;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public abstract class RestTask<A, B, C> extends AsyncTask<A, B, C> {
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
|
import javax.net.ssl.TrustManager;
|
||||||
|
import javax.net.ssl.X509TrustManager;
|
||||||
|
|
||||||
|
public abstract class RestTask extends
|
||||||
|
AsyncTask<Void, Void, Pair<Boolean, String>> {
|
||||||
|
|
||||||
private static final String TAG = "RestTask";
|
private static final String TAG = "RestTask";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the HTTP header used for the syncthing API key.
|
||||||
|
*/
|
||||||
|
private static final String HEADER_API_KEY = "X-API-Key";
|
||||||
|
|
||||||
|
public interface OnSuccessListener {
|
||||||
|
public void onSuccess(String result);
|
||||||
|
}
|
||||||
|
|
||||||
private final URL mUrl;
|
private final URL mUrl;
|
||||||
protected final String mPath;
|
protected final String mPath;
|
||||||
private final String mHttpsCertPath;
|
private final String mHttpsCertPath;
|
||||||
private final String mApiKey;
|
private final String mApiKey;
|
||||||
|
private final OnSuccessListener mListener;
|
||||||
|
|
||||||
public RestTask(URL url, String path, String httpsCertPath, String apiKey) {
|
public RestTask(URL url, String path, String httpsCertPath, String apiKey,
|
||||||
|
OnSuccessListener listener) {
|
||||||
mUrl = url;
|
mUrl = url;
|
||||||
mPath = path;
|
mPath = path;
|
||||||
mHttpsCertPath = httpsCertPath;
|
mHttpsCertPath = httpsCertPath;
|
||||||
mApiKey = apiKey;
|
mApiKey = apiKey;
|
||||||
|
mListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HttpsURLConnection openConnection(String... params) throws IOException {
|
public void execute() {
|
||||||
|
super.executeOnExecutor(THREAD_POOL_EXECUTOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HttpsURLConnection openConnection(Map<String, String> params) throws IOException {
|
||||||
Uri.Builder uriBuilder = Uri.parse(mUrl.toString())
|
Uri.Builder uriBuilder = Uri.parse(mUrl.toString())
|
||||||
.buildUpon()
|
.buildUpon()
|
||||||
.path(mPath);
|
.path(mPath);
|
||||||
for (int paramCounter = 0; paramCounter + 1 < params.length; ) {
|
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||||
uriBuilder.appendQueryParameter(params[paramCounter++], params[paramCounter++]);
|
uriBuilder.appendQueryParameter(entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
URL url = new URL(uriBuilder.build().toString());
|
URL url = new URL(uriBuilder.build().toString());
|
||||||
|
Log.v(TAG, "Calling Rest API at " + url);
|
||||||
|
|
||||||
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
|
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
|
||||||
connection.setRequestProperty(RestApi.HEADER_API_KEY, mApiKey);
|
connection.setRequestProperty(HEADER_API_KEY, mApiKey);
|
||||||
connection.setHostnameVerifier((h, s) -> true);
|
connection.setHostnameVerifier((h, s) -> true);
|
||||||
connection.setSSLSocketFactory(getSslSocketFactory());
|
connection.setSSLSocketFactory(getSslSocketFactory());
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the connection, then returns success status and response string.
|
||||||
|
*/
|
||||||
|
protected Pair<Boolean, String> connect(HttpsURLConnection connection) throws IOException {
|
||||||
|
connection.connect();
|
||||||
|
Pair<Boolean, String> result;
|
||||||
|
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||||
|
int responseCode = connection.getResponseCode();
|
||||||
|
String responseMessage = connection.getResponseMessage();
|
||||||
|
Log.i(TAG, "Request to " + connection.getURL() + " failed, code: " + responseCode +
|
||||||
|
", message: " + responseMessage);
|
||||||
|
result = new Pair<>(false, streamToString(connection.getErrorStream()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = new Pair<>(true, streamToString(connection.getInputStream()));
|
||||||
|
}
|
||||||
|
connection.disconnect();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String streamToString(InputStream is) throws IOException {
|
||||||
|
ByteSource byteSource = new ByteSource() {
|
||||||
|
@Override
|
||||||
|
public InputStream openStream() throws IOException {
|
||||||
|
return is;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return byteSource.asCharSource(Charsets.UTF_8).read();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void onPostExecute(Pair<Boolean, String> result) {
|
||||||
|
if (mListener == null || !result.first)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mListener.onSuccess(result.second);
|
||||||
|
}
|
||||||
|
|
||||||
private SSLSocketFactory getSslSocketFactory() {
|
private SSLSocketFactory getSslSocketFactory() {
|
||||||
try {
|
try {
|
||||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||||
|
|
23
src/main/java/com/nutomic/syncthingandroid/model/Config.java
Normal file
23
src/main/java/com/nutomic/syncthingandroid/model/Config.java
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package com.nutomic.syncthingandroid.model;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Config {
|
||||||
|
public int version;
|
||||||
|
public String[] ignoredDevices;
|
||||||
|
public List<Device> devices;
|
||||||
|
public List<Folder> folders;
|
||||||
|
public Gui gui;
|
||||||
|
public Options options;
|
||||||
|
|
||||||
|
public class Gui {
|
||||||
|
public boolean enabled;
|
||||||
|
public String address;
|
||||||
|
public String user;
|
||||||
|
public String password;
|
||||||
|
public boolean useTLS;
|
||||||
|
public String apiKey;
|
||||||
|
public boolean insecureAdminAccess;
|
||||||
|
public String theme;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.nutomic.syncthingandroid.model;
|
||||||
|
|
||||||
|
public class Connection {
|
||||||
|
public String at;
|
||||||
|
public long inBytesTotal;
|
||||||
|
public long outBytesTotal;
|
||||||
|
public long inBits;
|
||||||
|
public long outBits;
|
||||||
|
public String address;
|
||||||
|
public String clientVersion;
|
||||||
|
public int completion;
|
||||||
|
public boolean connected;
|
||||||
|
}
|
24
src/main/java/com/nutomic/syncthingandroid/model/Device.java
Normal file
24
src/main/java/com/nutomic/syncthingandroid/model/Device.java
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package com.nutomic.syncthingandroid.model;
|
||||||
|
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Device {
|
||||||
|
public String deviceID;
|
||||||
|
public String name;
|
||||||
|
public List<String> addresses;
|
||||||
|
public String compression;
|
||||||
|
public String certName;
|
||||||
|
public boolean introducer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the device name, or the first characters of the ID if the name is empty.
|
||||||
|
*/
|
||||||
|
public String getDisplayName() {
|
||||||
|
return (TextUtils.isEmpty(name))
|
||||||
|
? deviceID.substring(0, 7)
|
||||||
|
: name;
|
||||||
|
}
|
||||||
|
}
|
13
src/main/java/com/nutomic/syncthingandroid/model/Event.java
Normal file
13
src/main/java/com/nutomic/syncthingandroid/model/Event.java
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package com.nutomic.syncthingandroid.model;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class Event {
|
||||||
|
|
||||||
|
public int id;
|
||||||
|
public int globalID;
|
||||||
|
public String type;
|
||||||
|
public String time;
|
||||||
|
public Map<String, Object> data;
|
||||||
|
|
||||||
|
}
|
58
src/main/java/com/nutomic/syncthingandroid/model/Folder.java
Normal file
58
src/main/java/com/nutomic/syncthingandroid/model/Folder.java
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
package com.nutomic.syncthingandroid.model;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class Folder {
|
||||||
|
|
||||||
|
public String id;
|
||||||
|
public String label;
|
||||||
|
public String path;
|
||||||
|
public String type;
|
||||||
|
private transient List<Map<String, String>> devices = new ArrayList<>();
|
||||||
|
public int rescanIntervalS;
|
||||||
|
public boolean ignorePerms;
|
||||||
|
public boolean autoNormalize;
|
||||||
|
public int minDiskFreePct;
|
||||||
|
public Versioning versioning;
|
||||||
|
public int copiers;
|
||||||
|
public int pullers;
|
||||||
|
public int hashers;
|
||||||
|
public String order;
|
||||||
|
public boolean ignoreDelete;
|
||||||
|
public int scanProgressIntervalS;
|
||||||
|
public int pullerSleepS;
|
||||||
|
public int pullerPauseS;
|
||||||
|
public int maxConflicts;
|
||||||
|
public boolean disableSparseFiles;
|
||||||
|
public boolean disableTempIndexes;
|
||||||
|
public String invalid;
|
||||||
|
|
||||||
|
public static class Versioning implements Serializable {
|
||||||
|
public String type;
|
||||||
|
public Map<String, String> params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getDevices() {
|
||||||
|
if (devices == null)
|
||||||
|
return new ArrayList<>();
|
||||||
|
|
||||||
|
List<String> devicesList = new ArrayList<>();
|
||||||
|
for (Map<String, String> map : devices) {
|
||||||
|
devicesList.addAll(map.values());
|
||||||
|
}
|
||||||
|
return devicesList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDevices(List<String> newDevices) {
|
||||||
|
devices.clear();
|
||||||
|
for (String d : newDevices) {
|
||||||
|
Map<String, String> map = new HashMap<>();
|
||||||
|
map.put("deviceID", d);
|
||||||
|
devices.add(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
src/main/java/com/nutomic/syncthingandroid/model/Model.java
Normal file
17
src/main/java/com/nutomic/syncthingandroid/model/Model.java
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package com.nutomic.syncthingandroid.model;
|
||||||
|
|
||||||
|
public class Model {
|
||||||
|
public long globalBytes;
|
||||||
|
public long globalDeleted;
|
||||||
|
public long globalFiles;
|
||||||
|
public long localBytes;
|
||||||
|
public long localDeleted;
|
||||||
|
public long localFiles;
|
||||||
|
public long inSyncBytes;
|
||||||
|
public long inSyncFiles;
|
||||||
|
public long needBytes;
|
||||||
|
public long needFiles;
|
||||||
|
public long needDeletes;
|
||||||
|
public String state;
|
||||||
|
public String invalid;
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package com.nutomic.syncthingandroid.model;
|
||||||
|
|
||||||
|
public class Options {
|
||||||
|
public String[] listenAddresses;
|
||||||
|
public String[] globalAnnounceServers;
|
||||||
|
public boolean globalAnnounceEnabled;
|
||||||
|
public boolean localAnnounceEnabled;
|
||||||
|
public int localAnnouncePort;
|
||||||
|
public String localAnnounceMCAddr;
|
||||||
|
public int maxSendKbps;
|
||||||
|
public int maxRecvKbps;
|
||||||
|
public int reconnectionIntervalS;
|
||||||
|
public boolean relaysEnabled;
|
||||||
|
public int relayReconnectIntervalM;
|
||||||
|
public boolean startBrowser;
|
||||||
|
public boolean natEnabled;
|
||||||
|
public int natLeaseMinutes;
|
||||||
|
public int natRenewalMinutes;
|
||||||
|
public int natTimeoutSeconds;
|
||||||
|
public int urAccepted;
|
||||||
|
public String urUniqueId;
|
||||||
|
public String urURL;
|
||||||
|
public boolean urPostInsecurely;
|
||||||
|
public int urInitialDelayS;
|
||||||
|
public boolean restartOnWakeup;
|
||||||
|
public int autoUpgradeIntervalH;
|
||||||
|
public int keepTemporariesH;
|
||||||
|
public boolean cacheIgnoredFiles;
|
||||||
|
public int progressUpdateIntervalS;
|
||||||
|
public boolean symlinksEnabled;
|
||||||
|
public boolean limitBandwidthInLan;
|
||||||
|
public int minHomeDiskFreePct;
|
||||||
|
public String releasesURL;
|
||||||
|
public String[] alwaysLocalNets;
|
||||||
|
public boolean overwriteRemoteDeviceNamesOnConnect;
|
||||||
|
public int tempIndexMinBlocks;
|
||||||
|
|
||||||
|
public static final int USAGE_REPORTING_UNDECIDED = 0;
|
||||||
|
public static final int USAGE_REPORTING_ACCEPTED = 2;
|
||||||
|
public static final int USAGE_REPORTING_DENIED = -1;
|
||||||
|
|
||||||
|
public int getUsageReportValue() {
|
||||||
|
if (urAccepted > USAGE_REPORTING_ACCEPTED)
|
||||||
|
throw new RuntimeException("Inalid usage reporting value");
|
||||||
|
|
||||||
|
return (urAccepted == USAGE_REPORTING_ACCEPTED || urAccepted == USAGE_REPORTING_DENIED)
|
||||||
|
? urAccepted
|
||||||
|
: USAGE_REPORTING_UNDECIDED;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.nutomic.syncthingandroid.model;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class SystemInfo {
|
||||||
|
public long alloc;
|
||||||
|
public double cpuPercent;
|
||||||
|
public int goroutines;
|
||||||
|
public String myID;
|
||||||
|
public long sys;
|
||||||
|
public boolean discoveryEnabled;
|
||||||
|
public int discoveryMethods;
|
||||||
|
public Map<String, String> discoveryErrors;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.nutomic.syncthingandroid.model;
|
||||||
|
|
||||||
|
public class SystemVersion {
|
||||||
|
public String arch;
|
||||||
|
public String codename;
|
||||||
|
public String longVersion;
|
||||||
|
public String os;
|
||||||
|
public String version;
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.nutomic.syncthingandroid.syncthing;
|
package com.nutomic.syncthingandroid.receiver;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
|
@ -12,6 +12,7 @@ import android.support.v4.app.NotificationCompat;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.R;
|
import com.nutomic.syncthingandroid.R;
|
||||||
import com.nutomic.syncthingandroid.activities.MainActivity;
|
import com.nutomic.syncthingandroid.activities.MainActivity;
|
||||||
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcast-receiver to control and configure SyncThing remotely
|
* Broadcast-receiver to control and configure SyncThing remotely
|
|
@ -1,10 +1,13 @@
|
||||||
package com.nutomic.syncthingandroid.syncthing;
|
package com.nutomic.syncthingandroid.receiver;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.nutomic.syncthingandroid.service.DeviceStateHolder;
|
||||||
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receives battery plug/unplug intents and sends the charging state to {@link SyncthingService}.
|
* Receives battery plug/unplug intents and sends the charging state to {@link SyncthingService}.
|
||||||
*/
|
*/
|
|
@ -1,9 +1,11 @@
|
||||||
package com.nutomic.syncthingandroid.syncthing;
|
package com.nutomic.syncthingandroid.receiver;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
||||||
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
|
|
||||||
public class BootReceiver extends BroadcastReceiver {
|
public class BootReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
@Override
|
@Override
|
|
@ -1,4 +1,4 @@
|
||||||
package com.nutomic.syncthingandroid.syncthing;
|
package com.nutomic.syncthingandroid.receiver;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -7,6 +7,9 @@ import android.net.ConnectivityManager;
|
||||||
import android.net.NetworkInfo;
|
import android.net.NetworkInfo;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.nutomic.syncthingandroid.service.DeviceStateHolder;
|
||||||
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receives network connection change intents and sends the wifi state to {@link SyncthingService}.
|
* Receives network connection change intents and sends the wifi state to {@link SyncthingService}.
|
||||||
*/
|
*/
|
|
@ -1,4 +1,4 @@
|
||||||
package com.nutomic.syncthingandroid.syncthing;
|
package com.nutomic.syncthingandroid.service;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
|
@ -1,4 +1,4 @@
|
||||||
package com.nutomic.syncthingandroid.syncthing;
|
package com.nutomic.syncthingandroid.service;
|
||||||
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
|
@ -17,9 +17,9 @@ import com.nutomic.syncthingandroid.R;
|
||||||
import com.nutomic.syncthingandroid.activities.SettingsActivity;
|
import com.nutomic.syncthingandroid.activities.SettingsActivity;
|
||||||
import com.nutomic.syncthingandroid.fragments.DeviceFragment;
|
import com.nutomic.syncthingandroid.fragments.DeviceFragment;
|
||||||
import com.nutomic.syncthingandroid.fragments.FolderFragment;
|
import com.nutomic.syncthingandroid.fragments.FolderFragment;
|
||||||
|
import com.nutomic.syncthingandroid.model.Device;
|
||||||
import org.json.JSONException;
|
import com.nutomic.syncthingandroid.model.Event;
|
||||||
import org.json.JSONObject;
|
import com.nutomic.syncthingandroid.model.Folder;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
@ -70,8 +70,7 @@ public class EventProcessor implements SyncthingService.OnWebGuiAvailableListene
|
||||||
// If that's the case we've to start at zero because syncthing was restarted.
|
// If that's the case we've to start at zero because syncthing was restarted.
|
||||||
mApi.getEvents(0, 1, new RestApi.OnReceiveEventListener() {
|
mApi.getEvents(0, 1, new RestApi.OnReceiveEventListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onEvent(String eventType, JSONObject data) throws JSONException {
|
public void onEvent(Event event) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -89,10 +88,10 @@ public class EventProcessor implements SyncthingService.OnWebGuiAvailableListene
|
||||||
* Performs the actual event handling.
|
* Performs the actual event handling.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onEvent(String type, JSONObject data) throws JSONException {
|
public void onEvent(Event event) {
|
||||||
switch (type) {
|
switch (event.type) {
|
||||||
case "DeviceRejected":
|
case "DeviceRejected":
|
||||||
String deviceId = data.getString("device");
|
String deviceId = (String) event.data.get("device");
|
||||||
Log.d(TAG, "Unknwon device " + deviceId + " wants to connect");
|
Log.d(TAG, "Unknwon device " + deviceId + " wants to connect");
|
||||||
|
|
||||||
Intent intent = new Intent(mContext, SettingsActivity.class)
|
Intent intent = new Intent(mContext, SettingsActivity.class)
|
||||||
|
@ -110,9 +109,9 @@ public class EventProcessor implements SyncthingService.OnWebGuiAvailableListene
|
||||||
notify(title, pi);
|
notify(title, pi);
|
||||||
break;
|
break;
|
||||||
case "FolderRejected":
|
case "FolderRejected":
|
||||||
deviceId = data.getString("device");
|
deviceId = (String) event.data.get("device");
|
||||||
String folderId = data.getString("folder");
|
String folderId = (String) event.data.get("folder");
|
||||||
String folderLabel = data.getString("folderLabel");
|
String folderLabel = (String) event.data.get("folderLabel");
|
||||||
Log.d(TAG, "Device " + deviceId + " wants to share folder " + folderId);
|
Log.d(TAG, "Device " + deviceId + " wants to share folder " + folderId);
|
||||||
|
|
||||||
intent = new Intent(mContext, SettingsActivity.class)
|
intent = new Intent(mContext, SettingsActivity.class)
|
||||||
|
@ -127,9 +126,9 @@ public class EventProcessor implements SyncthingService.OnWebGuiAvailableListene
|
||||||
pi = PendingIntent.getActivity(mContext, requestCode, intent, 0);
|
pi = PendingIntent.getActivity(mContext, requestCode, intent, 0);
|
||||||
|
|
||||||
String deviceName = null;
|
String deviceName = null;
|
||||||
for (RestApi.Device d : mApi.getDevices(false)) {
|
for (Device d : mApi.getDevices(false)) {
|
||||||
if (d.deviceID.equals(deviceId))
|
if (d.deviceID.equals(deviceId))
|
||||||
deviceName = RestApi.getDeviceDisplayName(d);
|
deviceName = d.getDisplayName();
|
||||||
}
|
}
|
||||||
title = mContext.getString(R.string.folder_rejected, deviceName,
|
title = mContext.getString(R.string.folder_rejected, deviceName,
|
||||||
folderLabel.isEmpty() ? folderId : folderLabel + " (" + folderId + ")");
|
folderLabel.isEmpty() ? folderId : folderLabel + " (" + folderId + ")");
|
||||||
|
@ -137,7 +136,15 @@ public class EventProcessor implements SyncthingService.OnWebGuiAvailableListene
|
||||||
notify(title, pi);
|
notify(title, pi);
|
||||||
break;
|
break;
|
||||||
case "ItemFinished":
|
case "ItemFinished":
|
||||||
File updatedFile = new File(data.getString("folderpath"), data.getString("item"));
|
String folder = (String) event.data.get("folder");
|
||||||
|
String folderPath = null;
|
||||||
|
for (Folder f : mApi.getFolders()) {
|
||||||
|
if (f.id.equals(folder)) {
|
||||||
|
folderPath = f.path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
File updatedFile = new File(folderPath,
|
||||||
|
(String) event.data.get("item"));
|
||||||
Log.i(TAG, "Notified media scanner about " + updatedFile.toString());
|
Log.i(TAG, "Notified media scanner about " + updatedFile.toString());
|
||||||
mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
|
mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
|
||||||
Uri.fromFile(updatedFile)));
|
Uri.fromFile(updatedFile)));
|
||||||
|
@ -146,7 +153,7 @@ public class EventProcessor implements SyncthingService.OnWebGuiAvailableListene
|
||||||
// Ignored.
|
// Ignored.
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Log.i(TAG, "Unhandled event " + type);
|
Log.i(TAG, "Unhandled event " + event.type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
530
src/main/java/com/nutomic/syncthingandroid/service/RestApi.java
Normal file
530
src/main/java/com/nutomic/syncthingandroid/service/RestApi.java
Normal file
|
@ -0,0 +1,530 @@
|
||||||
|
package com.nutomic.syncthingandroid.service;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.reflect.TypeToken;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import com.nutomic.syncthingandroid.BuildConfig;
|
||||||
|
import com.nutomic.syncthingandroid.activities.RestartActivity;
|
||||||
|
import com.nutomic.syncthingandroid.http.GetTask;
|
||||||
|
import com.nutomic.syncthingandroid.http.PostConfigTask;
|
||||||
|
import com.nutomic.syncthingandroid.http.PostScanTask;
|
||||||
|
import com.nutomic.syncthingandroid.model.Config;
|
||||||
|
import com.nutomic.syncthingandroid.model.Connection;
|
||||||
|
import com.nutomic.syncthingandroid.model.Device;
|
||||||
|
import com.nutomic.syncthingandroid.model.Event;
|
||||||
|
import com.nutomic.syncthingandroid.model.Folder;
|
||||||
|
import com.nutomic.syncthingandroid.model.Model;
|
||||||
|
import com.nutomic.syncthingandroid.model.Options;
|
||||||
|
import com.nutomic.syncthingandroid.model.SystemInfo;
|
||||||
|
import com.nutomic.syncthingandroid.model.SystemVersion;
|
||||||
|
import com.nutomic.syncthingandroid.util.FolderObserver;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides functions to interact with the syncthing REST API.
|
||||||
|
*/
|
||||||
|
public class RestApi implements SyncthingService.OnWebGuiAvailableListener,
|
||||||
|
FolderObserver.OnFolderFileChangeListener {
|
||||||
|
|
||||||
|
private static final String TAG = "RestApi";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key of the map element containing connection info for the local device, in the return
|
||||||
|
* value of {@link #getConnections}
|
||||||
|
*/
|
||||||
|
public static final String TOTAL_STATS = "total";
|
||||||
|
|
||||||
|
public interface OnConfigChangedListener {
|
||||||
|
void onConfigChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OnResultListener1<T> {
|
||||||
|
public void onResult(T t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OnResultListener2<T, R> {
|
||||||
|
public void onResult(T t, R r);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
private final URL mUrl;
|
||||||
|
private final String mApiKey;
|
||||||
|
private final String mHttpsCertPath;
|
||||||
|
|
||||||
|
private String mVersion;
|
||||||
|
private Config mConfig;
|
||||||
|
private String mLocalDeviceId;
|
||||||
|
private boolean mRestartPostponed = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the result of the last successful request to {@link GetTask#URI_CONNECTIONS},
|
||||||
|
* or an empty Map.
|
||||||
|
*/
|
||||||
|
private Map<String, Connection> mPreviousConnections = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the timestamp of the last successful request to {@link GetTask#URI_CONNECTIONS}.
|
||||||
|
*/
|
||||||
|
private long mPreviousConnectionTime = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the latest result of {@link #getModel} for each folder, for calculating device
|
||||||
|
* percentage in {@link #getConnections}.
|
||||||
|
*/
|
||||||
|
private final HashMap<String, Model> mCachedModelInfo = new HashMap<>();
|
||||||
|
|
||||||
|
public RestApi(Context context, URL url, String apiKey, OnApiAvailableListener apiListener,
|
||||||
|
OnConfigChangedListener configListener) {
|
||||||
|
mContext = context;
|
||||||
|
mUrl = url;
|
||||||
|
mApiKey = apiKey;
|
||||||
|
mHttpsCertPath = mContext.getFilesDir() + "/" + SyncthingService.HTTPS_CERT_FILE;
|
||||||
|
mOnApiAvailableListener = apiListener;
|
||||||
|
mOnConfigChangedListener = configListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of previous calls to {@link #tryIsAvailable()}.
|
||||||
|
*/
|
||||||
|
private final AtomicInteger mAvailableCount = new AtomicInteger(0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of asynchronous calls performed in {@link #onWebGuiAvailable()}.
|
||||||
|
*/
|
||||||
|
private static final int TOTAL_STARTUP_CALLS = 3;
|
||||||
|
|
||||||
|
public interface OnApiAvailableListener {
|
||||||
|
public void onApiAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final OnApiAvailableListener mOnApiAvailableListener;
|
||||||
|
|
||||||
|
private final OnConfigChangedListener mOnConfigChangedListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets local device ID, syncthing version and config, then calls all OnApiAvailableListeners.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onWebGuiAvailable() {
|
||||||
|
mAvailableCount.set(0);
|
||||||
|
new GetTask(mUrl, GetTask.URI_VERSION, mHttpsCertPath, mApiKey, null, result -> {
|
||||||
|
JsonObject json = new JsonParser().parse(result).getAsJsonObject();
|
||||||
|
mVersion = json.get("version").getAsString();
|
||||||
|
Log.i(TAG, "Syncthing version is " + mVersion);
|
||||||
|
tryIsAvailable();
|
||||||
|
}).execute();
|
||||||
|
new GetTask(mUrl, GetTask.URI_CONFIG, mHttpsCertPath, mApiKey, null, result -> {
|
||||||
|
mConfig = new Gson().fromJson(result, Config.class);
|
||||||
|
tryIsAvailable();
|
||||||
|
}).execute();
|
||||||
|
getSystemInfo(info -> {
|
||||||
|
mLocalDeviceId = info.myID;
|
||||||
|
tryIsAvailable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments mAvailableCount by one, and, if it reached TOTAL_STARTUP_CALLS,
|
||||||
|
* calls {@link SyncthingService#onApiChange()}.
|
||||||
|
*/
|
||||||
|
private void tryIsAvailable() {
|
||||||
|
int value = mAvailableCount.incrementAndGet();
|
||||||
|
if (BuildConfig.DEBUG && value > TOTAL_STARTUP_CALLS) {
|
||||||
|
throw new AssertionError("Too many startup calls");
|
||||||
|
}
|
||||||
|
if (value == TOTAL_STARTUP_CALLS) {
|
||||||
|
mOnApiAvailableListener.onApiAvailable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Either shows a restart dialog, or only updates the config, depending on
|
||||||
|
* {@link #mRestartPostponed}.
|
||||||
|
*/
|
||||||
|
public void showRestartDialog(Activity activity) {
|
||||||
|
if (mRestartPostponed) {
|
||||||
|
sendConfig();
|
||||||
|
} else {
|
||||||
|
activity.startActivity(new Intent(mContext, RestartActivity.class));
|
||||||
|
}
|
||||||
|
mOnConfigChangedListener.onConfigChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends current config to Syncthing.
|
||||||
|
*/
|
||||||
|
private void sendConfig() {
|
||||||
|
new PostConfigTask(mUrl, mHttpsCertPath, mApiKey, new Gson().toJson(mConfig), null)
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends current config and restarts Syncthing.
|
||||||
|
*/
|
||||||
|
public void restart() {
|
||||||
|
new PostConfigTask(mUrl, mHttpsCertPath, mApiKey, new Gson().toJson(mConfig), result -> {
|
||||||
|
Intent intent = new Intent(mContext, SyncthingService.class)
|
||||||
|
.setAction(SyncthingService.ACTION_RESTART);
|
||||||
|
mContext.startService(intent);
|
||||||
|
}).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops syncthing and cancels notification.
|
||||||
|
*/
|
||||||
|
public void shutdown() {
|
||||||
|
NotificationManager nm = (NotificationManager)
|
||||||
|
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
nm.cancel(RestartActivity.NOTIFICATION_RESTART);
|
||||||
|
mRestartPostponed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the version name, or a (text) error message on failure.
|
||||||
|
*/
|
||||||
|
public String getVersion() {
|
||||||
|
return mVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Folder> getFolders() {
|
||||||
|
return deepCopy(mConfig.folders, new TypeToken<List<Folder>>(){}.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addFolder(Folder folder) {
|
||||||
|
mConfig.folders.add(folder);
|
||||||
|
sendConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void editFolder(Folder newFolder) {
|
||||||
|
removeFolderInternal(newFolder.id);
|
||||||
|
addFolder(newFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeFolder(String id) {
|
||||||
|
removeFolderInternal(id);
|
||||||
|
sendConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeFolderInternal(String id) {
|
||||||
|
Iterator<Folder> it = mConfig.folders.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
Folder f = it.next();
|
||||||
|
if (f.id.equals(id)) {
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all existing devices.
|
||||||
|
*
|
||||||
|
* @param includeLocal True if the local device should be included in the result.
|
||||||
|
*/
|
||||||
|
public List<Device> getDevices(boolean includeLocal) {
|
||||||
|
List<Device> devices = deepCopy(mConfig.devices, new TypeToken<List<Device>>(){}.getType());
|
||||||
|
|
||||||
|
Iterator<Device> it = devices.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
Device device = it.next();
|
||||||
|
boolean isLocalDevice = Objects.equal(mLocalDeviceId, device.deviceID);
|
||||||
|
if (!includeLocal && isLocalDevice)
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
return devices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Device getLocalDevice() {
|
||||||
|
for (Device d : getDevices(true)) {
|
||||||
|
if (d.deviceID.equals(mLocalDeviceId)) {
|
||||||
|
return deepCopy(d, Device.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addDevice(Device device, OnResultListener1<String> errorListener) {
|
||||||
|
normalizeDeviceId(device.deviceID, normalizedId -> {
|
||||||
|
mConfig.devices.add(device);
|
||||||
|
sendConfig();
|
||||||
|
}, errorListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void editDevice(Device newDevice) {
|
||||||
|
removeDeviceInternal(newDevice.deviceID);
|
||||||
|
mConfig.devices.add(newDevice);
|
||||||
|
sendConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeDevice(String deviceId) {
|
||||||
|
removeDeviceInternal(deviceId);
|
||||||
|
sendConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeDeviceInternal(String deviceId) {
|
||||||
|
Iterator<Device> it = mConfig.devices.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
Device d = it.next();
|
||||||
|
if (d.deviceID.equals(deviceId)) {
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Options getOptions() {
|
||||||
|
return deepCopy(mConfig.options, Options.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Config.Gui getGui() {
|
||||||
|
return deepCopy(mConfig.gui, Config.Gui.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void editSettings(Config.Gui newGui, Options newOptions, Activity activity) {
|
||||||
|
mConfig.gui = newGui;
|
||||||
|
mConfig.options = newOptions;
|
||||||
|
showRestartDialog(activity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a deep copy of object.
|
||||||
|
*
|
||||||
|
* This method uses Gson and only works with objects that can be converted with Gson.
|
||||||
|
*/
|
||||||
|
public <T> T deepCopy(T object, Type type) {
|
||||||
|
Gson gson = new Gson();
|
||||||
|
return gson.fromJson(gson.toJson(object, type), type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests and parses information about current system status and resource usage.
|
||||||
|
*/
|
||||||
|
public void getSystemInfo(OnResultListener1<SystemInfo> listener) {
|
||||||
|
new GetTask(mUrl, GetTask.URI_SYSTEM, mHttpsCertPath, mApiKey, null, result -> {
|
||||||
|
listener.onResult(new Gson().fromJson(result, SystemInfo.class));
|
||||||
|
}).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests and parses system version information.
|
||||||
|
*/
|
||||||
|
public void getSystemVersion(OnResultListener1<SystemVersion> listener) {
|
||||||
|
new GetTask(mUrl, GetTask.URI_VERSION, mHttpsCertPath, mApiKey, null, result -> {
|
||||||
|
SystemVersion systemVersion = new Gson().fromJson(result, SystemVersion.class);
|
||||||
|
listener.onResult(systemVersion);
|
||||||
|
}).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns connection info for the local device and all connected devices.
|
||||||
|
* <p/>
|
||||||
|
* Use the key {@link #TOTAL_STATS} to get connection info for the local device.
|
||||||
|
*
|
||||||
|
* The result is cached internally. Do not modify it or any of its contents.
|
||||||
|
*/
|
||||||
|
public void getConnections(final OnResultListener1<Map<String, Connection>> listener) {
|
||||||
|
new GetTask(mUrl, GetTask.URI_CONNECTIONS, mHttpsCertPath, mApiKey, null, result -> {
|
||||||
|
Long now = System.currentTimeMillis();
|
||||||
|
Long timeElapsed = (now - mPreviousConnectionTime) / 1000;
|
||||||
|
if (timeElapsed < 1) {
|
||||||
|
listener.onResult(mPreviousConnections);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
JSONObject json = new JSONObject(result);
|
||||||
|
Map<String, JSONObject> jsonConnections = new HashMap<>();
|
||||||
|
jsonConnections.put(TOTAL_STATS, json.getJSONObject(TOTAL_STATS));
|
||||||
|
JSONArray extConnections = json.getJSONObject("connections").names();
|
||||||
|
if (extConnections != null) {
|
||||||
|
for (int i = 0; i < extConnections.length(); i++) {
|
||||||
|
String deviceId = extConnections.get(i).toString();
|
||||||
|
jsonConnections.put(deviceId, json.getJSONObject("connections").getJSONObject(deviceId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Map<String, Connection> connections = new HashMap<>();
|
||||||
|
for (Map.Entry<String, JSONObject> jsonConnection : jsonConnections.entrySet()) {
|
||||||
|
String deviceId = jsonConnection.getKey();
|
||||||
|
Connection c = new Connection();
|
||||||
|
JSONObject conn = jsonConnection.getValue();
|
||||||
|
c.address = deviceId;
|
||||||
|
c.at = conn.getString("at");
|
||||||
|
c.inBytesTotal = conn.getLong("inBytesTotal");
|
||||||
|
c.outBytesTotal = conn.getLong("outBytesTotal");
|
||||||
|
c.address = conn.getString("address");
|
||||||
|
c.clientVersion = conn.getString("clientVersion");
|
||||||
|
c.completion = getDeviceCompletion(deviceId);
|
||||||
|
c.connected = conn.getBoolean("connected");
|
||||||
|
|
||||||
|
Connection prev = (mPreviousConnections.containsKey(deviceId))
|
||||||
|
? mPreviousConnections.get(deviceId)
|
||||||
|
: new Connection();
|
||||||
|
mPreviousConnectionTime = now;
|
||||||
|
c.inBits = Math.max(0, 8 *
|
||||||
|
(conn.getLong("inBytesTotal") - prev.inBytesTotal) / timeElapsed);
|
||||||
|
c.outBits = Math.max(0, 8 *
|
||||||
|
(conn.getLong("outBytesTotal") - prev.outBytesTotal) / timeElapsed);
|
||||||
|
|
||||||
|
connections.put(deviceId, c);
|
||||||
|
|
||||||
|
}
|
||||||
|
mPreviousConnections = connections;
|
||||||
|
listener.onResult(mPreviousConnections);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
Log.w(TAG, "Failed to parse connections", e);
|
||||||
|
}
|
||||||
|
}).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates completion percentage for the given device using {@link #mCachedModelInfo}.
|
||||||
|
*/
|
||||||
|
private int getDeviceCompletion(String deviceId) {
|
||||||
|
int folderCount = 0;
|
||||||
|
float percentageSum = 0;
|
||||||
|
// Syncthing UI limits pending deletes to 95% completion of a device
|
||||||
|
int maxPercentage = 100;
|
||||||
|
for (Map.Entry<String, Model> modelInfo : mCachedModelInfo.entrySet()) {
|
||||||
|
boolean isShared = false;
|
||||||
|
outerloop:
|
||||||
|
for (Folder r : getFolders()) {
|
||||||
|
for (String n : r.getDevices()) {
|
||||||
|
if (n.equals(deviceId)) {
|
||||||
|
isShared = true;
|
||||||
|
break outerloop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isShared) {
|
||||||
|
long global = modelInfo.getValue().globalBytes;
|
||||||
|
long local = modelInfo.getValue().inSyncBytes;
|
||||||
|
if (modelInfo.getValue().needFiles == 0 && modelInfo.getValue().needDeletes > 0)
|
||||||
|
maxPercentage = 95;
|
||||||
|
percentageSum += (global != 0)
|
||||||
|
? (local * 100f) / global
|
||||||
|
: 100f;
|
||||||
|
folderCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (folderCount != 0)
|
||||||
|
? Math.min(Math.round(percentageSum / folderCount), maxPercentage)
|
||||||
|
: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns status information about the folder with the given id.
|
||||||
|
*/
|
||||||
|
public void getModel(final String folderId, final OnResultListener2<String, Model> listener) {
|
||||||
|
new GetTask(mUrl, GetTask.URI_MODEL, mHttpsCertPath, mApiKey,
|
||||||
|
ImmutableMap.of("folder", folderId), result -> {
|
||||||
|
Model m = new Gson().fromJson(result, Model.class);
|
||||||
|
mCachedModelInfo.put(folderId, m);
|
||||||
|
listener.onResult(folderId, m);
|
||||||
|
}).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for {@link #getEvents}.
|
||||||
|
*/
|
||||||
|
public interface OnReceiveEventListener {
|
||||||
|
/**
|
||||||
|
* Called for each event.
|
||||||
|
*/
|
||||||
|
void onEvent(Event event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called after all available events have been processed.
|
||||||
|
* @param lastId The id of the last event processed. Should be used as a starting point for
|
||||||
|
* the next round of event processing.
|
||||||
|
*/
|
||||||
|
void onDone(long lastId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the events that have accumulated since the given event id.
|
||||||
|
*
|
||||||
|
* The OnReceiveEventListeners onEvent method is called for each event.
|
||||||
|
*/
|
||||||
|
public final void getEvents(final long sinceId, final long limit, final OnReceiveEventListener listener) {
|
||||||
|
Map<String, String> params =
|
||||||
|
ImmutableMap.of("since", String.valueOf(sinceId), "limit", String.valueOf(limit));
|
||||||
|
new GetTask(mUrl, GetTask.URI_EVENTS, mHttpsCertPath, mApiKey, params, result -> {
|
||||||
|
JsonArray jsonEvents = new JsonParser().parse(result).getAsJsonArray();
|
||||||
|
long lastId = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < jsonEvents.size(); i++) {
|
||||||
|
JsonElement json = jsonEvents.get(i);
|
||||||
|
Event event = new Gson().fromJson(json, Event.class);
|
||||||
|
|
||||||
|
if (lastId < event.id)
|
||||||
|
lastId = event.id;
|
||||||
|
|
||||||
|
listener.onEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
listener.onDone(lastId);
|
||||||
|
}).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes a given device ID.
|
||||||
|
*/
|
||||||
|
public void normalizeDeviceId(String id, OnResultListener1<String> listener,
|
||||||
|
OnResultListener1<String> errorListener) {
|
||||||
|
new GetTask(mUrl, GetTask.URI_DEVICEID, mHttpsCertPath, mApiKey, ImmutableMap.of("id", id),
|
||||||
|
result -> {
|
||||||
|
JsonObject json = new JsonParser().parse(result).getAsJsonObject();
|
||||||
|
JsonElement normalizedId = json.get("id");
|
||||||
|
JsonElement error = json.get("error");
|
||||||
|
if (normalizedId != null)
|
||||||
|
listener.onResult(normalizedId.getAsString());
|
||||||
|
if (error != null)
|
||||||
|
errorListener.onResult(error.getAsString());
|
||||||
|
}).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force a rescan of the given subdirectory in folder.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onFolderFileChange(String folderId, String relativePath) {
|
||||||
|
new PostScanTask(mUrl, mHttpsCertPath, mApiKey, folderId, relativePath)
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns prettyfied usage report.
|
||||||
|
*/
|
||||||
|
public void getUsageReport(final OnResultListener1<String> listener) {
|
||||||
|
new GetTask(mUrl, GetTask.URI_REPORT, mHttpsCertPath, mApiKey, null, result -> {
|
||||||
|
JsonElement json = new JsonParser().parse(result);
|
||||||
|
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||||
|
listener.onResult(gson.toJson(json));
|
||||||
|
}).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRestartPostponed() {
|
||||||
|
mRestartPostponed = true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.nutomic.syncthingandroid.syncthing;
|
package com.nutomic.syncthingandroid.service;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
@ -39,6 +39,11 @@ public class SyncthingRunnable implements Runnable {
|
||||||
|
|
||||||
public static final String UNIT_TEST_PATH = "was running";
|
public static final String UNIT_TEST_PATH = "was running";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Path to the native, integrated syncthing binary, relative to the data folder
|
||||||
|
*/
|
||||||
|
public static final String BINARY_NAME = "lib/libsyncthing.so";
|
||||||
|
|
||||||
private static final AtomicReference<Process> mSyncthing = new AtomicReference<>();
|
private static final AtomicReference<Process> mSyncthing = new AtomicReference<>();
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
|
@ -62,7 +67,7 @@ public class SyncthingRunnable implements Runnable {
|
||||||
*/
|
*/
|
||||||
public SyncthingRunnable(Context context, Command command) {
|
public SyncthingRunnable(Context context, Command command) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mSyncthingBinary = mContext.getApplicationInfo().dataDir + "/" + SyncthingService.BINARY_NAME;
|
mSyncthingBinary = mContext.getApplicationInfo().dataDir + "/" + BINARY_NAME;
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case generate:
|
case generate:
|
||||||
mCommand = new String[]{ mSyncthingBinary, "-generate", mContext.getFilesDir().toString() };
|
mCommand = new String[]{ mSyncthingBinary, "-generate", mContext.getFilesDir().toString() };
|
||||||
|
@ -85,7 +90,7 @@ public class SyncthingRunnable implements Runnable {
|
||||||
*/
|
*/
|
||||||
public SyncthingRunnable(Context context, String[] manualCommand) {
|
public SyncthingRunnable(Context context, String[] manualCommand) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mSyncthingBinary = mContext.getApplicationInfo().dataDir + "/" + SyncthingService.BINARY_NAME;
|
mSyncthingBinary = mContext.getApplicationInfo().dataDir + "/" + BINARY_NAME;
|
||||||
mCommand = manualCommand;
|
mCommand = manualCommand;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package com.nutomic.syncthingandroid.syncthing;
|
package com.nutomic.syncthingandroid.service;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
|
@ -20,19 +20,18 @@ import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.android.PRNGFixes;
|
||||||
|
import com.google.common.io.Files;
|
||||||
import com.nutomic.syncthingandroid.R;
|
import com.nutomic.syncthingandroid.R;
|
||||||
import com.nutomic.syncthingandroid.activities.MainActivity;
|
import com.nutomic.syncthingandroid.activities.MainActivity;
|
||||||
import com.nutomic.syncthingandroid.http.PollWebGuiAvailableTask;
|
import com.nutomic.syncthingandroid.http.PollWebGuiAvailableTask;
|
||||||
|
import com.nutomic.syncthingandroid.model.Folder;
|
||||||
import com.nutomic.syncthingandroid.util.ConfigXml;
|
import com.nutomic.syncthingandroid.util.ConfigXml;
|
||||||
import com.nutomic.syncthingandroid.util.FolderObserver;
|
import com.nutomic.syncthingandroid.util.FolderObserver;
|
||||||
import com.android.PRNGFixes;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.channels.FileChannel;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
@ -84,11 +83,6 @@ public class SyncthingService extends Service implements
|
||||||
public static final File EXPORT_PATH =
|
public static final File EXPORT_PATH =
|
||||||
new File(Environment.getExternalStorageDirectory(), "backups/syncthing");
|
new File(Environment.getExternalStorageDirectory(), "backups/syncthing");
|
||||||
|
|
||||||
/**
|
|
||||||
* path to the native, integrated syncthing binary, relative to the data folder
|
|
||||||
*/
|
|
||||||
public static final String BINARY_NAME = "lib/libsyncthing.so";
|
|
||||||
|
|
||||||
public static final String PREF_ALWAYS_RUN_IN_BACKGROUND = "always_run_in_background";
|
public static final String PREF_ALWAYS_RUN_IN_BACKGROUND = "always_run_in_background";
|
||||||
public static final String PREF_SYNC_ONLY_WIFI = "sync_only_wifi";
|
public static final String PREF_SYNC_ONLY_WIFI = "sync_only_wifi";
|
||||||
public static final String PREF_SYNC_ONLY_WIFI_SSIDS = "sync_only_wifi_ssids_set";
|
public static final String PREF_SYNC_ONLY_WIFI_SSIDS = "sync_only_wifi_ssids_set";
|
||||||
|
@ -158,7 +152,7 @@ public class SyncthingService extends Service implements
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if a stop was requested while syncthing is starting, in that case, perform stop in
|
* True if a stop was requested while syncthing is starting, in that case, perform stop in
|
||||||
* {@link PollWebGuiAvailableTaskImpl}.
|
* {@link #pollWebGui}.
|
||||||
*/
|
*/
|
||||||
private boolean mStopScheduled = false;
|
private boolean mStopScheduled = false;
|
||||||
|
|
||||||
|
@ -228,8 +222,7 @@ public class SyncthingService extends Service implements
|
||||||
registerOnWebGuiAvailableListener(mApi);
|
registerOnWebGuiAvailableListener(mApi);
|
||||||
if (mEventProcessor != null)
|
if (mEventProcessor != null)
|
||||||
registerOnWebGuiAvailableListener(mEventProcessor);
|
registerOnWebGuiAvailableListener(mEventProcessor);
|
||||||
new PollWebGuiAvailableTaskImpl(getWebGuiUrl(), getFilesDir() + "/" + HTTPS_CERT_FILE, mConfig.getApiKey())
|
pollWebGui();
|
||||||
.execute();
|
|
||||||
mRunnable = new SyncthingRunnable(this, SyncthingRunnable.Command.main);
|
mRunnable = new SyncthingRunnable(this, SyncthingRunnable.Command.main);
|
||||||
new Thread(mRunnable).start();
|
new Thread(mRunnable).start();
|
||||||
updateNotification();
|
updateNotification();
|
||||||
|
@ -313,7 +306,7 @@ public class SyncthingService extends Service implements
|
||||||
registerReceiver(mPowerSaveModeChangedReceiver,
|
registerReceiver(mPowerSaveModeChangedReceiver,
|
||||||
new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
|
new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
|
||||||
}
|
}
|
||||||
new StartupTask().execute();
|
new StartupTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
PreferenceManager.getDefaultSharedPreferences(this)
|
PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
.registerOnSharedPreferenceChangeListener(this);
|
.registerOnSharedPreferenceChangeListener(this);
|
||||||
}
|
}
|
||||||
|
@ -345,12 +338,11 @@ public class SyncthingService extends Service implements
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mApi = new RestApi(SyncthingService.this, urlAndKey.first, urlAndKey.second,
|
mApi = new RestApi(SyncthingService.this, urlAndKey.first, urlAndKey.second, () -> {
|
||||||
() -> {
|
|
||||||
mCurrentState = State.ACTIVE;
|
mCurrentState = State.ACTIVE;
|
||||||
onApiChange();
|
onApiChange();
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
for (RestApi.Folder r : mApi.getFolders()) {
|
for (Folder r : mApi.getFolders()) {
|
||||||
try {
|
try {
|
||||||
mObservers.add(new FolderObserver(mApi, r));
|
mObservers.add(new FolderObserver(mApi, r));
|
||||||
} catch (FolderObserver.FolderNotExistingException e) {
|
} catch (FolderObserver.FolderNotExistingException e) {
|
||||||
|
@ -478,12 +470,6 @@ public class SyncthingService extends Service implements
|
||||||
mOnApiChangeListeners.remove(listener);
|
mOnApiChangeListeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PollWebGuiAvailableTaskImpl extends PollWebGuiAvailableTask {
|
|
||||||
|
|
||||||
public PollWebGuiAvailableTaskImpl(URL url, String httpsCertPath, String apiKey) {
|
|
||||||
super(url, httpsCertPath, apiKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wait for the web-gui of the native syncthing binary to come online.
|
* Wait for the web-gui of the native syncthing binary to come online.
|
||||||
*
|
*
|
||||||
|
@ -491,8 +477,9 @@ public class SyncthingService extends Service implements
|
||||||
* to stop the binary in the time while waiting for the GUI to become active. See the comment
|
* to stop the binary in the time while waiting for the GUI to become active. See the comment
|
||||||
* for SyncthingService.onDestroy for details.
|
* for SyncthingService.onDestroy for details.
|
||||||
*/
|
*/
|
||||||
@Override
|
private void pollWebGui() {
|
||||||
protected void onPostExecute(Void aVoid) {
|
new PollWebGuiAvailableTask(getWebGuiUrl(), getFilesDir() + "/" + HTTPS_CERT_FILE,
|
||||||
|
mConfig.getApiKey(), result -> {
|
||||||
synchronized (stateLock) {
|
synchronized (stateLock) {
|
||||||
if (mStopScheduled) {
|
if (mStopScheduled) {
|
||||||
mCurrentState = State.DISABLED;
|
mCurrentState = State.DISABLED;
|
||||||
|
@ -510,7 +497,7 @@ public class SyncthingService extends Service implements
|
||||||
listener.onWebGuiAvailable();
|
listener.onWebGuiAvailable();
|
||||||
}
|
}
|
||||||
mOnWebGuiAvailableListeners.clear();
|
mOnWebGuiAvailableListeners.clear();
|
||||||
}
|
}).execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -547,12 +534,16 @@ public class SyncthingService extends Service implements
|
||||||
*/
|
*/
|
||||||
public void exportConfig() {
|
public void exportConfig() {
|
||||||
EXPORT_PATH.mkdirs();
|
EXPORT_PATH.mkdirs();
|
||||||
copyFile(new File(getFilesDir(), ConfigXml.CONFIG_FILE),
|
try {
|
||||||
|
Files.copy(new File(getFilesDir(), ConfigXml.CONFIG_FILE),
|
||||||
new File(EXPORT_PATH, ConfigXml.CONFIG_FILE));
|
new File(EXPORT_PATH, ConfigXml.CONFIG_FILE));
|
||||||
copyFile(new File(getFilesDir(), PRIVATE_KEY_FILE),
|
Files.copy(new File(getFilesDir(), PRIVATE_KEY_FILE),
|
||||||
new File(EXPORT_PATH, PRIVATE_KEY_FILE));
|
new File(EXPORT_PATH, PRIVATE_KEY_FILE));
|
||||||
copyFile(new File(getFilesDir(), PUBLIC_KEY_FILE),
|
Files.copy(new File(getFilesDir(), PUBLIC_KEY_FILE),
|
||||||
new File(EXPORT_PATH, PUBLIC_KEY_FILE));
|
new File(EXPORT_PATH, PUBLIC_KEY_FILE));
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, "Failed to export config", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -569,35 +560,15 @@ public class SyncthingService extends Service implements
|
||||||
if (!config.exists() || !privateKey.exists() || !publicKey.exists())
|
if (!config.exists() || !privateKey.exists() || !publicKey.exists())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
copyFile(config, new File(getFilesDir(), ConfigXml.CONFIG_FILE));
|
try {
|
||||||
copyFile(privateKey, new File(getFilesDir(), PRIVATE_KEY_FILE));
|
Files.copy(config, new File(getFilesDir(), ConfigXml.CONFIG_FILE));
|
||||||
copyFile(publicKey, new File(getFilesDir(), PUBLIC_KEY_FILE));
|
Files.copy(privateKey, new File(getFilesDir(), PRIVATE_KEY_FILE));
|
||||||
|
Files.copy(publicKey, new File(getFilesDir(), PUBLIC_KEY_FILE));
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, "Failed to import config", e);
|
||||||
|
}
|
||||||
mCurrentState = State.INIT;
|
mCurrentState = State.INIT;
|
||||||
updateState();
|
updateState();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies files between different storage devices.
|
|
||||||
*/
|
|
||||||
private void copyFile(File source, File dest) {
|
|
||||||
FileChannel is = null;
|
|
||||||
FileChannel os = null;
|
|
||||||
try {
|
|
||||||
is = new FileInputStream(source).getChannel();
|
|
||||||
os = new FileOutputStream(dest).getChannel();
|
|
||||||
is.transferTo(0, is.size(), os);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.w(TAG, "Failed to copy file", e);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (is != null)
|
|
||||||
is.close();
|
|
||||||
if (os != null)
|
|
||||||
os.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.w(TAG, "Failed to close stream", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.nutomic.syncthingandroid.syncthing;
|
package com.nutomic.syncthingandroid.service;
|
||||||
|
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,7 +7,7 @@ import android.preference.PreferenceManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.R;
|
import com.nutomic.syncthingandroid.R;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingRunnable;
|
import com.nutomic.syncthingandroid.service.SyncthingRunnable;
|
||||||
|
|
||||||
import org.mindrot.jbcrypt.BCrypt;
|
import org.mindrot.jbcrypt.BCrypt;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
|
@ -21,7 +21,6 @@ import java.io.IOException;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
package com.nutomic.syncthingandroid.util;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import static android.util.TypedValue.COMPLEX_UNIT_DIP;
|
|
||||||
import static android.util.TypedValue.applyDimension;
|
|
||||||
|
|
||||||
public abstract class DpConverter {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts dips to pixels.
|
|
||||||
*
|
|
||||||
* @param dp Number of dps
|
|
||||||
* @param c The context to convert in.
|
|
||||||
* @return Number of pixels that equal dp in context.
|
|
||||||
*/
|
|
||||||
public static int dp(int dp, Context c) {
|
|
||||||
return (int) applyDimension(COMPLEX_UNIT_DIP, dp, c.getResources().getDisplayMetrics());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,7 +3,7 @@ package com.nutomic.syncthingandroid.util;
|
||||||
import android.os.FileObserver;
|
import android.os.FileObserver;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.syncthing.RestApi;
|
import com.nutomic.syncthingandroid.model.Folder;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -17,7 +17,7 @@ public class FolderObserver extends FileObserver {
|
||||||
|
|
||||||
private final OnFolderFileChangeListener mListener;
|
private final OnFolderFileChangeListener mListener;
|
||||||
|
|
||||||
private final RestApi.Folder mFolder;
|
private final Folder mFolder;
|
||||||
|
|
||||||
private final String mPath;
|
private final String mPath;
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ public class FolderObserver extends FileObserver {
|
||||||
public void onFolderFileChange(String folderId, String relativePath);
|
public void onFolderFileChange(String folderId, String relativePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FolderObserver(OnFolderFileChangeListener listener, RestApi.Folder folder)
|
public FolderObserver(OnFolderFileChangeListener listener, Folder folder)
|
||||||
throws FolderNotExistingException {
|
throws FolderNotExistingException {
|
||||||
this(listener, folder, "");
|
this(listener, folder, "");
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ public class FolderObserver extends FileObserver {
|
||||||
* @param folder The folder where this folder belongs to.
|
* @param folder The folder where this folder belongs to.
|
||||||
* @param path path to the monitored folder, relative to folder root.
|
* @param path path to the monitored folder, relative to folder root.
|
||||||
*/
|
*/
|
||||||
private FolderObserver(OnFolderFileChangeListener listener, RestApi.Folder folder, String path)
|
private FolderObserver(OnFolderFileChangeListener listener, Folder folder, String path)
|
||||||
throws FolderNotExistingException {
|
throws FolderNotExistingException {
|
||||||
super(folder.path + "/" + path,
|
super(folder.path + "/" + path,
|
||||||
ATTRIB | CLOSE_WRITE | CREATE | DELETE | DELETE_SELF | MOVED_FROM |
|
ATTRIB | CLOSE_WRITE | CREATE | DELETE | DELETE_SELF | MOVED_FROM |
|
||||||
|
|
58
src/main/java/com/nutomic/syncthingandroid/util/Util.java
Normal file
58
src/main/java/com/nutomic/syncthingandroid/util/Util.java
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
package com.nutomic.syncthingandroid.util;
|
||||||
|
|
||||||
|
import android.content.ClipData;
|
||||||
|
import android.content.ClipboardManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.nutomic.syncthingandroid.R;
|
||||||
|
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
|
||||||
|
public class Util {
|
||||||
|
|
||||||
|
private Util() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the given device ID to the clipboard (and shows a Toast telling about it).
|
||||||
|
*
|
||||||
|
* @param id The device ID to copy.
|
||||||
|
*/
|
||||||
|
public static void copyDeviceId(Context context, String id) {
|
||||||
|
ClipboardManager clipboard = (ClipboardManager)
|
||||||
|
context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||||
|
ClipData clip = ClipData.newPlainText(context.getString(R.string.device_id), id);
|
||||||
|
clipboard.setPrimaryClip(clip);
|
||||||
|
Toast.makeText(context, R.string.device_id_copied_to_clipboard, Toast.LENGTH_SHORT)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a number of bytes to a human readable file size (eg 3.5 GiB).
|
||||||
|
*
|
||||||
|
* Based on http://stackoverflow.com/a/5599842
|
||||||
|
*/
|
||||||
|
public static String readableFileSize(Context context, long bytes) {
|
||||||
|
final String[] units = context.getResources().getStringArray(R.array.file_size_units);
|
||||||
|
if (bytes <= 0) return "0 " + units[0];
|
||||||
|
int digitGroups = (int) (Math.log10(bytes) / Math.log10(1024));
|
||||||
|
return new DecimalFormat("#,##0.#")
|
||||||
|
.format(bytes / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a number of bytes to a human readable transfer rate in bytes per second
|
||||||
|
* (eg 100 KiB/s).
|
||||||
|
*
|
||||||
|
* Based on http://stackoverflow.com/a/5599842
|
||||||
|
*/
|
||||||
|
public static String readableTransferRate(Context context, long bits) {
|
||||||
|
final String[] units = context.getResources().getStringArray(R.array.transfer_rate_units);
|
||||||
|
long bytes = bits / 8;
|
||||||
|
if (bytes <= 0) return "0 " + units[0];
|
||||||
|
int digitGroups = (int) (Math.log10(bytes) / Math.log10(1024));
|
||||||
|
return new DecimalFormat("#,##0.#")
|
||||||
|
.format(bytes / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.nutomic.syncthingandroid.util;
|
package com.nutomic.syncthingandroid.views;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
@ -11,7 +11,10 @@ import android.widget.ArrayAdapter;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.R;
|
import com.nutomic.syncthingandroid.R;
|
||||||
import com.nutomic.syncthingandroid.syncthing.RestApi;
|
import com.nutomic.syncthingandroid.model.Connection;
|
||||||
|
import com.nutomic.syncthingandroid.model.Device;
|
||||||
|
import com.nutomic.syncthingandroid.service.RestApi;
|
||||||
|
import com.nutomic.syncthingandroid.util.Util;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -19,10 +22,9 @@ import java.util.Map;
|
||||||
/**
|
/**
|
||||||
* Generates item views for device items.
|
* Generates item views for device items.
|
||||||
*/
|
*/
|
||||||
public class DevicesAdapter extends ArrayAdapter<RestApi.Device>
|
public class DevicesAdapter extends ArrayAdapter<Device> {
|
||||||
implements RestApi.OnReceiveConnectionsListener {
|
|
||||||
|
|
||||||
private Map<String, RestApi.Connection> mConnections =
|
private Map<String, Connection> mConnections =
|
||||||
new HashMap<>();
|
new HashMap<>();
|
||||||
|
|
||||||
public DevicesAdapter(Context context) {
|
public DevicesAdapter(Context context) {
|
||||||
|
@ -44,9 +46,9 @@ public class DevicesAdapter extends ArrayAdapter<RestApi.Device>
|
||||||
TextView upload = (TextView) convertView.findViewById(R.id.upload);
|
TextView upload = (TextView) convertView.findViewById(R.id.upload);
|
||||||
|
|
||||||
String deviceId = getItem(position).deviceID;
|
String deviceId = getItem(position).deviceID;
|
||||||
RestApi.Connection conn = mConnections.get(deviceId);
|
Connection conn = mConnections.get(deviceId);
|
||||||
|
|
||||||
name.setText(RestApi.getDeviceDisplayName(getItem(position)));
|
name.setText(getItem(position).getDisplayName());
|
||||||
Resources r = getContext().getResources();
|
Resources r = getContext().getResources();
|
||||||
if (conn != null && conn.connected) {
|
if (conn != null && conn.connected) {
|
||||||
if (conn.completion == 100) {
|
if (conn.completion == 100) {
|
||||||
|
@ -57,12 +59,12 @@ public class DevicesAdapter extends ArrayAdapter<RestApi.Device>
|
||||||
status.setText(r.getString(R.string.device_syncing, conn.completion));
|
status.setText(r.getString(R.string.device_syncing, conn.completion));
|
||||||
status.setTextColor(ContextCompat.getColor(getContext(), R.color.text_blue));
|
status.setTextColor(ContextCompat.getColor(getContext(), R.color.text_blue));
|
||||||
}
|
}
|
||||||
download.setText(RestApi.readableTransferRate(getContext(), conn.inBits));
|
download.setText(Util.readableTransferRate(getContext(), conn.inBits));
|
||||||
upload.setText(RestApi.readableTransferRate(getContext(), conn.outBits));
|
upload.setText(Util.readableTransferRate(getContext(), conn.outBits));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
download.setText(RestApi.readableTransferRate(getContext(), 0));
|
download.setText(Util.readableTransferRate(getContext(), 0));
|
||||||
upload.setText(RestApi.readableTransferRate(getContext(), 0));
|
upload.setText(Util.readableTransferRate(getContext(), 0));
|
||||||
status.setText(r.getString(R.string.device_disconnected));
|
status.setText(r.getString(R.string.device_disconnected));
|
||||||
status.setTextColor(ContextCompat.getColor(getContext(), R.color.text_red));
|
status.setTextColor(ContextCompat.getColor(getContext(), R.color.text_red));
|
||||||
}
|
}
|
||||||
|
@ -75,12 +77,11 @@ public class DevicesAdapter extends ArrayAdapter<RestApi.Device>
|
||||||
*/
|
*/
|
||||||
public void updateConnections(RestApi api) {
|
public void updateConnections(RestApi api) {
|
||||||
for (int i = 0; i < getCount(); i++) {
|
for (int i = 0; i < getCount(); i++) {
|
||||||
api.getConnections(this);
|
api.getConnections(this::onReceiveConnections);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void onReceiveConnections(Map<String, Connection> connections) {
|
||||||
public void onReceiveConnections(Map<String, RestApi.Connection> connections) {
|
|
||||||
mConnections = connections;
|
mConnections = connections;
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.nutomic.syncthingandroid.widget;
|
package com.nutomic.syncthingandroid.views;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
|
@ -1,4 +1,4 @@
|
||||||
package com.nutomic.syncthingandroid.util;
|
package com.nutomic.syncthingandroid.views;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
@ -12,21 +12,22 @@ import android.widget.TextView;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.BuildConfig;
|
import com.nutomic.syncthingandroid.BuildConfig;
|
||||||
import com.nutomic.syncthingandroid.R;
|
import com.nutomic.syncthingandroid.R;
|
||||||
import com.nutomic.syncthingandroid.syncthing.RestApi;
|
import com.nutomic.syncthingandroid.model.Folder;
|
||||||
|
import com.nutomic.syncthingandroid.model.Model;
|
||||||
|
import com.nutomic.syncthingandroid.service.RestApi;
|
||||||
|
import com.nutomic.syncthingandroid.util.Util;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
import static android.view.View.GONE;
|
import static android.view.View.GONE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
import static com.nutomic.syncthingandroid.syncthing.RestApi.readableFileSize;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates item views for folder items.
|
* Generates item views for folder items.
|
||||||
*/
|
*/
|
||||||
public class FoldersAdapter extends ArrayAdapter<RestApi.Folder>
|
public class FoldersAdapter extends ArrayAdapter<Folder> {
|
||||||
implements RestApi.OnReceiveModelListener {
|
|
||||||
|
|
||||||
private final HashMap<String, RestApi.Model> mModels = new HashMap<>();
|
private final HashMap<String, Model> mModels = new HashMap<>();
|
||||||
private final LayoutInflater mInflater;
|
private final LayoutInflater mInflater;
|
||||||
|
|
||||||
public FoldersAdapter(Context context) {
|
public FoldersAdapter(Context context) {
|
||||||
|
@ -47,8 +48,8 @@ public class FoldersAdapter extends ArrayAdapter<RestApi.Folder>
|
||||||
TextView size = (TextView) convertView.findViewById(R.id.size);
|
TextView size = (TextView) convertView.findViewById(R.id.size);
|
||||||
TextView invalid = (TextView) convertView.findViewById(R.id.invalid);
|
TextView invalid = (TextView) convertView.findViewById(R.id.invalid);
|
||||||
|
|
||||||
RestApi.Folder folder = getItem(position);
|
Folder folder = getItem(position);
|
||||||
RestApi.Model model = mModels.get(folder.id);
|
Model model = mModels.get(folder.id);
|
||||||
label.setText(TextUtils.isEmpty(folder.label) ? folder.id : folder.label);
|
label.setText(TextUtils.isEmpty(folder.label) ? folder.id : folder.label);
|
||||||
state.setTextColor(ContextCompat.getColor(getContext(), R.color.text_green));
|
state.setTextColor(ContextCompat.getColor(getContext(), R.color.text_green));
|
||||||
directory.setText(folder.path);
|
directory.setText(folder.path);
|
||||||
|
@ -62,8 +63,8 @@ public class FoldersAdapter extends ArrayAdapter<RestApi.Folder>
|
||||||
.getString(R.string.files, model.inSyncFiles, model.globalFiles));
|
.getString(R.string.files, model.inSyncFiles, model.globalFiles));
|
||||||
size.setVisibility(VISIBLE);
|
size.setVisibility(VISIBLE);
|
||||||
size.setText(getContext().getString(R.string.folder_size_format,
|
size.setText(getContext().getString(R.string.folder_size_format,
|
||||||
readableFileSize(getContext(), model.inSyncBytes),
|
Util.readableFileSize(getContext(), model.inSyncBytes),
|
||||||
readableFileSize(getContext(), model.globalBytes)));
|
Util.readableFileSize(getContext(), model.globalBytes)));
|
||||||
setTextOrHide(invalid, model.invalid);
|
setTextOrHide(invalid, model.invalid);
|
||||||
} else {
|
} else {
|
||||||
items.setVisibility(GONE);
|
items.setVisibility(GONE);
|
||||||
|
@ -98,12 +99,11 @@ public class FoldersAdapter extends ArrayAdapter<RestApi.Folder>
|
||||||
*/
|
*/
|
||||||
public void updateModel(RestApi api) {
|
public void updateModel(RestApi api) {
|
||||||
for (int i = 0; i < getCount(); i++) {
|
for (int i = 0; i < getCount(); i++) {
|
||||||
api.getModel(getItem(i).id, this);
|
api.getModel(getItem(i).id, this::onReceiveModel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void onReceiveModel(String folderId, Model model) {
|
||||||
public void onReceiveModel(String folderId, RestApi.Model model) {
|
|
||||||
mModels.put(folderId, model);
|
mModels.put(folderId, model);
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.nutomic.syncthingandroid.preferences;
|
package com.nutomic.syncthingandroid.views;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.wifi.WifiConfiguration;
|
import android.net.wifi.WifiConfiguration;
|
||||||
|
@ -14,6 +14,7 @@ import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MultiSelectListPreference which allows the user to select on which WiFi networks (based on SSID)
|
* MultiSelectListPreference which allows the user to select on which WiFi networks (based on SSID)
|
||||||
|
@ -34,10 +35,11 @@ public class WifiSsidPreference extends MultiSelectListPreference {
|
||||||
|
|
||||||
public WifiSsidPreference(Context context, AttributeSet attrs) {
|
public WifiSsidPreference(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
|
setDefaultValue(new TreeSet<String>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public WifiSsidPreference(Context context) {
|
public WifiSsidPreference(Context context) {
|
||||||
super(context);
|
this(context, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -21,7 +21,7 @@
|
||||||
android:background="?selectableItemBackground"
|
android:background="?selectableItemBackground"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<com.nutomic.syncthingandroid.widget.EnhancedEditText
|
<com.nutomic.syncthingandroid.views.EnhancedEditText
|
||||||
android:id="@+id/id"
|
android:id="@+id/id"
|
||||||
style="@style/Widget.Syncthing.TextView.Label.Details.Field"
|
style="@style/Widget.Syncthing.TextView.Label.Details.Field"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
|
|
@ -125,7 +125,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">Настройки</string>
|
<string name="settings_title">Настройки</string>
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">Постоянна работа на заден план</string>
|
<string name="always_run_in_background">Постоянна работа на заден план</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -146,8 +145,7 @@
|
||||||
<item>С нисък приоритет</item>
|
<item>С нисък приоритет</item>
|
||||||
<item>Без известия</item>
|
<item>Без известия</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing_options">Настройки на Syncthing</string>
|
||||||
<string name="syncthing_options">Настройки на Syncthing</string>
|
|
||||||
<string name="device_name">Име на устройството</string>
|
<string name="device_name">Име на устройството</string>
|
||||||
<string name="listen_address">Адрес за слушане на синхронизиращия протокол</string>
|
<string name="listen_address">Адрес за слушане на синхронизиращия протокол</string>
|
||||||
<string name="max_recv_kbps">Лимит на скоростта за сваляне (KiB/s)</string>
|
<string name="max_recv_kbps">Лимит на скоростта за сваляне (KiB/s)</string>
|
||||||
|
@ -156,12 +154,11 @@
|
||||||
<string name="local_announce_enabled">Локално откриване</string>
|
<string name="local_announce_enabled">Локално откриване</string>
|
||||||
<string name="global_announce_server">Сървър за глобално откриване</string>
|
<string name="global_announce_server">Сървър за глобално откриване</string>
|
||||||
<string name="usage_reporting"> Анонимен доклад за ползване на програмата</string>
|
<string name="usage_reporting"> Анонимен доклад за ползване на програмата</string>
|
||||||
<string name="syncthing_gui">Потребителски интерфейс на Syncthing</string>
|
|
||||||
<string name="gui_address">Адрес за свързване с потребителския интерфейс</string>
|
<string name="gui_address">Адрес за свързване с потребителския интерфейс</string>
|
||||||
<string name="gui_user">Потребител за потребителския интерфейс</string>
|
<string name="gui_user">Потребител за потребителския интерфейс</string>
|
||||||
<string name="gui_password">Парола за потребителския интерфейс</string>
|
<string name="gui_password">Парола за потребителския интерфейс</string>
|
||||||
<string name="export_config">Изнасяне на настройките</string>
|
<string name="export_config">Изнасяне на настройките</string>
|
||||||
<string name="experimental_settings">Експериментално</string>
|
<string name="category_experimental">Експериментално</string>
|
||||||
<!--Dialog shown before config export-->
|
<!--Dialog shown before config export-->
|
||||||
<string name="dialog_confirm_export">Наистина ли желаете настройките да бъдат изнесени? Съществуващите файлове ще бъдат презаписани.\n\nВНИМАНИЕ! Програми могат да извлекат частния ви ключ от генерирания файл, а чрез него да свалят и синхронизират файлове.</string>
|
<string name="dialog_confirm_export">Наистина ли желаете настройките да бъдат изнесени? Съществуващите файлове ще бъдат презаписани.\n\nВНИМАНИЕ! Програми могат да извлекат частния ви ключ от генерирания файл, а чрез него да свалят и синхронизират файлове.</string>
|
||||||
<!--Dialog shown before config import-->
|
<!--Dialog shown before config import-->
|
||||||
|
|
|
@ -130,7 +130,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">Nastavení</string>
|
<string name="settings_title">Nastavení</string>
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">Vždy spuštěné na pozadí</string>
|
<string name="always_run_in_background">Vždy spuštěné na pozadí</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -152,8 +151,7 @@
|
||||||
<item>Nízká priorita</item>
|
<item>Nízká priorita</item>
|
||||||
<item>Źádné</item>
|
<item>Źádné</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing_options">Nastavení Syncthing</string>
|
||||||
<string name="syncthing_options">Nastavení Syncthing</string>
|
|
||||||
<string name="device_name">Jméno přístroje</string>
|
<string name="device_name">Jméno přístroje</string>
|
||||||
<string name="listen_address">Adresy naslouchání protokolu synchronizace</string>
|
<string name="listen_address">Adresy naslouchání protokolu synchronizace</string>
|
||||||
<string name="max_recv_kbps">Omezení příchozí rychlosti (KiB/s)</string>
|
<string name="max_recv_kbps">Omezení příchozí rychlosti (KiB/s)</string>
|
||||||
|
@ -164,12 +162,11 @@
|
||||||
<string name="global_announce_server">Server globálního oznamování</string>
|
<string name="global_announce_server">Server globálního oznamování</string>
|
||||||
<string name="enable_relaying">Povolit relaying</string>
|
<string name="enable_relaying">Povolit relaying</string>
|
||||||
<string name="usage_reporting">Anonymní hlášení o používání</string>
|
<string name="usage_reporting">Anonymní hlášení o používání</string>
|
||||||
<string name="syncthing_gui">Syncthing GUI</string>
|
|
||||||
<string name="gui_address">Adresy naslouchání GUI</string>
|
<string name="gui_address">Adresy naslouchání GUI</string>
|
||||||
<string name="gui_user">Přihlašovací jméno pro GUI</string>
|
<string name="gui_user">Přihlašovací jméno pro GUI</string>
|
||||||
<string name="gui_password">Přihlašovací heslo pro GUI</string>
|
<string name="gui_password">Přihlašovací heslo pro GUI</string>
|
||||||
<string name="export_config">Zálohovat nastavení</string>
|
<string name="export_config">Zálohovat nastavení</string>
|
||||||
<string name="experimental_settings">Experimentální</string>
|
<string name="category_experimental">Experimentální</string>
|
||||||
<string name="keep_wakelock_while_binary_running">Udržovat CPU aktivní pokud běží Syncthing</string>
|
<string name="keep_wakelock_while_binary_running">Udržovat CPU aktivní pokud běží Syncthing</string>
|
||||||
<string name="keep_wakelock_while_binary_running_summary">Použijte toto nastavení pokud zaznamenáváte neočekávaná ukončení spojení při běhu na baterii. Toto bude mít za následek vyšší spotřebu energie.</string>
|
<string name="keep_wakelock_while_binary_running_summary">Použijte toto nastavení pokud zaznamenáváte neočekávaná ukončení spojení při běhu na baterii. Toto bude mít za následek vyšší spotřebu energie.</string>
|
||||||
<string name="run_as_foreground_service">Spustit službu na popředí</string>
|
<string name="run_as_foreground_service">Spustit službu na popředí</string>
|
||||||
|
|
|
@ -130,7 +130,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">Einstellungen</string>
|
<string name="settings_title">Einstellungen</string>
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">Immer im Hintergrund ausführen</string>
|
<string name="always_run_in_background">Immer im Hintergrund ausführen</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -152,8 +151,7 @@
|
||||||
<item>Geringe Priorität</item>
|
<item>Geringe Priorität</item>
|
||||||
<item>Keine Priorität</item>
|
<item>Keine Priorität</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing_options">Syncthing-Optionen</string>
|
||||||
<string name="syncthing_options">Syncthing-Optionen</string>
|
|
||||||
<string name="device_name">Gerätename</string>
|
<string name="device_name">Gerätename</string>
|
||||||
<string name="listen_address">Adresse(n) für das Synchronisierungsprotokoll</string>
|
<string name="listen_address">Adresse(n) für das Synchronisierungsprotokoll</string>
|
||||||
<string name="max_recv_kbps">Eingehende Datenrate Limite (KiB/s)</string>
|
<string name="max_recv_kbps">Eingehende Datenrate Limite (KiB/s)</string>
|
||||||
|
@ -164,12 +162,11 @@
|
||||||
<string name="global_announce_server">Globaler Indexserver</string>
|
<string name="global_announce_server">Globaler Indexserver</string>
|
||||||
<string name="enable_relaying">Weiterleitung aktivieren</string>
|
<string name="enable_relaying">Weiterleitung aktivieren</string>
|
||||||
<string name="usage_reporting">Anonymer Nutzungsbericht</string>
|
<string name="usage_reporting">Anonymer Nutzungsbericht</string>
|
||||||
<string name="syncthing_gui">Syncthing-Weboberfläche</string>
|
|
||||||
<string name="gui_address">Adressen für Weboberfläche</string>
|
<string name="gui_address">Adressen für Weboberfläche</string>
|
||||||
<string name="gui_user">Nutzername für Weboberfläche</string>
|
<string name="gui_user">Nutzername für Weboberfläche</string>
|
||||||
<string name="gui_password">Passwort für Weboberfläche</string>
|
<string name="gui_password">Passwort für Weboberfläche</string>
|
||||||
<string name="export_config">Konfiguration exportieren</string>
|
<string name="export_config">Konfiguration exportieren</string>
|
||||||
<string name="experimental_settings">Experimentell</string>
|
<string name="category_experimental">Experimentell</string>
|
||||||
<string name="keep_wakelock_while_binary_running">Prozessor wach halten während Syncthing läuft.</string>
|
<string name="keep_wakelock_while_binary_running">Prozessor wach halten während Syncthing läuft.</string>
|
||||||
<string name="keep_wakelock_while_binary_running_summary">Nutze dieses Einstellung, wenn du unerwartete Verbindungsabbrüche hast, während du im Batteriebetrieb arbeitest. Das wird zu einem erhöhten Energieverbrauch führen.</string>
|
<string name="keep_wakelock_while_binary_running_summary">Nutze dieses Einstellung, wenn du unerwartete Verbindungsabbrüche hast, während du im Batteriebetrieb arbeitest. Das wird zu einem erhöhten Energieverbrauch führen.</string>
|
||||||
<string name="run_as_foreground_service">Führe Dienst mit Vordergrund-Priorität aus</string>
|
<string name="run_as_foreground_service">Führe Dienst mit Vordergrund-Priorität aus</string>
|
||||||
|
|
|
@ -126,7 +126,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">Configuración</string>
|
<string name="settings_title">Configuración</string>
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">Siempre ejecutar en el fondo</string>
|
<string name="always_run_in_background">Siempre ejecutar en el fondo</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -147,8 +146,7 @@
|
||||||
<item>Baja Prioridad</item>
|
<item>Baja Prioridad</item>
|
||||||
<item>Ninguna</item>
|
<item>Ninguna</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing_options">Opciones de Syncthing</string>
|
||||||
<string name="syncthing_options">Opciones de Syncthing</string>
|
|
||||||
<string name="device_name">Nombre del dispositivo</string>
|
<string name="device_name">Nombre del dispositivo</string>
|
||||||
<string name="listen_address">Direcciones de escucha del Protocolo de Sincronización</string>
|
<string name="listen_address">Direcciones de escucha del Protocolo de Sincronización</string>
|
||||||
<string name="max_recv_kbps">Límite de Tasa de Entrada (KiB/s)</string>
|
<string name="max_recv_kbps">Límite de Tasa de Entrada (KiB/s)</string>
|
||||||
|
@ -157,12 +155,11 @@
|
||||||
<string name="local_announce_enabled">Descubrimiento Local</string>
|
<string name="local_announce_enabled">Descubrimiento Local</string>
|
||||||
<string name="global_announce_server">Servidor de Descubrimiento Global</string>
|
<string name="global_announce_server">Servidor de Descubrimiento Global</string>
|
||||||
<string name="usage_reporting">Reporte de uso anónimo</string>
|
<string name="usage_reporting">Reporte de uso anónimo</string>
|
||||||
<string name="syncthing_gui">Interfaz gráfica de Syncthing</string>
|
|
||||||
<string name="gui_address">Direcciones de escucha de la interfaz gráfica</string>
|
<string name="gui_address">Direcciones de escucha de la interfaz gráfica</string>
|
||||||
<string name="gui_user">Autenticación del Usuario en la Interfaz Gráfica</string>
|
<string name="gui_user">Autenticación del Usuario en la Interfaz Gráfica</string>
|
||||||
<string name="gui_password">Autenticación de la Contraseña en la Interfaz Gráfica</string>
|
<string name="gui_password">Autenticación de la Contraseña en la Interfaz Gráfica</string>
|
||||||
<string name="export_config">Exportar Configuración</string>
|
<string name="export_config">Exportar Configuración</string>
|
||||||
<string name="experimental_settings">Experimental</string>
|
<string name="category_experimental">Experimental</string>
|
||||||
<string name="keep_wakelock_while_binary_running">Mantener el CPU encendido mientras Syncthing está en ejecución</string>
|
<string name="keep_wakelock_while_binary_running">Mantener el CPU encendido mientras Syncthing está en ejecución</string>
|
||||||
<string name="keep_wakelock_while_binary_running_summary">Use estos ajustes si experimenta desconexiones inesperadas mientras opera con la batería. Esto resultará en un consumo elevado de batería.</string>
|
<string name="keep_wakelock_while_binary_running_summary">Use estos ajustes si experimenta desconexiones inesperadas mientras opera con la batería. Esto resultará en un consumo elevado de batería.</string>
|
||||||
<!--Dialog shown before config export-->
|
<!--Dialog shown before config export-->
|
||||||
|
|
|
@ -130,7 +130,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">Ajustes</string>
|
<string name="settings_title">Ajustes</string>
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">Ejecutar siempre en segundo plano</string>
|
<string name="always_run_in_background">Ejecutar siempre en segundo plano</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -155,6 +154,7 @@
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing">Syncthing</string>
|
||||||
<string name="syncthing_options">Opciones de Syncthing</string>
|
<string name="syncthing_options">Opciones de Syncthing</string>
|
||||||
<string name="device_name">Nombre del dispositivo</string>
|
<string name="device_name">Nombre del dispositivo</string>
|
||||||
|
<string name="category_syncthing_options">Opciones de Syncthing</string>
|
||||||
<string name="listen_address">Direcciones de escucha del protocolo de sincronización</string>
|
<string name="listen_address">Direcciones de escucha del protocolo de sincronización</string>
|
||||||
<string name="max_recv_kbps">Límite de tráfico de entrada (KiB/s)</string>
|
<string name="max_recv_kbps">Límite de tráfico de entrada (KiB/s)</string>
|
||||||
<string name="max_send_kbps">Límite de tráfico de salida (KiB/s)</string>
|
<string name="max_send_kbps">Límite de tráfico de salida (KiB/s)</string>
|
||||||
|
|
|
@ -130,7 +130,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">Paramètres</string>
|
<string name="settings_title">Paramètres</string>
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">Fonctionner en tâche de fond.</string>
|
<string name="always_run_in_background">Fonctionner en tâche de fond.</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -152,8 +151,7 @@
|
||||||
<item>Discrète</item>
|
<item>Discrète</item>
|
||||||
<item>Aucune</item>
|
<item>Aucune</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing_options">Options Syncthing</string>
|
||||||
<string name="syncthing_options">Options Syncthing</string>
|
|
||||||
<string name="device_name">Nom de l\'appareil</string>
|
<string name="device_name">Nom de l\'appareil</string>
|
||||||
<string name="listen_address">Adresse d\'écoute pour la synchro</string>
|
<string name="listen_address">Adresse d\'écoute pour la synchro</string>
|
||||||
<string name="max_recv_kbps">Limite du débit de réception (Ko/s)</string>
|
<string name="max_recv_kbps">Limite du débit de réception (Ko/s)</string>
|
||||||
|
@ -164,12 +162,11 @@
|
||||||
<string name="global_announce_server">Serveur de découverte globale</string>
|
<string name="global_announce_server">Serveur de découverte globale</string>
|
||||||
<string name="enable_relaying">Activer le relayage</string>
|
<string name="enable_relaying">Activer le relayage</string>
|
||||||
<string name="usage_reporting">Rapports anonymes d\'utilisation</string>
|
<string name="usage_reporting">Rapports anonymes d\'utilisation</string>
|
||||||
<string name="syncthing_gui">Interface WEB Syncthing</string>
|
|
||||||
<string name="gui_address">Adresse pour l\'interface WEB</string>
|
<string name="gui_address">Adresse pour l\'interface WEB</string>
|
||||||
<string name="gui_user">Nom d\'authentification pour l\'interface WEB</string>
|
<string name="gui_user">Nom d\'authentification pour l\'interface WEB</string>
|
||||||
<string name="gui_password">Mot de passe d\'authentification pour l\'interface WEB</string>
|
<string name="gui_password">Mot de passe d\'authentification pour l\'interface WEB</string>
|
||||||
<string name="export_config">Exporter la configuration</string>
|
<string name="export_config">Exporter la configuration</string>
|
||||||
<string name="experimental_settings">Expérimental</string>
|
<string name="category_experimental">Expérimental</string>
|
||||||
<string name="keep_wakelock_while_binary_running">Garder le CPU en éveil quand Syncthing fonctionne.</string>
|
<string name="keep_wakelock_while_binary_running">Garder le CPU en éveil quand Syncthing fonctionne.</string>
|
||||||
<string name="keep_wakelock_while_binary_running_summary">Utilisez ce paramètre si vous rencontrez des déconnexions inattendues en fonctionnant sur batterie. Il en résultera une augmentation de la consommation de la batterie.</string>
|
<string name="keep_wakelock_while_binary_running_summary">Utilisez ce paramètre si vous rencontrez des déconnexions inattendues en fonctionnant sur batterie. Il en résultera une augmentation de la consommation de la batterie.</string>
|
||||||
<string name="run_as_foreground_service">Fonctionner avec prioriré de premier plan</string>
|
<string name="run_as_foreground_service">Fonctionner avec prioriré de premier plan</string>
|
||||||
|
|
|
@ -111,7 +111,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">Beállítások</string>
|
<string name="settings_title">Beállítások</string>
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">Mindig fusson a háttérben</string>
|
<string name="always_run_in_background">Mindig fusson a háttérben</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -123,13 +122,11 @@
|
||||||
<string name="use_root_title">Syncthing futtatása Superuser-ként</string>
|
<string name="use_root_title">Syncthing futtatása Superuser-ként</string>
|
||||||
<string name="notification_type_title">Értesítés</string>
|
<string name="notification_type_title">Értesítés</string>
|
||||||
<string name="notification_type_summary">Értesítés típusának kiválasztása</string>
|
<string name="notification_type_summary">Értesítés típusának kiválasztása</string>
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing_options">Syncthing beállításai</string>
|
||||||
<string name="syncthing_options">Syncthing beállításai</string>
|
|
||||||
<string name="device_name">Eszköz név</string>
|
<string name="device_name">Eszköz név</string>
|
||||||
<string name="global_announce_enabled">Globális felfedezés</string>
|
<string name="global_announce_enabled">Globális felfedezés</string>
|
||||||
<string name="local_announce_enabled">Helyi felfedezés</string>
|
<string name="local_announce_enabled">Helyi felfedezés</string>
|
||||||
<string name="global_announce_server">Globális felfedező szerver</string>
|
<string name="global_announce_server">Globális felfedező szerver</string>
|
||||||
<string name="syncthing_gui">Syncthing GUI</string>
|
|
||||||
<string name="export_config">Beállítások mentése</string>
|
<string name="export_config">Beállítások mentése</string>
|
||||||
<!--Dialog shown before config export-->
|
<!--Dialog shown before config export-->
|
||||||
<!--Dialog shown before config import-->
|
<!--Dialog shown before config import-->
|
||||||
|
|
|
@ -90,7 +90,6 @@
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
<!--Preference summary in case it is disabled-->
|
<!--Preference summary in case it is disabled-->
|
||||||
<string name="category_syncthing">Syncthing</string>
|
|
||||||
<!--Dialog shown before config export-->
|
<!--Dialog shown before config export-->
|
||||||
<!--Dialog shown before config import-->
|
<!--Dialog shown before config import-->
|
||||||
<!--Toast shown after config was successfully exported-->
|
<!--Toast shown after config was successfully exported-->
|
||||||
|
|
|
@ -130,7 +130,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">Impostazioni</string>
|
<string name="settings_title">Impostazioni</string>
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">Sempre in background</string>
|
<string name="always_run_in_background">Sempre in background</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -152,8 +151,7 @@
|
||||||
<item>Bassa priorità</item>
|
<item>Bassa priorità</item>
|
||||||
<item>Nessuno</item>
|
<item>Nessuno</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing_options">Opzioni di Syncthing</string>
|
||||||
<string name="syncthing_options">Opzioni di Syncthing</string>
|
|
||||||
<string name="device_name">Nome Dispositivo</string>
|
<string name="device_name">Nome Dispositivo</string>
|
||||||
<string name="listen_address">Indirizzi Protocollo Sincronizzazione</string>
|
<string name="listen_address">Indirizzi Protocollo Sincronizzazione</string>
|
||||||
<string name="max_recv_kbps">Limite Velocità in Ingresso (KiB/s)</string>
|
<string name="max_recv_kbps">Limite Velocità in Ingresso (KiB/s)</string>
|
||||||
|
@ -164,12 +162,11 @@
|
||||||
<string name="global_announce_server">Server Individuazione Globale</string>
|
<string name="global_announce_server">Server Individuazione Globale</string>
|
||||||
<string name="enable_relaying">Abilita Reindirizzamento</string>
|
<string name="enable_relaying">Abilita Reindirizzamento</string>
|
||||||
<string name="usage_reporting">Statistiche Anonime Utilizzo</string>
|
<string name="usage_reporting">Statistiche Anonime Utilizzo</string>
|
||||||
<string name="syncthing_gui">Interfaccia Grafica di Syncthing</string>
|
|
||||||
<string name="gui_address">Indirizzi Interfaccia Grafica</string>
|
<string name="gui_address">Indirizzi Interfaccia Grafica</string>
|
||||||
<string name="gui_user">Utente Interfaccia Grafica</string>
|
<string name="gui_user">Utente Interfaccia Grafica</string>
|
||||||
<string name="gui_password">Password Autenticazione Utente</string>
|
<string name="gui_password">Password Autenticazione Utente</string>
|
||||||
<string name="export_config">Esporta Configurazione</string>
|
<string name="export_config">Esporta Configurazione</string>
|
||||||
<string name="experimental_settings">Sperimentale</string>
|
<string name="category_experimental">Sperimentale</string>
|
||||||
<string name="keep_wakelock_while_binary_running">Mantieni attiva la CPU quando syncthing è in esecuzione</string>
|
<string name="keep_wakelock_while_binary_running">Mantieni attiva la CPU quando syncthing è in esecuzione</string>
|
||||||
<string name="keep_wakelock_while_binary_running_summary">Usa questa impostazione se rilevi disconnessioni inaspettate durante il funzionamento a batteria. Questo aumenterà il consumo della batteria.</string>
|
<string name="keep_wakelock_while_binary_running_summary">Usa questa impostazione se rilevi disconnessioni inaspettate durante il funzionamento a batteria. Questo aumenterà il consumo della batteria.</string>
|
||||||
<string name="run_as_foreground_service">Esegui il servizio con la priorità di primo piano</string>
|
<string name="run_as_foreground_service">Esegui il servizio con la priorità di primo piano</string>
|
||||||
|
|
|
@ -130,7 +130,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">設定</string>
|
<string name="settings_title">設定</string>
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">常にバックグラウンドで実行</string>
|
<string name="always_run_in_background">常にバックグラウンドで実行</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -152,8 +151,7 @@
|
||||||
<item>優先度低</item>
|
<item>優先度低</item>
|
||||||
<item>なし</item>
|
<item>なし</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing_options">同期オプション</string>
|
||||||
<string name="syncthing_options">同期オプション</string>
|
|
||||||
<string name="device_name">デバイス名</string>
|
<string name="device_name">デバイス名</string>
|
||||||
<string name="listen_address">同期プロトコル リスンアドレス</string>
|
<string name="listen_address">同期プロトコル リスンアドレス</string>
|
||||||
<string name="max_recv_kbps">着信レート制限 (KiB/秒)</string>
|
<string name="max_recv_kbps">着信レート制限 (KiB/秒)</string>
|
||||||
|
@ -164,12 +162,11 @@
|
||||||
<string name="global_announce_server">グローバル探索サーバー</string>
|
<string name="global_announce_server">グローバル探索サーバー</string>
|
||||||
<string name="enable_relaying">リレーを有効にする</string>
|
<string name="enable_relaying">リレーを有効にする</string>
|
||||||
<string name="usage_reporting">匿名使用状況レポート</string>
|
<string name="usage_reporting">匿名使用状況レポート</string>
|
||||||
<string name="syncthing_gui">同期中 GUI</string>
|
|
||||||
<string name="gui_address">GUI リスンアドレス</string>
|
<string name="gui_address">GUI リスンアドレス</string>
|
||||||
<string name="gui_user">GUI 認証ユーザー</string>
|
<string name="gui_user">GUI 認証ユーザー</string>
|
||||||
<string name="gui_password">GUI 認証パスワード</string>
|
<string name="gui_password">GUI 認証パスワード</string>
|
||||||
<string name="export_config">設定をエクスポート</string>
|
<string name="export_config">設定をエクスポート</string>
|
||||||
<string name="experimental_settings">実験的</string>
|
<string name="category_experimental">実験的</string>
|
||||||
<string name="keep_wakelock_while_binary_running">Syncthing の実行中、CPU をオンのままにする</string>
|
<string name="keep_wakelock_while_binary_running">Syncthing の実行中、CPU をオンのままにする</string>
|
||||||
<string name="keep_wakelock_while_binary_running_summary">バッテリーで動作しているときに予期しない接続の切断が発生した場合、この設定を使用します。これは、バッテリー消費を増やします。</string>
|
<string name="keep_wakelock_while_binary_running_summary">バッテリーで動作しているときに予期しない接続の切断が発生した場合、この設定を使用します。これは、バッテリー消費を増やします。</string>
|
||||||
<string name="run_as_foreground_service">フォアグラウンドの優先度でサービスを実行する</string>
|
<string name="run_as_foreground_service">フォアグラウンドの優先度でサービスを実行する</string>
|
||||||
|
|
|
@ -130,7 +130,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">설정</string>
|
<string name="settings_title">설정</string>
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">백그라운드에서 항상 실행</string>
|
<string name="always_run_in_background">백그라운드에서 항상 실행</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -152,8 +151,7 @@
|
||||||
<item>우선 순위 낮음</item>
|
<item>우선 순위 낮음</item>
|
||||||
<item>사용 안 함</item>
|
<item>사용 안 함</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing_options">Syncthing 옵션 </string>
|
||||||
<string name="syncthing_options">Syncthing 옵션 </string>
|
|
||||||
<string name="device_name">기기명</string>
|
<string name="device_name">기기명</string>
|
||||||
<string name="listen_address">동기화 프로토콜 수신 주소</string>
|
<string name="listen_address">동기화 프로토콜 수신 주소</string>
|
||||||
<string name="max_recv_kbps">다운로드 속도 제한 (KiB/s)</string>
|
<string name="max_recv_kbps">다운로드 속도 제한 (KiB/s)</string>
|
||||||
|
@ -164,12 +162,11 @@
|
||||||
<string name="global_announce_server">글로벌 탐색 서버</string>
|
<string name="global_announce_server">글로벌 탐색 서버</string>
|
||||||
<string name="enable_relaying">Relaying 활성화</string>
|
<string name="enable_relaying">Relaying 활성화</string>
|
||||||
<string name="usage_reporting">익명 사용 기록 </string>
|
<string name="usage_reporting">익명 사용 기록 </string>
|
||||||
<string name="syncthing_gui">Syncthing GUI</string>
|
|
||||||
<string name="gui_address">접속 대기 주소</string>
|
<string name="gui_address">접속 대기 주소</string>
|
||||||
<string name="gui_user">GUI 인증 사용자</string>
|
<string name="gui_user">GUI 인증 사용자</string>
|
||||||
<string name="gui_password">GUI 인증 비밀번호</string>
|
<string name="gui_password">GUI 인증 비밀번호</string>
|
||||||
<string name="export_config">설정 내보내기</string>
|
<string name="export_config">설정 내보내기</string>
|
||||||
<string name="experimental_settings">실험적인 기능</string>
|
<string name="category_experimental">실험적인 기능</string>
|
||||||
<string name="keep_wakelock_while_binary_running">Syncthing이 실행 중일 때 CPU를 깨어 있는 상태로 두기</string>
|
<string name="keep_wakelock_while_binary_running">Syncthing이 실행 중일 때 CPU를 깨어 있는 상태로 두기</string>
|
||||||
<string name="keep_wakelock_while_binary_running_summary">만약 배터리로 사용중 예상하지 못한 접속 끊김이 발생 했다면 이 설정을 사용합니다. 이 기능은 배터리 소비를 늘립니다.</string>
|
<string name="keep_wakelock_while_binary_running_summary">만약 배터리로 사용중 예상하지 못한 접속 끊김이 발생 했다면 이 설정을 사용합니다. 이 기능은 배터리 소비를 늘립니다.</string>
|
||||||
<string name="run_as_foreground_service">서비스를 포그라운드로 실행</string>
|
<string name="run_as_foreground_service">서비스를 포그라운드로 실행</string>
|
||||||
|
|
|
@ -128,7 +128,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">Innstillinger</string>
|
<string name="settings_title">Innstillinger</string>
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">Kjør alltid i bakgrunnen</string>
|
<string name="always_run_in_background">Kjør alltid i bakgrunnen</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -150,8 +149,7 @@
|
||||||
<item>Lav prioritet</item>
|
<item>Lav prioritet</item>
|
||||||
<item>Ingen</item>
|
<item>Ingen</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing_options">Valg for Syncthing</string>
|
||||||
<string name="syncthing_options">Valg for Syncthing</string>
|
|
||||||
<string name="device_name">Enhetsnavn</string>
|
<string name="device_name">Enhetsnavn</string>
|
||||||
<string name="listen_address">Lytteadresser for synkeprotokoll</string>
|
<string name="listen_address">Lytteadresser for synkeprotokoll</string>
|
||||||
<string name="max_recv_kbps">Grense for innkommende trafikk (KiB/s)</string>
|
<string name="max_recv_kbps">Grense for innkommende trafikk (KiB/s)</string>
|
||||||
|
@ -162,12 +160,11 @@
|
||||||
<string name="global_announce_server">Global søketjener</string>
|
<string name="global_announce_server">Global søketjener</string>
|
||||||
<string name="enable_relaying">Aktiver relésending</string>
|
<string name="enable_relaying">Aktiver relésending</string>
|
||||||
<string name="usage_reporting">Anonym bruksrapportering</string>
|
<string name="usage_reporting">Anonym bruksrapportering</string>
|
||||||
<string name="syncthing_gui">Syncthing-GUI</string>
|
|
||||||
<string name="gui_address">GUI Lytteadresser</string>
|
<string name="gui_address">GUI Lytteadresser</string>
|
||||||
<string name="gui_user">GUI Autentiseringsbruker</string>
|
<string name="gui_user">GUI Autentiseringsbruker</string>
|
||||||
<string name="gui_password">GUI Autentiseringspassord</string>
|
<string name="gui_password">GUI Autentiseringspassord</string>
|
||||||
<string name="export_config">Eksporter innstillinger</string>
|
<string name="export_config">Eksporter innstillinger</string>
|
||||||
<string name="experimental_settings">Eksperimentelt</string>
|
<string name="category_experimental">Eksperimentelt</string>
|
||||||
<string name="keep_wakelock_while_binary_running">Hold prosessoren våken mens Syncthing kjører</string>
|
<string name="keep_wakelock_while_binary_running">Hold prosessoren våken mens Syncthing kjører</string>
|
||||||
<string name="keep_wakelock_while_binary_running_summary">Bruk denne innstillingen dersom du opplever uventede frakoblinger mens enheten går på batteri. Dette vil medføre økt batteriforbruk.</string>
|
<string name="keep_wakelock_while_binary_running_summary">Bruk denne innstillingen dersom du opplever uventede frakoblinger mens enheten går på batteri. Dette vil medføre økt batteriforbruk.</string>
|
||||||
<string name="run_as_foreground_service">Kjør tjenesten med forgrunnsprioritet</string>
|
<string name="run_as_foreground_service">Kjør tjenesten med forgrunnsprioritet</string>
|
||||||
|
|
|
@ -130,7 +130,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">Instellingen</string>
|
<string name="settings_title">Instellingen</string>
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">Altijd draaien in achtergrond</string>
|
<string name="always_run_in_background">Altijd draaien in achtergrond</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -152,8 +151,7 @@
|
||||||
<item>Lage prioriteit</item>
|
<item>Lage prioriteit</item>
|
||||||
<item>Geen</item>
|
<item>Geen</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing_options">Syncthing-opties</string>
|
||||||
<string name="syncthing_options">Syncthing-opties</string>
|
|
||||||
<string name="device_name">Apparaatnaam</string>
|
<string name="device_name">Apparaatnaam</string>
|
||||||
<string name="listen_address">Synchronisatieprotocol luister-adressen</string>
|
<string name="listen_address">Synchronisatieprotocol luister-adressen</string>
|
||||||
<string name="max_recv_kbps">Inkomende snelheidslimiet (KiB/s)</string>
|
<string name="max_recv_kbps">Inkomende snelheidslimiet (KiB/s)</string>
|
||||||
|
@ -164,12 +162,11 @@
|
||||||
<string name="global_announce_server">Globale ontdekkingsserver</string>
|
<string name="global_announce_server">Globale ontdekkingsserver</string>
|
||||||
<string name="enable_relaying">Relayen inschakelen</string>
|
<string name="enable_relaying">Relayen inschakelen</string>
|
||||||
<string name="usage_reporting">Anoniem gebruiksrapportage</string>
|
<string name="usage_reporting">Anoniem gebruiksrapportage</string>
|
||||||
<string name="syncthing_gui">Syncthing-GUI</string>
|
|
||||||
<string name="gui_address">GUI luister-adressen</string>
|
<string name="gui_address">GUI luister-adressen</string>
|
||||||
<string name="gui_user">GUI-authenticatie gebruiker</string>
|
<string name="gui_user">GUI-authenticatie gebruiker</string>
|
||||||
<string name="gui_password">GUI-authenticatie wachtwoord</string>
|
<string name="gui_password">GUI-authenticatie wachtwoord</string>
|
||||||
<string name="export_config">Configuratie exporteren</string>
|
<string name="export_config">Configuratie exporteren</string>
|
||||||
<string name="experimental_settings">Experimenteel</string>
|
<string name="category_experimental">Experimenteel</string>
|
||||||
<string name="keep_wakelock_while_binary_running">Laat de CPU niet slapen wanneer Syncthing wordt uitgevoerd</string>
|
<string name="keep_wakelock_while_binary_running">Laat de CPU niet slapen wanneer Syncthing wordt uitgevoerd</string>
|
||||||
<string name="keep_wakelock_while_binary_running_summary">Gebruik deze instelling als je onverwacht losgekoppeld wordt wanneer je op batterij werkt. Dit zal leiden tot verhoogd batterijverbruik.</string>
|
<string name="keep_wakelock_while_binary_running_summary">Gebruik deze instelling als je onverwacht losgekoppeld wordt wanneer je op batterij werkt. Dit zal leiden tot verhoogd batterijverbruik.</string>
|
||||||
<string name="run_as_foreground_service">Dienst uitvoeren met voorgrondprioriteit</string>
|
<string name="run_as_foreground_service">Dienst uitvoeren met voorgrondprioriteit</string>
|
||||||
|
|
|
@ -128,7 +128,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">Innstillingar</string>
|
<string name="settings_title">Innstillingar</string>
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">Køyr alltid i bakgrunnen</string>
|
<string name="always_run_in_background">Køyr alltid i bakgrunnen</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -150,8 +149,7 @@
|
||||||
<item>Låg prioritet</item>
|
<item>Låg prioritet</item>
|
||||||
<item>Ingen</item>
|
<item>Ingen</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing_options">Syncthing-innstillingar</string>
|
||||||
<string name="syncthing_options">Syncthing-innstillingar</string>
|
|
||||||
<string name="device_name">Einingsnamn</string>
|
<string name="device_name">Einingsnamn</string>
|
||||||
<string name="listen_address">Lytteadresse for synkroniseringsprotokoll</string>
|
<string name="listen_address">Lytteadresse for synkroniseringsprotokoll</string>
|
||||||
<string name="max_recv_kbps">Nedlastingsgrense (KiB/s)</string>
|
<string name="max_recv_kbps">Nedlastingsgrense (KiB/s)</string>
|
||||||
|
@ -162,12 +160,11 @@
|
||||||
<string name="global_announce_server">Tener for global søketeneste</string>
|
<string name="global_announce_server">Tener for global søketeneste</string>
|
||||||
<string name="enable_relaying">Aktiver Reléer</string>
|
<string name="enable_relaying">Aktiver Reléer</string>
|
||||||
<string name="usage_reporting">Anonym rapportering av bruk</string>
|
<string name="usage_reporting">Anonym rapportering av bruk</string>
|
||||||
<string name="syncthing_gui">Grafisk grensesnitt for Syncthing</string>
|
|
||||||
<string name="gui_address">Grensesnitt: lytteadresser</string>
|
<string name="gui_address">Grensesnitt: lytteadresser</string>
|
||||||
<string name="gui_user">Grensesnitt: Brukarnamn</string>
|
<string name="gui_user">Grensesnitt: Brukarnamn</string>
|
||||||
<string name="gui_password">Grensesnitt: Passord</string>
|
<string name="gui_password">Grensesnitt: Passord</string>
|
||||||
<string name="export_config">Eksporter innstillingar</string>
|
<string name="export_config">Eksporter innstillingar</string>
|
||||||
<string name="experimental_settings">Eksperiment</string>
|
<string name="category_experimental">Eksperiment</string>
|
||||||
<string name="keep_wakelock_while_binary_running">Hald prosessoren vaken medan Syncthing køyrer</string>
|
<string name="keep_wakelock_while_binary_running">Hald prosessoren vaken medan Syncthing køyrer</string>
|
||||||
<string name="keep_wakelock_while_binary_running_summary">Bruk denne innstillinga om du opplever uventa avkoplingar medan du køyrer på batteri. Dette vil føre til auka batteriforbruk.</string>
|
<string name="keep_wakelock_while_binary_running_summary">Bruk denne innstillinga om du opplever uventa avkoplingar medan du køyrer på batteri. Dette vil føre til auka batteriforbruk.</string>
|
||||||
<string name="run_as_foreground_service">Køyr tenesten med forgrunnsprioritet</string>
|
<string name="run_as_foreground_service">Køyr tenesten med forgrunnsprioritet</string>
|
||||||
|
|
|
@ -66,7 +66,6 @@
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
<!--Preference summary in case it is disabled-->
|
<!--Preference summary in case it is disabled-->
|
||||||
<string name="category_syncthing">Syncthing</string>
|
|
||||||
<!--Toast shown after config was successfully exported-->
|
<!--Toast shown after config was successfully exported-->
|
||||||
<!--Toast shown after config was successfully imported-->
|
<!--Toast shown after config was successfully imported-->
|
||||||
<!--Toast shown after config was successfully imported-->
|
<!--Toast shown after config was successfully imported-->
|
||||||
|
|
|
@ -130,7 +130,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">Ustawienia</string>
|
<string name="settings_title">Ustawienia</string>
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">Działanie w tle</string>
|
<string name="always_run_in_background">Działanie w tle</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -146,8 +145,7 @@
|
||||||
<string name="use_root_title">Synchronizuje zawartość z uprawnieniami użytkownika Superuser</string>
|
<string name="use_root_title">Synchronizuje zawartość z uprawnieniami użytkownika Superuser</string>
|
||||||
<string name="notification_type_title">Powiadomienie</string>
|
<string name="notification_type_title">Powiadomienie</string>
|
||||||
<string name="notification_type_summary">Wybiera rodzaj powiadomienia</string>
|
<string name="notification_type_summary">Wybiera rodzaj powiadomienia</string>
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing_options">Ustawienia Syncthing</string>
|
||||||
<string name="syncthing_options">Ustawienia Syncthing</string>
|
|
||||||
<string name="device_name">Nazwa urządzenia</string>
|
<string name="device_name">Nazwa urządzenia</string>
|
||||||
<string name="listen_address">Adres nasłuchiwania protokołu</string>
|
<string name="listen_address">Adres nasłuchiwania protokołu</string>
|
||||||
<string name="max_recv_kbps">Limit pobierania (KiB/s)</string>
|
<string name="max_recv_kbps">Limit pobierania (KiB/s)</string>
|
||||||
|
@ -165,6 +163,7 @@
|
||||||
<string name="export_config">Eksportuj ustawienia</string>
|
<string name="export_config">Eksportuj ustawienia</string>
|
||||||
<string name="experimental_settings">Eksperymentalne</string>
|
<string name="experimental_settings">Eksperymentalne</string>
|
||||||
<string name="keep_wakelock_while_binary_running">Utrzymywanie wybudzonego CPU podczas działania</string>
|
<string name="keep_wakelock_while_binary_running">Utrzymywanie wybudzonego CPU podczas działania</string>
|
||||||
|
<string name="category_experimental">Eksperymelne!</string>
|
||||||
<string name="keep_wakelock_while_binary_running_summary">Używaj, jeśli doświadczasz nieoczekiwanych rozłączeń w trakcie działania na baterii. Spowoduje to zwiększone jej zużycie.</string>
|
<string name="keep_wakelock_while_binary_running_summary">Używaj, jeśli doświadczasz nieoczekiwanych rozłączeń w trakcie działania na baterii. Spowoduje to zwiększone jej zużycie.</string>
|
||||||
<string name="run_as_foreground_service">Pierwszoplanowy priorytet usługi</string>
|
<string name="run_as_foreground_service">Pierwszoplanowy priorytet usługi</string>
|
||||||
<string name="use_tor_title">Korzystanie z Tor</string>
|
<string name="use_tor_title">Korzystanie z Tor</string>
|
||||||
|
|
|
@ -130,7 +130,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">Configurações</string>
|
<string name="settings_title">Configurações</string>
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">Sempre rodar em segundo plano</string>
|
<string name="always_run_in_background">Sempre rodar em segundo plano</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -152,8 +151,7 @@
|
||||||
<item>Baixa prioridade</item>
|
<item>Baixa prioridade</item>
|
||||||
<item>Nenhuma</item>
|
<item>Nenhuma</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing_options">Opções do Syncthing</string>
|
||||||
<string name="syncthing_options">Opções do Syncthing</string>
|
|
||||||
<string name="device_name">Nome do dispositivo</string>
|
<string name="device_name">Nome do dispositivo</string>
|
||||||
<string name="listen_address">Endereços de escuta do protocolo de sincronização</string>
|
<string name="listen_address">Endereços de escuta do protocolo de sincronização</string>
|
||||||
<string name="max_recv_kbps">Limite de velocidade de recepção (KiB/s)</string>
|
<string name="max_recv_kbps">Limite de velocidade de recepção (KiB/s)</string>
|
||||||
|
@ -164,12 +162,11 @@
|
||||||
<string name="global_announce_server">Descoberta global</string>
|
<string name="global_announce_server">Descoberta global</string>
|
||||||
<string name="enable_relaying">Habilitar retransmissão</string>
|
<string name="enable_relaying">Habilitar retransmissão</string>
|
||||||
<string name="usage_reporting">Relatório anônimo de uso</string>
|
<string name="usage_reporting">Relatório anônimo de uso</string>
|
||||||
<string name="syncthing_gui">Interface do Syncthing</string>
|
|
||||||
<string name="gui_address">Endereços de escuta da interface</string>
|
<string name="gui_address">Endereços de escuta da interface</string>
|
||||||
<string name="gui_user">Nome de usuário da interface</string>
|
<string name="gui_user">Nome de usuário da interface</string>
|
||||||
<string name="gui_password">Senha da interface</string>
|
<string name="gui_password">Senha da interface</string>
|
||||||
<string name="export_config">Exportar configuração</string>
|
<string name="export_config">Exportar configuração</string>
|
||||||
<string name="experimental_settings">Configurações experimentais</string>
|
<string name="category_experimental">Configurações experimentais</string>
|
||||||
<string name="keep_wakelock_while_binary_running">Manter a CPU acordada</string>
|
<string name="keep_wakelock_while_binary_running">Manter a CPU acordada</string>
|
||||||
<string name="keep_wakelock_while_binary_running_summary">Marque esta opção se você observar desconexões inesperadas enquanto a bateria do dispositivo não está sendo carregada. Isto resultará em maior uso da bateria.</string>
|
<string name="keep_wakelock_while_binary_running_summary">Marque esta opção se você observar desconexões inesperadas enquanto a bateria do dispositivo não está sendo carregada. Isto resultará em maior uso da bateria.</string>
|
||||||
<string name="run_as_foreground_service">Rodar serviço com prioridade de primeiro plano</string>
|
<string name="run_as_foreground_service">Rodar serviço com prioridade de primeiro plano</string>
|
||||||
|
|
|
@ -121,7 +121,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">Configurações</string>
|
<string name="settings_title">Configurações</string>
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">Correr sempre em segundo plano</string>
|
<string name="always_run_in_background">Correr sempre em segundo plano</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -140,8 +139,7 @@
|
||||||
<item>Baixa prioridade</item>
|
<item>Baixa prioridade</item>
|
||||||
<item>Nenhuma</item>
|
<item>Nenhuma</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing_options">Opções do Syncthing</string>
|
||||||
<string name="syncthing_options">Opções do Syncthing</string>
|
|
||||||
<string name="device_name">Nome do dispositivo</string>
|
<string name="device_name">Nome do dispositivo</string>
|
||||||
<string name="listen_address">Endereços de escuta do protocolo de sincronização</string>
|
<string name="listen_address">Endereços de escuta do protocolo de sincronização</string>
|
||||||
<string name="max_recv_kbps">Limite de velocidade de recepção (KiB/s)</string>
|
<string name="max_recv_kbps">Limite de velocidade de recepção (KiB/s)</string>
|
||||||
|
@ -150,7 +148,6 @@
|
||||||
<string name="local_announce_enabled">Busca local</string>
|
<string name="local_announce_enabled">Busca local</string>
|
||||||
<string name="global_announce_server">Servidor da busca global</string>
|
<string name="global_announce_server">Servidor da busca global</string>
|
||||||
<string name="usage_reporting">Enviar relatórios anónimos de utilização</string>
|
<string name="usage_reporting">Enviar relatórios anónimos de utilização</string>
|
||||||
<string name="syncthing_gui">Interface gráfica do Syncthing</string>
|
|
||||||
<string name="gui_address">Endereço de escuta da interface gráfica</string>
|
<string name="gui_address">Endereço de escuta da interface gráfica</string>
|
||||||
<string name="gui_user">Utilizador da autenticação na interface gráfica</string>
|
<string name="gui_user">Utilizador da autenticação na interface gráfica</string>
|
||||||
<string name="gui_password">Senha da autenticação na interface gráfica</string>
|
<string name="gui_password">Senha da autenticação na interface gráfica</string>
|
||||||
|
|
|
@ -127,7 +127,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">Настройки</string>
|
<string name="settings_title">Настройки</string>
|
||||||
<string name="category_syncthing_android">Настройки приложения</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">Фоновый режим</string>
|
<string name="always_run_in_background">Фоновый режим</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -149,8 +148,7 @@
|
||||||
<item>Низкий</item>
|
<item>Низкий</item>
|
||||||
<item>Никогда</item>
|
<item>Никогда</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="category_syncthing">Общие настройки Syncthing</string>
|
<string name="category_syncthing_options">Настройки устройства</string>
|
||||||
<string name="syncthing_options">Настройки устройства</string>
|
|
||||||
<string name="device_name">Имя устройства</string>
|
<string name="device_name">Имя устройства</string>
|
||||||
<string name="listen_address">Адрес Ожидания Протокола Синхронизации</string>
|
<string name="listen_address">Адрес Ожидания Протокола Синхронизации</string>
|
||||||
<string name="max_recv_kbps">Лимит Скачивания (КБ/с)</string>
|
<string name="max_recv_kbps">Лимит Скачивания (КБ/с)</string>
|
||||||
|
@ -161,7 +159,6 @@
|
||||||
<string name="global_announce_server">Глобальный сервер обнаружения</string>
|
<string name="global_announce_server">Глобальный сервер обнаружения</string>
|
||||||
<string name="enable_relaying">Включить релеи</string>
|
<string name="enable_relaying">Включить релеи</string>
|
||||||
<string name="usage_reporting">Анонимные Отчёты Использования</string>
|
<string name="usage_reporting">Анонимные Отчёты Использования</string>
|
||||||
<string name="syncthing_gui">Syncthing GUI</string>
|
|
||||||
<string name="gui_address">Адрес Ожидания GUI</string>
|
<string name="gui_address">Адрес Ожидания GUI</string>
|
||||||
<string name="gui_user">Пользователь Идентификации GUI</string>
|
<string name="gui_user">Пользователь Идентификации GUI</string>
|
||||||
<string name="gui_password">Пароль Идентификации GUI</string>
|
<string name="gui_password">Пароль Идентификации GUI</string>
|
||||||
|
|
|
@ -120,7 +120,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">Nastavenia</string>
|
<string name="settings_title">Nastavenia</string>
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">Vždy bežať na pozadí</string>
|
<string name="always_run_in_background">Vždy bežať na pozadí</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -139,8 +138,7 @@
|
||||||
<item>S nízkou prioritou</item>
|
<item>S nízkou prioritou</item>
|
||||||
<item>Žiadne</item>
|
<item>Žiadne</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing_options">Nastavenia Syncthing</string>
|
||||||
<string name="syncthing_options">Nastavenia Syncthing</string>
|
|
||||||
<string name="device_name">Názov Zariadenia</string>
|
<string name="device_name">Názov Zariadenia</string>
|
||||||
<string name="listen_address">Adresa pre Sync Protokol</string>
|
<string name="listen_address">Adresa pre Sync Protokol</string>
|
||||||
<string name="max_recv_kbps">Limit Rýchlosti Sťahovania (KiB/s)</string>
|
<string name="max_recv_kbps">Limit Rýchlosti Sťahovania (KiB/s)</string>
|
||||||
|
@ -149,7 +147,6 @@
|
||||||
<string name="local_announce_enabled">Lokálne Vyhľadávanie</string>
|
<string name="local_announce_enabled">Lokálne Vyhľadávanie</string>
|
||||||
<string name="global_announce_server">Adresa Serveru pre Globálne Vyhľadávanie</string>
|
<string name="global_announce_server">Adresa Serveru pre Globálne Vyhľadávanie</string>
|
||||||
<string name="usage_reporting">Povoliť Anonymné Hlásenia o Používaní</string>
|
<string name="usage_reporting">Povoliť Anonymné Hlásenia o Používaní</string>
|
||||||
<string name="syncthing_gui">Syncthing GUI</string>
|
|
||||||
<string name="gui_address">Adresa pre GUI</string>
|
<string name="gui_address">Adresa pre GUI</string>
|
||||||
<string name="gui_user">Užívateľské Meno pre GUI</string>
|
<string name="gui_user">Užívateľské Meno pre GUI</string>
|
||||||
<string name="gui_password">Užívateľské Heslo pre GUI</string>
|
<string name="gui_password">Užívateľské Heslo pre GUI</string>
|
||||||
|
|
|
@ -134,7 +134,6 @@ Vänligen rapportera eventuella problem du stöter på via Github.</string>
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">Inställningar</string>
|
<string name="settings_title">Inställningar</string>
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">Körs alltid i bakgrunden</string>
|
<string name="always_run_in_background">Körs alltid i bakgrunden</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -156,8 +155,7 @@ Vänligen rapportera eventuella problem du stöter på via Github.</string>
|
||||||
<item>Låg prioritet</item>
|
<item>Låg prioritet</item>
|
||||||
<item>Ingen</item>
|
<item>Ingen</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing_options">Syncthing alternativ</string>
|
||||||
<string name="syncthing_options">Syncthing alternativ</string>
|
|
||||||
<string name="device_name">Enhets namn</string>
|
<string name="device_name">Enhets namn</string>
|
||||||
<string name="listen_address">Lyssnaradresser för synkroniseringsprotokoll</string>
|
<string name="listen_address">Lyssnaradresser för synkroniseringsprotokoll</string>
|
||||||
<string name="max_recv_kbps">Inkommande hastighetsbegränsning (KiB/s)</string>
|
<string name="max_recv_kbps">Inkommande hastighetsbegränsning (KiB/s)</string>
|
||||||
|
@ -168,12 +166,11 @@ Vänligen rapportera eventuella problem du stöter på via Github.</string>
|
||||||
<string name="global_announce_server">Global upptäktsserver</string>
|
<string name="global_announce_server">Global upptäktsserver</string>
|
||||||
<string name="enable_relaying">Aktivera reläa</string>
|
<string name="enable_relaying">Aktivera reläa</string>
|
||||||
<string name="usage_reporting">Anonym användningsrapportering</string>
|
<string name="usage_reporting">Anonym användningsrapportering</string>
|
||||||
<string name="syncthing_gui">Syncting-GUI</string>
|
|
||||||
<string name="gui_address">Lyssnaradresser för GUI</string>
|
<string name="gui_address">Lyssnaradresser för GUI</string>
|
||||||
<string name="gui_user">GUI autentiseringsanvändare</string>
|
<string name="gui_user">GUI autentiseringsanvändare</string>
|
||||||
<string name="gui_password">GUI autentiseringslösenord</string>
|
<string name="gui_password">GUI autentiseringslösenord</string>
|
||||||
<string name="export_config">Exportera konfiguration</string>
|
<string name="export_config">Exportera konfiguration</string>
|
||||||
<string name="experimental_settings">Experimentell</string>
|
<string name="category_experimental">Experimentell</string>
|
||||||
<string name="keep_wakelock_while_binary_running">Håll CPU vaken medan Syncthing körs</string>
|
<string name="keep_wakelock_while_binary_running">Håll CPU vaken medan Syncthing körs</string>
|
||||||
<string name="keep_wakelock_while_binary_running_summary">Använd den här inställningen om du får oväntade frånkopplingar under batteridrift. Detta kommer att resultera i ökad batteriförbrukning .</string>
|
<string name="keep_wakelock_while_binary_running_summary">Använd den här inställningen om du får oväntade frånkopplingar under batteridrift. Detta kommer att resultera i ökad batteriförbrukning .</string>
|
||||||
<string name="run_as_foreground_service">Kör tjänst med förgrundsprioritet</string>
|
<string name="run_as_foreground_service">Kör tjänst med förgrundsprioritet</string>
|
||||||
|
|
|
@ -130,7 +130,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">Inställningar</string>
|
<string name="settings_title">Inställningar</string>
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">Körs alltid i bakgrunden</string>
|
<string name="always_run_in_background">Körs alltid i bakgrunden</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -152,8 +151,7 @@
|
||||||
<item>Låg prioritet</item>
|
<item>Låg prioritet</item>
|
||||||
<item>Ingen</item>
|
<item>Ingen</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing_options">Syncthing alternativ</string>
|
||||||
<string name="syncthing_options">Syncthing alternativ</string>
|
|
||||||
<string name="device_name">Enhets namn</string>
|
<string name="device_name">Enhets namn</string>
|
||||||
<string name="listen_address">Synkroniseringsprotokollets lyssnaradresser</string>
|
<string name="listen_address">Synkroniseringsprotokollets lyssnaradresser</string>
|
||||||
<string name="max_recv_kbps">Inkommande hastighetsgräns (KiB/s)</string>
|
<string name="max_recv_kbps">Inkommande hastighetsgräns (KiB/s)</string>
|
||||||
|
@ -164,12 +162,11 @@
|
||||||
<string name="global_announce_server">Global upptäktsserver</string>
|
<string name="global_announce_server">Global upptäktsserver</string>
|
||||||
<string name="enable_relaying">Aktivera reläa</string>
|
<string name="enable_relaying">Aktivera reläa</string>
|
||||||
<string name="usage_reporting">Anonym användningsrapportering</string>
|
<string name="usage_reporting">Anonym användningsrapportering</string>
|
||||||
<string name="syncthing_gui">Syncthing-GUI</string>
|
|
||||||
<string name="gui_address">GUI lyssnaradresser</string>
|
<string name="gui_address">GUI lyssnaradresser</string>
|
||||||
<string name="gui_user">GUI autentiseringsanvändare</string>
|
<string name="gui_user">GUI autentiseringsanvändare</string>
|
||||||
<string name="gui_password">GUI autentiseringslösenord</string>
|
<string name="gui_password">GUI autentiseringslösenord</string>
|
||||||
<string name="export_config">Exportera konfiguration</string>
|
<string name="export_config">Exportera konfiguration</string>
|
||||||
<string name="experimental_settings">Experimentell</string>
|
<string name="category_experimental">Experimentell</string>
|
||||||
<string name="keep_wakelock_while_binary_running">Håll CPU:n vaken medan Syncthing körs</string>
|
<string name="keep_wakelock_while_binary_running">Håll CPU:n vaken medan Syncthing körs</string>
|
||||||
<string name="keep_wakelock_while_binary_running_summary">Använd den här inställningen om du får oväntade frånkopplingar under batteridrift. Detta kommer att resultera i ökad batteriförbrukning.</string>
|
<string name="keep_wakelock_while_binary_running_summary">Använd den här inställningen om du får oväntade frånkopplingar under batteridrift. Detta kommer att resultera i ökad batteriförbrukning.</string>
|
||||||
<string name="run_as_foreground_service">Kör tjänst med förgrundsprioritet</string>
|
<string name="run_as_foreground_service">Kör tjänst med förgrundsprioritet</string>
|
||||||
|
|
|
@ -121,7 +121,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">Ayarlar</string>
|
<string name="settings_title">Ayarlar</string>
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">Arkaplanda herzaman çalış</string>
|
<string name="always_run_in_background">Arkaplanda herzaman çalış</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -142,8 +141,7 @@
|
||||||
<item>Düşük Öncelikli</item>
|
<item>Düşük Öncelikli</item>
|
||||||
<item>Hiçbiri</item>
|
<item>Hiçbiri</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing_options">Syncthing Seçenekler</string>
|
||||||
<string name="syncthing_options">Syncthing Seçenekler</string>
|
|
||||||
<string name="device_name">Cihaz Adı</string>
|
<string name="device_name">Cihaz Adı</string>
|
||||||
<string name="listen_address">Eşzamanlama Protokolü Dinleme/Bağlanma Adresleri</string>
|
<string name="listen_address">Eşzamanlama Protokolü Dinleme/Bağlanma Adresleri</string>
|
||||||
<string name="max_recv_kbps">Gelen Hız Sınırı (KiB/s)</string>
|
<string name="max_recv_kbps">Gelen Hız Sınırı (KiB/s)</string>
|
||||||
|
@ -152,7 +150,6 @@
|
||||||
<string name="local_announce_enabled">Yerel Bulunabilirlik</string>
|
<string name="local_announce_enabled">Yerel Bulunabilirlik</string>
|
||||||
<string name="global_announce_server">Küresel Bulunabilirlik Sunucusu</string>
|
<string name="global_announce_server">Küresel Bulunabilirlik Sunucusu</string>
|
||||||
<string name="usage_reporting">Anonim olarak Kullanım Raporlama</string>
|
<string name="usage_reporting">Anonim olarak Kullanım Raporlama</string>
|
||||||
<string name="syncthing_gui">Syncthing Arayüzü</string>
|
|
||||||
<string name="gui_address">Arayüz Dinleme Adresleri</string>
|
<string name="gui_address">Arayüz Dinleme Adresleri</string>
|
||||||
<string name="gui_user">Arayüz Kullanıcı Doğrulaması için Kullanıcı Adı</string>
|
<string name="gui_user">Arayüz Kullanıcı Doğrulaması için Kullanıcı Adı</string>
|
||||||
<string name="gui_password">Arayüz Kullanıcı Doğrulaması için Kullanıcı Parolası</string>
|
<string name="gui_password">Arayüz Kullanıcı Doğrulaması için Kullanıcı Parolası</string>
|
||||||
|
|
|
@ -126,7 +126,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">Cài đặt</string>
|
<string name="settings_title">Cài đặt</string>
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">Luôn chạy nền</string>
|
<string name="always_run_in_background">Luôn chạy nền</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -147,8 +146,7 @@
|
||||||
<item>Ưu tiên thấp</item>
|
<item>Ưu tiên thấp</item>
|
||||||
<item>Không thông báo</item>
|
<item>Không thông báo</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing_options">Tuỳ chọn Syncthing</string>
|
||||||
<string name="syncthing_options">Tuỳ chọn Syncthing</string>
|
|
||||||
<string name="device_name">Tên thiết bị</string>
|
<string name="device_name">Tên thiết bị</string>
|
||||||
<string name="listen_address">Đồng bộ các đ.chỉ lắng nghe giao thức</string>
|
<string name="listen_address">Đồng bộ các đ.chỉ lắng nghe giao thức</string>
|
||||||
<string name="max_recv_kbps">Giới hạn t.độ đầu vào (KiB/s)</string>
|
<string name="max_recv_kbps">Giới hạn t.độ đầu vào (KiB/s)</string>
|
||||||
|
@ -157,12 +155,11 @@
|
||||||
<string name="local_announce_enabled">Dò tìm cục bộ</string>
|
<string name="local_announce_enabled">Dò tìm cục bộ</string>
|
||||||
<string name="global_announce_server">Máy chủ dò tìm toàn cầu</string>
|
<string name="global_announce_server">Máy chủ dò tìm toàn cầu</string>
|
||||||
<string name="usage_reporting">Báo cáo sử dụng ẩn danh</string>
|
<string name="usage_reporting">Báo cáo sử dụng ẩn danh</string>
|
||||||
<string name="syncthing_gui">GUI Syncthing</string>
|
|
||||||
<string name="gui_address">Các đ.chỉ lắng nghe GUI</string>
|
<string name="gui_address">Các đ.chỉ lắng nghe GUI</string>
|
||||||
<string name="gui_user">Người dùng xác thực GUI</string>
|
<string name="gui_user">Người dùng xác thực GUI</string>
|
||||||
<string name="gui_password">Mật khẩu xác thực GUI</string>
|
<string name="gui_password">Mật khẩu xác thực GUI</string>
|
||||||
<string name="export_config">Xuất cấu hình</string>
|
<string name="export_config">Xuất cấu hình</string>
|
||||||
<string name="experimental_settings">Thực nghiệm</string>
|
<string name="category_experimental">Thực nghiệm</string>
|
||||||
<string name="keep_wakelock_while_binary_running">Giữ CPU thức khi Syncthing đang chạy</string>
|
<string name="keep_wakelock_while_binary_running">Giữ CPU thức khi Syncthing đang chạy</string>
|
||||||
<string name="keep_wakelock_while_binary_running_summary">Dùng tuỳ chỉnh này nếu bạn bị mất kết nối bất ngờ khi đang dùng pin. Nó sẽ tiêu thụ nhiều pin hơn.</string>
|
<string name="keep_wakelock_while_binary_running_summary">Dùng tuỳ chỉnh này nếu bạn bị mất kết nối bất ngờ khi đang dùng pin. Nó sẽ tiêu thụ nhiều pin hơn.</string>
|
||||||
<!--Dialog shown before config export-->
|
<!--Dialog shown before config export-->
|
||||||
|
|
|
@ -130,7 +130,6 @@
|
||||||
<!--SettingsFragment-->
|
<!--SettingsFragment-->
|
||||||
<!--Activity title-->
|
<!--Activity title-->
|
||||||
<string name="settings_title">设置</string>
|
<string name="settings_title">设置</string>
|
||||||
<string name="category_syncthing_android">Android 版 Syncthing 功能</string>
|
|
||||||
<!--Preference title-->
|
<!--Preference title-->
|
||||||
<string name="always_run_in_background">总是在后台运行</string>
|
<string name="always_run_in_background">总是在后台运行</string>
|
||||||
<!--Preference summary in case it is enabled-->
|
<!--Preference summary in case it is enabled-->
|
||||||
|
@ -152,8 +151,7 @@
|
||||||
<item>低优先级</item>
|
<item>低优先级</item>
|
||||||
<item>隐藏</item>
|
<item>隐藏</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="category_syncthing">Syncthing 通用功能</string>
|
<string name="category_syncthing_options">同步设置</string>
|
||||||
<string name="syncthing_options">同步设置</string>
|
|
||||||
<string name="device_name">设备名称</string>
|
<string name="device_name">设备名称</string>
|
||||||
<string name="listen_address">同步协议监听地址</string>
|
<string name="listen_address">同步协议监听地址</string>
|
||||||
<string name="max_recv_kbps">下载限速(KiB/s)</string>
|
<string name="max_recv_kbps">下载限速(KiB/s)</string>
|
||||||
|
@ -164,12 +162,11 @@
|
||||||
<string name="global_announce_server">用以在互联网上寻找节点的发布服务器地址</string>
|
<string name="global_announce_server">用以在互联网上寻找节点的发布服务器地址</string>
|
||||||
<string name="enable_relaying">启用中继</string>
|
<string name="enable_relaying">启用中继</string>
|
||||||
<string name="usage_reporting">匿名使用报告</string>
|
<string name="usage_reporting">匿名使用报告</string>
|
||||||
<string name="syncthing_gui">Syncthing 管理页</string>
|
|
||||||
<string name="gui_address">管理页监听地址</string>
|
<string name="gui_address">管理页监听地址</string>
|
||||||
<string name="gui_user">管理页认证用户</string>
|
<string name="gui_user">管理页认证用户</string>
|
||||||
<string name="gui_password">管理页认证密码</string>
|
<string name="gui_password">管理页认证密码</string>
|
||||||
<string name="export_config">导出设置</string>
|
<string name="export_config">导出设置</string>
|
||||||
<string name="experimental_settings">实验性</string>
|
<string name="category_experimental">实验性</string>
|
||||||
<string name="keep_wakelock_while_binary_running">当 Syncthing 正在运行时保持 CPU 唤醒</string>
|
<string name="keep_wakelock_while_binary_running">当 Syncthing 正在运行时保持 CPU 唤醒</string>
|
||||||
<string name="keep_wakelock_while_binary_running_summary">使用此设置如果您在电池上运行时遇到意外的断开连接。这将会导致电量消耗的增加。</string>
|
<string name="keep_wakelock_while_binary_running_summary">使用此设置如果您在电池上运行时遇到意外的断开连接。这将会导致电量消耗的增加。</string>
|
||||||
<string name="run_as_foreground_service">以前台优先级运行服务</string>
|
<string name="run_as_foreground_service">以前台优先级运行服务</string>
|
||||||
|
|
|
@ -113,14 +113,12 @@
|
||||||
<string name="sync_only_charging">只在充電時同步</string>
|
<string name="sync_only_charging">只在充電時同步</string>
|
||||||
<string name="sync_only_wifi">只透過 Wi-Fi 網路同步</string>
|
<string name="sync_only_wifi">只透過 Wi-Fi 網路同步</string>
|
||||||
<string name="advanced_folder_picker">使用進階的資料夾選擇器</string>
|
<string name="advanced_folder_picker">使用進階的資料夾選擇器</string>
|
||||||
<string name="category_syncthing">Syncthing</string>
|
<string name="category_syncthing_options">Syncthing 選項</string>
|
||||||
<string name="syncthing_options">Syncthing 選項</string>
|
|
||||||
<string name="listen_address">同步通訊協定監聽位址</string>
|
<string name="listen_address">同步通訊協定監聽位址</string>
|
||||||
<string name="max_recv_kbps">下載速率限制(KiB/s)</string>
|
<string name="max_recv_kbps">下載速率限制(KiB/s)</string>
|
||||||
<string name="max_send_kbps">上傳速率限制(KiB/s)</string>
|
<string name="max_send_kbps">上傳速率限制(KiB/s)</string>
|
||||||
<string name="global_announce_enabled">全域探索</string>
|
<string name="global_announce_enabled">全域探索</string>
|
||||||
<string name="local_announce_enabled">本地探索</string>
|
<string name="local_announce_enabled">本地探索</string>
|
||||||
<string name="syncthing_gui">Syncthing GUI</string>
|
|
||||||
<string name="gui_address">GUI 監聽位址</string>
|
<string name="gui_address">GUI 監聽位址</string>
|
||||||
<string name="gui_user">GUI 認證使用者名稱</string>
|
<string name="gui_user">GUI 認證使用者名稱</string>
|
||||||
<string name="gui_password">GUI 認證密碼</string>
|
<string name="gui_password">GUI 認證密碼</string>
|
||||||
|
|
|
@ -217,12 +217,15 @@ Please report any problems you encounter via Github.</string>
|
||||||
<!-- SettingsFragment -->
|
<!-- SettingsFragment -->
|
||||||
|
|
||||||
|
|
||||||
<!-- Activity title -->
|
|
||||||
<string name="settings_title">Settings</string>
|
<string name="settings_title">Settings</string>
|
||||||
|
|
||||||
<string name="category_syncthing_android">Syncthing-Android</string>
|
<string name="category_run_conditions">Run Conditions</string>
|
||||||
|
<string name="category_behaviour">Behaviour</string>
|
||||||
|
<string name="category_syncthing_options">Syncthing Options</string>
|
||||||
|
<string name="category_backup">Backup</string>
|
||||||
|
<string name="category_debug">Debug</string>
|
||||||
|
<string name="category_experimental">Experimental</string>
|
||||||
|
|
||||||
<!-- Preference title -->
|
|
||||||
<string name="always_run_in_background">Always run in background</string>
|
<string name="always_run_in_background">Always run in background</string>
|
||||||
|
|
||||||
<!-- Preference summary in case it is enabled -->
|
<!-- Preference summary in case it is enabled -->
|
||||||
|
@ -257,10 +260,6 @@ Please report any problems you encounter via Github.</string>
|
||||||
<item>None</item>
|
<item>None</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string name="category_syncthing">Syncthing</string>
|
|
||||||
|
|
||||||
<string name="syncthing_options">Syncthing Options</string>
|
|
||||||
|
|
||||||
<string name="device_name">Device Name</string>
|
<string name="device_name">Device Name</string>
|
||||||
|
|
||||||
<string name="listen_address">Sync Protocol Listen Addresses</string>
|
<string name="listen_address">Sync Protocol Listen Addresses</string>
|
||||||
|
@ -275,14 +274,12 @@ Please report any problems you encounter via Github.</string>
|
||||||
|
|
||||||
<string name="enable_nat_traversal">Enable NAT Traversal</string>
|
<string name="enable_nat_traversal">Enable NAT Traversal</string>
|
||||||
|
|
||||||
<string name="global_announce_server">Global Discovery Server</string>
|
<string name="global_announce_server">Global Discovery Servers</string>
|
||||||
|
|
||||||
<string name="enable_relaying">Enable Relaying</string>
|
<string name="enable_relaying">Enable Relaying</string>
|
||||||
|
|
||||||
<string name="usage_reporting">Anonymous Usage Reporting</string>
|
<string name="usage_reporting">Anonymous Usage Reporting</string>
|
||||||
|
|
||||||
<string name="syncthing_gui">Syncthing GUI</string>
|
|
||||||
|
|
||||||
<string name="gui_address">GUI Listen Addresses</string>
|
<string name="gui_address">GUI Listen Addresses</string>
|
||||||
|
|
||||||
<string name="gui_user">GUI Authentication User</string>
|
<string name="gui_user">GUI Authentication User</string>
|
||||||
|
@ -291,8 +288,6 @@ Please report any problems you encounter via Github.</string>
|
||||||
|
|
||||||
<string name="export_config">Export Configuration</string>
|
<string name="export_config">Export Configuration</string>
|
||||||
|
|
||||||
<string name="experimental_settings">Experimental</string>
|
|
||||||
|
|
||||||
<string name="keep_wakelock_while_binary_running">Keep the CPU awake while Syncthing is running</string>
|
<string name="keep_wakelock_while_binary_running">Keep the CPU awake while Syncthing is running</string>
|
||||||
|
|
||||||
<string name="keep_wakelock_while_binary_running_summary">Use this setting if you experience unexpected disconnects while operating on battery. This will result in increased battery consumption.</string>
|
<string name="keep_wakelock_while_binary_running_summary">Use this setting if you experience unexpected disconnects while operating on battery. This will result in increased battery consumption.</string>
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceScreen
|
||||||
android:title="@string/category_syncthing_android">
|
android:title="@string/category_run_conditions"
|
||||||
|
android:key="category_run_conditions">
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:key="always_run_in_background"
|
android:key="always_run_in_background"
|
||||||
|
@ -19,10 +20,15 @@
|
||||||
android:title="@string/sync_only_wifi"
|
android:title="@string/sync_only_wifi"
|
||||||
android:defaultValue="false" />
|
android:defaultValue="false" />
|
||||||
|
|
||||||
<com.nutomic.syncthingandroid.preferences.WifiSsidPreference
|
<com.nutomic.syncthingandroid.views.WifiSsidPreference
|
||||||
android:key="sync_only_wifi_ssids_set"
|
android:key="sync_only_wifi_ssids_set"
|
||||||
android:title="@string/sync_only_wifi_ssids" />
|
android:title="@string/sync_only_wifi_ssids" />
|
||||||
|
|
||||||
|
</PreferenceScreen>
|
||||||
|
|
||||||
|
<PreferenceScreen
|
||||||
|
android:title="@string/category_behaviour">
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:key="advanced_folder_picker"
|
android:key="advanced_folder_picker"
|
||||||
android:title="@string/advanced_folder_picker"
|
android:title="@string/advanced_folder_picker"
|
||||||
|
@ -37,14 +43,11 @@
|
||||||
android:summary="@string/notification_type_summary"
|
android:summary="@string/notification_type_summary"
|
||||||
android:defaultValue="low_priority" />
|
android:defaultValue="low_priority" />
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceScreen>
|
||||||
|
|
||||||
<PreferenceCategory
|
|
||||||
android:title="@string/category_syncthing">
|
|
||||||
|
|
||||||
<PreferenceScreen
|
<PreferenceScreen
|
||||||
android:key="syncthing_options"
|
android:key="category_syncthing_options"
|
||||||
android:title="@string/syncthing_options">
|
android:title="@string/category_syncthing_options">
|
||||||
|
|
||||||
<EditTextPreference
|
<EditTextPreference
|
||||||
android:key="deviceName"
|
android:key="deviceName"
|
||||||
|
@ -73,9 +76,9 @@
|
||||||
android:inputType="number" />
|
android:inputType="number" />
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:key="globalAnnounceEnabled"
|
android:key="natEnabled"
|
||||||
android:title="@string/global_announce_enabled"
|
android:title="@string/enable_nat_traversal"
|
||||||
android:persistent="false" />
|
android:persistent="false"/>
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:key="localAnnounceEnabled"
|
android:key="localAnnounceEnabled"
|
||||||
|
@ -83,31 +86,20 @@
|
||||||
android:persistent="false" />
|
android:persistent="false" />
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:key="natEnabled"
|
android:key="globalAnnounceEnabled"
|
||||||
android:title="@string/enable_nat_traversal"
|
android:title="@string/global_announce_enabled"
|
||||||
android:persistent="false"/>
|
android:persistent="false" />
|
||||||
|
|
||||||
<EditTextPreference
|
|
||||||
android:key="globalAnnounceServers"
|
|
||||||
android:title="@string/global_announce_server"
|
|
||||||
android:persistent="false"
|
|
||||||
android:inputType="textNoSuggestions" />
|
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:key="relaysEnabled"
|
android:key="relaysEnabled"
|
||||||
android:title="@string/enable_relaying"
|
android:title="@string/enable_relaying"
|
||||||
android:persistent="false" />
|
android:persistent="false" />
|
||||||
|
|
||||||
<CheckBoxPreference
|
<EditTextPreference
|
||||||
android:key="urAccepted"
|
android:key="globalAnnounceServers"
|
||||||
android:title="@string/usage_reporting"
|
android:title="@string/global_announce_server"
|
||||||
android:persistent="false" />
|
android:persistent="false"
|
||||||
|
android:inputType="textNoSuggestions" />
|
||||||
</PreferenceScreen>
|
|
||||||
|
|
||||||
<PreferenceScreen
|
|
||||||
android:key="syncthing_gui"
|
|
||||||
android:title="@string/syncthing_gui">
|
|
||||||
|
|
||||||
<EditTextPreference
|
<EditTextPreference
|
||||||
android:key="address"
|
android:key="address"
|
||||||
|
@ -122,12 +114,20 @@
|
||||||
android:persistent="false" />
|
android:persistent="false" />
|
||||||
|
|
||||||
<EditTextPreference
|
<EditTextPreference
|
||||||
android:key="web_gui_password"
|
android:key="password"
|
||||||
android:title="@string/gui_password"
|
android:title="@string/gui_password"
|
||||||
android:inputType="textVisiblePassword" />
|
android:inputType="textVisiblePassword" />
|
||||||
|
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:key="urAccepted"
|
||||||
|
android:title="@string/usage_reporting"
|
||||||
|
android:persistent="false" />
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
||||||
|
<PreferenceScreen
|
||||||
|
android:title="@string/category_backup">
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
android:key="export_config"
|
android:key="export_config"
|
||||||
android:title="@string/export_config" />
|
android:title="@string/export_config" />
|
||||||
|
@ -136,6 +136,18 @@
|
||||||
android:key="import_config"
|
android:key="import_config"
|
||||||
android:title="@string/import_config" />
|
android:title="@string/import_config" />
|
||||||
|
|
||||||
|
</PreferenceScreen>
|
||||||
|
|
||||||
|
<PreferenceScreen
|
||||||
|
android:title="@string/category_debug">
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:title="@string/open_log"
|
||||||
|
android:summary="@string/open_log_summary">
|
||||||
|
<intent
|
||||||
|
android:action=".activities.LogActivity" />
|
||||||
|
</Preference>
|
||||||
|
|
||||||
<EditTextPreference
|
<EditTextPreference
|
||||||
android:key="sttrace"
|
android:key="sttrace"
|
||||||
android:title="@string/sttrace_title"
|
android:title="@string/sttrace_title"
|
||||||
|
@ -147,9 +159,11 @@
|
||||||
android:title="@string/streset_title"
|
android:title="@string/streset_title"
|
||||||
android:singleLine="true" />
|
android:singleLine="true" />
|
||||||
|
|
||||||
|
</PreferenceScreen>
|
||||||
|
|
||||||
<PreferenceScreen
|
<PreferenceScreen
|
||||||
android:key="syncthing_experimental"
|
android:title="@string/category_experimental"
|
||||||
android:title="@string/experimental_settings">
|
android:key="category_experimental">
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:key="use_root"
|
android:key="use_root"
|
||||||
|
@ -176,18 +190,9 @@
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
||||||
</PreferenceCategory>
|
<PreferenceScreen
|
||||||
|
|
||||||
<PreferenceCategory
|
|
||||||
android:title="@string/category_about">
|
android:title="@string/category_about">
|
||||||
|
|
||||||
<Preference
|
|
||||||
android:title="@string/open_log"
|
|
||||||
android:summary="@string/open_log_summary">
|
|
||||||
<intent
|
|
||||||
android:action=".activities.LogActivity" />
|
|
||||||
</Preference>
|
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
android:title="@string/report_issue_title"
|
android:title="@string/report_issue_title"
|
||||||
android:summary="@string/report_issue_summary">
|
android:summary="@string/report_issue_summary">
|
||||||
|
@ -214,6 +219,6 @@
|
||||||
android:title="@string/app_version_title"
|
android:title="@string/app_version_title"
|
||||||
style="?android:preferenceInformationStyle" />
|
style="?android:preferenceInformationStyle" />
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceScreen>
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
Loading…
Reference in a new issue