mirror of
https://github.com/syncthing/syncthing-android.git
synced 2024-12-22 19:01:30 +00:00
Changed code style to use spaces instead of tabs.
It is impossible to add a custom code style in Android Studio that is stored in the project repository. So change style to something that's easy to use in practice now rather than later.
This commit is contained in:
parent
c3b027e8b5
commit
b1749ce7cb
49 changed files with 3611 additions and 3668 deletions
|
@ -41,6 +41,6 @@ screenshots: *link to file* (only for UI problems)
|
|||
|
||||
Always welcome.
|
||||
|
||||
Code should follow the [Android Code Style Guidelines](https://source.android.com/source/code-style.html#java-language-rules), with the exception that we use tabs, not spaces for indentation.
|
||||
Code should follow the [Android Code Style Guidelines](https://source.android.com/source/code-style.html#java-language-rules). This can be done automatically in Android Studio.
|
||||
|
||||
Lint warnings should be fixed. If that's not possible, they should be ignored as specifically as possible.
|
||||
|
|
190
build.gradle
190
build.gradle
|
@ -1,12 +1,12 @@
|
|||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:0.12.+'
|
||||
classpath 'com.alexvasilkov:android_sign:0.2+'
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:0.12.+'
|
||||
classpath 'com.alexvasilkov:android_sign:0.2+'
|
||||
}
|
||||
}
|
||||
|
||||
import java.util.regex.Pattern
|
||||
|
@ -15,126 +15,126 @@ apply plugin: 'com.android.application'
|
|||
apply plugin: 'android_sign'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.android.support:appcompat-v7:19.1.+'
|
||||
compile project(':android-support-v4-preferencefragment')
|
||||
compile 'com.android.support:appcompat-v7:19.1.+'
|
||||
compile project(':android-support-v4-preferencefragment')
|
||||
}
|
||||
|
||||
preBuild {
|
||||
dependsOn 'buildNative'
|
||||
dependsOn 'buildNative'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 19
|
||||
buildToolsVersion "19.1.0"
|
||||
compileSdkVersion 19
|
||||
buildToolsVersion "19.1.0"
|
||||
|
||||
defaultConfig {
|
||||
versionCode getVersionCodeFromManifest()
|
||||
}
|
||||
defaultConfig {
|
||||
versionCode getVersionCodeFromManifest()
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
jniLibs.srcDir file("libs/")
|
||||
}
|
||||
}
|
||||
sourceSets {
|
||||
main {
|
||||
jniLibs.srcDir file("libs/")
|
||||
}
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
release {
|
||||
// Android Studio does not pass environment variables.
|
||||
// This means you have to use the command line for release builds.
|
||||
def ks = System.getenv("KEYSTORE")
|
||||
def ka = System.getenv("KEY_ALIAS")
|
||||
if (ks != null && ka != null) {
|
||||
storeFile file(ks)
|
||||
keyAlias ka
|
||||
}
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
release {
|
||||
// Android Studio does not pass environment variables.
|
||||
// This means you have to use the command line for release builds.
|
||||
def ks = System.getenv("KEYSTORE")
|
||||
def ka = System.getenv("KEY_ALIAS")
|
||||
if (ks != null && ka != null) {
|
||||
storeFile file(ks)
|
||||
keyAlias ka
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
applicationIdSuffix ".debug"
|
||||
debuggable true
|
||||
}
|
||||
release {
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
debug {
|
||||
applicationIdSuffix ".debug"
|
||||
debuggable true
|
||||
}
|
||||
release {
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
|
||||
productFlavors {
|
||||
x86 {
|
||||
versionCode Integer.parseInt("4" + defaultConfig.versionCode)
|
||||
ndk {
|
||||
abiFilter "x86"
|
||||
}
|
||||
}
|
||||
armeabi_v7a {
|
||||
versionCode Integer.parseInt("3" + defaultConfig.versionCode)
|
||||
ndk {
|
||||
abiFilter "armeabi-v7a"
|
||||
}
|
||||
}
|
||||
armeabi {
|
||||
versionCode Integer.parseInt("2" + defaultConfig.versionCode)
|
||||
ndk {
|
||||
abiFilter "armeabi"
|
||||
}
|
||||
}
|
||||
mips {
|
||||
versionCode Integer.parseInt("1" + defaultConfig.versionCode)
|
||||
ndk {
|
||||
abiFilter "mips"
|
||||
}
|
||||
}
|
||||
fat {
|
||||
versionCode Integer.parseInt("0" + defaultConfig.versionCode)
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
}
|
||||
productFlavors {
|
||||
x86 {
|
||||
versionCode Integer.parseInt("4" + defaultConfig.versionCode)
|
||||
ndk {
|
||||
abiFilter "x86"
|
||||
}
|
||||
}
|
||||
armeabi_v7a {
|
||||
versionCode Integer.parseInt("3" + defaultConfig.versionCode)
|
||||
ndk {
|
||||
abiFilter "armeabi-v7a"
|
||||
}
|
||||
}
|
||||
armeabi {
|
||||
versionCode Integer.parseInt("2" + defaultConfig.versionCode)
|
||||
ndk {
|
||||
abiFilter "armeabi"
|
||||
}
|
||||
}
|
||||
mips {
|
||||
versionCode Integer.parseInt("1" + defaultConfig.versionCode)
|
||||
ndk {
|
||||
abiFilter "mips"
|
||||
}
|
||||
}
|
||||
fat {
|
||||
versionCode Integer.parseInt("0" + defaultConfig.versionCode)
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
}
|
||||
}
|
||||
|
||||
def getVersionCodeFromManifest() {
|
||||
def manifestFile = file(android.sourceSets.main.manifest.srcFile)
|
||||
def pattern = Pattern.compile("versionCode=\"(\\d+)\"")
|
||||
def matcher = pattern.matcher(manifestFile.getText())
|
||||
matcher.find()
|
||||
return Integer.parseInt(matcher.group(1))
|
||||
def manifestFile = file(android.sourceSets.main.manifest.srcFile)
|
||||
def pattern = Pattern.compile("versionCode=\"(\\d+)\"")
|
||||
def matcher = pattern.matcher(manifestFile.getText())
|
||||
matcher.find()
|
||||
return Integer.parseInt(matcher.group(1))
|
||||
}
|
||||
|
||||
task buildNative(type: Exec) {
|
||||
outputs.upToDateWhen { false }
|
||||
executable = './build-syncthing.sh'
|
||||
outputs.upToDateWhen { false }
|
||||
executable = './build-syncthing.sh'
|
||||
}
|
||||
|
||||
task copyNative(type: Copy) {
|
||||
def lib_dir = "libs/"
|
||||
new File(lib_dir).mkdirs()
|
||||
def st_dir = "bin/";
|
||||
from st_dir + 'syncthing-x86', st_dir + 'syncthing-armeabi', st_dir + 'syncthing-armeabi-v7a';
|
||||
into lib_dir
|
||||
rename('syncthing-x86', 'x86/libsyncthing.so')
|
||||
def lib_dir = "libs/"
|
||||
new File(lib_dir).mkdirs()
|
||||
def st_dir = "bin/";
|
||||
from st_dir + 'syncthing-x86', st_dir + 'syncthing-armeabi', st_dir + 'syncthing-armeabi-v7a';
|
||||
into lib_dir
|
||||
rename('syncthing-x86', 'x86/libsyncthing.so')
|
||||
rename('syncthing-armeabi-v7a', 'armeabi-v7a/libsyncthing.so')
|
||||
rename('syncthing-armeabi', 'armeabi/libsyncthing.so')
|
||||
rename('syncthing-armeabi', 'armeabi/libsyncthing.so')
|
||||
}
|
||||
buildNative.finalizedBy copyNative
|
||||
|
||||
task cleanBin(type: Delete) {
|
||||
delete 'bin/'
|
||||
delete 'bin/'
|
||||
}
|
||||
copyNative.finalizedBy cleanBin
|
||||
|
||||
task cleanNative(type: Delete) {
|
||||
delete 'bin/'
|
||||
delete 'build/'
|
||||
delete 'libs/'
|
||||
delete 'ext/syncthing/bin/'
|
||||
delete 'ext/syncthing/pkg/'
|
||||
delete 'bin/'
|
||||
delete 'build/'
|
||||
delete 'libs/'
|
||||
delete 'ext/syncthing/bin/'
|
||||
delete 'ext/syncthing/pkg/'
|
||||
}
|
||||
clean.dependsOn cleanNative
|
||||
|
||||
|
|
|
@ -1,75 +1,75 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.nutomic.syncthingandroid"
|
||||
android:versionCode="33"
|
||||
android:versionName="0.4.19"
|
||||
tools:ignore="GradleOverrides" >
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.nutomic.syncthingandroid"
|
||||
android:versionCode="33"
|
||||
android:versionName="0.4.19"
|
||||
tools:ignore="GradleOverrides" >
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="8"
|
||||
android:targetSdkVersion="19" />
|
||||
<uses-sdk
|
||||
android:minSdkVersion="8"
|
||||
android:targetSdkVersion="19" />
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme" >
|
||||
<activity
|
||||
android:name=".activities.MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTop" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity
|
||||
android:name=".activities.MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTop">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activities.WebGuiActivity"
|
||||
android:label="@string/web_gui_title" >
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".gui.MainActivity" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activities.SettingsActivity" >
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".gui.MainActivity" />
|
||||
</activity>
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activities.WebGuiActivity"
|
||||
android:label="@string/web_gui_title">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".gui.MainActivity" />
|
||||
</activity>
|
||||
<activity android:name=".activities.SettingsActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".gui.MainActivity" />
|
||||
</activity>
|
||||
|
||||
<service android:name=".syncthing.SyncthingService" />
|
||||
<service android:name=".syncthing.SyncthingService" />
|
||||
|
||||
<activity
|
||||
android:name=".activities.FolderPickerActivity"
|
||||
android:label="@string/folder_picker_title" >
|
||||
<meta-data
|
||||
android:name="android.support.UI_OPTIONS"
|
||||
android:value="splitActionBarWhenNarrow" />
|
||||
</activity>
|
||||
<receiver android:name=".syncthing.NetworkReceiver" >
|
||||
<intent-filter>
|
||||
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver android:name=".syncthing.BatteryReceiver" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
|
||||
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<activity
|
||||
android:name=".activities.FolderPickerActivity"
|
||||
android:label="@string/folder_picker_title">
|
||||
<meta-data
|
||||
android:name="android.support.UI_OPTIONS"
|
||||
android:value="splitActionBarWhenNarrow" />
|
||||
</activity>
|
||||
|
||||
<receiver android:name=".syncthing.NetworkReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver android:name=".syncthing.BatteryReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
|
||||
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver android:name=".syncthing.BootReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
</application>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -32,42 +32,42 @@ import java.util.Arrays;
|
|||
* Activity that allows selecting a directory in the local file system.
|
||||
*/
|
||||
public class FolderPickerActivity extends SyncthingActivity
|
||||
implements AdapterView.OnItemClickListener, SyncthingService.OnApiChangeListener {
|
||||
implements AdapterView.OnItemClickListener, SyncthingService.OnApiChangeListener {
|
||||
|
||||
private static final String TAG = "FolderPickerActivity";
|
||||
private static final String TAG = "FolderPickerActivity";
|
||||
|
||||
public static final String EXTRA_INITIAL_DIRECTORY = "initial_directory";
|
||||
public static final String EXTRA_INITIAL_DIRECTORY = "initial_directory";
|
||||
|
||||
public static final String EXTRA_RESULT_DIRECTORY = "result_directory";
|
||||
public static final String EXTRA_RESULT_DIRECTORY = "result_directory";
|
||||
|
||||
private ListView mListView;
|
||||
private ListView mListView;
|
||||
|
||||
private FileAdapter mAdapter;
|
||||
private FileAdapter mAdapter;
|
||||
|
||||
private File mLocation;
|
||||
private File mLocation;
|
||||
|
||||
@Override
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
setContentView(R.layout.folder_picker_activity);
|
||||
mListView = (ListView) findViewById(android.R.id.list);
|
||||
mListView.setOnItemClickListener(this);
|
||||
mListView.setEmptyView(findViewById(android.R.id.empty));
|
||||
mAdapter = new FileAdapter(this);
|
||||
mListView.setAdapter(mAdapter);
|
||||
mListView = (ListView) findViewById(android.R.id.list);
|
||||
mListView.setOnItemClickListener(this);
|
||||
mListView.setEmptyView(findViewById(android.R.id.empty));
|
||||
mAdapter = new FileAdapter(this);
|
||||
mListView.setAdapter(mAdapter);
|
||||
|
||||
mLocation = new File(getIntent().getStringExtra(EXTRA_INITIAL_DIRECTORY));
|
||||
refresh();
|
||||
mLocation = new File(getIntent().getStringExtra(EXTRA_INITIAL_DIRECTORY));
|
||||
refresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
|
||||
super.onServiceConnected(componentName, iBinder);
|
||||
getService().registerOnApiChangeListener(this);
|
||||
}
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
|
||||
super.onServiceConnected(componentName, iBinder);
|
||||
getService().registerOnApiChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
|
@ -78,116 +78,116 @@ public class FolderPickerActivity extends SyncthingActivity
|
|||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.create_folder:
|
||||
final EditText et = new EditText(this);
|
||||
AlertDialog dialog = new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.create_folder)
|
||||
.setView(et)
|
||||
.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
createFolder(et.getText().toString());
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
|
||||
@Override
|
||||
public void onShow(DialogInterface dialogInterface) {
|
||||
((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE))
|
||||
.showSoftInput(et, InputMethodManager.SHOW_IMPLICIT);
|
||||
}
|
||||
});
|
||||
dialog.show();
|
||||
return true;
|
||||
case R.id.select:
|
||||
Intent intent = new Intent()
|
||||
.putExtra(EXTRA_RESULT_DIRECTORY, mLocation.getAbsolutePath());
|
||||
setResult(Activity.RESULT_OK, intent);
|
||||
finish();
|
||||
return true;
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
switch (item.getItemId()) {
|
||||
case R.id.create_folder:
|
||||
final EditText et = new EditText(this);
|
||||
AlertDialog dialog = new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.create_folder)
|
||||
.setView(et)
|
||||
.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
createFolder(et.getText().toString());
|
||||
}
|
||||
}
|
||||
)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
|
||||
@Override
|
||||
public void onShow(DialogInterface dialogInterface) {
|
||||
((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE))
|
||||
.showSoftInput(et, InputMethodManager.SHOW_IMPLICIT);
|
||||
}
|
||||
});
|
||||
dialog.show();
|
||||
return true;
|
||||
case R.id.select:
|
||||
Intent intent = new Intent()
|
||||
.putExtra(EXTRA_RESULT_DIRECTORY, mLocation.getAbsolutePath());
|
||||
setResult(Activity.RESULT_OK, intent);
|
||||
finish();
|
||||
return true;
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new folder with the given name and enters it.
|
||||
*/
|
||||
private void createFolder(String name) {
|
||||
File newFolder = new File(mLocation, name);
|
||||
newFolder.mkdir();
|
||||
mLocation = newFolder;
|
||||
refresh();
|
||||
}
|
||||
/**
|
||||
* Creates a new folder with the given name and enters it.
|
||||
*/
|
||||
private void createFolder(String name) {
|
||||
File newFolder = new File(mLocation, name);
|
||||
newFolder.mkdir();
|
||||
mLocation = newFolder;
|
||||
refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the ListView to show the contents of the folder in {@code }mLocation.peek()}.
|
||||
*/
|
||||
private void refresh() {
|
||||
mAdapter.clear();
|
||||
File[] contents = mLocation.listFiles(new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File file) {
|
||||
return file.isDirectory();
|
||||
}
|
||||
});
|
||||
Arrays.sort(contents);
|
||||
for (File f : contents) {
|
||||
mAdapter.add(f);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Refreshes the ListView to show the contents of the folder in {@code }mLocation.peek()}.
|
||||
*/
|
||||
private void refresh() {
|
||||
mAdapter.clear();
|
||||
File[] contents = mLocation.listFiles(new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File file) {
|
||||
return file.isDirectory();
|
||||
}
|
||||
});
|
||||
Arrays.sort(contents);
|
||||
for (File f : contents) {
|
||||
mAdapter.add(f);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
mLocation = mAdapter.getItem(i);
|
||||
refresh();
|
||||
}
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
mLocation = mAdapter.getItem(i);
|
||||
refresh();
|
||||
}
|
||||
|
||||
private class FileAdapter extends ArrayAdapter<File> {
|
||||
private class FileAdapter extends ArrayAdapter<File> {
|
||||
|
||||
public FileAdapter(Context context) {
|
||||
super(context, android.R.layout.simple_list_item_1);
|
||||
}
|
||||
public FileAdapter(Context context) {
|
||||
super(context, android.R.layout.simple_list_item_1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
LayoutInflater inflater = (LayoutInflater) getContext()
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
convertView = inflater.inflate(android.R.layout.simple_list_item_1, parent, false);
|
||||
}
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
LayoutInflater inflater = (LayoutInflater) getContext()
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
convertView = inflater.inflate(android.R.layout.simple_list_item_1, parent, false);
|
||||
}
|
||||
|
||||
TextView title = (TextView) convertView.findViewById(android.R.id.text1);
|
||||
title.setText(getItem(position).getName());
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
TextView title = (TextView) convertView.findViewById(android.R.id.text1);
|
||||
title.setText(getItem(position).getName());
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (!mLocation.equals(Environment.getExternalStorageDirectory())) {
|
||||
mLocation = mLocation.getParentFile();
|
||||
refresh();
|
||||
}
|
||||
else {
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (!mLocation.equals(Environment.getExternalStorageDirectory())) {
|
||||
mLocation = mLocation.getParentFile();
|
||||
refresh();
|
||||
} else {
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApiChange(SyncthingService.State currentState) {
|
||||
if (currentState != SyncthingService.State.ACTIVE) {
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
SyncthingService.showDisabledDialog(this);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onApiChange(SyncthingService.State currentState) {
|
||||
if (currentState != SyncthingService.State.ACTIVE) {
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
SyncthingService.showDisabledDialog(this);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,253 +37,254 @@ import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
|||
* {@link com.nutomic.syncthingandroid.fragments.LocalNodeInfoFragment} in the navigation drawer.
|
||||
*/
|
||||
public class MainActivity extends SyncthingActivity
|
||||
implements SyncthingService.OnApiChangeListener {
|
||||
implements SyncthingService.OnApiChangeListener {
|
||||
|
||||
private AlertDialog mLoadingDialog;
|
||||
private AlertDialog mLoadingDialog;
|
||||
|
||||
/**
|
||||
* Causes population of repo and node lists, unlocks info drawer.
|
||||
*/
|
||||
@Override
|
||||
@SuppressLint("InflateParams")
|
||||
public void onApiChange(SyncthingService.State currentState) {
|
||||
if (currentState != SyncthingService.State.ACTIVE && !isFinishing()) {
|
||||
if (currentState == SyncthingService.State.DISABLED) {
|
||||
if (mLoadingDialog != null) {
|
||||
mLoadingDialog.dismiss();
|
||||
}
|
||||
SyncthingService.showDisabledDialog(this);
|
||||
}
|
||||
else if (mLoadingDialog == null) {
|
||||
final SharedPreferences prefs =
|
||||
PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
|
||||
/**
|
||||
* Causes population of repo and node lists, unlocks info drawer.
|
||||
*/
|
||||
@Override
|
||||
@SuppressLint("InflateParams")
|
||||
public void onApiChange(SyncthingService.State currentState) {
|
||||
if (currentState != SyncthingService.State.ACTIVE && !isFinishing()) {
|
||||
if (currentState == SyncthingService.State.DISABLED) {
|
||||
if (mLoadingDialog != null) {
|
||||
mLoadingDialog.dismiss();
|
||||
}
|
||||
SyncthingService.showDisabledDialog(this);
|
||||
} else if (mLoadingDialog == null) {
|
||||
final SharedPreferences prefs =
|
||||
PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
|
||||
|
||||
LayoutInflater inflater = getLayoutInflater();
|
||||
View dialogLayout = inflater.inflate(R.layout.loading_dialog, null);
|
||||
TextView loadingText = (TextView) dialogLayout.findViewById(R.id.loading_text);
|
||||
loadingText.setText((getService().isFirstStart())
|
||||
? R.string.web_gui_creating_key
|
||||
: R.string.api_loading);
|
||||
LayoutInflater inflater = getLayoutInflater();
|
||||
View dialogLayout = inflater.inflate(R.layout.loading_dialog, null);
|
||||
TextView loadingText = (TextView) dialogLayout.findViewById(R.id.loading_text);
|
||||
loadingText.setText((getService().isFirstStart())
|
||||
? R.string.web_gui_creating_key
|
||||
: R.string.api_loading);
|
||||
|
||||
mLoadingDialog = new AlertDialog.Builder(this)
|
||||
.setCancelable(false)
|
||||
.setView(dialogLayout)
|
||||
.show();
|
||||
mLoadingDialog = new AlertDialog.Builder(this)
|
||||
.setCancelable(false)
|
||||
.setView(dialogLayout)
|
||||
.show();
|
||||
|
||||
// Make sure the first start dialog is shown on top.
|
||||
if (prefs.getBoolean("first_start", true)) {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.welcome_title)
|
||||
.setMessage(R.string.welcome_text)
|
||||
.setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
prefs.edit().putBoolean("first_start", false).commit();
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Make sure the first start dialog is shown on top.
|
||||
if (prefs.getBoolean("first_start", true)) {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.welcome_title)
|
||||
.setMessage(R.string.welcome_text)
|
||||
.setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
prefs.edit().putBoolean("first_start", false).commit();
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (mLoadingDialog != null) {
|
||||
mLoadingDialog.dismiss();
|
||||
}
|
||||
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
|
||||
mDrawerLayout.setDrawerListener(mDrawerToggle);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setHomeButtonEnabled(true);
|
||||
}
|
||||
if (mLoadingDialog != null) {
|
||||
mLoadingDialog.dismiss();
|
||||
}
|
||||
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
|
||||
mDrawerLayout.setDrawerListener(mDrawerToggle);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setHomeButtonEnabled(true);
|
||||
}
|
||||
|
||||
private final FragmentPagerAdapter mSectionsPagerAdapter =
|
||||
new FragmentPagerAdapter(getSupportFragmentManager()) {
|
||||
private final FragmentPagerAdapter mSectionsPagerAdapter =
|
||||
new FragmentPagerAdapter(getSupportFragmentManager()) {
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
switch (position) {
|
||||
case 0: return mRepositoriesFragment;
|
||||
case 1: return mNodesFragment;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return mRepositoriesFragment;
|
||||
case 1:
|
||||
return mNodesFragment;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return 2;
|
||||
}
|
||||
@Override
|
||||
public int getCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
private ReposFragment mRepositoriesFragment;
|
||||
private ReposFragment mRepositoriesFragment;
|
||||
|
||||
private NodesFragment mNodesFragment;
|
||||
private NodesFragment mNodesFragment;
|
||||
|
||||
private LocalNodeInfoFragment mLocalNodeInfoFragment;
|
||||
private LocalNodeInfoFragment mLocalNodeInfoFragment;
|
||||
|
||||
private ViewPager mViewPager;
|
||||
private ViewPager mViewPager;
|
||||
|
||||
private ActionBarDrawerToggle mDrawerToggle;
|
||||
private ActionBarDrawerToggle mDrawerToggle;
|
||||
|
||||
private DrawerLayout mDrawerLayout;
|
||||
private DrawerLayout mDrawerLayout;
|
||||
|
||||
/**
|
||||
* Initializes tab navigation.
|
||||
*/
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
final ActionBar actionBar = getSupportActionBar();
|
||||
/**
|
||||
* Initializes tab navigation.
|
||||
*/
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
final ActionBar actionBar = getSupportActionBar();
|
||||
|
||||
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
|
||||
setContentView(R.layout.main_activity);
|
||||
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
|
||||
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
|
||||
setContentView(R.layout.main_activity);
|
||||
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
|
||||
|
||||
mViewPager = (ViewPager) findViewById(R.id.pager);
|
||||
mViewPager.setAdapter(mSectionsPagerAdapter);
|
||||
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
actionBar.setSelectedNavigationItem(position);
|
||||
}
|
||||
});
|
||||
mViewPager = (ViewPager) findViewById(R.id.pager);
|
||||
mViewPager.setAdapter(mSectionsPagerAdapter);
|
||||
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
actionBar.setSelectedNavigationItem(position);
|
||||
}
|
||||
});
|
||||
|
||||
TabListener tabListener = new TabListener() {
|
||||
public void onTabSelected(Tab tab, FragmentTransaction ft) {
|
||||
mViewPager.setCurrentItem(tab.getPosition());
|
||||
}
|
||||
TabListener tabListener = new TabListener() {
|
||||
public void onTabSelected(Tab tab, FragmentTransaction ft) {
|
||||
mViewPager.setCurrentItem(tab.getPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabReselected(Tab tab, FragmentTransaction ft) {
|
||||
}
|
||||
@Override
|
||||
public void onTabReselected(Tab tab, FragmentTransaction ft) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
|
||||
}
|
||||
};
|
||||
|
||||
actionBar.addTab(actionBar.newTab()
|
||||
.setText(R.string.repositories_fragment_title)
|
||||
.setTabListener(tabListener));
|
||||
actionBar.addTab(actionBar.newTab()
|
||||
.setText(R.string.nodes_fragment_title)
|
||||
.setTabListener(tabListener));
|
||||
actionBar.addTab(actionBar.newTab()
|
||||
.setText(R.string.repositories_fragment_title)
|
||||
.setTabListener(tabListener));
|
||||
actionBar.addTab(actionBar.newTab()
|
||||
.setText(R.string.nodes_fragment_title)
|
||||
.setTabListener(tabListener));
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
FragmentManager fm = getSupportFragmentManager();
|
||||
mRepositoriesFragment = (ReposFragment) fm.getFragment(
|
||||
savedInstanceState, ReposFragment.class.getName());
|
||||
mNodesFragment = (NodesFragment) fm.getFragment(
|
||||
savedInstanceState, NodesFragment.class.getName());
|
||||
mLocalNodeInfoFragment = (LocalNodeInfoFragment) fm.getFragment(
|
||||
savedInstanceState, LocalNodeInfoFragment.class.getName());
|
||||
mViewPager.setCurrentItem(savedInstanceState.getInt("currentTab"));
|
||||
}
|
||||
else {
|
||||
mRepositoriesFragment = new ReposFragment();
|
||||
mNodesFragment = new NodesFragment();
|
||||
mLocalNodeInfoFragment = new LocalNodeInfoFragment();
|
||||
}
|
||||
if (savedInstanceState != null) {
|
||||
FragmentManager fm = getSupportFragmentManager();
|
||||
mRepositoriesFragment = (ReposFragment) fm.getFragment(
|
||||
savedInstanceState, ReposFragment.class.getName());
|
||||
mNodesFragment = (NodesFragment) fm.getFragment(
|
||||
savedInstanceState, NodesFragment.class.getName());
|
||||
mLocalNodeInfoFragment = (LocalNodeInfoFragment) fm.getFragment(
|
||||
savedInstanceState, LocalNodeInfoFragment.class.getName());
|
||||
mViewPager.setCurrentItem(savedInstanceState.getInt("currentTab"));
|
||||
} else {
|
||||
mRepositoriesFragment = new ReposFragment();
|
||||
mNodesFragment = new NodesFragment();
|
||||
mLocalNodeInfoFragment = new LocalNodeInfoFragment();
|
||||
}
|
||||
|
||||
getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.replace(R.id.drawer, mLocalNodeInfoFragment)
|
||||
.commit();
|
||||
mDrawerToggle = mLocalNodeInfoFragment.new Toggle(this, mDrawerLayout,
|
||||
R.drawable.ic_drawer);
|
||||
mDrawerLayout.setDrawerListener(mDrawerToggle);
|
||||
}
|
||||
getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.replace(R.id.drawer, mLocalNodeInfoFragment)
|
||||
.commit();
|
||||
mDrawerToggle = mLocalNodeInfoFragment.new Toggle(this, mDrawerLayout,
|
||||
R.drawable.ic_drawer);
|
||||
mDrawerLayout.setDrawerListener(mDrawerToggle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (mLoadingDialog != null) {
|
||||
mLoadingDialog.dismiss();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (mLoadingDialog != null) {
|
||||
mLoadingDialog.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
|
||||
super.onServiceConnected(componentName, iBinder);
|
||||
getService().registerOnApiChangeListener(mRepositoriesFragment);
|
||||
getService().registerOnApiChangeListener(mNodesFragment);
|
||||
}
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
|
||||
super.onServiceConnected(componentName, iBinder);
|
||||
getService().registerOnApiChangeListener(mRepositoriesFragment);
|
||||
getService().registerOnApiChangeListener(mNodesFragment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves fragment states.
|
||||
*/
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
// Avoid crash if called during startup.
|
||||
if (mRepositoriesFragment != null && mNodesFragment != null &&
|
||||
mLocalNodeInfoFragment != null) {
|
||||
FragmentManager fm = getSupportFragmentManager();
|
||||
fm.putFragment(outState, ReposFragment.class.getName(), mRepositoriesFragment);
|
||||
fm.putFragment(outState, NodesFragment.class.getName(), mNodesFragment);
|
||||
fm.putFragment(outState, LocalNodeInfoFragment.class.getName(), mLocalNodeInfoFragment);
|
||||
outState.putInt("currentTab", mViewPager.getCurrentItem());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Saves fragment states.
|
||||
*/
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
// Avoid crash if called during startup.
|
||||
if (mRepositoriesFragment != null && mNodesFragment != null &&
|
||||
mLocalNodeInfoFragment != null) {
|
||||
FragmentManager fm = getSupportFragmentManager();
|
||||
fm.putFragment(outState, ReposFragment.class.getName(), mRepositoriesFragment);
|
||||
fm.putFragment(outState, NodesFragment.class.getName(), mNodesFragment);
|
||||
fm.putFragment(outState, LocalNodeInfoFragment.class.getName(), mLocalNodeInfoFragment);
|
||||
outState.putInt("currentTab", mViewPager.getCurrentItem());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.main, menu);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.main, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows menu only once syncthing service is running, and shows "share" option only when
|
||||
* drawer is open.
|
||||
*/
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
boolean drawerOpen = mDrawerLayout.isDrawerOpen(findViewById(R.id.drawer));
|
||||
menu.findItem(R.id.share_node_id).setVisible(drawerOpen);
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Shows menu only once syncthing service is running, and shows "share" option only when
|
||||
* drawer is open.
|
||||
*/
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
boolean drawerOpen = mDrawerLayout.isDrawerOpen(findViewById(R.id.drawer));
|
||||
menu.findItem(R.id.share_node_id).setVisible(drawerOpen);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (mLocalNodeInfoFragment.onOptionsItemSelected(item) ||
|
||||
mDrawerToggle.onOptionsItemSelected(item)) {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (mLocalNodeInfoFragment.onOptionsItemSelected(item) ||
|
||||
mDrawerToggle.onOptionsItemSelected(item)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (item.getItemId()) {
|
||||
case R.id.add_repo:
|
||||
Intent intent = new Intent(this, SettingsActivity.class)
|
||||
.setAction(SettingsActivity.ACTION_REPO_SETTINGS_FRAGMENT)
|
||||
.putExtra(SettingsActivity.EXTRA_IS_CREATE, true);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
case R.id.add_node:
|
||||
intent = new Intent(this, SettingsActivity.class)
|
||||
.setAction(SettingsActivity.ACTION_NODE_SETTINGS_FRAGMENT)
|
||||
.putExtra(SettingsActivity.EXTRA_IS_CREATE, true);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
case R.id.web_gui:
|
||||
startActivity(new Intent(this, WebGuiActivity.class));
|
||||
return true;
|
||||
case R.id.settings:
|
||||
startActivity(new Intent(this, SettingsActivity.class)
|
||||
.setAction(SettingsActivity.ACTION_APP_SETTINGS_FRAGMENT));
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
switch (item.getItemId()) {
|
||||
case R.id.add_repo:
|
||||
Intent intent = new Intent(this, SettingsActivity.class)
|
||||
.setAction(SettingsActivity.ACTION_REPO_SETTINGS_FRAGMENT)
|
||||
.putExtra(SettingsActivity.EXTRA_IS_CREATE, true);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
case R.id.add_node:
|
||||
intent = new Intent(this, SettingsActivity.class)
|
||||
.setAction(SettingsActivity.ACTION_NODE_SETTINGS_FRAGMENT)
|
||||
.putExtra(SettingsActivity.EXTRA_IS_CREATE, true);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
case R.id.web_gui:
|
||||
startActivity(new Intent(this, WebGuiActivity.class));
|
||||
return true;
|
||||
case R.id.settings:
|
||||
startActivity(new Intent(this, SettingsActivity.class)
|
||||
.setAction(SettingsActivity.ACTION_APP_SETTINGS_FRAGMENT));
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
mDrawerToggle.syncState();
|
||||
}
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
mDrawerToggle.syncState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
mDrawerToggle.onConfigurationChanged(newConfig);
|
||||
}
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
mDrawerToggle.onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,75 +14,74 @@ import com.nutomic.syncthingandroid.fragments.SettingsFragment;
|
|||
*/
|
||||
public class SettingsActivity extends SyncthingActivity {
|
||||
|
||||
public static final String ACTION_APP_SETTINGS_FRAGMENT = "app_settings_fragment";
|
||||
public static final String ACTION_APP_SETTINGS_FRAGMENT = "app_settings_fragment";
|
||||
|
||||
public static final String ACTION_NODE_SETTINGS_FRAGMENT = "node_settings_fragment";
|
||||
public static final String ACTION_NODE_SETTINGS_FRAGMENT = "node_settings_fragment";
|
||||
|
||||
public static final String ACTION_REPO_SETTINGS_FRAGMENT = "repo_settings_fragment";
|
||||
public static final String ACTION_REPO_SETTINGS_FRAGMENT = "repo_settings_fragment";
|
||||
|
||||
/**
|
||||
* Must be set for {@link #ACTION_NODE_SETTINGS_FRAGMENT} and
|
||||
* {@link #ACTION_REPO_SETTINGS_FRAGMENT} to determine if an existing repo/node should be
|
||||
* edited or a new one created.
|
||||
*
|
||||
* If this is false, {@link com.nutomic.syncthingandroid.fragments.RepoSettingsFragment#EXTRA_REPO_ID} or
|
||||
* {@link com.nutomic.syncthingandroid.fragments.NodeSettingsFragment#EXTRA_NODE_ID} must be set (according to the selected fragment).
|
||||
*/
|
||||
public static final String EXTRA_IS_CREATE = "create";
|
||||
/**
|
||||
* Must be set for {@link #ACTION_NODE_SETTINGS_FRAGMENT} and
|
||||
* {@link #ACTION_REPO_SETTINGS_FRAGMENT} to determine if an existing repo/node should be
|
||||
* edited or a new one created.
|
||||
* <p/>
|
||||
* If this is false, {@link com.nutomic.syncthingandroid.fragments.RepoSettingsFragment#EXTRA_REPO_ID} or
|
||||
* {@link com.nutomic.syncthingandroid.fragments.NodeSettingsFragment#EXTRA_NODE_ID} must be set (according to the selected fragment).
|
||||
*/
|
||||
public static final String EXTRA_IS_CREATE = "create";
|
||||
|
||||
private Fragment mFragment;
|
||||
private Fragment mFragment;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
FragmentManager fm = getSupportFragmentManager();
|
||||
if (savedInstanceState != null) {
|
||||
mFragment = fm.getFragment(savedInstanceState,
|
||||
savedInstanceState.getString("fragment_name"));
|
||||
}
|
||||
else {
|
||||
switch (getIntent().getAction()) {
|
||||
case ACTION_APP_SETTINGS_FRAGMENT:
|
||||
setTitle(R.string.settings_title);
|
||||
mFragment = new SettingsFragment();
|
||||
break;
|
||||
case ACTION_NODE_SETTINGS_FRAGMENT:
|
||||
mFragment = new NodeSettingsFragment();
|
||||
if (!getIntent().hasExtra(EXTRA_IS_CREATE)) {
|
||||
throw new IllegalArgumentException("EXTRA_IS_CREATE must be set");
|
||||
}
|
||||
break;
|
||||
case ACTION_REPO_SETTINGS_FRAGMENT:
|
||||
mFragment = new RepoSettingsFragment();
|
||||
if (!getIntent().hasExtra(EXTRA_IS_CREATE)) {
|
||||
throw new IllegalArgumentException("EXTRA_IS_CREATE must be set");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"You must provide the requested fragment type as an extra.");
|
||||
}
|
||||
}
|
||||
FragmentManager fm = getSupportFragmentManager();
|
||||
if (savedInstanceState != null) {
|
||||
mFragment = fm.getFragment(savedInstanceState,
|
||||
savedInstanceState.getString("fragment_name"));
|
||||
} else {
|
||||
switch (getIntent().getAction()) {
|
||||
case ACTION_APP_SETTINGS_FRAGMENT:
|
||||
setTitle(R.string.settings_title);
|
||||
mFragment = new SettingsFragment();
|
||||
break;
|
||||
case ACTION_NODE_SETTINGS_FRAGMENT:
|
||||
mFragment = new NodeSettingsFragment();
|
||||
if (!getIntent().hasExtra(EXTRA_IS_CREATE)) {
|
||||
throw new IllegalArgumentException("EXTRA_IS_CREATE must be set");
|
||||
}
|
||||
break;
|
||||
case ACTION_REPO_SETTINGS_FRAGMENT:
|
||||
mFragment = new RepoSettingsFragment();
|
||||
if (!getIntent().hasExtra(EXTRA_IS_CREATE)) {
|
||||
throw new IllegalArgumentException("EXTRA_IS_CREATE must be set");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"You must provide the requested fragment type as an extra.");
|
||||
}
|
||||
}
|
||||
|
||||
fm.beginTransaction()
|
||||
.replace(android.R.id.content, mFragment)
|
||||
.commit();
|
||||
}
|
||||
fm.beginTransaction()
|
||||
.replace(android.R.id.content, mFragment)
|
||||
.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
String fragmentClassName = mFragment.getClass().getName();
|
||||
outState.putString("fragment_name", fragmentClassName);
|
||||
FragmentManager fm = getSupportFragmentManager();
|
||||
fm.putFragment(outState, fragmentClassName, mFragment);
|
||||
}
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
String fragmentClassName = mFragment.getClass().getName();
|
||||
outState.putString("fragment_name", fragmentClassName);
|
||||
FragmentManager fm = getSupportFragmentManager();
|
||||
fm.putFragment(outState, fragmentClassName, mFragment);
|
||||
}
|
||||
|
||||
public boolean getIsCreate() {
|
||||
return getIntent().getBooleanExtra(EXTRA_IS_CREATE, false);
|
||||
}
|
||||
public boolean getIsCreate() {
|
||||
return getIntent().getBooleanExtra(EXTRA_IS_CREATE, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,71 +19,70 @@ import java.util.LinkedList;
|
|||
*/
|
||||
public class SyncthingActivity extends ActionBarActivity implements ServiceConnection {
|
||||
|
||||
private SyncthingService mSyncthingService;
|
||||
private SyncthingService mSyncthingService;
|
||||
|
||||
private LinkedList<OnServiceConnectedListener> mServiceConnectedListeners = new LinkedList<>();
|
||||
private LinkedList<OnServiceConnectedListener> mServiceConnectedListeners = new LinkedList<>();
|
||||
|
||||
/**
|
||||
* To be used for Fragments.
|
||||
*/
|
||||
public interface OnServiceConnectedListener {
|
||||
public void onServiceConnected();
|
||||
}
|
||||
/**
|
||||
* To be used for Fragments.
|
||||
*/
|
||||
public interface OnServiceConnectedListener {
|
||||
public void onServiceConnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
bindService(new Intent(this, SyncthingService.class),
|
||||
this, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
bindService(new Intent(this, SyncthingService.class),
|
||||
this, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
unbindService(this);
|
||||
}
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
unbindService(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
|
||||
SyncthingServiceBinder binder = (SyncthingServiceBinder) iBinder;
|
||||
mSyncthingService = binder.getService();
|
||||
for (OnServiceConnectedListener listener : mServiceConnectedListeners) {
|
||||
listener.onServiceConnected();
|
||||
}
|
||||
mServiceConnectedListeners.clear();
|
||||
}
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
|
||||
SyncthingServiceBinder binder = (SyncthingServiceBinder) iBinder;
|
||||
mSyncthingService = binder.getService();
|
||||
for (OnServiceConnectedListener listener : mServiceConnectedListeners) {
|
||||
listener.onServiceConnected();
|
||||
}
|
||||
mServiceConnectedListeners.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName componentName) {
|
||||
mSyncthingService = null;
|
||||
}
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName componentName) {
|
||||
mSyncthingService = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for Fragments to use the Activity's service connection.
|
||||
*/
|
||||
public void registerOnServiceConnectedListener(OnServiceConnectedListener listener) {
|
||||
if (mSyncthingService != null) {
|
||||
listener.onServiceConnected();
|
||||
}
|
||||
else {
|
||||
mServiceConnectedListeners.addLast(listener);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Used for Fragments to use the Activity's service connection.
|
||||
*/
|
||||
public void registerOnServiceConnectedListener(OnServiceConnectedListener listener) {
|
||||
if (mSyncthingService != null) {
|
||||
listener.onServiceConnected();
|
||||
} else {
|
||||
mServiceConnectedListeners.addLast(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns service object (or null if not bound).
|
||||
*/
|
||||
public SyncthingService getService() {
|
||||
return mSyncthingService;
|
||||
}
|
||||
/**
|
||||
* Returns service object (or null if not bound).
|
||||
*/
|
||||
public SyncthingService getService() {
|
||||
return mSyncthingService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns RestApi instance, or null if SyncthingService is not yet connected.
|
||||
*/
|
||||
public RestApi getApi() {
|
||||
return (getService() != null)
|
||||
? getService().getApi()
|
||||
: null;
|
||||
}
|
||||
/**
|
||||
* Returns RestApi instance, or null if SyncthingService is not yet connected.
|
||||
*/
|
||||
public RestApi getApi() {
|
||||
return (getService() != null)
|
||||
? getService().getApi()
|
||||
: null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,56 +17,56 @@ import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
|||
*/
|
||||
public class WebGuiActivity extends SyncthingActivity implements SyncthingService.OnWebGuiAvailableListener {
|
||||
|
||||
private WebView mWebView;
|
||||
private WebView mWebView;
|
||||
|
||||
private View mLoadingView;
|
||||
private View mLoadingView;
|
||||
|
||||
/**
|
||||
* Hides the loading screen and shows the WebView once it is fully loaded.
|
||||
*/
|
||||
private final WebViewClient mWebViewClient = new WebViewClient() {
|
||||
/**
|
||||
* Hides the loading screen and shows the WebView once it is fully loaded.
|
||||
*/
|
||||
private final WebViewClient mWebViewClient = new WebViewClient() {
|
||||
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
mWebView.setVisibility(View.VISIBLE);
|
||||
mLoadingView.setVisibility(View.GONE);
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
mWebView.setVisibility(View.VISIBLE);
|
||||
mLoadingView.setVisibility(View.GONE);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize WebView.
|
||||
*
|
||||
* Ignore lint javascript warning as js is loaded only from our known, local service.
|
||||
*/
|
||||
@Override
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
/**
|
||||
* Initialize WebView.
|
||||
* <p/>
|
||||
* Ignore lint javascript warning as js is loaded only from our known, local service.
|
||||
*/
|
||||
@Override
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.web_gui_activity);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setContentView(R.layout.web_gui_activity);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
mLoadingView = findViewById(R.id.loading);
|
||||
ProgressBar pb = (ProgressBar) mLoadingView.findViewById(R.id.progress);
|
||||
pb.setIndeterminate(true);
|
||||
mLoadingView = findViewById(R.id.loading);
|
||||
ProgressBar pb = (ProgressBar) mLoadingView.findViewById(R.id.progress);
|
||||
pb.setIndeterminate(true);
|
||||
|
||||
mWebView = (WebView) findViewById(R.id.webview);
|
||||
mWebView.getSettings().setJavaScriptEnabled(true);
|
||||
mWebView.setWebViewClient(mWebViewClient);
|
||||
}
|
||||
mWebView = (WebView) findViewById(R.id.webview);
|
||||
mWebView.getSettings().setJavaScriptEnabled(true);
|
||||
mWebView.setWebViewClient(mWebViewClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
|
||||
super.onServiceConnected(componentName, iBinder);
|
||||
getService().registerOnWebGuiAvailableListener(WebGuiActivity.this);
|
||||
}
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
|
||||
super.onServiceConnected(componentName, iBinder);
|
||||
getService().registerOnWebGuiAvailableListener(WebGuiActivity.this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and shows WebView, hides loading view.
|
||||
*/
|
||||
@Override
|
||||
public void onWebGuiAvailable() {
|
||||
mWebView.loadUrl(getApi().getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and shows WebView, hides loading view.
|
||||
*/
|
||||
@Override
|
||||
public void onWebGuiAvailable() {
|
||||
mWebView.loadUrl(getApi().getUrl());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,152 +26,153 @@ import java.util.TimerTask;
|
|||
* Displays information about the local node.
|
||||
*/
|
||||
public class LocalNodeInfoFragment extends Fragment
|
||||
implements RestApi.OnReceiveSystemInfoListener, RestApi.OnReceiveConnectionsListener {
|
||||
implements RestApi.OnReceiveSystemInfoListener, RestApi.OnReceiveConnectionsListener {
|
||||
|
||||
private TextView mNodeId;
|
||||
private TextView mNodeId;
|
||||
|
||||
private TextView mCpuUsage;
|
||||
private TextView mCpuUsage;
|
||||
|
||||
private TextView mRamUsage;
|
||||
private TextView mRamUsage;
|
||||
|
||||
private TextView mDownload;
|
||||
private TextView mDownload;
|
||||
|
||||
private TextView mUpload;
|
||||
private TextView mUpload;
|
||||
|
||||
private TextView mAnnounceServer;
|
||||
private TextView mAnnounceServer;
|
||||
|
||||
private Timer mTimer;
|
||||
private Timer mTimer;
|
||||
|
||||
private MainActivity mActivity;
|
||||
private MainActivity mActivity;
|
||||
|
||||
/**
|
||||
* Starts polling for status when opened, stops when closed.
|
||||
*/
|
||||
public class Toggle extends ActionBarDrawerToggle {
|
||||
public Toggle(Activity activity, DrawerLayout drawerLayout, int drawerImageRes) {
|
||||
super(activity, drawerLayout, drawerImageRes, R.string.app_name, R.string.system_info);
|
||||
}
|
||||
/**
|
||||
* Starts polling for status when opened, stops when closed.
|
||||
*/
|
||||
public class Toggle extends ActionBarDrawerToggle {
|
||||
public Toggle(Activity activity, DrawerLayout drawerLayout, int drawerImageRes) {
|
||||
super(activity, drawerLayout, drawerImageRes, R.string.app_name, R.string.system_info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrawerClosed(View view) {
|
||||
super.onDrawerClosed(view);
|
||||
mTimer.cancel();
|
||||
mTimer = null;
|
||||
mActivity.getSupportActionBar().setTitle(R.string.app_name);
|
||||
mActivity.supportInvalidateOptionsMenu();
|
||||
}
|
||||
@Override
|
||||
public void onDrawerClosed(View view) {
|
||||
super.onDrawerClosed(view);
|
||||
mTimer.cancel();
|
||||
mTimer = null;
|
||||
mActivity.getSupportActionBar().setTitle(R.string.app_name);
|
||||
mActivity.supportInvalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrawerOpened(View drawerView) {
|
||||
super.onDrawerOpened(drawerView);
|
||||
LocalNodeInfoFragment.this.onDrawerOpened();
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void onDrawerOpened(View drawerView) {
|
||||
super.onDrawerOpened(drawerView);
|
||||
LocalNodeInfoFragment.this.onDrawerOpened();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.local_node_info_fragment, container, false);
|
||||
mNodeId = (TextView) view.findViewById(R.id.node_id);
|
||||
mCpuUsage = (TextView) view.findViewById(R.id.cpu_usage);
|
||||
mRamUsage = (TextView) view.findViewById(R.id.ram_usage);
|
||||
mDownload = (TextView) view.findViewById(R.id.download);
|
||||
mUpload = (TextView) view.findViewById(R.id.upload);
|
||||
mAnnounceServer = (TextView) view.findViewById(R.id.announce_server);
|
||||
;
|
||||
|
||||
return view;
|
||||
}
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.local_node_info_fragment, container, false);
|
||||
mNodeId = (TextView) view.findViewById(R.id.node_id);
|
||||
mCpuUsage = (TextView) view.findViewById(R.id.cpu_usage);
|
||||
mRamUsage = (TextView) view.findViewById(R.id.ram_usage);
|
||||
mDownload = (TextView) view.findViewById(R.id.download);
|
||||
mUpload = (TextView) view.findViewById(R.id.upload);
|
||||
mAnnounceServer = (TextView) view.findViewById(R.id.announce_server);
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
mActivity = (MainActivity) getActivity();
|
||||
return view;
|
||||
}
|
||||
|
||||
if (savedInstanceState != null && savedInstanceState.getBoolean("active")) {
|
||||
onDrawerOpened();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
mActivity = (MainActivity) getActivity();
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putBoolean("active", mTimer != null);
|
||||
}
|
||||
if (savedInstanceState != null && savedInstanceState.getBoolean("active")) {
|
||||
onDrawerOpened();
|
||||
}
|
||||
}
|
||||
|
||||
private void onDrawerOpened() {
|
||||
// FIXME: never called
|
||||
mTimer = new Timer();
|
||||
mTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateGui();
|
||||
}
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putBoolean("active", mTimer != null);
|
||||
}
|
||||
|
||||
}, 0, SyncthingService.GUI_UPDATE_INTERVAL);
|
||||
mActivity.getSupportActionBar().setTitle(R.string.system_info);
|
||||
mActivity.supportInvalidateOptionsMenu();
|
||||
}
|
||||
private void onDrawerOpened() {
|
||||
// FIXME: never called
|
||||
mTimer = new Timer();
|
||||
mTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateGui();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes status callbacks.
|
||||
*/
|
||||
private void updateGui() {
|
||||
if (mActivity.getApi() != null) {
|
||||
mActivity.getApi().getSystemInfo(this);
|
||||
mActivity.getApi().getConnections(this);
|
||||
}
|
||||
}
|
||||
}, 0, SyncthingService.GUI_UPDATE_INTERVAL);
|
||||
mActivity.getSupportActionBar().setTitle(R.string.system_info);
|
||||
mActivity.supportInvalidateOptionsMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates views with status received via {@link RestApi#getSystemInfo}.
|
||||
*/
|
||||
@Override
|
||||
public void onReceiveSystemInfo(RestApi.SystemInfo info) {
|
||||
if (getActivity() == null)
|
||||
return;
|
||||
/**
|
||||
* Invokes status callbacks.
|
||||
*/
|
||||
private void updateGui() {
|
||||
if (mActivity.getApi() != null) {
|
||||
mActivity.getApi().getSystemInfo(this);
|
||||
mActivity.getApi().getConnections(this);
|
||||
}
|
||||
}
|
||||
|
||||
mNodeId.setText(info.myID);
|
||||
mNodeId.setOnTouchListener(new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View view, MotionEvent motionEvent) {
|
||||
mActivity.getApi().copyNodeId(mNodeId.getText().toString());
|
||||
view.performClick();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
mCpuUsage.setText(new DecimalFormat("0.00").format(info.cpuPercent) + "%");
|
||||
mRamUsage.setText(RestApi.readableFileSize(mActivity, info.sys));
|
||||
if (info.extAnnounceOK) {
|
||||
mAnnounceServer.setText("Online");
|
||||
mAnnounceServer.setTextColor(getResources().getColor(R.color.text_green));
|
||||
}
|
||||
else {
|
||||
mAnnounceServer.setText("Offline");
|
||||
mAnnounceServer.setTextColor(getResources().getColor(R.color.text_red));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Populates views with status received via {@link RestApi#getSystemInfo}.
|
||||
*/
|
||||
@Override
|
||||
public void onReceiveSystemInfo(RestApi.SystemInfo info) {
|
||||
if (getActivity() == null)
|
||||
return;
|
||||
|
||||
/**
|
||||
* Populates views with status received via {@link RestApi#getConnections}.
|
||||
*/
|
||||
@Override
|
||||
public void onReceiveConnections(Map<String, RestApi.Connection> connections) {
|
||||
RestApi.Connection c = connections.get(RestApi.LOCAL_NODE_CONNECTIONS);
|
||||
mDownload.setText(RestApi.readableTransferRate(mActivity, c.InBits));
|
||||
mUpload.setText(RestApi.readableTransferRate(mActivity, c.OutBits));
|
||||
}
|
||||
mNodeId.setText(info.myID);
|
||||
mNodeId.setOnTouchListener(new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View view, MotionEvent motionEvent) {
|
||||
mActivity.getApi().copyNodeId(mNodeId.getText().toString());
|
||||
view.performClick();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
mCpuUsage.setText(new DecimalFormat("0.00").format(info.cpuPercent) + "%");
|
||||
mRamUsage.setText(RestApi.readableFileSize(mActivity, info.sys));
|
||||
if (info.extAnnounceOK) {
|
||||
mAnnounceServer.setText("Online");
|
||||
mAnnounceServer.setTextColor(getResources().getColor(R.color.text_green));
|
||||
} else {
|
||||
mAnnounceServer.setText("Offline");
|
||||
mAnnounceServer.setTextColor(getResources().getColor(R.color.text_red));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shares the local node ID when "share" is clicked.
|
||||
*/
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.share_node_id:
|
||||
RestApi.shareNodeId(getActivity(), mNodeId.getText().toString());
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Populates views with status received via {@link RestApi#getConnections}.
|
||||
*/
|
||||
@Override
|
||||
public void onReceiveConnections(Map<String, RestApi.Connection> connections) {
|
||||
RestApi.Connection c = connections.get(RestApi.LOCAL_NODE_CONNECTIONS);
|
||||
mDownload.setText(RestApi.readableTransferRate(mActivity, c.InBits));
|
||||
mUpload.setText(RestApi.readableTransferRate(mActivity, c.OutBits));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shares the local node ID when "share" is clicked.
|
||||
*/
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.share_node_id:
|
||||
RestApi.shareNodeId(getActivity(), mNodeId.getText().toString());
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.nutomic.syncthingandroid.fragments;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.ActivityNotFoundException;
|
||||
|
@ -29,259 +28,253 @@ import java.util.Map;
|
|||
* Shows node details and allows changing them.
|
||||
*/
|
||||
public class NodeSettingsFragment extends PreferenceFragment implements
|
||||
SyncthingActivity.OnServiceConnectedListener, Preference.OnPreferenceChangeListener,
|
||||
Preference.OnPreferenceClickListener, RestApi.OnReceiveConnectionsListener,
|
||||
SyncthingService.OnApiChangeListener, RestApi.OnNodeIdNormalizedListener {
|
||||
SyncthingActivity.OnServiceConnectedListener, Preference.OnPreferenceChangeListener,
|
||||
Preference.OnPreferenceClickListener, RestApi.OnReceiveConnectionsListener,
|
||||
SyncthingService.OnApiChangeListener, RestApi.OnNodeIdNormalizedListener {
|
||||
|
||||
public static final String EXTRA_NODE_ID = "node_id";
|
||||
public static final String EXTRA_NODE_ID = "node_id";
|
||||
|
||||
private static final int SCAN_QR_REQUEST_CODE = 235;
|
||||
private static final int SCAN_QR_REQUEST_CODE = 235;
|
||||
|
||||
private SyncthingService mSyncthingService;
|
||||
private SyncthingService mSyncthingService;
|
||||
|
||||
private RestApi.Node mNode;
|
||||
private RestApi.Node mNode;
|
||||
|
||||
private Preference mNodeId;
|
||||
private Preference mNodeId;
|
||||
|
||||
private EditTextPreference mName;
|
||||
private EditTextPreference mName;
|
||||
|
||||
private EditTextPreference mAddresses;
|
||||
private EditTextPreference mAddresses;
|
||||
|
||||
private Preference mVersion;
|
||||
private Preference mVersion;
|
||||
|
||||
private Preference mCurrentAddress;
|
||||
private Preference mCurrentAddress;
|
||||
|
||||
private boolean mIsCreate;
|
||||
private boolean mIsCreate;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
((SyncthingActivity) getActivity()).registerOnServiceConnectedListener(this);
|
||||
((SyncthingActivity) getActivity()).registerOnServiceConnectedListener(this);
|
||||
|
||||
mIsCreate = ((SettingsActivity) getActivity()).getIsCreate();
|
||||
setHasOptionsMenu(true);
|
||||
mIsCreate = ((SettingsActivity) getActivity()).getIsCreate();
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
if (mIsCreate) {
|
||||
addPreferencesFromResource(R.xml.node_settings_create);
|
||||
}
|
||||
else {
|
||||
addPreferencesFromResource(R.xml.node_settings_edit);
|
||||
}
|
||||
if (mIsCreate) {
|
||||
addPreferencesFromResource(R.xml.node_settings_create);
|
||||
} else {
|
||||
addPreferencesFromResource(R.xml.node_settings_edit);
|
||||
}
|
||||
|
||||
mNodeId = findPreference("node_id");
|
||||
mNodeId.setOnPreferenceChangeListener(this);
|
||||
mName = (EditTextPreference) findPreference("name");
|
||||
mName.setOnPreferenceChangeListener(this);
|
||||
mAddresses = (EditTextPreference) findPreference("addresses");
|
||||
mAddresses.setOnPreferenceChangeListener(this);
|
||||
if (!mIsCreate) {
|
||||
mVersion = findPreference("version");
|
||||
mVersion.setSummary("?");
|
||||
mCurrentAddress = findPreference("current_address");
|
||||
mCurrentAddress.setSummary("?");
|
||||
}
|
||||
}
|
||||
mNodeId = findPreference("node_id");
|
||||
mNodeId.setOnPreferenceChangeListener(this);
|
||||
mName = (EditTextPreference) findPreference("name");
|
||||
mName.setOnPreferenceChangeListener(this);
|
||||
mAddresses = (EditTextPreference) findPreference("addresses");
|
||||
mAddresses.setOnPreferenceChangeListener(this);
|
||||
if (!mIsCreate) {
|
||||
mVersion = findPreference("version");
|
||||
mVersion.setSummary("?");
|
||||
mCurrentAddress = findPreference("current_address");
|
||||
mCurrentAddress.setSummary("?");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected() {
|
||||
mSyncthingService = ((SyncthingActivity) getActivity()).getService();
|
||||
mSyncthingService.registerOnApiChangeListener(this);
|
||||
}
|
||||
@Override
|
||||
public void onServiceConnected() {
|
||||
mSyncthingService = ((SyncthingActivity) getActivity()).getService();
|
||||
mSyncthingService.registerOnApiChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApiChange(SyncthingService.State currentState) {
|
||||
if (currentState != SyncthingService.State.ACTIVE) {
|
||||
getActivity().finish();
|
||||
return;
|
||||
}
|
||||
@Override
|
||||
public void onApiChange(SyncthingService.State currentState) {
|
||||
if (currentState != SyncthingService.State.ACTIVE) {
|
||||
getActivity().finish();
|
||||
return;
|
||||
}
|
||||
|
||||
if (getActivity() == null || getActivity().isFinishing())
|
||||
return;
|
||||
if (getActivity() == null || getActivity().isFinishing())
|
||||
return;
|
||||
|
||||
if (mIsCreate) {
|
||||
getActivity().setTitle(R.string.add_node);
|
||||
mNode = new RestApi.Node();
|
||||
mNode.Name = "";
|
||||
mNode.NodeID = "";
|
||||
mNode.Addresses = "dynamic";
|
||||
((EditTextPreference) mNodeId).setText(mNode.NodeID);
|
||||
}
|
||||
else {
|
||||
getActivity().setTitle(R.string.edit_node);
|
||||
List<RestApi.Node> nodes = mSyncthingService.getApi().getNodes();
|
||||
for (int i = 0; i < nodes.size(); i++) {
|
||||
if (nodes.get(i).NodeID.equals(
|
||||
getActivity().getIntent().getStringExtra(EXTRA_NODE_ID))) {
|
||||
mNode = nodes.get(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mNodeId.setOnPreferenceClickListener(this);
|
||||
}
|
||||
mSyncthingService.getApi().getConnections(NodeSettingsFragment.this);
|
||||
if (mIsCreate) {
|
||||
getActivity().setTitle(R.string.add_node);
|
||||
mNode = new RestApi.Node();
|
||||
mNode.Name = "";
|
||||
mNode.NodeID = "";
|
||||
mNode.Addresses = "dynamic";
|
||||
((EditTextPreference) mNodeId).setText(mNode.NodeID);
|
||||
} else {
|
||||
getActivity().setTitle(R.string.edit_node);
|
||||
List<RestApi.Node> nodes = mSyncthingService.getApi().getNodes();
|
||||
for (int i = 0; i < nodes.size(); i++) {
|
||||
if (nodes.get(i).NodeID.equals(
|
||||
getActivity().getIntent().getStringExtra(EXTRA_NODE_ID))) {
|
||||
mNode = nodes.get(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mNodeId.setOnPreferenceClickListener(this);
|
||||
}
|
||||
mSyncthingService.getApi().getConnections(NodeSettingsFragment.this);
|
||||
|
||||
mNodeId.setSummary(mNode.NodeID);
|
||||
mName.setText((mNode.Name));
|
||||
mName.setSummary(mNode.Name);
|
||||
mAddresses.setText(mNode.Addresses);
|
||||
mAddresses.setSummary(mNode.Addresses);
|
||||
}
|
||||
mNodeId.setSummary(mNode.NodeID);
|
||||
mName.setText((mNode.Name));
|
||||
mName.setSummary(mNode.Name);
|
||||
mAddresses.setText(mNode.Addresses);
|
||||
mAddresses.setSummary(mNode.Addresses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
inflater.inflate(R.menu.node_settings, menu);
|
||||
}
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
inflater.inflate(R.menu.node_settings, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
menu.findItem(R.id.create).setVisible(mIsCreate);
|
||||
menu.findItem(R.id.share_node_id).setVisible(!mIsCreate);
|
||||
menu.findItem(R.id.delete).setVisible(!mIsCreate);
|
||||
}
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
menu.findItem(R.id.create).setVisible(mIsCreate);
|
||||
menu.findItem(R.id.share_node_id).setVisible(!mIsCreate);
|
||||
menu.findItem(R.id.delete).setVisible(!mIsCreate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.create:
|
||||
if (mNode.NodeID.equals("")) {
|
||||
Toast.makeText(getActivity(), R.string.node_id_required, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
return true;
|
||||
}
|
||||
if (mNode.Name.equals("")) {
|
||||
Toast.makeText(getActivity(), R.string.node_name_required, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
return true;
|
||||
}
|
||||
mSyncthingService.getApi().editNode(mNode, this);
|
||||
return true;
|
||||
case R.id.share_node_id:
|
||||
RestApi.shareNodeId(getActivity(), mNode.NodeID);
|
||||
return true;
|
||||
case R.id.delete:
|
||||
new AlertDialog.Builder(getActivity())
|
||||
.setMessage(R.string.delete_node_confirm)
|
||||
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
mSyncthingService.getApi().deleteNode(mNode, getActivity());
|
||||
getActivity().finish();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.no, null)
|
||||
.show();
|
||||
return true;
|
||||
case android.R.id.home:
|
||||
getActivity().finish();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.create:
|
||||
if (mNode.NodeID.equals("")) {
|
||||
Toast.makeText(getActivity(), R.string.node_id_required, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
return true;
|
||||
}
|
||||
if (mNode.Name.equals("")) {
|
||||
Toast.makeText(getActivity(), R.string.node_name_required, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
return true;
|
||||
}
|
||||
mSyncthingService.getApi().editNode(mNode, this);
|
||||
return true;
|
||||
case R.id.share_node_id:
|
||||
RestApi.shareNodeId(getActivity(), mNode.NodeID);
|
||||
return true;
|
||||
case R.id.delete:
|
||||
new AlertDialog.Builder(getActivity())
|
||||
.setMessage(R.string.delete_node_confirm)
|
||||
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
mSyncthingService.getApi().deleteNode(mNode, getActivity());
|
||||
getActivity().finish();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.no, null)
|
||||
.show();
|
||||
return true;
|
||||
case android.R.id.home:
|
||||
getActivity().finish();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object o) {
|
||||
if (preference instanceof EditTextPreference) {
|
||||
EditTextPreference pref = (EditTextPreference) preference;
|
||||
pref.setSummary((String) o);
|
||||
}
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object o) {
|
||||
if (preference instanceof EditTextPreference) {
|
||||
EditTextPreference pref = (EditTextPreference) preference;
|
||||
pref.setSummary((String) o);
|
||||
}
|
||||
|
||||
if (preference.equals(mNodeId)) {
|
||||
mNode.NodeID = (String) o;
|
||||
nodeUpdated();
|
||||
return true;
|
||||
}
|
||||
else if (preference.equals(mName)) {
|
||||
mNode.Name = (String) o;
|
||||
nodeUpdated();
|
||||
return true;
|
||||
}
|
||||
else if (preference.equals(mAddresses)) {
|
||||
mNode.Addresses = (String) o;
|
||||
nodeUpdated();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (preference.equals(mNodeId)) {
|
||||
mNode.NodeID = (String) o;
|
||||
nodeUpdated();
|
||||
return true;
|
||||
} else if (preference.equals(mName)) {
|
||||
mNode.Name = (String) o;
|
||||
nodeUpdated();
|
||||
return true;
|
||||
} else if (preference.equals(mAddresses)) {
|
||||
mNode.Addresses = (String) o;
|
||||
nodeUpdated();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
if (preference.equals(mNodeId)) {
|
||||
mSyncthingService.getApi().copyNodeId(mNode.NodeID);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
if (preference.equals(mNodeId)) {
|
||||
mSyncthingService.getApi().copyNodeId(mNode.NodeID);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets version and current address of the node.
|
||||
*
|
||||
* NOTE: This is only called once on startup, should be called more often to properly display
|
||||
* version/address changes.
|
||||
*/
|
||||
@Override
|
||||
public void onReceiveConnections(Map<String, RestApi.Connection> connections) {
|
||||
if (connections.containsKey(mNode.NodeID)) {
|
||||
mVersion.setSummary(connections.get(mNode.NodeID).ClientVersion);
|
||||
mCurrentAddress.setSummary(connections.get(mNode.NodeID).Address);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sets version and current address of the node.
|
||||
* <p/>
|
||||
* NOTE: This is only called once on startup, should be called more often to properly display
|
||||
* version/address changes.
|
||||
*/
|
||||
@Override
|
||||
public void onReceiveConnections(Map<String, RestApi.Connection> connections) {
|
||||
if (connections.containsKey(mNode.NodeID)) {
|
||||
mVersion.setSummary(connections.get(mNode.NodeID).ClientVersion);
|
||||
mCurrentAddress.setSummary(connections.get(mNode.NodeID).Address);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the updated node info if in edit mode.
|
||||
*/
|
||||
private void nodeUpdated() {
|
||||
if (!mIsCreate) {
|
||||
mSyncthingService.getApi().editNode(mNode, this);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sends the updated node info if in edit mode.
|
||||
*/
|
||||
private void nodeUpdated() {
|
||||
if (!mIsCreate) {
|
||||
mSyncthingService.getApi().editNode(mNode, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends QR code scanning intent when clicking the qrcode icon.
|
||||
*/
|
||||
public void onClick(View view) {
|
||||
Intent intentScan = new Intent("com.google.zxing.client.android.SCAN");
|
||||
intentScan.addCategory(Intent.CATEGORY_DEFAULT);
|
||||
intentScan.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
intentScan.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
|
||||
try {
|
||||
startActivityForResult(intentScan, SCAN_QR_REQUEST_CODE);
|
||||
}
|
||||
catch (ActivityNotFoundException e) {
|
||||
Toast.makeText(getActivity(), R.string.no_qr_scanner_installed,
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sends QR code scanning intent when clicking the qrcode icon.
|
||||
*/
|
||||
public void onClick(View view) {
|
||||
Intent intentScan = new Intent("com.google.zxing.client.android.SCAN");
|
||||
intentScan.addCategory(Intent.CATEGORY_DEFAULT);
|
||||
intentScan.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
intentScan.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
|
||||
try {
|
||||
startActivityForResult(intentScan, SCAN_QR_REQUEST_CODE);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Toast.makeText(getActivity(), R.string.no_qr_scanner_installed,
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives value of scanned QR code and sets it as node ID.
|
||||
*/
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == SCAN_QR_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
|
||||
mNode.NodeID = data.getStringExtra("SCAN_RESULT");
|
||||
((EditTextPreference) mNodeId).setText(mNode.NodeID);
|
||||
mNodeId.setSummary(mNode.NodeID);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Receives value of scanned QR code and sets it as node ID.
|
||||
*/
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == SCAN_QR_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
|
||||
mNode.NodeID = data.getStringExtra("SCAN_RESULT");
|
||||
((EditTextPreference) mNodeId).setText(mNode.NodeID);
|
||||
mNodeId.setSummary(mNode.NodeID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for {@link RestApi#editNode(RestApi.Node, RestApi.OnNodeIdNormalizedListener)}.
|
||||
* Displays an error message if present, or finishes the Activity on success in edit mode.
|
||||
*
|
||||
* @param normalizedId The normalized node ID, or null on error.
|
||||
* @param error An error message, or null on success.
|
||||
*/
|
||||
@Override
|
||||
public void onNodeIdNormalized(String normalizedId, String error) {
|
||||
if (error != null) {
|
||||
Toast.makeText(getActivity(), error, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
else if (mIsCreate) {
|
||||
getActivity().finish();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Callback for {@link RestApi#editNode(RestApi.Node, RestApi.OnNodeIdNormalizedListener)}.
|
||||
* Displays an error message if present, or finishes the Activity on success in edit mode.
|
||||
*
|
||||
* @param normalizedId The normalized node ID, or null on error.
|
||||
* @param error An error message, or null on success.
|
||||
*/
|
||||
@Override
|
||||
public void onNodeIdNormalized(String normalizedId, String error) {
|
||||
if (error != null) {
|
||||
Toast.makeText(getActivity(), error, Toast.LENGTH_LONG).show();
|
||||
} else if (mIsCreate) {
|
||||
getActivity().finish();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,80 +21,79 @@ import java.util.TimerTask;
|
|||
* Displays a list of all existing nodes.
|
||||
*/
|
||||
public class NodesFragment extends ListFragment implements SyncthingService.OnApiChangeListener,
|
||||
ListView.OnItemClickListener {
|
||||
ListView.OnItemClickListener {
|
||||
|
||||
private NodesAdapter mAdapter;
|
||||
private NodesAdapter mAdapter;
|
||||
|
||||
private Timer mTimer;
|
||||
private Timer mTimer;
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
setListShown(true);
|
||||
}
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
setListShown(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApiChange(SyncthingService.State currentState) {
|
||||
if (currentState != SyncthingService.State.ACTIVE)
|
||||
return;
|
||||
@Override
|
||||
public void onApiChange(SyncthingService.State currentState) {
|
||||
if (currentState != SyncthingService.State.ACTIVE)
|
||||
return;
|
||||
|
||||
initAdapter();
|
||||
}
|
||||
initAdapter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
initAdapter();
|
||||
}
|
||||
initAdapter();
|
||||
}
|
||||
|
||||
private void initAdapter() {
|
||||
SyncthingActivity activity = (SyncthingActivity) getActivity();
|
||||
if (activity == null || activity.getApi() == null)
|
||||
return;
|
||||
private void initAdapter() {
|
||||
SyncthingActivity activity = (SyncthingActivity) getActivity();
|
||||
if (activity == null || activity.getApi() == null)
|
||||
return;
|
||||
|
||||
mAdapter = new NodesAdapter(activity);
|
||||
mAdapter.add(activity.getApi().getNodes());
|
||||
setListAdapter(mAdapter);
|
||||
setEmptyText(getString(R.string.nodes_list_empty));
|
||||
getListView().setOnItemClickListener(this);
|
||||
}
|
||||
mAdapter = new NodesAdapter(activity);
|
||||
mAdapter.add(activity.getApi().getNodes());
|
||||
setListAdapter(mAdapter);
|
||||
setEmptyText(getString(R.string.nodes_list_empty));
|
||||
getListView().setOnItemClickListener(this);
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
if (mAdapter == null || getView() == null)
|
||||
return;
|
||||
private void updateList() {
|
||||
if (mAdapter == null || getView() == null)
|
||||
return;
|
||||
|
||||
MainActivity activity = (MainActivity) getActivity();
|
||||
mAdapter.updateConnections(activity.getApi(), getListView());
|
||||
}
|
||||
MainActivity activity = (MainActivity) getActivity();
|
||||
mAdapter.updateConnections(activity.getApi(), getListView());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||
super.setUserVisibleHint(isVisibleToUser);
|
||||
@Override
|
||||
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||
super.setUserVisibleHint(isVisibleToUser);
|
||||
|
||||
if (isVisibleToUser) {
|
||||
mTimer = new Timer();
|
||||
mTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateList();
|
||||
}
|
||||
if (isVisibleToUser) {
|
||||
mTimer = new Timer();
|
||||
mTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateList();
|
||||
}
|
||||
|
||||
}, 0, SyncthingService.GUI_UPDATE_INTERVAL);
|
||||
}
|
||||
else if (mTimer != null) {
|
||||
mTimer.cancel();
|
||||
mTimer = null;
|
||||
}
|
||||
}
|
||||
}, 0, SyncthingService.GUI_UPDATE_INTERVAL);
|
||||
} else if (mTimer != null) {
|
||||
mTimer.cancel();
|
||||
mTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
Intent intent = new Intent(getActivity(), SettingsActivity.class);
|
||||
intent.setAction(SettingsActivity.ACTION_NODE_SETTINGS_FRAGMENT);
|
||||
intent.putExtra(SettingsActivity.EXTRA_IS_CREATE, false);
|
||||
intent.putExtra(NodeSettingsFragment.EXTRA_NODE_ID, mAdapter.getItem(i).NodeID);
|
||||
startActivity(intent);
|
||||
}
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
Intent intent = new Intent(getActivity(), SettingsActivity.class);
|
||||
intent.setAction(SettingsActivity.ACTION_NODE_SETTINGS_FRAGMENT);
|
||||
intent.putExtra(SettingsActivity.EXTRA_IS_CREATE, false);
|
||||
intent.putExtra(NodeSettingsFragment.EXTRA_NODE_ID, mAdapter.getItem(i).NodeID);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,275 +31,265 @@ import java.util.List;
|
|||
* Shows repo details and allows changing them.
|
||||
*/
|
||||
public class RepoSettingsFragment extends PreferenceFragment
|
||||
implements SyncthingActivity.OnServiceConnectedListener,
|
||||
Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener,
|
||||
SyncthingService.OnApiChangeListener {
|
||||
implements SyncthingActivity.OnServiceConnectedListener,
|
||||
Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener,
|
||||
SyncthingService.OnApiChangeListener {
|
||||
|
||||
private static final int DIRECTORY_REQUEST_CODE = 234;
|
||||
private static final int DIRECTORY_REQUEST_CODE = 234;
|
||||
|
||||
/**
|
||||
* The ID of the repo to be edited. To be used with {@link com.nutomic.syncthingandroid.activities.SettingsActivity#EXTRA_IS_CREATE}
|
||||
* set to false.
|
||||
*/
|
||||
public static final String EXTRA_REPO_ID = "repo_id";
|
||||
/**
|
||||
* The ID of the repo to be edited. To be used with {@link com.nutomic.syncthingandroid.activities.SettingsActivity#EXTRA_IS_CREATE}
|
||||
* set to false.
|
||||
*/
|
||||
public static final String EXTRA_REPO_ID = "repo_id";
|
||||
|
||||
private static final String KEY_NODE_SHARED = "node_shared";
|
||||
private static final String KEY_NODE_SHARED = "node_shared";
|
||||
|
||||
private SyncthingService mSyncthingService;
|
||||
private SyncthingService mSyncthingService;
|
||||
|
||||
private RestApi.Repo mRepo;
|
||||
private RestApi.Repo mRepo;
|
||||
|
||||
private EditTextPreference mRepoId;
|
||||
private EditTextPreference mRepoId;
|
||||
|
||||
private Preference mDirectory;
|
||||
private Preference mDirectory;
|
||||
|
||||
private CheckBoxPreference mRepoMaster;
|
||||
private CheckBoxPreference mRepoMaster;
|
||||
|
||||
private PreferenceScreen mNodes;
|
||||
private PreferenceScreen mNodes;
|
||||
|
||||
private CheckBoxPreference mVersioning;
|
||||
private CheckBoxPreference mVersioning;
|
||||
|
||||
private EditTextPreference mVersioningKeep;
|
||||
private EditTextPreference mVersioningKeep;
|
||||
|
||||
private boolean mIsCreate;
|
||||
private boolean mIsCreate;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
SettingsActivity activity = (SettingsActivity) getActivity();
|
||||
activity.registerOnServiceConnectedListener(this);
|
||||
mIsCreate = activity.getIsCreate();
|
||||
setHasOptionsMenu(true);
|
||||
SettingsActivity activity = (SettingsActivity) getActivity();
|
||||
activity.registerOnServiceConnectedListener(this);
|
||||
mIsCreate = activity.getIsCreate();
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
if (mIsCreate) {
|
||||
addPreferencesFromResource(R.xml.repo_settings_create);
|
||||
}
|
||||
else {
|
||||
addPreferencesFromResource(R.xml.repo_settings_edit);
|
||||
}
|
||||
if (mIsCreate) {
|
||||
addPreferencesFromResource(R.xml.repo_settings_create);
|
||||
} else {
|
||||
addPreferencesFromResource(R.xml.repo_settings_edit);
|
||||
}
|
||||
|
||||
mRepoId = (EditTextPreference) findPreference("repo_id");
|
||||
mRepoId.setOnPreferenceChangeListener(this);
|
||||
mDirectory = findPreference("directory");
|
||||
mDirectory.setOnPreferenceClickListener(this);
|
||||
mRepoMaster = (CheckBoxPreference) findPreference("repo_master");
|
||||
mRepoMaster.setOnPreferenceChangeListener(this);
|
||||
mNodes = (PreferenceScreen) findPreference("nodes");
|
||||
mNodes.setOnPreferenceClickListener(this);
|
||||
mVersioning = (CheckBoxPreference) findPreference("versioning");
|
||||
mVersioning.setOnPreferenceChangeListener(this);
|
||||
mVersioningKeep = (EditTextPreference) findPreference("versioning_keep");
|
||||
mVersioningKeep.setOnPreferenceChangeListener(this);
|
||||
}
|
||||
mRepoId = (EditTextPreference) findPreference("repo_id");
|
||||
mRepoId.setOnPreferenceChangeListener(this);
|
||||
mDirectory = findPreference("directory");
|
||||
mDirectory.setOnPreferenceClickListener(this);
|
||||
mRepoMaster = (CheckBoxPreference) findPreference("repo_master");
|
||||
mRepoMaster.setOnPreferenceChangeListener(this);
|
||||
mNodes = (PreferenceScreen) findPreference("nodes");
|
||||
mNodes.setOnPreferenceClickListener(this);
|
||||
mVersioning = (CheckBoxPreference) findPreference("versioning");
|
||||
mVersioning.setOnPreferenceChangeListener(this);
|
||||
mVersioningKeep = (EditTextPreference) findPreference("versioning_keep");
|
||||
mVersioningKeep.setOnPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApiChange(SyncthingService.State currentState) {
|
||||
if (currentState != SyncthingService.State.ACTIVE) {
|
||||
getActivity().finish();
|
||||
return;
|
||||
}
|
||||
@Override
|
||||
public void onApiChange(SyncthingService.State currentState) {
|
||||
if (currentState != SyncthingService.State.ACTIVE) {
|
||||
getActivity().finish();
|
||||
return;
|
||||
}
|
||||
|
||||
if (getActivity() == null || getActivity().isFinishing())
|
||||
return;
|
||||
if (getActivity() == null || getActivity().isFinishing())
|
||||
return;
|
||||
|
||||
if (mIsCreate) {
|
||||
getActivity().setTitle(R.string.create_repo);
|
||||
mRepo = new RestApi.Repo();
|
||||
mRepo.ID = "";
|
||||
mRepo.Directory = "";
|
||||
mRepo.Nodes = new ArrayList<RestApi.Node>();
|
||||
mRepo.Versioning = new RestApi.Versioning();
|
||||
}
|
||||
else {
|
||||
getActivity().setTitle(R.string.edit_repo);
|
||||
List<RestApi.Repo> repos = mSyncthingService.getApi().getRepos();
|
||||
for (int i = 0; i < repos.size(); i++) {
|
||||
if (repos.get(i).ID.equals(
|
||||
getActivity().getIntent().getStringExtra(EXTRA_REPO_ID))) {
|
||||
mRepo = repos.get(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mIsCreate) {
|
||||
getActivity().setTitle(R.string.create_repo);
|
||||
mRepo = new RestApi.Repo();
|
||||
mRepo.ID = "";
|
||||
mRepo.Directory = "";
|
||||
mRepo.Nodes = new ArrayList<RestApi.Node>();
|
||||
mRepo.Versioning = new RestApi.Versioning();
|
||||
} else {
|
||||
getActivity().setTitle(R.string.edit_repo);
|
||||
List<RestApi.Repo> repos = mSyncthingService.getApi().getRepos();
|
||||
for (int i = 0; i < repos.size(); i++) {
|
||||
if (repos.get(i).ID.equals(
|
||||
getActivity().getIntent().getStringExtra(EXTRA_REPO_ID))) {
|
||||
mRepo = repos.get(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mRepoId.setText(mRepo.ID);
|
||||
mRepoId.setSummary(mRepo.ID);
|
||||
mDirectory.setSummary(mRepo.Directory);
|
||||
mRepoMaster.setChecked(mRepo.ReadOnly);
|
||||
List<RestApi.Node> nodesList = mSyncthingService.getApi().getNodes();
|
||||
for (RestApi.Node n : nodesList) {
|
||||
ExtendedCheckBoxPreference cbp = new ExtendedCheckBoxPreference(getActivity(), n);
|
||||
cbp.setTitle(n.Name);
|
||||
cbp.setKey(KEY_NODE_SHARED);
|
||||
cbp.setOnPreferenceChangeListener(RepoSettingsFragment.this);
|
||||
cbp.setChecked(false);
|
||||
for (RestApi.Node n2 : mRepo.Nodes) {
|
||||
if (n2.NodeID.equals(n.NodeID)) {
|
||||
cbp.setChecked(true);
|
||||
}
|
||||
}
|
||||
mNodes.addPreference(cbp);
|
||||
}
|
||||
mVersioning.setChecked(mRepo.Versioning instanceof RestApi.SimpleVersioning);
|
||||
if (mVersioning.isChecked()) {
|
||||
mVersioningKeep.setText(mRepo.Versioning.getParams().get("keep"));
|
||||
mVersioningKeep.setSummary(mRepo.Versioning.getParams().get("keep"));
|
||||
mVersioningKeep.setEnabled(true);
|
||||
}
|
||||
else {
|
||||
mVersioningKeep.setEnabled(false);
|
||||
}
|
||||
}
|
||||
mRepoId.setText(mRepo.ID);
|
||||
mRepoId.setSummary(mRepo.ID);
|
||||
mDirectory.setSummary(mRepo.Directory);
|
||||
mRepoMaster.setChecked(mRepo.ReadOnly);
|
||||
List<RestApi.Node> nodesList = mSyncthingService.getApi().getNodes();
|
||||
for (RestApi.Node n : nodesList) {
|
||||
ExtendedCheckBoxPreference cbp = new ExtendedCheckBoxPreference(getActivity(), n);
|
||||
cbp.setTitle(n.Name);
|
||||
cbp.setKey(KEY_NODE_SHARED);
|
||||
cbp.setOnPreferenceChangeListener(RepoSettingsFragment.this);
|
||||
cbp.setChecked(false);
|
||||
for (RestApi.Node n2 : mRepo.Nodes) {
|
||||
if (n2.NodeID.equals(n.NodeID)) {
|
||||
cbp.setChecked(true);
|
||||
}
|
||||
}
|
||||
mNodes.addPreference(cbp);
|
||||
}
|
||||
mVersioning.setChecked(mRepo.Versioning instanceof RestApi.SimpleVersioning);
|
||||
if (mVersioning.isChecked()) {
|
||||
mVersioningKeep.setText(mRepo.Versioning.getParams().get("keep"));
|
||||
mVersioningKeep.setSummary(mRepo.Versioning.getParams().get("keep"));
|
||||
mVersioningKeep.setEnabled(true);
|
||||
} else {
|
||||
mVersioningKeep.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected() {
|
||||
mSyncthingService = ((SyncthingActivity) getActivity()).getService();
|
||||
mSyncthingService.registerOnApiChangeListener(this);
|
||||
}
|
||||
@Override
|
||||
public void onServiceConnected() {
|
||||
mSyncthingService = ((SyncthingActivity) getActivity()).getService();
|
||||
mSyncthingService.registerOnApiChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
inflater.inflate(R.menu.repo_settings, menu);
|
||||
}
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
inflater.inflate(R.menu.repo_settings, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
menu.findItem(R.id.create).setVisible(mIsCreate);
|
||||
menu.findItem(R.id.delete).setVisible(!mIsCreate);
|
||||
}
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
menu.findItem(R.id.create).setVisible(mIsCreate);
|
||||
menu.findItem(R.id.delete).setVisible(!mIsCreate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.create:
|
||||
if (mRepo.ID.equals("")) {
|
||||
Toast.makeText(getActivity(), R.string.repo_id_required, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
return true;
|
||||
}
|
||||
if (mRepo.Directory.equals("")) {
|
||||
Toast.makeText(getActivity(), R.string.repo_path_required, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
return true;
|
||||
}
|
||||
mSyncthingService.getApi().editRepo(mRepo, true, getActivity());
|
||||
getActivity().finish();
|
||||
return true;
|
||||
case R.id.delete:
|
||||
new AlertDialog.Builder(getActivity())
|
||||
.setMessage(R.string.delete_repo_confirm)
|
||||
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
mSyncthingService.getApi().deleteRepo(mRepo, getActivity());
|
||||
getActivity().finish();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.no, null)
|
||||
.show();
|
||||
return true;
|
||||
case android.R.id.home:
|
||||
getActivity().finish();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.create:
|
||||
if (mRepo.ID.equals("")) {
|
||||
Toast.makeText(getActivity(), R.string.repo_id_required, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
return true;
|
||||
}
|
||||
if (mRepo.Directory.equals("")) {
|
||||
Toast.makeText(getActivity(), R.string.repo_path_required, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
return true;
|
||||
}
|
||||
mSyncthingService.getApi().editRepo(mRepo, true, getActivity());
|
||||
getActivity().finish();
|
||||
return true;
|
||||
case R.id.delete:
|
||||
new AlertDialog.Builder(getActivity())
|
||||
.setMessage(R.string.delete_repo_confirm)
|
||||
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
mSyncthingService.getApi().deleteRepo(mRepo, getActivity());
|
||||
getActivity().finish();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.no, null)
|
||||
.show();
|
||||
return true;
|
||||
case android.R.id.home:
|
||||
getActivity().finish();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object o) {
|
||||
if (preference instanceof EditTextPreference) {
|
||||
EditTextPreference pref = (EditTextPreference) preference;
|
||||
pref.setSummary((String) o);
|
||||
}
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object o) {
|
||||
if (preference instanceof EditTextPreference) {
|
||||
EditTextPreference pref = (EditTextPreference) preference;
|
||||
pref.setSummary((String) o);
|
||||
}
|
||||
|
||||
if (preference.equals(mRepoId)) {
|
||||
mRepo.ID = (String) o;
|
||||
repoUpdated();
|
||||
return true;
|
||||
}
|
||||
else if (preference.equals(mDirectory)) {
|
||||
mRepo.Directory = (String) o;
|
||||
repoUpdated();
|
||||
return true;
|
||||
}
|
||||
else if (preference.equals(mRepoMaster)) {
|
||||
mRepo.ReadOnly = (Boolean) o;
|
||||
repoUpdated();
|
||||
return true;
|
||||
}
|
||||
else if (preference.getKey().equals(KEY_NODE_SHARED)) {
|
||||
ExtendedCheckBoxPreference pref = (ExtendedCheckBoxPreference) preference;
|
||||
RestApi.Node node = (RestApi.Node) pref.getObject();
|
||||
if ((Boolean) o) {
|
||||
mRepo.Nodes.add(node);
|
||||
}
|
||||
else {
|
||||
for (RestApi.Node n : mRepo.Nodes) {
|
||||
if (n.NodeID.equals(node.NodeID)) {
|
||||
mRepo.Nodes.remove(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
repoUpdated();
|
||||
return true;
|
||||
}
|
||||
else if (preference.equals(mVersioning)) {
|
||||
mVersioningKeep.setEnabled((Boolean) o);
|
||||
if ((Boolean) o) {
|
||||
RestApi.SimpleVersioning v = new RestApi.SimpleVersioning();
|
||||
mRepo.Versioning = v;
|
||||
v.setParams(5);
|
||||
mVersioningKeep.setText("5");
|
||||
mVersioningKeep.setSummary("5");
|
||||
}
|
||||
else {
|
||||
mRepo.Versioning = new RestApi.Versioning();
|
||||
}
|
||||
repoUpdated();
|
||||
return true;
|
||||
}
|
||||
else if (preference.equals(mVersioningKeep)) {
|
||||
((RestApi.SimpleVersioning) mRepo.Versioning)
|
||||
.setParams(Integer.parseInt((String) o));
|
||||
repoUpdated();
|
||||
return true;
|
||||
}
|
||||
if (preference.equals(mRepoId)) {
|
||||
mRepo.ID = (String) o;
|
||||
repoUpdated();
|
||||
return true;
|
||||
} else if (preference.equals(mDirectory)) {
|
||||
mRepo.Directory = (String) o;
|
||||
repoUpdated();
|
||||
return true;
|
||||
} else if (preference.equals(mRepoMaster)) {
|
||||
mRepo.ReadOnly = (Boolean) o;
|
||||
repoUpdated();
|
||||
return true;
|
||||
} else if (preference.getKey().equals(KEY_NODE_SHARED)) {
|
||||
ExtendedCheckBoxPreference pref = (ExtendedCheckBoxPreference) preference;
|
||||
RestApi.Node node = (RestApi.Node) pref.getObject();
|
||||
if ((Boolean) o) {
|
||||
mRepo.Nodes.add(node);
|
||||
} else {
|
||||
for (RestApi.Node n : mRepo.Nodes) {
|
||||
if (n.NodeID.equals(node.NodeID)) {
|
||||
mRepo.Nodes.remove(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
repoUpdated();
|
||||
return true;
|
||||
} else if (preference.equals(mVersioning)) {
|
||||
mVersioningKeep.setEnabled((Boolean) o);
|
||||
if ((Boolean) o) {
|
||||
RestApi.SimpleVersioning v = new RestApi.SimpleVersioning();
|
||||
mRepo.Versioning = v;
|
||||
v.setParams(5);
|
||||
mVersioningKeep.setText("5");
|
||||
mVersioningKeep.setSummary("5");
|
||||
} else {
|
||||
mRepo.Versioning = new RestApi.Versioning();
|
||||
}
|
||||
repoUpdated();
|
||||
return true;
|
||||
} else if (preference.equals(mVersioningKeep)) {
|
||||
((RestApi.SimpleVersioning) mRepo.Versioning)
|
||||
.setParams(Integer.parseInt((String) o));
|
||||
repoUpdated();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
if (preference.equals(mDirectory)) {
|
||||
Intent intent = new Intent(getActivity(), FolderPickerActivity.class)
|
||||
.putExtra(FolderPickerActivity.EXTRA_INITIAL_DIRECTORY,
|
||||
(mRepo.Directory.length() != 0)
|
||||
? mRepo.Directory
|
||||
: Environment.getExternalStorageDirectory().getAbsolutePath());
|
||||
startActivityForResult(intent, DIRECTORY_REQUEST_CODE);
|
||||
}
|
||||
else if (preference.equals(mNodes) && mSyncthingService.getApi().getNodes().isEmpty()) {
|
||||
Toast.makeText(getActivity(), R.string.no_nodes, Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
if (preference.equals(mDirectory)) {
|
||||
Intent intent = new Intent(getActivity(), FolderPickerActivity.class)
|
||||
.putExtra(FolderPickerActivity.EXTRA_INITIAL_DIRECTORY,
|
||||
(mRepo.Directory.length() != 0)
|
||||
? mRepo.Directory
|
||||
: Environment.getExternalStorageDirectory().getAbsolutePath()
|
||||
);
|
||||
startActivityForResult(intent, DIRECTORY_REQUEST_CODE);
|
||||
} else if (preference.equals(mNodes) && mSyncthingService.getApi().getNodes().isEmpty()) {
|
||||
Toast.makeText(getActivity(), R.string.no_nodes, Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (resultCode == Activity.RESULT_OK && requestCode == DIRECTORY_REQUEST_CODE) {
|
||||
mRepo.Directory = data.getStringExtra(FolderPickerActivity.EXTRA_RESULT_DIRECTORY);
|
||||
mDirectory.setSummary(mRepo.Directory);
|
||||
repoUpdated();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (resultCode == Activity.RESULT_OK && requestCode == DIRECTORY_REQUEST_CODE) {
|
||||
mRepo.Directory = data.getStringExtra(FolderPickerActivity.EXTRA_RESULT_DIRECTORY);
|
||||
mDirectory.setSummary(mRepo.Directory);
|
||||
repoUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
private void repoUpdated() {
|
||||
if (!mIsCreate) {
|
||||
mSyncthingService.getApi().editRepo(mRepo, false, getActivity());
|
||||
}
|
||||
}
|
||||
private void repoUpdated() {
|
||||
if (!mIsCreate) {
|
||||
mSyncthingService.getApi().editRepo(mRepo, false, getActivity());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,80 +19,79 @@ import java.util.TimerTask;
|
|||
* Displays a list of all existing repositories.
|
||||
*/
|
||||
public class ReposFragment extends ListFragment implements SyncthingService.OnApiChangeListener,
|
||||
AdapterView.OnItemClickListener {
|
||||
AdapterView.OnItemClickListener {
|
||||
|
||||
private ReposAdapter mAdapter;
|
||||
private ReposAdapter mAdapter;
|
||||
|
||||
private Timer mTimer;
|
||||
private Timer mTimer;
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
setListShown(true);
|
||||
}
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
setListShown(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApiChange(SyncthingService.State currentState) {
|
||||
if (currentState != SyncthingService.State.ACTIVE)
|
||||
return;
|
||||
@Override
|
||||
public void onApiChange(SyncthingService.State currentState) {
|
||||
if (currentState != SyncthingService.State.ACTIVE)
|
||||
return;
|
||||
|
||||
initAdapter();
|
||||
}
|
||||
initAdapter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
initAdapter();
|
||||
}
|
||||
initAdapter();
|
||||
}
|
||||
|
||||
private void initAdapter() {
|
||||
MainActivity activity = (MainActivity) getActivity();
|
||||
if (activity == null || activity.getApi() == null)
|
||||
return;
|
||||
private void initAdapter() {
|
||||
MainActivity activity = (MainActivity) getActivity();
|
||||
if (activity == null || activity.getApi() == null)
|
||||
return;
|
||||
|
||||
mAdapter = new ReposAdapter(activity);
|
||||
mAdapter.add(activity.getApi().getRepos());
|
||||
setListAdapter(mAdapter);
|
||||
setEmptyText(getString(R.string.repositories_list_empty));
|
||||
getListView().setOnItemClickListener(this);
|
||||
}
|
||||
mAdapter = new ReposAdapter(activity);
|
||||
mAdapter.add(activity.getApi().getRepos());
|
||||
setListAdapter(mAdapter);
|
||||
setEmptyText(getString(R.string.repositories_list_empty));
|
||||
getListView().setOnItemClickListener(this);
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
if (mAdapter == null || getView() == null)
|
||||
return;
|
||||
private void updateList() {
|
||||
if (mAdapter == null || getView() == null)
|
||||
return;
|
||||
|
||||
MainActivity activity = (MainActivity) getActivity();
|
||||
mAdapter.updateModel(activity.getApi(), getListView());
|
||||
}
|
||||
MainActivity activity = (MainActivity) getActivity();
|
||||
mAdapter.updateModel(activity.getApi(), getListView());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||
super.setUserVisibleHint(isVisibleToUser);
|
||||
@Override
|
||||
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||
super.setUserVisibleHint(isVisibleToUser);
|
||||
|
||||
if (isVisibleToUser) {
|
||||
mTimer = new Timer();
|
||||
mTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateList();
|
||||
}
|
||||
if (isVisibleToUser) {
|
||||
mTimer = new Timer();
|
||||
mTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateList();
|
||||
}
|
||||
|
||||
}, 0, SyncthingService.GUI_UPDATE_INTERVAL);
|
||||
}
|
||||
else if (mTimer != null) {
|
||||
mTimer.cancel();
|
||||
mTimer = null;
|
||||
}
|
||||
}
|
||||
}, 0, SyncthingService.GUI_UPDATE_INTERVAL);
|
||||
} else if (mTimer != null) {
|
||||
mTimer.cancel();
|
||||
mTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
Intent intent = new Intent(getActivity(), SettingsActivity.class)
|
||||
.setAction(SettingsActivity.ACTION_REPO_SETTINGS_FRAGMENT)
|
||||
.putExtra(SettingsActivity.EXTRA_IS_CREATE, false)
|
||||
.putExtra(RepoSettingsFragment.EXTRA_REPO_ID, mAdapter.getItem(i).ID);
|
||||
startActivity(intent);
|
||||
}
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
Intent intent = new Intent(getActivity(), SettingsActivity.class)
|
||||
.setAction(SettingsActivity.ACTION_REPO_SETTINGS_FRAGMENT)
|
||||
.putExtra(SettingsActivity.EXTRA_IS_CREATE, false)
|
||||
.putExtra(RepoSettingsFragment.EXTRA_REPO_ID, mAdapter.getItem(i).ID);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,139 +16,136 @@ import com.nutomic.syncthingandroid.syncthing.RestApi;
|
|||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
||||
|
||||
public class SettingsFragment extends PreferenceFragment
|
||||
implements SyncthingActivity.OnServiceConnectedListener,
|
||||
SyncthingService.OnApiChangeListener, Preference.OnPreferenceChangeListener {
|
||||
implements SyncthingActivity.OnServiceConnectedListener,
|
||||
SyncthingService.OnApiChangeListener, Preference.OnPreferenceChangeListener {
|
||||
|
||||
private static final String SYNCTHING_OPTIONS_KEY = "syncthing_options";
|
||||
private static final String SYNCTHING_OPTIONS_KEY = "syncthing_options";
|
||||
|
||||
private static final String SYNCTHING_GUI_KEY = "syncthing_gui";
|
||||
private static final String SYNCTHING_GUI_KEY = "syncthing_gui";
|
||||
|
||||
private static final String SYNCTHING_VERSION_KEY = "syncthing_version";
|
||||
private static final String SYNCTHING_VERSION_KEY = "syncthing_version";
|
||||
|
||||
private CheckBoxPreference mStopNotCharging;
|
||||
private CheckBoxPreference mStopNotCharging;
|
||||
|
||||
private CheckBoxPreference mStopMobileData;
|
||||
private CheckBoxPreference mStopMobileData;
|
||||
|
||||
private Preference mVersion;
|
||||
private Preference mVersion;
|
||||
|
||||
private PreferenceScreen mOptionsScreen;
|
||||
private PreferenceScreen mOptionsScreen;
|
||||
|
||||
private PreferenceScreen mGuiScreen;
|
||||
private PreferenceScreen mGuiScreen;
|
||||
|
||||
private SyncthingService mSyncthingService;
|
||||
private SyncthingService mSyncthingService;
|
||||
|
||||
@Override
|
||||
public void onApiChange(SyncthingService.State currentState) {
|
||||
mOptionsScreen.setEnabled(currentState == SyncthingService.State.ACTIVE);
|
||||
mGuiScreen.setEnabled(currentState == SyncthingService.State.ACTIVE);
|
||||
@Override
|
||||
public void onApiChange(SyncthingService.State currentState) {
|
||||
mOptionsScreen.setEnabled(currentState == SyncthingService.State.ACTIVE);
|
||||
mGuiScreen.setEnabled(currentState == SyncthingService.State.ACTIVE);
|
||||
|
||||
mVersion.setSummary(mSyncthingService.getApi().getVersion());
|
||||
mVersion.setSummary(mSyncthingService.getApi().getVersion());
|
||||
|
||||
if (currentState == SyncthingService.State.ACTIVE) {
|
||||
for (int i = 0; i < mOptionsScreen.getPreferenceCount(); i++) {
|
||||
Preference pref = mOptionsScreen.getPreference(i);
|
||||
pref.setOnPreferenceChangeListener(SettingsFragment.this);
|
||||
String value = mSyncthingService.getApi()
|
||||
.getValue(RestApi.TYPE_OPTIONS, pref.getKey());
|
||||
applyPreference(pref, value);
|
||||
}
|
||||
if (currentState == SyncthingService.State.ACTIVE) {
|
||||
for (int i = 0; i < mOptionsScreen.getPreferenceCount(); i++) {
|
||||
Preference pref = mOptionsScreen.getPreference(i);
|
||||
pref.setOnPreferenceChangeListener(SettingsFragment.this);
|
||||
String value = mSyncthingService.getApi()
|
||||
.getValue(RestApi.TYPE_OPTIONS, pref.getKey());
|
||||
applyPreference(pref, value);
|
||||
}
|
||||
|
||||
for (int i = 0; i < mGuiScreen.getPreferenceCount(); i++) {
|
||||
Preference pref = mGuiScreen.getPreference(i);
|
||||
pref.setOnPreferenceChangeListener(SettingsFragment.this);
|
||||
String value = mSyncthingService.getApi()
|
||||
.getValue(RestApi.TYPE_GUI, pref.getKey());
|
||||
applyPreference(pref, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < mGuiScreen.getPreferenceCount(); i++) {
|
||||
Preference pref = mGuiScreen.getPreference(i);
|
||||
pref.setOnPreferenceChangeListener(SettingsFragment.this);
|
||||
String value = mSyncthingService.getApi()
|
||||
.getValue(RestApi.TYPE_GUI, pref.getKey());
|
||||
applyPreference(pref, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
pref.setSummary(value);
|
||||
}
|
||||
else if (pref instanceof CheckBoxPreference) {
|
||||
((CheckBoxPreference) pref).setChecked(Boolean.parseBoolean(value));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Applies the given value to the preference.
|
||||
* <p/>
|
||||
* 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);
|
||||
pref.setSummary(value);
|
||||
} else if (pref instanceof CheckBoxPreference) {
|
||||
((CheckBoxPreference) pref).setChecked(Boolean.parseBoolean(value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Loads layout, sets version from Rest API.
|
||||
*
|
||||
* Manual target API as we manually check if ActionBar is available (for ActionBar back button).
|
||||
*/
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
/**
|
||||
* Loads layout, sets version from Rest API.
|
||||
* <p/>
|
||||
* Manual target API as we manually check if ActionBar is available (for ActionBar back button).
|
||||
*/
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
((SyncthingActivity) getActivity()).registerOnServiceConnectedListener(this);
|
||||
((SyncthingActivity) getActivity()).registerOnServiceConnectedListener(this);
|
||||
|
||||
addPreferencesFromResource(R.xml.app_settings);
|
||||
PreferenceScreen screen = getPreferenceScreen();
|
||||
mStopNotCharging = (CheckBoxPreference) findPreference("stop_sync_on_mobile_data");
|
||||
mStopNotCharging.setOnPreferenceChangeListener(this);
|
||||
mStopMobileData = (CheckBoxPreference) findPreference("stop_sync_while_not_charging");
|
||||
mStopMobileData.setOnPreferenceChangeListener(this);
|
||||
mVersion = screen.findPreference(SYNCTHING_VERSION_KEY);
|
||||
mOptionsScreen = (PreferenceScreen) screen.findPreference(SYNCTHING_OPTIONS_KEY);
|
||||
mGuiScreen = (PreferenceScreen) screen.findPreference(SYNCTHING_GUI_KEY);
|
||||
}
|
||||
addPreferencesFromResource(R.xml.app_settings);
|
||||
PreferenceScreen screen = getPreferenceScreen();
|
||||
mStopNotCharging = (CheckBoxPreference) findPreference("stop_sync_on_mobile_data");
|
||||
mStopNotCharging.setOnPreferenceChangeListener(this);
|
||||
mStopMobileData = (CheckBoxPreference) findPreference("stop_sync_while_not_charging");
|
||||
mStopMobileData.setOnPreferenceChangeListener(this);
|
||||
mVersion = screen.findPreference(SYNCTHING_VERSION_KEY);
|
||||
mOptionsScreen = (PreferenceScreen) screen.findPreference(SYNCTHING_OPTIONS_KEY);
|
||||
mGuiScreen = (PreferenceScreen) screen.findPreference(SYNCTHING_GUI_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected() {
|
||||
mSyncthingService = ((SyncthingActivity) getActivity()).getService();
|
||||
mSyncthingService.registerOnApiChangeListener(this);
|
||||
}
|
||||
@Override
|
||||
public void onServiceConnected() {
|
||||
mSyncthingService = ((SyncthingActivity) getActivity()).getService();
|
||||
mSyncthingService.registerOnApiChangeListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles ActionBar back selected.
|
||||
*/
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
NavUtils.navigateUpFromSameTask(getActivity());
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Handles ActionBar back selected.
|
||||
*/
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
NavUtils.navigateUpFromSameTask(getActivity());
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the updated value to {@link }RestApi}, and sets it as the summary
|
||||
* for EditTextPreference.
|
||||
*/
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object o) {
|
||||
if (preference instanceof EditTextPreference) {
|
||||
String value = (String) o;
|
||||
preference.setSummary(value);
|
||||
EditTextPreference etp = (EditTextPreference) preference;
|
||||
if (etp.getEditText().getInputType() == InputType.TYPE_CLASS_NUMBER) {
|
||||
o = Integer.parseInt((String) o);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sends the updated value to {@link }RestApi}, and sets it as the summary
|
||||
* for EditTextPreference.
|
||||
*/
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object o) {
|
||||
if (preference instanceof EditTextPreference) {
|
||||
String value = (String) o;
|
||||
preference.setSummary(value);
|
||||
EditTextPreference etp = (EditTextPreference) preference;
|
||||
if (etp.getEditText().getInputType() == InputType.TYPE_CLASS_NUMBER) {
|
||||
o = Integer.parseInt((String) o);
|
||||
}
|
||||
}
|
||||
|
||||
if (preference.equals(mStopNotCharging) || preference.equals(mStopMobileData)) {
|
||||
mSyncthingService.updateState();
|
||||
}
|
||||
else if (mOptionsScreen.findPreference(preference.getKey()) != null) {
|
||||
mSyncthingService.getApi().setValue(RestApi.TYPE_OPTIONS, preference.getKey(), o,
|
||||
preference.getKey().equals("ListenAddress"), getActivity());
|
||||
}
|
||||
else if (mGuiScreen.findPreference(preference.getKey()) != null) {
|
||||
mSyncthingService.getApi().setValue(
|
||||
RestApi.TYPE_GUI, preference.getKey(), o, false, getActivity());
|
||||
}
|
||||
if (preference.equals(mStopNotCharging) || preference.equals(mStopMobileData)) {
|
||||
mSyncthingService.updateState();
|
||||
} else if (mOptionsScreen.findPreference(preference.getKey()) != null) {
|
||||
mSyncthingService.getApi().setValue(RestApi.TYPE_OPTIONS, preference.getKey(), o,
|
||||
preference.getKey().equals("ListenAddress"), getActivity());
|
||||
} else if (mGuiScreen.findPreference(preference.getKey()) != null) {
|
||||
mSyncthingService.getApi().setValue(
|
||||
RestApi.TYPE_GUI, preference.getKey(), o, false, getActivity());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,12 +9,12 @@ import android.content.Intent;
|
|||
*/
|
||||
public class BatteryReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
boolean isCharging = Intent.ACTION_POWER_CONNECTED.equals(intent.getAction());
|
||||
Intent i = new Intent(context, SyncthingService.class);
|
||||
i.putExtra(DeviceStateHolder.EXTRA_IS_CHARGING, isCharging);
|
||||
context.startService(i);
|
||||
}
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
boolean isCharging = Intent.ACTION_POWER_CONNECTED.equals(intent.getAction());
|
||||
Intent i = new Intent(context, SyncthingService.class);
|
||||
i.putExtra(DeviceStateHolder.EXTRA_IS_CHARGING, isCharging);
|
||||
context.startService(i);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import android.os.BatteryManager;
|
|||
|
||||
/**
|
||||
* Holds information about the current wifi and charging state of the device.
|
||||
*
|
||||
* <p/>
|
||||
* This information is actively read on construction, and then updated from intents that are passed
|
||||
* to {@link #update(android.content.Intent)}.
|
||||
*/
|
||||
|
@ -17,30 +17,30 @@ public class DeviceStateHolder extends BroadcastReceiver {
|
|||
/**
|
||||
* Intent extra containing a boolean saying whether wifi is connected or not.
|
||||
*/
|
||||
public static final String EXTRA_HAS_WIFI = "has_wifi";
|
||||
public static final String EXTRA_HAS_WIFI = "has_wifi";
|
||||
|
||||
/**
|
||||
* Intent extra containging a boolean saying whether the device is
|
||||
* charging or not (any power source).
|
||||
*/
|
||||
public static final String EXTRA_IS_CHARGING = "is_charging";
|
||||
public static final String EXTRA_IS_CHARGING = "is_charging";
|
||||
|
||||
private boolean mIsInitialized = false;
|
||||
private boolean mIsInitialized = false;
|
||||
|
||||
private boolean mIsWifiConnected = false;
|
||||
private boolean mIsWifiConnected = false;
|
||||
|
||||
private boolean mIsCharging = false;
|
||||
private boolean mIsCharging = false;
|
||||
|
||||
private SyncthingService mService;
|
||||
|
||||
public DeviceStateHolder(SyncthingService service) {
|
||||
public DeviceStateHolder(SyncthingService service) {
|
||||
mService = service;
|
||||
ConnectivityManager cm = (ConnectivityManager)
|
||||
ConnectivityManager cm = (ConnectivityManager)
|
||||
mService.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
mIsWifiConnected = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected();
|
||||
}
|
||||
mIsWifiConnected = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
context.unregisterReceiver(this);
|
||||
int status = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
|
||||
|
@ -48,16 +48,16 @@ public class DeviceStateHolder extends BroadcastReceiver {
|
|||
mIsInitialized = true;
|
||||
}
|
||||
|
||||
public boolean isCharging() {
|
||||
return mIsCharging;
|
||||
}
|
||||
public boolean isCharging() {
|
||||
return mIsCharging;
|
||||
}
|
||||
|
||||
public boolean isWifiConnected() {
|
||||
public boolean isWifiConnected() {
|
||||
return mIsWifiConnected;
|
||||
}
|
||||
|
||||
public void update(Intent intent) {
|
||||
mIsWifiConnected = intent.getBooleanExtra(EXTRA_HAS_WIFI, mIsWifiConnected);
|
||||
mIsCharging = intent.getBooleanExtra(EXTRA_IS_CHARGING, mIsCharging);
|
||||
}
|
||||
public void update(Intent intent) {
|
||||
mIsWifiConnected = intent.getBooleanExtra(EXTRA_HAS_WIFI, mIsWifiConnected);
|
||||
mIsCharging = intent.getBooleanExtra(EXTRA_IS_CHARGING, mIsCharging);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,60 +25,59 @@ import java.util.LinkedList;
|
|||
*/
|
||||
public class GetTask extends AsyncTask<String, Void, String> {
|
||||
|
||||
private static final String TAG = "GetTask";
|
||||
private static final String TAG = "GetTask";
|
||||
|
||||
public static final String URI_CONFIG = "/rest/config";
|
||||
public static final String URI_CONFIG = "/rest/config";
|
||||
|
||||
public static final String URI_VERSION = "/rest/version";
|
||||
public static final String URI_VERSION = "/rest/version";
|
||||
|
||||
public static final String URI_SYSTEM = "/rest/system";
|
||||
public static final String URI_SYSTEM = "/rest/system";
|
||||
|
||||
public static final String URI_CONNECTIONS = "/rest/connections";
|
||||
public static final String URI_CONNECTIONS = "/rest/connections";
|
||||
|
||||
public static final String URI_MODEL = "/rest/model";
|
||||
public static final String URI_MODEL = "/rest/model";
|
||||
|
||||
public static final String URI_NODEID = "/rest/nodeid";
|
||||
public static final String URI_NODEID = "/rest/nodeid";
|
||||
|
||||
/**
|
||||
* params[0] Syncthing hostname
|
||||
* params[1] URI to call
|
||||
* params[2] Syncthing API key
|
||||
* params[3] optional parameter key
|
||||
* params[4] optional parameter value
|
||||
*/
|
||||
@Override
|
||||
protected String doInBackground(String... params) {
|
||||
String fullUri = params[0] + params[1];
|
||||
HttpClient httpclient = new DefaultHttpClient();
|
||||
if (params.length == 5) {
|
||||
LinkedList<NameValuePair> urlParams = new LinkedList<>();
|
||||
urlParams.add(new BasicNameValuePair(params[3], params[4]));
|
||||
fullUri += "?" + URLEncodedUtils.format(urlParams, "utf-8");
|
||||
}
|
||||
HttpGet get = new HttpGet(fullUri);
|
||||
get.addHeader(new BasicHeader("X-API-Key", params[2]));
|
||||
/**
|
||||
* params[0] Syncthing hostname
|
||||
* params[1] URI to call
|
||||
* params[2] Syncthing API key
|
||||
* params[3] optional parameter key
|
||||
* params[4] optional parameter value
|
||||
*/
|
||||
@Override
|
||||
protected String doInBackground(String... params) {
|
||||
String fullUri = params[0] + params[1];
|
||||
HttpClient httpclient = new DefaultHttpClient();
|
||||
if (params.length == 5) {
|
||||
LinkedList<NameValuePair> urlParams = new LinkedList<>();
|
||||
urlParams.add(new BasicNameValuePair(params[3], params[4]));
|
||||
fullUri += "?" + URLEncodedUtils.format(urlParams, "utf-8");
|
||||
}
|
||||
HttpGet get = new HttpGet(fullUri);
|
||||
get.addHeader(new BasicHeader("X-API-Key", params[2]));
|
||||
|
||||
try {
|
||||
HttpResponse response = httpclient.execute(get);
|
||||
HttpEntity entity = response.getEntity();
|
||||
try {
|
||||
HttpResponse response = httpclient.execute(get);
|
||||
HttpEntity entity = response.getEntity();
|
||||
|
||||
if (entity != null) {
|
||||
InputStream is = entity.getContent();
|
||||
if (entity != null) {
|
||||
InputStream is = entity.getContent();
|
||||
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(is));
|
||||
String line;
|
||||
String result = "";
|
||||
while((line = br.readLine()) != null) {
|
||||
result += line;
|
||||
}
|
||||
br.close();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
Log.w(TAG, "Failed to call Rest API at " + fullUri, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(is));
|
||||
String line;
|
||||
String result = "";
|
||||
while ((line = br.readLine()) != null) {
|
||||
result += line;
|
||||
}
|
||||
br.close();
|
||||
return result;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "Failed to call Rest API at " + fullUri, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,17 +11,17 @@ import android.net.NetworkInfo;
|
|||
*/
|
||||
public class NetworkReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
ConnectivityManager cm =
|
||||
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo wifiInfo = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
|
||||
NetworkInfo activeNetworkInfo = cm.getActiveNetworkInfo();
|
||||
boolean isWifiConnected = (wifiInfo != null && wifiInfo.isConnected()) ||
|
||||
activeNetworkInfo == null;
|
||||
Intent i = new Intent(context, SyncthingService.class);
|
||||
i.putExtra(DeviceStateHolder.EXTRA_HAS_WIFI, isWifiConnected);
|
||||
context.startService(i);
|
||||
}
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
ConnectivityManager cm =
|
||||
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo wifiInfo = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
|
||||
NetworkInfo activeNetworkInfo = cm.getActiveNetworkInfo();
|
||||
boolean isWifiConnected = (wifiInfo != null && wifiInfo.isConnected()) ||
|
||||
activeNetworkInfo == null;
|
||||
Intent i = new Intent(context, SyncthingService.class);
|
||||
i.putExtra(DeviceStateHolder.EXTRA_HAS_WIFI, isWifiConnected);
|
||||
context.startService(i);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,37 +16,36 @@ import java.io.IOException;
|
|||
*/
|
||||
public class PostTask extends AsyncTask<String, Void, Void> {
|
||||
|
||||
private static final String TAG = "PostTask";
|
||||
private static final String TAG = "PostTask";
|
||||
|
||||
public static final String URI_CONFIG = "/rest/config";
|
||||
public static final String URI_CONFIG = "/rest/config";
|
||||
|
||||
public static final String URI_RESTART = "/rest/restart";
|
||||
public static final String URI_RESTART = "/rest/restart";
|
||||
|
||||
public static final String URI_SHUTDOWN = "/rest/shutdown";
|
||||
public static final String URI_SHUTDOWN = "/rest/shutdown";
|
||||
|
||||
/**
|
||||
* params[0] Syncthing hostname
|
||||
* params[1] URI to call
|
||||
* params[2] Syncthing API key
|
||||
* params[3] The request content (optional)
|
||||
*/
|
||||
@Override
|
||||
protected Void doInBackground(String... params) {
|
||||
String fullUri = params[0] + params[1];
|
||||
HttpClient httpclient = new DefaultHttpClient();
|
||||
HttpPost post = new HttpPost(fullUri);
|
||||
post.addHeader(new BasicHeader("X-API-Key", params[2]));
|
||||
/**
|
||||
* params[0] Syncthing hostname
|
||||
* params[1] URI to call
|
||||
* params[2] Syncthing API key
|
||||
* params[3] The request content (optional)
|
||||
*/
|
||||
@Override
|
||||
protected Void doInBackground(String... params) {
|
||||
String fullUri = params[0] + params[1];
|
||||
HttpClient httpclient = new DefaultHttpClient();
|
||||
HttpPost post = new HttpPost(fullUri);
|
||||
post.addHeader(new BasicHeader("X-API-Key", params[2]));
|
||||
|
||||
try {
|
||||
if (params.length > 3) {
|
||||
post.setEntity(new StringEntity(params[3]));
|
||||
}
|
||||
httpclient.execute(post);
|
||||
}
|
||||
catch (IOException e) {
|
||||
Log.w(TAG, "Failed to call Rest API at " + fullUri, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
if (params.length > 3) {
|
||||
post.setEntity(new StringEntity(params[3]));
|
||||
}
|
||||
httpclient.execute(post);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "Failed to call Rest API at " + fullUri, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -43,7 +43,7 @@ public class SyncthingRunnable implements Runnable {
|
|||
DataOutputStream dos = null;
|
||||
int ret = 1;
|
||||
Process process = null;
|
||||
try {
|
||||
try {
|
||||
process = Runtime.getRuntime().exec("sh");
|
||||
dos = new DataOutputStream(process.getOutputStream());
|
||||
// Set home directory to data folder for syncthing to use.
|
||||
|
@ -57,22 +57,19 @@ public class SyncthingRunnable implements Runnable {
|
|||
log(process.getInputStream());
|
||||
|
||||
ret = process.waitFor();
|
||||
}
|
||||
catch(IOException | InterruptedException e) {
|
||||
} catch (IOException | InterruptedException e) {
|
||||
Log.e(TAG, "Failed to execute syncthing binary or read output", e);
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
try {
|
||||
dos.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "Failed to close shell stream", e);
|
||||
}
|
||||
process.destroy();
|
||||
final int retVal = ret;
|
||||
if (ret != 0) {
|
||||
Log.w(TAG_NATIVE, "Syncthing binary crashed with error code " + Integer.toString(retVal));
|
||||
postCrashDialog(retVal);
|
||||
Log.w(TAG_NATIVE, "Syncthing binary crashed with error code " + Integer.toString(retVal));
|
||||
postCrashDialog(retVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +92,8 @@ public class SyncthingRunnable implements Runnable {
|
|||
int i) {
|
||||
System.exit(0);
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
.create();
|
||||
dialog.getWindow()
|
||||
.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
|
||||
|
@ -120,8 +118,7 @@ public class SyncthingRunnable implements Runnable {
|
|||
while ((line = br.readLine()) != null) {
|
||||
Log.i(TAG_NATIVE, line);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
} catch (IOException e) {
|
||||
// NOTE: This is sometimes called on shutdown, as
|
||||
// Process.destroy() closes the stream.
|
||||
Log.w(TAG, "Failed to read syncthing command line output", e);
|
||||
|
|
|
@ -40,56 +40,56 @@ import java.util.Iterator;
|
|||
*/
|
||||
public class SyncthingService extends Service {
|
||||
|
||||
private static final String TAG = "SyncthingService";
|
||||
private static final String TAG = "SyncthingService";
|
||||
|
||||
private static final int NOTIFICATION_RUNNING = 1;
|
||||
private static final int NOTIFICATION_RUNNING = 1;
|
||||
|
||||
/**
|
||||
* Intent action to perform a syncthing restart.
|
||||
*/
|
||||
public static final String ACTION_RESTART = "restart";
|
||||
/**
|
||||
* Intent action to perform a syncthing restart.
|
||||
*/
|
||||
public static final String ACTION_RESTART = "restart";
|
||||
|
||||
/**
|
||||
* Interval in ms at which the GUI is updated (eg {@link }LocalNodeInfoFragment}).
|
||||
*/
|
||||
public static final int GUI_UPDATE_INTERVAL = 1000;
|
||||
/**
|
||||
* Interval in ms at which the GUI is updated (eg {@link }LocalNodeInfoFragment}).
|
||||
*/
|
||||
public static final int GUI_UPDATE_INTERVAL = 1000;
|
||||
|
||||
/**
|
||||
* Interval in ms, at which connections to the web gui are performed on first start
|
||||
* to find out if it's online.
|
||||
*/
|
||||
private static final long WEB_GUI_POLL_INTERVAL = 100;
|
||||
/**
|
||||
* Interval in ms, at which connections to the web gui are performed on first start
|
||||
* to find out if it's online.
|
||||
*/
|
||||
private static final long WEB_GUI_POLL_INTERVAL = 100;
|
||||
|
||||
/**
|
||||
* Name of the public key file in the data directory.
|
||||
*/
|
||||
private static final String PUBLIC_KEY_FILE = "cert.pem";
|
||||
/**
|
||||
* Name of the public key file in the data directory.
|
||||
*/
|
||||
private static final String PUBLIC_KEY_FILE = "cert.pem";
|
||||
|
||||
/**
|
||||
* Name of the private key file in the data directory.
|
||||
*/
|
||||
private static final String PRIVATE_KEY_FILE = "key.pem";
|
||||
/**
|
||||
* Name of the private key file in the data directory.
|
||||
*/
|
||||
private static final String PRIVATE_KEY_FILE = "key.pem";
|
||||
|
||||
private RestApi mApi;
|
||||
private RestApi mApi;
|
||||
|
||||
private final SyncthingServiceBinder mBinder = new SyncthingServiceBinder(this);
|
||||
private final SyncthingServiceBinder mBinder = new SyncthingServiceBinder(this);
|
||||
|
||||
/**
|
||||
* Callback for when the Syncthing web interface becomes first available after service start.
|
||||
*/
|
||||
public interface OnWebGuiAvailableListener {
|
||||
public void onWebGuiAvailable();
|
||||
}
|
||||
/**
|
||||
* Callback for when the Syncthing web interface becomes first available after service start.
|
||||
*/
|
||||
public interface OnWebGuiAvailableListener {
|
||||
public void onWebGuiAvailable();
|
||||
}
|
||||
|
||||
private final HashSet<OnWebGuiAvailableListener> mOnWebGuiAvailableListeners =
|
||||
new HashSet<>();
|
||||
private final HashSet<OnWebGuiAvailableListener> mOnWebGuiAvailableListeners =
|
||||
new HashSet<>();
|
||||
|
||||
public interface OnApiChangeListener {
|
||||
public void onApiChange(State currentState);
|
||||
}
|
||||
public interface OnApiChangeListener {
|
||||
public void onApiChange(State currentState);
|
||||
}
|
||||
|
||||
private final HashSet<WeakReference<OnApiChangeListener>> mOnApiChangeListeners =
|
||||
new HashSet<>();
|
||||
private final HashSet<WeakReference<OnApiChangeListener>> mOnApiChangeListeners =
|
||||
new HashSet<>();
|
||||
|
||||
/**
|
||||
* INIT: Service is starting up and initializing.
|
||||
|
@ -97,334 +97,328 @@ public class SyncthingService extends Service {
|
|||
* ACTIVE: Syncthing binary is up and running.
|
||||
* DISABLED: Syncthing binary is stopped according to user preferences.
|
||||
*/
|
||||
public enum State {
|
||||
public enum State {
|
||||
INIT,
|
||||
STARTING,
|
||||
ACTIVE,
|
||||
DISABLED
|
||||
}
|
||||
STARTING,
|
||||
ACTIVE,
|
||||
DISABLED
|
||||
}
|
||||
|
||||
private State mCurrentState = State.INIT;
|
||||
private State mCurrentState = State.INIT;
|
||||
|
||||
/**
|
||||
* True if a stop was requested while syncthing is starting, in that case, perform stop in
|
||||
* {@link PollWebGuiAvailableTask}.
|
||||
*/
|
||||
private boolean mStopScheduled = false;
|
||||
/**
|
||||
* True if a stop was requested while syncthing is starting, in that case, perform stop in
|
||||
* {@link PollWebGuiAvailableTask}.
|
||||
*/
|
||||
private boolean mStopScheduled = false;
|
||||
|
||||
private DeviceStateHolder mDeviceStateHolder;
|
||||
private DeviceStateHolder mDeviceStateHolder;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Handles intents, either {@link #ACTION_RESTART}, or intents having
|
||||
* {@link DeviceStateHolder.EXTRA_HAS_WIFI} or {@link DeviceStateHolder.EXTRA_IS_CHARGING}
|
||||
* (which are handled by {@link DeviceStateHolder}.
|
||||
*/
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
// Just catch the empty intent and return.
|
||||
if (intent == null) {
|
||||
}
|
||||
else if (ACTION_RESTART.equals(intent.getAction()) && mCurrentState == State.ACTIVE) {
|
||||
new PostTask() {
|
||||
@Override
|
||||
protected void onPostExecute(Void aVoid) {
|
||||
ConfigXml config = new ConfigXml(SyncthingService.this);
|
||||
mApi = new RestApi(SyncthingService.this,
|
||||
config.getWebGuiUrl(), config.getApiKey());
|
||||
mCurrentState = State.STARTING;
|
||||
registerOnWebGuiAvailableListener(mApi);
|
||||
new PollWebGuiAvailableTask().execute();
|
||||
}
|
||||
}.execute(mApi.getUrl(), PostTask.URI_RESTART, mApi.getApiKey());
|
||||
}
|
||||
else if (mCurrentState != State.INIT) {
|
||||
mDeviceStateHolder.update(intent);
|
||||
updateState();
|
||||
}
|
||||
return START_STICKY;
|
||||
}
|
||||
*/
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
// Just catch the empty intent and return.
|
||||
if (intent == null) {
|
||||
} else if (ACTION_RESTART.equals(intent.getAction()) && mCurrentState == State.ACTIVE) {
|
||||
new PostTask() {
|
||||
@Override
|
||||
protected void onPostExecute(Void aVoid) {
|
||||
ConfigXml config = new ConfigXml(SyncthingService.this);
|
||||
mApi = new RestApi(SyncthingService.this,
|
||||
config.getWebGuiUrl(), config.getApiKey());
|
||||
mCurrentState = State.STARTING;
|
||||
registerOnWebGuiAvailableListener(mApi);
|
||||
new PollWebGuiAvailableTask().execute();
|
||||
}
|
||||
}.execute(mApi.getUrl(), PostTask.URI_RESTART, mApi.getApiKey());
|
||||
} else if (mCurrentState != State.INIT) {
|
||||
mDeviceStateHolder.update(intent);
|
||||
updateState();
|
||||
}
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks according to preferences and charging/wifi state, whether syncthing should be enabled
|
||||
/**
|
||||
* Checks according to preferences and charging/wifi state, whether syncthing should be enabled
|
||||
* or not.
|
||||
*
|
||||
* <p/>
|
||||
* Depending on the result, syncthing is started or stopped, and {@link #onApiChange()} is
|
||||
* called.
|
||||
*/
|
||||
public void updateState() {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
boolean prefStopMobileData = prefs.getBoolean("stop_sync_on_mobile_data", true);
|
||||
boolean prefStopNotCharging = prefs.getBoolean("stop_sync_while_not_charging", true);
|
||||
*/
|
||||
public void updateState() {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
boolean prefStopMobileData = prefs.getBoolean("stop_sync_on_mobile_data", true);
|
||||
boolean prefStopNotCharging = prefs.getBoolean("stop_sync_while_not_charging", true);
|
||||
|
||||
// Start syncthing.
|
||||
if ((mDeviceStateHolder.isCharging() || !prefStopNotCharging) &&
|
||||
(mDeviceStateHolder.isWifiConnected() || !prefStopMobileData)) {
|
||||
if (mCurrentState == State.ACTIVE || mCurrentState == State.STARTING) {
|
||||
mStopScheduled = false;
|
||||
return;
|
||||
}
|
||||
// Start syncthing.
|
||||
if ((mDeviceStateHolder.isCharging() || !prefStopNotCharging) &&
|
||||
(mDeviceStateHolder.isWifiConnected() || !prefStopMobileData)) {
|
||||
if (mCurrentState == State.ACTIVE || mCurrentState == State.STARTING) {
|
||||
mStopScheduled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
mCurrentState = State.STARTING;
|
||||
registerOnWebGuiAvailableListener(mApi);
|
||||
new PollWebGuiAvailableTask().execute();
|
||||
new Thread(new SyncthingRunnable(this)).start();
|
||||
}
|
||||
// Stop syncthing.
|
||||
else {
|
||||
if (mCurrentState == State.DISABLED)
|
||||
return;
|
||||
mCurrentState = State.STARTING;
|
||||
registerOnWebGuiAvailableListener(mApi);
|
||||
new PollWebGuiAvailableTask().execute();
|
||||
new Thread(new SyncthingRunnable(this)).start();
|
||||
}
|
||||
// Stop syncthing.
|
||||
else {
|
||||
if (mCurrentState == State.DISABLED)
|
||||
return;
|
||||
|
||||
mCurrentState = State.DISABLED;
|
||||
mCurrentState = State.DISABLED;
|
||||
|
||||
// Syncthing is currently started, perform the stop later.
|
||||
if (mCurrentState == State.STARTING) {
|
||||
mStopScheduled = true;
|
||||
} else if (mApi != null) {
|
||||
mApi.shutdown();
|
||||
}
|
||||
}
|
||||
onApiChange();
|
||||
}
|
||||
// Syncthing is currently started, perform the stop later.
|
||||
if (mCurrentState == State.STARTING) {
|
||||
mStopScheduled = true;
|
||||
} else if (mApi != null) {
|
||||
mApi.shutdown();
|
||||
}
|
||||
}
|
||||
onApiChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Polls SYNCTHING_URL until it returns HTTP status OK, then calls all listeners
|
||||
* in mOnWebGuiAvailableListeners and clears it.
|
||||
*/
|
||||
private class PollWebGuiAvailableTask extends AsyncTask<Void, Void, Void> {
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
int status = 0;
|
||||
HttpClient httpclient = new DefaultHttpClient();
|
||||
HttpHead head = new HttpHead(mApi.getUrl());
|
||||
do {
|
||||
try {
|
||||
Thread.sleep(WEB_GUI_POLL_INTERVAL);
|
||||
HttpResponse response = httpclient.execute(head);
|
||||
// NOTE: status is not really needed, as HttpHostConnectException is thrown
|
||||
// earlier.
|
||||
status = response.getStatusLine().getStatusCode();
|
||||
}
|
||||
catch (HttpHostConnectException e) {
|
||||
// We catch this in every call, as long as the service is not online,
|
||||
// so we ignore and continue.
|
||||
}
|
||||
catch (IOException e) {
|
||||
Log.w(TAG, "Failed to poll for web interface", e);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
Log.w(TAG, "Failed to poll for web interface", e);
|
||||
}
|
||||
} while(status != HttpStatus.SC_OK);
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Polls SYNCTHING_URL until it returns HTTP status OK, then calls all listeners
|
||||
* in mOnWebGuiAvailableListeners and clears it.
|
||||
*/
|
||||
private class PollWebGuiAvailableTask extends AsyncTask<Void, Void, Void> {
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
int status = 0;
|
||||
HttpClient httpclient = new DefaultHttpClient();
|
||||
HttpHead head = new HttpHead(mApi.getUrl());
|
||||
do {
|
||||
try {
|
||||
Thread.sleep(WEB_GUI_POLL_INTERVAL);
|
||||
HttpResponse response = httpclient.execute(head);
|
||||
// NOTE: status is not really needed, as HttpHostConnectException is thrown
|
||||
// earlier.
|
||||
status = response.getStatusLine().getStatusCode();
|
||||
} catch (HttpHostConnectException e) {
|
||||
// We catch this in every call, as long as the service is not online,
|
||||
// so we ignore and continue.
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "Failed to poll for web interface", e);
|
||||
} catch (InterruptedException e) {
|
||||
Log.w(TAG, "Failed to poll for web interface", e);
|
||||
}
|
||||
} while (status != HttpStatus.SC_OK);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void aVoid) {
|
||||
if (mStopScheduled) {
|
||||
mCurrentState = State.DISABLED;
|
||||
onApiChange();
|
||||
mApi.shutdown();
|
||||
mStopScheduled = false;
|
||||
return;
|
||||
}
|
||||
Log.i(TAG, "Web GUI has come online at " + mApi.getUrl());
|
||||
mCurrentState = State.ACTIVE;
|
||||
for (OnWebGuiAvailableListener listener : mOnWebGuiAvailableListeners) {
|
||||
listener.onWebGuiAvailable();
|
||||
}
|
||||
mOnWebGuiAvailableListeners.clear();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void onPostExecute(Void aVoid) {
|
||||
if (mStopScheduled) {
|
||||
mCurrentState = State.DISABLED;
|
||||
onApiChange();
|
||||
mApi.shutdown();
|
||||
mStopScheduled = false;
|
||||
return;
|
||||
}
|
||||
Log.i(TAG, "Web GUI has come online at " + mApi.getUrl());
|
||||
mCurrentState = State.ACTIVE;
|
||||
for (OnWebGuiAvailableListener listener : mOnWebGuiAvailableListeners) {
|
||||
listener.onWebGuiAvailable();
|
||||
}
|
||||
mOnWebGuiAvailableListeners.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move config file, keys, and index files to "official" folder
|
||||
*
|
||||
* Intended to bring the file locations in older installs in line with
|
||||
* newer versions.
|
||||
*/
|
||||
private void moveConfigFiles() {
|
||||
FilenameFilter idxFilter = new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.endsWith(".idx.gz");
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Move config file, keys, and index files to "official" folder
|
||||
* <p/>
|
||||
* Intended to bring the file locations in older installs in line with
|
||||
* newer versions.
|
||||
*/
|
||||
private void moveConfigFiles() {
|
||||
FilenameFilter idxFilter = new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.endsWith(".idx.gz");
|
||||
}
|
||||
};
|
||||
|
||||
if (new File(getApplicationInfo().dataDir, PUBLIC_KEY_FILE).exists()) {
|
||||
File publicKey = new File(getApplicationInfo().dataDir, PUBLIC_KEY_FILE);
|
||||
publicKey.renameTo(new File(getFilesDir(), PUBLIC_KEY_FILE));
|
||||
File privateKey = new File(getApplicationInfo().dataDir, PRIVATE_KEY_FILE);
|
||||
privateKey.renameTo(new File(getFilesDir(), PRIVATE_KEY_FILE));
|
||||
File config = new File(getApplicationInfo().dataDir, ConfigXml.CONFIG_FILE);
|
||||
config.renameTo(new File(getFilesDir(), ConfigXml.CONFIG_FILE));
|
||||
if (new File(getApplicationInfo().dataDir, PUBLIC_KEY_FILE).exists()) {
|
||||
File publicKey = new File(getApplicationInfo().dataDir, PUBLIC_KEY_FILE);
|
||||
publicKey.renameTo(new File(getFilesDir(), PUBLIC_KEY_FILE));
|
||||
File privateKey = new File(getApplicationInfo().dataDir, PRIVATE_KEY_FILE);
|
||||
privateKey.renameTo(new File(getFilesDir(), PRIVATE_KEY_FILE));
|
||||
File config = new File(getApplicationInfo().dataDir, ConfigXml.CONFIG_FILE);
|
||||
config.renameTo(new File(getFilesDir(), ConfigXml.CONFIG_FILE));
|
||||
|
||||
File oldStorageDir = new File(getApplicationInfo().dataDir);
|
||||
File[] files = oldStorageDir.listFiles(idxFilter);
|
||||
for (File file : files) {
|
||||
if (file.isFile()) {
|
||||
file.renameTo(new File(getFilesDir(), file.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File oldStorageDir = new File(getApplicationInfo().dataDir);
|
||||
File[] files = oldStorageDir.listFiles(idxFilter);
|
||||
for (File file : files) {
|
||||
if (file.isFile()) {
|
||||
file.renameTo(new File(getFilesDir(), file.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates notification, starts native binary.
|
||||
*/
|
||||
@Override
|
||||
public void onCreate() {
|
||||
PendingIntent pi = PendingIntent.getActivity(
|
||||
this, 0, new Intent(this, MainActivity.class),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
Notification n = new NotificationCompat.Builder(this)
|
||||
.setContentTitle(getString(R.string.app_name))
|
||||
.setSmallIcon(R.drawable.ic_launcher)
|
||||
.setContentIntent(pi)
|
||||
.setPriority(NotificationCompat.PRIORITY_MIN)
|
||||
.build();
|
||||
n.flags |= Notification.FLAG_ONGOING_EVENT;
|
||||
startForeground(NOTIFICATION_RUNNING, n);
|
||||
/**
|
||||
* Creates notification, starts native binary.
|
||||
*/
|
||||
@Override
|
||||
public void onCreate() {
|
||||
PendingIntent pi = PendingIntent.getActivity(
|
||||
this, 0, new Intent(this, MainActivity.class),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
Notification n = new NotificationCompat.Builder(this)
|
||||
.setContentTitle(getString(R.string.app_name))
|
||||
.setSmallIcon(R.drawable.ic_launcher)
|
||||
.setContentIntent(pi)
|
||||
.setPriority(NotificationCompat.PRIORITY_MIN)
|
||||
.build();
|
||||
n.flags |= Notification.FLAG_ONGOING_EVENT;
|
||||
startForeground(NOTIFICATION_RUNNING, n);
|
||||
|
||||
mDeviceStateHolder = new DeviceStateHolder(SyncthingService.this);
|
||||
registerReceiver(mDeviceStateHolder, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
|
||||
new StartupTask().execute();
|
||||
}
|
||||
new StartupTask().execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the initial configuration, updates the config when coming from an old
|
||||
* version, and reads syncthing URL and API key (these are passed internally as
|
||||
* {@code Pair<String, String>}.
|
||||
*/
|
||||
private class StartupTask extends AsyncTask<Void, Void, Pair<String, String>> {
|
||||
@Override
|
||||
protected Pair<String, String> doInBackground(Void... voids) {
|
||||
moveConfigFiles();
|
||||
ConfigXml config = new ConfigXml(SyncthingService.this);
|
||||
config.updateIfNeeded();
|
||||
/**
|
||||
* Sets up the initial configuration, updates the config when coming from an old
|
||||
* version, and reads syncthing URL and API key (these are passed internally as
|
||||
* {@code Pair<String, String>}.
|
||||
*/
|
||||
private class StartupTask extends AsyncTask<Void, Void, Pair<String, String>> {
|
||||
@Override
|
||||
protected Pair<String, String> doInBackground(Void... voids) {
|
||||
moveConfigFiles();
|
||||
ConfigXml config = new ConfigXml(SyncthingService.this);
|
||||
config.updateIfNeeded();
|
||||
|
||||
if (isFirstStart()) {
|
||||
Log.i(TAG, "App started for the first time. " +
|
||||
"Copying default config, keys will be generated automatically");
|
||||
config.createCameraRepo();
|
||||
}
|
||||
if (isFirstStart()) {
|
||||
Log.i(TAG, "App started for the first time. " +
|
||||
"Copying default config, keys will be generated automatically");
|
||||
config.createCameraRepo();
|
||||
}
|
||||
|
||||
return new Pair<>(config.getWebGuiUrl(), config.getApiKey());
|
||||
}
|
||||
return new Pair<>(config.getWebGuiUrl(), config.getApiKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Pair<String, String> urlAndKey) {
|
||||
mApi = new RestApi(SyncthingService.this, urlAndKey.first, urlAndKey.second);
|
||||
Log.i(TAG, "Web GUI will be available at " + mApi.getUrl());
|
||||
@Override
|
||||
protected void onPostExecute(Pair<String, String> urlAndKey) {
|
||||
mApi = new RestApi(SyncthingService.this, urlAndKey.first, urlAndKey.second);
|
||||
Log.i(TAG, "Web GUI will be available at " + mApi.getUrl());
|
||||
|
||||
// HACK: Make sure there is no syncthing binary left running from an improper
|
||||
// shutdown (eg Play Store updateIfNeeded).
|
||||
// NOTE: This will log an exception if syncthing is not actually running.
|
||||
mApi.shutdown();
|
||||
// HACK: Make sure there is no syncthing binary left running from an improper
|
||||
// shutdown (eg Play Store updateIfNeeded).
|
||||
// NOTE: This will log an exception if syncthing is not actually running.
|
||||
mApi.shutdown();
|
||||
updateState();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the native binary.
|
||||
*/
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
Log.i(TAG, "Shutting down service");
|
||||
mApi.shutdown();
|
||||
}
|
||||
/**
|
||||
* Stops the native binary.
|
||||
*/
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
Log.i(TAG, "Shutting down service");
|
||||
mApi.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a listener for the web gui becoming available..
|
||||
*
|
||||
* If the web gui is already available, listener will be called immediately.
|
||||
* Listeners are unregistered automatically after being called.
|
||||
*/
|
||||
public void registerOnWebGuiAvailableListener(OnWebGuiAvailableListener listener) {
|
||||
if (mCurrentState == State.ACTIVE) {
|
||||
listener.onWebGuiAvailable();
|
||||
}
|
||||
else {
|
||||
mOnWebGuiAvailableListeners.add(listener);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Register a listener for the web gui becoming available..
|
||||
* <p/>
|
||||
* If the web gui is already available, listener will be called immediately.
|
||||
* Listeners are unregistered automatically after being called.
|
||||
*/
|
||||
public void registerOnWebGuiAvailableListener(OnWebGuiAvailableListener listener) {
|
||||
if (mCurrentState == State.ACTIVE) {
|
||||
listener.onWebGuiAvailable();
|
||||
} else {
|
||||
mOnWebGuiAvailableListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this service has not been started before (ie config.xml does not exist).
|
||||
*
|
||||
* This will return true until the public key file has been generated.
|
||||
*/
|
||||
public boolean isFirstStart() {
|
||||
return !new File(getFilesDir(), PUBLIC_KEY_FILE).exists();
|
||||
}
|
||||
/**
|
||||
* Returns true if this service has not been started before (ie config.xml does not exist).
|
||||
* <p/>
|
||||
* This will return true until the public key file has been generated.
|
||||
*/
|
||||
public boolean isFirstStart() {
|
||||
return !new File(getFilesDir(), PUBLIC_KEY_FILE).exists();
|
||||
}
|
||||
|
||||
public RestApi getApi() {
|
||||
return mApi;
|
||||
}
|
||||
public RestApi getApi() {
|
||||
return mApi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a listener for the syncthing API state changing.
|
||||
*
|
||||
* The listener is called immediately with the current state, and again whenever the state
|
||||
* changes.
|
||||
*/
|
||||
public void registerOnApiChangeListener(OnApiChangeListener listener) {
|
||||
/**
|
||||
* Register a listener for the syncthing API state changing.
|
||||
* <p/>
|
||||
* The listener is called immediately with the current state, and again whenever the state
|
||||
* changes.
|
||||
*/
|
||||
public void registerOnApiChangeListener(OnApiChangeListener listener) {
|
||||
// Make sure we don't send an invalid state or syncthing might shwow a "disabled" message
|
||||
// when it's just starting up.
|
||||
listener.onApiChange(mCurrentState);
|
||||
mOnApiChangeListeners.add(new WeakReference<OnApiChangeListener>(listener));
|
||||
}
|
||||
listener.onApiChange(mCurrentState);
|
||||
mOnApiChangeListeners.add(new WeakReference<OnApiChangeListener>(listener));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to notifiy listeners of an API change.
|
||||
*
|
||||
/**
|
||||
* Called to notifiy listeners of an API change.
|
||||
* <p/>
|
||||
* Must only be called from SyncthingService or {@link RestApi}.
|
||||
*/
|
||||
public void onApiChange() {
|
||||
for (Iterator<WeakReference<OnApiChangeListener>> i = mOnApiChangeListeners.iterator();
|
||||
*/
|
||||
public void onApiChange() {
|
||||
for (Iterator<WeakReference<OnApiChangeListener>> i = mOnApiChangeListeners.iterator();
|
||||
i.hasNext(); ) {
|
||||
WeakReference<OnApiChangeListener> listener = i.next();
|
||||
if (listener.get() != null) {
|
||||
listener.get().onApiChange(mCurrentState);
|
||||
}
|
||||
else {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
WeakReference<OnApiChangeListener> listener = i.next();
|
||||
if (listener.get() != null) {
|
||||
listener.get().onApiChange(mCurrentState);
|
||||
} else {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dialog to be shown when attempting to start syncthing while it is disabled according
|
||||
* to settings (because the device is not charging or wifi is disconnected).
|
||||
*/
|
||||
public static void showDisabledDialog(final Activity activity) {
|
||||
new AlertDialog.Builder(activity)
|
||||
/**
|
||||
* Dialog to be shown when attempting to start syncthing while it is disabled according
|
||||
* to settings (because the device is not charging or wifi is disconnected).
|
||||
*/
|
||||
public static void showDisabledDialog(final Activity activity) {
|
||||
new AlertDialog.Builder(activity)
|
||||
.setTitle(R.string.syncthing_disabled_title)
|
||||
.setMessage(R.string.syncthing_disabled_message)
|
||||
.setPositiveButton(R.string.syncthing_disabled_change_settings,
|
||||
.setMessage(R.string.syncthing_disabled_message)
|
||||
.setPositiveButton(R.string.syncthing_disabled_change_settings,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
activity.finish();
|
||||
Intent intent = new Intent(activity, SettingsActivity.class)
|
||||
.setAction(SettingsActivity.ACTION_APP_SETTINGS_FRAGMENT);
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.exit,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
activity.finish();
|
||||
}
|
||||
}
|
||||
)
|
||||
.show()
|
||||
.setCancelable(false);
|
||||
}
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
activity.finish();
|
||||
Intent intent = new Intent(activity, SettingsActivity.class)
|
||||
.setAction(SettingsActivity.ACTION_APP_SETTINGS_FRAGMENT);
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
}
|
||||
)
|
||||
.setNegativeButton(R.string.exit,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
activity.finish();
|
||||
}
|
||||
}
|
||||
)
|
||||
.show()
|
||||
.setCancelable(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,14 +4,14 @@ import android.os.Binder;
|
|||
|
||||
public class SyncthingServiceBinder extends Binder {
|
||||
|
||||
private final SyncthingService mService;
|
||||
private final SyncthingService mService;
|
||||
|
||||
public SyncthingServiceBinder(SyncthingService service) {
|
||||
mService = service;
|
||||
}
|
||||
public SyncthingServiceBinder(SyncthingService service) {
|
||||
mService = service;
|
||||
}
|
||||
|
||||
public SyncthingService getService() {
|
||||
return mService;
|
||||
}
|
||||
public SyncthingService getService() {
|
||||
return mService;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,184 +28,180 @@ import javax.xml.transform.stream.StreamResult;
|
|||
|
||||
/**
|
||||
* Provides direct access to the config.xml file in the file system.
|
||||
*
|
||||
* <p/>
|
||||
* This class should only be used if the syncthing API is not available (usually during startup).
|
||||
*/
|
||||
public class ConfigXml {
|
||||
|
||||
private static final String TAG = "ConfigXml";
|
||||
private static final String TAG = "ConfigXml";
|
||||
|
||||
/**
|
||||
* File in the config folder that contains configuration.
|
||||
*/
|
||||
public static final String CONFIG_FILE = "config.xml";
|
||||
/**
|
||||
* File in the config folder that contains configuration.
|
||||
*/
|
||||
public static final String CONFIG_FILE = "config.xml";
|
||||
|
||||
private File mConfigFile;
|
||||
private File mConfigFile;
|
||||
|
||||
private Document mConfig;
|
||||
private Document mConfig;
|
||||
|
||||
public ConfigXml(Context context) {
|
||||
mConfigFile = new File(context.getFilesDir(), CONFIG_FILE);
|
||||
if (!mConfigFile.exists()) {
|
||||
copyDefaultConfig(context);
|
||||
}
|
||||
try {
|
||||
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
mConfig = db.parse(mConfigFile);
|
||||
} catch (SAXException | ParserConfigurationException | IOException e) {
|
||||
throw new RuntimeException("Failed to open config file", e);
|
||||
}
|
||||
}
|
||||
public ConfigXml(Context context) {
|
||||
mConfigFile = new File(context.getFilesDir(), CONFIG_FILE);
|
||||
if (!mConfigFile.exists()) {
|
||||
copyDefaultConfig(context);
|
||||
}
|
||||
try {
|
||||
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
mConfig = db.parse(mConfigFile);
|
||||
} catch (SAXException | ParserConfigurationException | IOException e) {
|
||||
throw new RuntimeException("Failed to open config file", e);
|
||||
}
|
||||
}
|
||||
|
||||
public String getWebGuiUrl() {
|
||||
return "http://" + getGuiElement().getElementsByTagName("address").item(0).getTextContent();
|
||||
}
|
||||
public String getWebGuiUrl() {
|
||||
return "http://" + getGuiElement().getElementsByTagName("address").item(0).getTextContent();
|
||||
}
|
||||
|
||||
public String getApiKey() {
|
||||
return getGuiElement().getElementsByTagName("apikey").item(0).getTextContent();
|
||||
}
|
||||
public String getApiKey() {
|
||||
return getGuiElement().getElementsByTagName("apikey").item(0).getTextContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the config file.
|
||||
*
|
||||
* Coming from 0.2.0 and earlier, globalAnnounceServer value "announce.syncthing.net:22025" is
|
||||
* replaced with "194.126.249.5:22025" (as domain resolve is broken).
|
||||
*
|
||||
* Coming from 0.3.0 and earlier, the ignorePerms flag is set to true on every repository.
|
||||
*/
|
||||
@SuppressWarnings("SdCardPath")
|
||||
public void updateIfNeeded() {
|
||||
Log.i(TAG, "Checking for needed config updates");
|
||||
boolean changed = false;
|
||||
Element options = (Element) mConfig.getDocumentElement()
|
||||
.getElementsByTagName("options").item(0);
|
||||
Element gui = (Element) mConfig.getDocumentElement()
|
||||
.getElementsByTagName("gui").item(0);
|
||||
/**
|
||||
* Updates the config file.
|
||||
* <p/>
|
||||
* Coming from 0.2.0 and earlier, globalAnnounceServer value "announce.syncthing.net:22025" is
|
||||
* replaced with "194.126.249.5:22025" (as domain resolve is broken).
|
||||
* <p/>
|
||||
* Coming from 0.3.0 and earlier, the ignorePerms flag is set to true on every repository.
|
||||
*/
|
||||
@SuppressWarnings("SdCardPath")
|
||||
public void updateIfNeeded() {
|
||||
Log.i(TAG, "Checking for needed config updates");
|
||||
boolean changed = false;
|
||||
Element options = (Element) mConfig.getDocumentElement()
|
||||
.getElementsByTagName("options").item(0);
|
||||
Element gui = (Element) mConfig.getDocumentElement()
|
||||
.getElementsByTagName("gui").item(0);
|
||||
|
||||
// Create an API key if it does not exist.
|
||||
if (gui.getElementsByTagName("apikey").getLength() == 0) {
|
||||
Log.i(TAG, "Initializing API key with random string");
|
||||
char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < 20; i++) {
|
||||
sb.append(chars[random.nextInt(chars.length)]);
|
||||
}
|
||||
Element apiKey = mConfig.createElement("apikey");
|
||||
apiKey.setTextContent(sb.toString());
|
||||
gui.appendChild(apiKey);
|
||||
changed = true;
|
||||
}
|
||||
// Create an API key if it does not exist.
|
||||
if (gui.getElementsByTagName("apikey").getLength() == 0) {
|
||||
Log.i(TAG, "Initializing API key with random string");
|
||||
char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < 20; i++) {
|
||||
sb.append(chars[random.nextInt(chars.length)]);
|
||||
}
|
||||
Element apiKey = mConfig.createElement("apikey");
|
||||
apiKey.setTextContent(sb.toString());
|
||||
gui.appendChild(apiKey);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// Hardcode default globalAnnounceServer ip.
|
||||
Element globalAnnounceServer = (Element)
|
||||
options.getElementsByTagName("globalAnnounceServer").item(0);
|
||||
if (globalAnnounceServer.getTextContent().equals("announce.syncthing.net:22025")) {
|
||||
Log.i(TAG, "Replacing globalAnnounceServer host with ip");
|
||||
globalAnnounceServer.setTextContent("194.126.249.5:22025");
|
||||
changed = true;
|
||||
}
|
||||
// Hardcode default globalAnnounceServer ip.
|
||||
Element globalAnnounceServer = (Element)
|
||||
options.getElementsByTagName("globalAnnounceServer").item(0);
|
||||
if (globalAnnounceServer.getTextContent().equals("announce.syncthing.net:22025")) {
|
||||
Log.i(TAG, "Replacing globalAnnounceServer host with ip");
|
||||
globalAnnounceServer.setTextContent("194.126.249.5:22025");
|
||||
changed = true;
|
||||
}
|
||||
|
||||
NodeList repos = mConfig.getDocumentElement().getElementsByTagName("repository");
|
||||
for (int i = 0; i < repos.getLength(); i++) {
|
||||
Element r = (Element) repos.item(i);
|
||||
// Set ignorePerms attribute.
|
||||
if (!r.hasAttribute("ignorePerms") ||
|
||||
!Boolean.parseBoolean(r.getAttribute("ignorePerms"))) {
|
||||
Log.i(TAG, "Set 'ignorePerms' on repository " + r.getAttribute("id"));
|
||||
r.setAttribute("ignorePerms", Boolean.toString(true));
|
||||
changed = true;
|
||||
}
|
||||
NodeList repos = mConfig.getDocumentElement().getElementsByTagName("repository");
|
||||
for (int i = 0; i < repos.getLength(); i++) {
|
||||
Element r = (Element) repos.item(i);
|
||||
// Set ignorePerms attribute.
|
||||
if (!r.hasAttribute("ignorePerms") ||
|
||||
!Boolean.parseBoolean(r.getAttribute("ignorePerms"))) {
|
||||
Log.i(TAG, "Set 'ignorePerms' on repository " + r.getAttribute("id"));
|
||||
r.setAttribute("ignorePerms", Boolean.toString(true));
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// Replace /sdcard/ in repository path with proper path.
|
||||
String dir = r.getAttribute("directory");
|
||||
if (dir.startsWith("/sdcard")) {
|
||||
String newDir = dir.replace("/sdcard",
|
||||
Environment.getExternalStorageDirectory().getAbsolutePath());
|
||||
r.setAttribute("directory", newDir);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
// Replace /sdcard/ in repository path with proper path.
|
||||
String dir = r.getAttribute("directory");
|
||||
if (dir.startsWith("/sdcard")) {
|
||||
String newDir = dir.replace("/sdcard",
|
||||
Environment.getExternalStorageDirectory().getAbsolutePath());
|
||||
r.setAttribute("directory", newDir);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Change global announce server port to 22026 for syncthing v0.9.0.
|
||||
if (globalAnnounceServer.getTextContent().equals("194.126.249.5:22025")) {
|
||||
Log.i(TAG, "Changing announce server port for v0.9.0");
|
||||
globalAnnounceServer.setTextContent("194.126.249.5:22026");
|
||||
changed = true;
|
||||
}
|
||||
// Change global announce server port to 22026 for syncthing v0.9.0.
|
||||
if (globalAnnounceServer.getTextContent().equals("194.126.249.5:22025")) {
|
||||
Log.i(TAG, "Changing announce server port for v0.9.0");
|
||||
globalAnnounceServer.setTextContent("194.126.249.5:22026");
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
saveChanges();
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
saveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
private Element getGuiElement() {
|
||||
return (Element) mConfig.getDocumentElement()
|
||||
.getElementsByTagName("gui").item(0);
|
||||
}
|
||||
private Element getGuiElement() {
|
||||
return (Element) mConfig.getDocumentElement()
|
||||
.getElementsByTagName("gui").item(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a repository for the default camera folder.
|
||||
*/
|
||||
public void createCameraRepo() {
|
||||
File cameraFolder =
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
|
||||
/**
|
||||
* Creates a repository for the default camera folder.
|
||||
*/
|
||||
public void createCameraRepo() {
|
||||
File cameraFolder =
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
|
||||
|
||||
Element cameraRepo = mConfig.createElement("repository");
|
||||
cameraRepo.setAttribute("id", "camera");
|
||||
cameraRepo.setAttribute("directory", cameraFolder.getAbsolutePath());
|
||||
cameraRepo.setAttribute("ro", "true");
|
||||
cameraRepo.setAttribute("ignorePerms", "true");
|
||||
mConfig.getDocumentElement().appendChild(cameraRepo);
|
||||
Element cameraRepo = mConfig.createElement("repository");
|
||||
cameraRepo.setAttribute("id", "camera");
|
||||
cameraRepo.setAttribute("directory", cameraFolder.getAbsolutePath());
|
||||
cameraRepo.setAttribute("ro", "true");
|
||||
cameraRepo.setAttribute("ignorePerms", "true");
|
||||
mConfig.getDocumentElement().appendChild(cameraRepo);
|
||||
|
||||
saveChanges();
|
||||
}
|
||||
saveChanges();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes updated mConfig back to file.
|
||||
*/
|
||||
private void saveChanges() {
|
||||
try {
|
||||
Log.i(TAG, "Writing updated config back to file");
|
||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||
Transformer transformer = transformerFactory.newTransformer();
|
||||
DOMSource domSource = new DOMSource(mConfig);
|
||||
StreamResult streamResult = new StreamResult(mConfigFile);
|
||||
transformer.transform(domSource, streamResult);
|
||||
}
|
||||
catch (TransformerException e) {
|
||||
Log.w(TAG, "Failed to save updated config", e);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Writes updated mConfig back to file.
|
||||
*/
|
||||
private void saveChanges() {
|
||||
try {
|
||||
Log.i(TAG, "Writing updated config back to file");
|
||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||
Transformer transformer = transformerFactory.newTransformer();
|
||||
DOMSource domSource = new DOMSource(mConfig);
|
||||
StreamResult streamResult = new StreamResult(mConfigFile);
|
||||
transformer.transform(domSource, streamResult);
|
||||
} catch (TransformerException e) {
|
||||
Log.w(TAG, "Failed to save updated config", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the default config file from res/raw/config_default.xml to (data folder)/config.xml.
|
||||
*/
|
||||
private void copyDefaultConfig(Context context) {
|
||||
InputStream in = null;
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
in = context.getResources().openRawResource(R.raw.config_default);
|
||||
out = new FileOutputStream(mConfigFile);
|
||||
byte[] buff = new byte[1024];
|
||||
int read;
|
||||
/**
|
||||
* Copies the default config file from res/raw/config_default.xml to (data folder)/config.xml.
|
||||
*/
|
||||
private void copyDefaultConfig(Context context) {
|
||||
InputStream in = null;
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
in = context.getResources().openRawResource(R.raw.config_default);
|
||||
out = new FileOutputStream(mConfigFile);
|
||||
byte[] buff = new byte[1024];
|
||||
int read;
|
||||
|
||||
while ((read = in.read(buff)) > 0) {
|
||||
out.write(buff, 0, read);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException("Failed to write config file", e);
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
in.close();
|
||||
out.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
Log.w(TAG, "Failed to close stream while copying config", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
while ((read = in.read(buff)) > 0) {
|
||||
out.write(buff, 0, read);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to write config file", e);
|
||||
} finally {
|
||||
try {
|
||||
in.close();
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "Failed to close stream while copying config", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,15 +8,15 @@ import android.preference.CheckBoxPreference;
|
|||
*/
|
||||
public class ExtendedCheckBoxPreference extends CheckBoxPreference {
|
||||
|
||||
private final Object mObject;
|
||||
private final Object mObject;
|
||||
|
||||
public ExtendedCheckBoxPreference(Context context, Object object) {
|
||||
super(context);
|
||||
mObject = object;
|
||||
}
|
||||
public ExtendedCheckBoxPreference(Context context, Object object) {
|
||||
super(context);
|
||||
mObject = object;
|
||||
}
|
||||
|
||||
public Object getObject() {
|
||||
return mObject;
|
||||
}
|
||||
public Object getObject() {
|
||||
return mObject;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,79 +20,77 @@ import java.util.Map;
|
|||
* Generates item views for node items.
|
||||
*/
|
||||
public class NodesAdapter extends ArrayAdapter<RestApi.Node>
|
||||
implements RestApi.OnReceiveConnectionsListener {
|
||||
implements RestApi.OnReceiveConnectionsListener {
|
||||
|
||||
private Map<String, RestApi.Connection> mConnections =
|
||||
new HashMap<>();
|
||||
private Map<String, RestApi.Connection> mConnections =
|
||||
new HashMap<>();
|
||||
|
||||
public NodesAdapter(Context context) {
|
||||
super(context, R.layout.node_list_item);
|
||||
}
|
||||
public NodesAdapter(Context context) {
|
||||
super(context, R.layout.node_list_item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
LayoutInflater inflater = (LayoutInflater) getContext()
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
convertView = inflater.inflate(R.layout.node_list_item, parent, false);
|
||||
}
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
LayoutInflater inflater = (LayoutInflater) getContext()
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
convertView = inflater.inflate(R.layout.node_list_item, parent, false);
|
||||
}
|
||||
|
||||
TextView name = (TextView) convertView.findViewById(R.id.name);
|
||||
TextView status = (TextView) convertView.findViewById(R.id.status);
|
||||
TextView download = (TextView) convertView.findViewById(R.id.download);
|
||||
TextView upload = (TextView) convertView.findViewById(R.id.upload);
|
||||
TextView name = (TextView) convertView.findViewById(R.id.name);
|
||||
TextView status = (TextView) convertView.findViewById(R.id.status);
|
||||
TextView download = (TextView) convertView.findViewById(R.id.download);
|
||||
TextView upload = (TextView) convertView.findViewById(R.id.upload);
|
||||
|
||||
name.setText(getItem(position).Name);
|
||||
final String nodeId = getItem(position).NodeID;
|
||||
name.setText(getItem(position).Name);
|
||||
final String nodeId = getItem(position).NodeID;
|
||||
|
||||
RestApi.Connection conn = mConnections.get(nodeId);
|
||||
Resources res = getContext().getResources();
|
||||
if (conn != null) {
|
||||
if (conn.Completion == 100) {
|
||||
status.setText(res.getString(R.string.node_up_to_date));
|
||||
status.setTextColor(res.getColor(R.color.text_green));
|
||||
}
|
||||
else {
|
||||
status.setText(res.getString(R.string.node_syncing, conn.Completion));
|
||||
status.setTextColor(res.getColor(R.color.text_blue));
|
||||
}
|
||||
download.setText(RestApi.readableTransferRate(getContext(), conn.InBits));
|
||||
upload.setText(RestApi.readableTransferRate(getContext(), conn.OutBits));
|
||||
}
|
||||
else {
|
||||
download.setText("0 " + res.getStringArray(R.array.transfer_rate_units)[0]);
|
||||
upload.setText("0 " + res.getStringArray(R.array.transfer_rate_units)[0]);
|
||||
status.setText(res.getString(R.string.node_disconnected));
|
||||
status.setTextColor(res.getColor(R.color.text_red));
|
||||
}
|
||||
RestApi.Connection conn = mConnections.get(nodeId);
|
||||
Resources res = getContext().getResources();
|
||||
if (conn != null) {
|
||||
if (conn.Completion == 100) {
|
||||
status.setText(res.getString(R.string.node_up_to_date));
|
||||
status.setTextColor(res.getColor(R.color.text_green));
|
||||
} else {
|
||||
status.setText(res.getString(R.string.node_syncing, conn.Completion));
|
||||
status.setTextColor(res.getColor(R.color.text_blue));
|
||||
}
|
||||
download.setText(RestApi.readableTransferRate(getContext(), conn.InBits));
|
||||
upload.setText(RestApi.readableTransferRate(getContext(), conn.OutBits));
|
||||
} else {
|
||||
download.setText("0 " + res.getStringArray(R.array.transfer_rate_units)[0]);
|
||||
upload.setText("0 " + res.getStringArray(R.array.transfer_rate_units)[0]);
|
||||
status.setText(res.getString(R.string.node_disconnected));
|
||||
status.setTextColor(res.getColor(R.color.text_red));
|
||||
}
|
||||
|
||||
return convertView;
|
||||
}
|
||||
return convertView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replacement for addAll, which is not implemented on lower API levels.
|
||||
*/
|
||||
public void add(List<RestApi.Node> nodes) {
|
||||
for (RestApi.Node n : nodes) {
|
||||
add(n);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Replacement for addAll, which is not implemented on lower API levels.
|
||||
*/
|
||||
public void add(List<RestApi.Node> nodes) {
|
||||
for (RestApi.Node n : nodes) {
|
||||
add(n);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests new connection info for all nodes visible in listView.
|
||||
*/
|
||||
public void updateConnections(RestApi api, ListView listView) {
|
||||
for (int i = 0; i < getCount(); i++) {
|
||||
if ( i >= listView.getFirstVisiblePosition() &&
|
||||
i <= listView.getLastVisiblePosition()) {
|
||||
api.getConnections(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Requests new connection info for all nodes visible in listView.
|
||||
*/
|
||||
public void updateConnections(RestApi api, ListView listView) {
|
||||
for (int i = 0; i < getCount(); i++) {
|
||||
if (i >= listView.getFirstVisiblePosition() &&
|
||||
i <= listView.getLastVisiblePosition()) {
|
||||
api.getConnections(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceiveConnections(Map<String, RestApi.Connection> connections) {
|
||||
mConnections = connections;
|
||||
notifyDataSetInvalidated();
|
||||
}
|
||||
@Override
|
||||
public void onReceiveConnections(Map<String, RestApi.Connection> connections) {
|
||||
mConnections = connections;
|
||||
notifyDataSetInvalidated();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,77 +18,77 @@ import java.util.List;
|
|||
* Generates item views for repository items.
|
||||
*/
|
||||
public class ReposAdapter extends ArrayAdapter<RestApi.Repo>
|
||||
implements RestApi.OnReceiveModelListener {
|
||||
implements RestApi.OnReceiveModelListener {
|
||||
|
||||
private HashMap<String, RestApi.Model> mModels = new HashMap<>();
|
||||
private HashMap<String, RestApi.Model> mModels = new HashMap<>();
|
||||
|
||||
public ReposAdapter(Context context) {
|
||||
super(context, R.layout.repo_list_item);
|
||||
}
|
||||
public ReposAdapter(Context context) {
|
||||
super(context, R.layout.repo_list_item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
LayoutInflater inflater = (LayoutInflater) getContext()
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
convertView = inflater.inflate(R.layout.repo_list_item, parent, false);
|
||||
}
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
LayoutInflater inflater = (LayoutInflater) getContext()
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
convertView = inflater.inflate(R.layout.repo_list_item, parent, false);
|
||||
}
|
||||
|
||||
TextView id = (TextView) convertView.findViewById(R.id.id);
|
||||
TextView id = (TextView) convertView.findViewById(R.id.id);
|
||||
|
||||
TextView state = (TextView) convertView.findViewById(R.id.state);
|
||||
TextView folder = (TextView) convertView.findViewById(R.id.folder);
|
||||
TextView items = (TextView) convertView.findViewById(R.id.items);
|
||||
TextView size = (TextView) convertView.findViewById(R.id.size);
|
||||
TextView invalid = (TextView) convertView.findViewById(R.id.invalid);
|
||||
TextView state = (TextView) convertView.findViewById(R.id.state);
|
||||
TextView folder = (TextView) convertView.findViewById(R.id.folder);
|
||||
TextView items = (TextView) convertView.findViewById(R.id.items);
|
||||
TextView size = (TextView) convertView.findViewById(R.id.size);
|
||||
TextView invalid = (TextView) convertView.findViewById(R.id.invalid);
|
||||
|
||||
id.setText(getItem(position).ID);
|
||||
state.setTextColor(getContext().getResources().getColor(R.color.text_green));
|
||||
folder.setText((getItem(position).Directory));
|
||||
RestApi.Model model = mModels.get(getItem(position).ID);
|
||||
if (model != null) {
|
||||
state.setText(getContext().getString(R.string.repo_progress_format, model.state,
|
||||
(model.globalBytes <= 0)
|
||||
? 100
|
||||
: (int) ((model.localBytes / (float) model.globalBytes) * 100)));
|
||||
items.setText(getContext()
|
||||
.getString(R.string.files, model.localFiles, model.globalFiles));
|
||||
size.setText(RestApi.readableFileSize(getContext(), model.localBytes) + " / " +
|
||||
RestApi.readableFileSize(getContext(), model.globalBytes));
|
||||
invalid.setText(model.invalid);
|
||||
invalid.setVisibility((model.invalid.equals("")) ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
else {
|
||||
invalid.setVisibility(View.GONE);
|
||||
}
|
||||
id.setText(getItem(position).ID);
|
||||
state.setTextColor(getContext().getResources().getColor(R.color.text_green));
|
||||
folder.setText((getItem(position).Directory));
|
||||
RestApi.Model model = mModels.get(getItem(position).ID);
|
||||
if (model != null) {
|
||||
state.setText(getContext().getString(R.string.repo_progress_format, model.state,
|
||||
(model.globalBytes <= 0)
|
||||
? 100
|
||||
: (int) ((model.localBytes / (float) model.globalBytes) * 100)
|
||||
));
|
||||
items.setText(getContext()
|
||||
.getString(R.string.files, model.localFiles, model.globalFiles));
|
||||
size.setText(RestApi.readableFileSize(getContext(), model.localBytes) + " / " +
|
||||
RestApi.readableFileSize(getContext(), model.globalBytes));
|
||||
invalid.setText(model.invalid);
|
||||
invalid.setVisibility((model.invalid.equals("")) ? View.GONE : View.VISIBLE);
|
||||
} else {
|
||||
invalid.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
return convertView;
|
||||
}
|
||||
return convertView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replacement for addAll, which is not implemented on lower API levels.
|
||||
*/
|
||||
public void add(List<RestApi.Repo> nodes) {
|
||||
for (RestApi.Repo r : nodes) {
|
||||
add(r);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Replacement for addAll, which is not implemented on lower API levels.
|
||||
*/
|
||||
public void add(List<RestApi.Repo> nodes) {
|
||||
for (RestApi.Repo r : nodes) {
|
||||
add(r);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests updated model info from the api for all visible items.
|
||||
*/
|
||||
public void updateModel(RestApi api, ListView listView) {
|
||||
for (int i = 0; i < getCount(); i++) {
|
||||
if ( i >= listView.getFirstVisiblePosition() &&
|
||||
i <= listView.getLastVisiblePosition()) {
|
||||
api.getModel(getItem(i).ID, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Requests updated model info from the api for all visible items.
|
||||
*/
|
||||
public void updateModel(RestApi api, ListView listView) {
|
||||
for (int i = 0; i < getCount(); i++) {
|
||||
if (i >= listView.getFirstVisiblePosition() &&
|
||||
i <= listView.getLastVisiblePosition()) {
|
||||
api.getModel(getItem(i).ID, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceiveModel(String repoId, RestApi.Model model) {
|
||||
mModels.put(repoId, model);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
@Override
|
||||
public void onReceiveModel(String repoId, RestApi.Model model) {
|
||||
mModels.put(repoId, model);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ListView
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
<ListView
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/empty"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/directory_empty"
|
||||
android:layout_centerInParent="true"/>
|
||||
<TextView
|
||||
android:id="@android:id/empty"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/directory_empty"
|
||||
android:layout_centerInParent="true" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_gravity="center"
|
||||
android:padding="10dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" >
|
||||
android:layout_gravity="center"
|
||||
android:padding="10dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ProgressBar
|
||||
style="?android:attr/progressBarStyleLarge"
|
||||
android:id="@+id/progress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<ProgressBar
|
||||
style="?android:attr/progressBarStyleLarge"
|
||||
android:id="@+id/progress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/loading_text"
|
||||
android:layout_toRightOf="@id/progress"
|
||||
android:layout_alignBottom="@id/progress"
|
||||
android:layout_alignTop="@id/progress"
|
||||
android:gravity="center"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:id="@+id/loading_text"
|
||||
android:layout_toRightOf="@id/progress"
|
||||
android:layout_alignBottom="@id/progress"
|
||||
android:layout_alignTop="@id/progress"
|
||||
android:gravity="center"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</RelativeLayout>
|
||||
</RelativeLayout>
|
||||
|
|
|
@ -1,117 +1,123 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dip"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
android:orientation="vertical"
|
||||
android:padding="10dip"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<TextView
|
||||
android:id="@+id/node_id_title"
|
||||
android:textStyle="bold"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/node_id"
|
||||
android:lines="1"
|
||||
android:ellipsize="end"
|
||||
android:layout_below="@id/node_id_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</RelativeLayout>
|
||||
<TextView
|
||||
android:id="@+id/node_id_title"
|
||||
android:textStyle="bold"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
<TextView
|
||||
android:id="@+id/cpu_usage_title"
|
||||
android:text="@string/cpu_usage"
|
||||
android:textStyle="bold"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:id="@+id/node_id"
|
||||
android:lines="1"
|
||||
android:ellipsize="end"
|
||||
android:layout_below="@id/node_id_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cpu_usage"
|
||||
android:layout_alignBottom="@id/cpu_usage_title"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</RelativeLayout>
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
<TextView
|
||||
android:id="@+id/ram_usage_title"
|
||||
android:text="@string/ram_usage"
|
||||
android:textStyle="bold"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:id="@+id/cpu_usage_title"
|
||||
android:text="@string/cpu_usage"
|
||||
android:textStyle="bold"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/ram_usage"
|
||||
android:layout_alignBottom="@id/ram_usage_title"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</RelativeLayout>
|
||||
<TextView
|
||||
android:id="@+id/cpu_usage"
|
||||
android:layout_alignBottom="@id/cpu_usage_title"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
<TextView
|
||||
android:id="@+id/download_title"
|
||||
android:text="@string/download_title"
|
||||
android:textStyle="bold"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/download"
|
||||
android:layout_alignBottom="@id/download_title"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</RelativeLayout>
|
||||
<TextView
|
||||
android:id="@+id/ram_usage_title"
|
||||
android:text="@string/ram_usage"
|
||||
android:textStyle="bold"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
<TextView
|
||||
android:id="@+id/upload_title"
|
||||
android:text="@string/upload_title"
|
||||
android:textStyle="bold"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:id="@+id/ram_usage"
|
||||
android:layout_alignBottom="@id/ram_usage_title"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/upload"
|
||||
android:layout_alignBottom="@id/upload_title"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</RelativeLayout>
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
<TextView
|
||||
android:id="@+id/announce_server_title"
|
||||
android:text="@string/announce_server"
|
||||
android:textStyle="bold"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:id="@+id/download_title"
|
||||
android:text="@string/download_title"
|
||||
android:textStyle="bold"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/announce_server"
|
||||
android:layout_alignBottom="@id/announce_server_title"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</RelativeLayout>
|
||||
<TextView
|
||||
android:id="@+id/download"
|
||||
android:layout_alignBottom="@id/download_title"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/upload_title"
|
||||
android:text="@string/upload_title"
|
||||
android:textStyle="bold"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/upload"
|
||||
android:layout_alignBottom="@id/upload_title"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/announce_server_title"
|
||||
android:text="@string/announce_server"
|
||||
android:textStyle="bold"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/announce_server"
|
||||
android:layout_alignBottom="@id/announce_server_title"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<android.support.v4.widget.DrawerLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.v4.view.ViewPager
|
||||
android:id="@+id/pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
<android.support.v4.view.ViewPager
|
||||
android:id="@+id/pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/drawer"
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="start"
|
||||
android:layout_width="260dip"
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="true"
|
||||
android:background="@android:color/background_light" />
|
||||
<LinearLayout
|
||||
android:id="@+id/drawer"
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="start"
|
||||
android:layout_width="260dip"
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="true"
|
||||
android:background="@android:color/background_light" />
|
||||
|
||||
</android.support.v4.widget.DrawerLayout>
|
||||
</android.support.v4.widget.DrawerLayout>
|
||||
|
|
|
@ -1,59 +1,59 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4dip" >
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4dip">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_toLeftOf="@+id/status"
|
||||
android:lines="1"
|
||||
android:ellipsize="end" />
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_toLeftOf="@+id/status"
|
||||
android:lines="1"
|
||||
android:ellipsize="end" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignBottom="@+id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:ellipsize="end" />
|
||||
<TextView
|
||||
android:id="@+id/status"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignBottom="@+id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/download_title"
|
||||
android:text="@string/download_title_colon"
|
||||
android:layout_below="@id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
<TextView
|
||||
android:id="@+id/download_title"
|
||||
android:text="@string/download_title_colon"
|
||||
android:layout_below="@id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/download"
|
||||
android:layout_alignBaseline="@id/download_title"
|
||||
android:layout_toRightOf="@id/download_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
<TextView
|
||||
android:id="@+id/download"
|
||||
android:layout_alignBaseline="@id/download_title"
|
||||
android:layout_toRightOf="@id/download_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/upload_title"
|
||||
android:text="@string/upload_title_colon"
|
||||
android:layout_below="@id/download_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
<TextView
|
||||
android:id="@+id/upload_title"
|
||||
android:text="@string/upload_title_colon"
|
||||
android:layout_below="@id/download_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/upload"
|
||||
android:layout_alignBaseline="@id/upload_title"
|
||||
android:layout_toRightOf="@id/upload_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
<TextView
|
||||
android:id="@+id/upload"
|
||||
android:layout_alignBaseline="@id/upload_title"
|
||||
android:layout_toRightOf="@id/upload_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
>>>>>>> Changed code style to use spaces instead of tabs.
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
|
@ -1,55 +1,55 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4dip" >
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4dip">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/id"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_toLeftOf="@+id/state"
|
||||
android:lines="1"
|
||||
android:ellipsize="end" />
|
||||
<TextView
|
||||
android:id="@+id/id"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_toLeftOf="@+id/state"
|
||||
android:lines="1"
|
||||
android:ellipsize="end" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/state"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignBottom="@+id/id"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:id="@+id/state"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignBottom="@+id/id"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/folder"
|
||||
android:layout_below="@id/state"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end" />
|
||||
<TextView
|
||||
android:id="@+id/folder"
|
||||
android:layout_below="@id/state"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/items"
|
||||
android:layout_below="@id/folder"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:id="@+id/items"
|
||||
android:layout_below="@id/folder"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/size"
|
||||
android:layout_below="@id/items"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:id="@+id/size"
|
||||
android:layout_below="@id/items"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/invalid"
|
||||
android:textColor="@color/text_red"
|
||||
android:layout_below="@id/size"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:id="@+id/invalid"
|
||||
android:textColor="@color/text_red"
|
||||
android:layout_below="@id/size"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:src="@drawable/ic_qrcode"
|
||||
android:onClick="onClick"
|
||||
android:contentDescription="@string/scan_qr_code_description" />
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:src="@drawable/ic_qrcode"
|
||||
android:onClick="onClick"
|
||||
android:contentDescription="@string/scan_qr_code_description" />
|
||||
|
|
|
@ -1,37 +1,36 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<WebView
|
||||
android:id="@+id/webview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone" />
|
||||
<WebView
|
||||
android:id="@+id/webview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/loading"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" >
|
||||
<RelativeLayout
|
||||
android:id="@+id/loading"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress"
|
||||
android:layout_centerInParent="true"
|
||||
style="?android:attr/progressBarStyleLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dip" />
|
||||
<ProgressBar
|
||||
android:id="@+id/progress"
|
||||
android:layout_centerInParent="true"
|
||||
style="?android:attr/progressBarStyleLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dip" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/loading_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/progress"
|
||||
android:text="@string/web_gui_loading" />
|
||||
<TextView
|
||||
android:id="@+id/loading_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/progress"
|
||||
android:text="@string/web_gui_loading" />
|
||||
|
||||
</RelativeLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto" >
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/select"
|
||||
android:title="@string/select_folder"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/select"
|
||||
android:title="@string/select_folder"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/create_folder"
|
||||
android:title="@string/create_folder"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/create_folder"
|
||||
android:title="@string/create_folder"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
</menu>
|
||||
|
|
|
@ -1,32 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto" >
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/share_node_id"
|
||||
android:icon="@android:drawable/ic_menu_share"
|
||||
android:title="@string/share_node_id"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/share_node_id"
|
||||
android:icon="@android:drawable/ic_menu_share"
|
||||
android:title="@string/share_node_id"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/add_repo"
|
||||
android:title="@string/add_repo"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/add_repo"
|
||||
android:title="@string/add_repo"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/add_node"
|
||||
android:title="@string/add_node"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/add_node"
|
||||
android:title="@string/add_node"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
|
||||
<item
|
||||
android:id="@+id/web_gui"
|
||||
android:title="@string/web_gui_title" />
|
||||
<item
|
||||
android:id="@+id/web_gui"
|
||||
android:title="@string/web_gui_title" />
|
||||
|
||||
<item
|
||||
android:id="@+id/settings"
|
||||
android:title="@string/settings_title" />
|
||||
<item
|
||||
android:id="@+id/settings"
|
||||
android:title="@string/settings_title" />
|
||||
|
||||
</menu>
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto" >
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/create"
|
||||
android:title="@string/add"
|
||||
app:showAsAction="always" />
|
||||
<item
|
||||
android:id="@+id/create"
|
||||
android:title="@string/add"
|
||||
app:showAsAction="always" />
|
||||
|
||||
<item
|
||||
android:id="@+id/share_node_id"
|
||||
android:icon="@android:drawable/ic_menu_share"
|
||||
android:title="@string/share_node_id"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/share_node_id"
|
||||
android:icon="@android:drawable/ic_menu_share"
|
||||
android:title="@string/share_node_id"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/delete"
|
||||
android:icon="@drawable/ic_delete"
|
||||
android:title="@string/delete_node"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/delete"
|
||||
android:icon="@drawable/ic_delete"
|
||||
android:title="@string/delete_node"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
</menu>
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto" >
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/create"
|
||||
android:title="@string/create"
|
||||
app:showAsAction="always" />
|
||||
<item
|
||||
android:id="@+id/create"
|
||||
android:title="@string/create"
|
||||
app:showAsAction="always" />
|
||||
|
||||
<item
|
||||
android:id="@+id/delete"
|
||||
android:icon="@drawable/ic_delete"
|
||||
android:title="@string/delete_repo"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/delete"
|
||||
android:icon="@drawable/ic_delete"
|
||||
android:title="@string/delete_repo"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
</menu>
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
<configuration version="2">
|
||||
<gui enabled="true">
|
||||
<address>127.0.0.1:8080</address>
|
||||
</gui>
|
||||
<options>
|
||||
<listenAddress>0.0.0.0:22000</listenAddress>
|
||||
<globalAnnounceServer>194.126.249.5:22026</globalAnnounceServer>
|
||||
<globalAnnounceEnabled>true</globalAnnounceEnabled>
|
||||
<localAnnounceEnabled>true</localAnnounceEnabled>
|
||||
<parallelRequests>16</parallelRequests>
|
||||
<maxSendKbps>0</maxSendKbps>
|
||||
<rescanIntervalS>60</rescanIntervalS>
|
||||
<reconnectionIntervalS>60</reconnectionIntervalS>
|
||||
<maxChangeKbps>1000</maxChangeKbps>
|
||||
<startBrowser>false</startBrowser>
|
||||
<upnpEnabled>true</upnpEnabled>
|
||||
</options>
|
||||
<gui enabled="true">
|
||||
<address>127.0.0.1:8080</address>
|
||||
</gui>
|
||||
<options>
|
||||
<listenAddress>0.0.0.0:22000</listenAddress>
|
||||
<globalAnnounceServer>194.126.249.5:22026</globalAnnounceServer>
|
||||
<globalAnnounceEnabled>true</globalAnnounceEnabled>
|
||||
<localAnnounceEnabled>true</localAnnounceEnabled>
|
||||
<parallelRequests>16</parallelRequests>
|
||||
<maxSendKbps>0</maxSendKbps>
|
||||
<rescanIntervalS>60</rescanIntervalS>
|
||||
<reconnectionIntervalS>60</reconnectionIntervalS>
|
||||
<maxChangeKbps>1000</maxChangeKbps>
|
||||
<startBrowser>false</startBrowser>
|
||||
<upnpEnabled>true</upnpEnabled>
|
||||
</options>
|
||||
</configuration>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="AppTheme" parent="@style/Theme.AppCompat.Light.DarkActionBar" />
|
||||
|
||||
<style name="AppTheme" parent="@style/Theme.AppCompat.Light.DarkActionBar" />
|
||||
</resources>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="text_red">#ffff4444</color>
|
||||
<color name="text_blue">#ff33b5e5</color>
|
||||
<color name="text_green">#ff99cc00</color>
|
||||
</resources>
|
||||
<color name="text_red">#ffff4444</color>
|
||||
<color name="text_blue">#ff33b5e5</color>
|
||||
<color name="text_green">#ff99cc00</color>
|
||||
</resources>
|
||||
|
|
|
@ -1,234 +1,234 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="app_name">Syncthing</string>
|
||||
<string name="app_name">Syncthing</string>
|
||||
|
||||
<!-- MainActivity -->
|
||||
<!-- MainActivity -->
|
||||
|
||||
|
||||
<!-- Title of the "add repo" menu action -->
|
||||
<string name="add_repo">Add Repository</string>
|
||||
<!-- Title of the "add repo" menu action -->
|
||||
<string name="add_repo">Add Repository</string>
|
||||
|
||||
<!-- Title of the "share node id" menu action -->
|
||||
<string name="share_node_id">Share Node ID</string>
|
||||
<!-- Title of the "share node id" menu action -->
|
||||
<string name="share_node_id">Share Node ID</string>
|
||||
|
||||
<!-- Shown in the chooser dialog when sharing a Node ID -->
|
||||
<string name="send_node_id_to">Send Node ID to</string>
|
||||
<!-- Shown in the chooser dialog when sharing a Node ID -->
|
||||
<string name="send_node_id_to">Send Node ID to</string>
|
||||
|
||||
<!-- Text for RepositoriesFragment and NodesFragment loading view -->
|
||||
<string name="api_loading">Waiting for API</string>
|
||||
<!-- Text for RepositoriesFragment and NodesFragment loading view -->
|
||||
<string name="api_loading">Waiting for API</string>
|
||||
|
||||
<!-- RepositoriesFragment -->
|
||||
<!-- RepositoriesFragment -->
|
||||
|
||||
|
||||
<string name="repositories_fragment_title">Repositories</string>
|
||||
<string name="repositories_fragment_title">Repositories</string>
|
||||
|
||||
<!-- Format string for repository progress. First parameter is status string, second is sync percentage -->
|
||||
<string name="repo_progress_format">%1$s (%2$d%%)</string>
|
||||
<!-- Format string for repository progress. First parameter is status string, second is sync percentage -->
|
||||
<string name="repo_progress_format">%1$s (%2$d%%)</string>
|
||||
|
||||
<!-- Shown if no repos exist -->
|
||||
<string name="repositories_list_empty">No repositories found</string>
|
||||
<!-- Shown if no repos exist -->
|
||||
<string name="repositories_list_empty">No repositories found</string>
|
||||
|
||||
<!-- Format string for repository file count -->
|
||||
<string name="files">%1$d / %2$d Files</string>
|
||||
<!-- Format string for repository file count -->
|
||||
<string name="files">%1$d / %2$d Files</string>
|
||||
|
||||
<!-- NodesFragment -->
|
||||
<!-- NodesFragment -->
|
||||
|
||||
|
||||
<string name="nodes_fragment_title">Nodes</string>
|
||||
<string name="nodes_fragment_title">Nodes</string>
|
||||
|
||||
<!-- Shown if no nodes exist -->
|
||||
<string name="nodes_list_empty">No nodes found</string>
|
||||
<!-- Shown if no nodes exist -->
|
||||
<string name="nodes_list_empty">No nodes found</string>
|
||||
|
||||
<!-- Indicates that a repo is fully synced to the local node -->
|
||||
<string name="node_up_to_date">Up to Date</string>
|
||||
<!-- Indicates that a repo is fully synced to the local node -->
|
||||
<string name="node_up_to_date">Up to Date</string>
|
||||
|
||||
<!-- Indicates that the node is currently syncing. Parameter is sync percentage -->
|
||||
<string name="node_syncing">Syncing (%1$d%%)</string>
|
||||
<!-- Indicates that the node is currently syncing. Parameter is sync percentage -->
|
||||
<string name="node_syncing">Syncing (%1$d%%)</string>
|
||||
|
||||
<!-- Indicates that there is no connection to the node -->
|
||||
<string name="node_disconnected">Disconnected</string>
|
||||
<!-- Indicates that there is no connection to the node -->
|
||||
<string name="node_disconnected">Disconnected</string>
|
||||
|
||||
<!-- Title for current download rate -->
|
||||
<string name="download_title">Download</string>
|
||||
<!-- Title for current download rate -->
|
||||
<string name="download_title">Download</string>
|
||||
|
||||
<!-- Title for current upload rate -->
|
||||
<string name="upload_title">Upload</string>
|
||||
<!-- Title for current upload rate -->
|
||||
<string name="upload_title">Upload</string>
|
||||
|
||||
<!-- LocalNodeInfoFragment -->
|
||||
<!-- LocalNodeInfoFragment -->
|
||||
|
||||
|
||||
<!-- ActionBar title shown when the drawer is open -->
|
||||
<string name="system_info">System Info</string>
|
||||
<!-- ActionBar title shown when the drawer is open -->
|
||||
<string name="system_info">System Info</string>
|
||||
|
||||
<!-- Same as download_title with a colon and space appended -->
|
||||
<string name="download_title_colon">Download:\u0020</string>
|
||||
<!-- Same as download_title with a colon and space appended -->
|
||||
<string name="download_title_colon">Download:\u0020</string>
|
||||
|
||||
<!-- Same as upload_title with a colon and space appended -->
|
||||
<string name="upload_title_colon">Upload:\u0020</string>
|
||||
<!-- Same as upload_title with a colon and space appended -->
|
||||
<string name="upload_title_colon">Upload:\u0020</string>
|
||||
|
||||
<!-- Title for current CPU usage -->
|
||||
<string name="cpu_usage">CPU Usage</string>
|
||||
<!-- Title for current CPU usage -->
|
||||
<string name="cpu_usage">CPU Usage</string>
|
||||
|
||||
<!-- Title for current RAM usage -->
|
||||
<string name="ram_usage">RAM Usage</string>
|
||||
<!-- Title for current RAM usage -->
|
||||
<string name="ram_usage">RAM Usage</string>
|
||||
|
||||
<!-- Title for announce server status -->
|
||||
<string name="announce_server">Announce Server</string>
|
||||
<!-- Title for announce server status -->
|
||||
<string name="announce_server">Announce Server</string>
|
||||
|
||||
<!-- RepoSettingsFragment -->
|
||||
<!-- RepoSettingsFragment -->
|
||||
|
||||
|
||||
<!-- Setting title -->
|
||||
<string name="repo_id">Repository ID</string>
|
||||
<!-- Setting title -->
|
||||
<string name="repo_id">Repository ID</string>
|
||||
|
||||
<!-- Setting title -->
|
||||
<string name="directory">Directory</string>
|
||||
<!-- Setting title -->
|
||||
<string name="directory">Directory</string>
|
||||
|
||||
<!-- Setting title -->
|
||||
<string name="repo_master">Repository Master</string>
|
||||
<!-- Setting title -->
|
||||
<string name="repo_master">Repository Master</string>
|
||||
|
||||
<!-- Setting title -->
|
||||
<string name="nodes">Nodes</string>
|
||||
<!-- Setting title -->
|
||||
<string name="nodes">Nodes</string>
|
||||
|
||||
<!-- Setting title -->
|
||||
<string name="file_versioning">File Versioning</string>
|
||||
<!-- Setting title -->
|
||||
<string name="file_versioning">File Versioning</string>
|
||||
|
||||
<!-- Setting title -->
|
||||
<string name="keep_versions">Keep Versions</string>
|
||||
<!-- Setting title -->
|
||||
<string name="keep_versions">Keep Versions</string>
|
||||
|
||||
<!-- Setting title -->
|
||||
<string name="delete_repo">Delete Repository</string>
|
||||
<!-- Setting title -->
|
||||
<string name="delete_repo">Delete Repository</string>
|
||||
|
||||
<!-- Title for RepoSettingsFragment in create mode -->
|
||||
<string name="create_repo">Create Repository</string>
|
||||
<!-- Title for RepoSettingsFragment in create mode -->
|
||||
<string name="create_repo">Create Repository</string>
|
||||
|
||||
<!-- Title for RepoSettingsFragment in edit mode -->
|
||||
<string name="edit_repo">Edit Repository</string>
|
||||
<!-- Title for RepoSettingsFragment in edit mode -->
|
||||
<string name="edit_repo">Edit Repository</string>
|
||||
|
||||
<!-- Menu item to confirm repo creation -->
|
||||
<string name="create">Create</string>
|
||||
<!-- Menu item to confirm repo creation -->
|
||||
<string name="create">Create</string>
|
||||
|
||||
<!-- Dialog shown when attempting to delete a repository -->
|
||||
<string name="delete_repo_confirm">Do you really want to delete this repository?</string>
|
||||
<!-- Dialog shown when attempting to delete a repository -->
|
||||
<string name="delete_repo_confirm">Do you really want to delete this repository?</string>
|
||||
|
||||
<!-- Toast shown when trying to create a repository with an empty ID -->
|
||||
<string name="repo_id_required">The repository ID must not be empty</string>
|
||||
<!-- Toast shown when trying to create a repository with an empty ID -->
|
||||
<string name="repo_id_required">The repository ID must not be empty</string>
|
||||
|
||||
<!-- Toast shown when trying to create a repository with an empty path -->
|
||||
<string name="repo_path_required">The repository path must not be empty</string>
|
||||
<!-- Toast shown when trying to create a repository with an empty path -->
|
||||
<string name="repo_path_required">The repository path must not be empty</string>
|
||||
|
||||
<!-- Toast shown when selecting 'nodes' if no nodes have been added -->
|
||||
<string name="no_nodes">Please connect a node first.</string>
|
||||
<!-- Toast shown when selecting 'nodes' if no nodes have been added -->
|
||||
<string name="no_nodes">Please connect a node first.</string>
|
||||
|
||||
<!-- NodeSettingsFragment -->
|
||||
<!-- NodeSettingsFragment -->
|
||||
|
||||
|
||||
<!-- Setting title -->
|
||||
<string name="node_id">Node ID</string>
|
||||
<!-- Setting title -->
|
||||
<string name="node_id">Node ID</string>
|
||||
|
||||
<!-- Setting title -->
|
||||
<string name="name">Name</string>
|
||||
<!-- Setting title -->
|
||||
<string name="name">Name</string>
|
||||
|
||||
<!-- Setting title -->
|
||||
<string name="addresses">Addresses</string>
|
||||
<!-- Setting title -->
|
||||
<string name="addresses">Addresses</string>
|
||||
|
||||
<!-- Setting title -->
|
||||
<string name="current_address">Current Address</string>
|
||||
<!-- Setting title -->
|
||||
<string name="current_address">Current Address</string>
|
||||
|
||||
<!-- Setting title -->
|
||||
<string name="delete_node">Delete Node</string>
|
||||
<!-- Setting title -->
|
||||
<string name="delete_node">Delete Node</string>
|
||||
|
||||
<!-- Title for NodeSettingsFragment in create mode -->
|
||||
<string name="add_node">Add Node</string>
|
||||
<!-- Title for NodeSettingsFragment in create mode -->
|
||||
<string name="add_node">Add Node</string>
|
||||
|
||||
<!-- Menu item to confirm adding a node -->
|
||||
<string name="add">Add</string>
|
||||
<!-- Menu item to confirm adding a node -->
|
||||
<string name="add">Add</string>
|
||||
|
||||
<!-- Title for NodeSettingsFragment in edit mode -->
|
||||
<string name="edit_node">Edit Node</string>
|
||||
<!-- Title for NodeSettingsFragment in edit mode -->
|
||||
<string name="edit_node">Edit Node</string>
|
||||
|
||||
<!-- Dialog shown when attempting to delete a node -->
|
||||
<string name="delete_node_confirm">Do you really want to delete this node?</string>
|
||||
<!-- Dialog shown when attempting to delete a node -->
|
||||
<string name="delete_node_confirm">Do you really want to delete this node?</string>
|
||||
|
||||
<!-- Toast shown when trying to create a node with an empty ID -->
|
||||
<string name="node_id_required">The node ID must not be empty</string>
|
||||
<!-- Toast shown when trying to create a node with an empty ID -->
|
||||
<string name="node_id_required">The node ID must not be empty</string>
|
||||
|
||||
<!-- Toast shown when trying to create a node with an empty name -->
|
||||
<string name="node_name_required">The node name must not be empty</string>
|
||||
<!-- Toast shown when trying to create a node with an empty name -->
|
||||
<string name="node_name_required">The node name must not be empty</string>
|
||||
|
||||
<!-- Content description for node ID qr code icon -->
|
||||
<string name="scan_qr_code_description">Scan QR Code</string>
|
||||
<!-- Content description for node ID qr code icon -->
|
||||
<string name="scan_qr_code_description">Scan QR Code</string>
|
||||
|
||||
<!-- Text for toast shown if the "scan QR code" intent fails with an ActivityNotFoundException -->
|
||||
<!-- Text for toast shown if the "scan QR code" intent fails with an ActivityNotFoundException -->
|
||||
<string name="no_qr_scanner_installed">You have no QR scanner installed or your scanner is not supported. \
|
||||
Please install a scanner or enter the node ID manually.</string>
|
||||
|
||||
<!-- WebGuiActivity -->
|
||||
<!-- WebGuiActivity -->
|
||||
|
||||
|
||||
<!-- Title of the web gui activity -->
|
||||
<string name="web_gui_title">Web GUI</string>
|
||||
<!-- Title of the web gui activity -->
|
||||
<string name="web_gui_title">Web GUI</string>
|
||||
|
||||
<!-- Text for WebGuiActivity loading view -->
|
||||
<string name="web_gui_loading">Waiting for GUI</string>
|
||||
<!-- Text for WebGuiActivity loading view -->
|
||||
<string name="web_gui_loading">Waiting for GUI</string>
|
||||
|
||||
<!-- Shown instead of web_gui_loading if the key does not exist and has to be created -->
|
||||
<string name="web_gui_creating_key">Generating keys. This may take a while.</string>
|
||||
<!-- Shown instead of web_gui_loading if the key does not exist and has to be created -->
|
||||
<string name="web_gui_creating_key">Generating keys. This may take a while.</string>
|
||||
|
||||
<!-- Title for dialog displayed on first start -->
|
||||
<string name="welcome_title">First Start</string>
|
||||
<!-- Title for dialog displayed on first start -->
|
||||
<string name="welcome_title">First Start</string>
|
||||
|
||||
<!-- Text for dialog displayed on first start -->
|
||||
<!-- Text for dialog displayed on first start -->
|
||||
<string name="welcome_text">Welcome to Syncthing for Android!\n\n\
|
||||
This app is currently in Alpha state, and you may experience bugs, performance problems or data loss.\n\n\
|
||||
There is currently no special handling for mobile data, so it may use up your data volume if active.\n\n\
|
||||
Please report any problems you encounter.</string>
|
||||
|
||||
<!-- SettingsFragment -->
|
||||
<!-- SettingsFragment -->
|
||||
|
||||
|
||||
<!-- Activity title -->
|
||||
<string name="settings_title">Settings</string>
|
||||
<!-- Activity title -->
|
||||
<string name="settings_title">Settings</string>
|
||||
|
||||
<string name="stop_sync_while_not_charging">Stop sync when not charging</string>
|
||||
<string name="stop_sync_while_not_charging">Stop sync when not charging</string>
|
||||
|
||||
<string name="stop_sync_on_mobile_data">Stop sync on mobile data</string>
|
||||
<string name="stop_sync_on_mobile_data">Stop sync on mobile data</string>
|
||||
|
||||
<!-- Settings item that opens issue tracker -->
|
||||
<string name="report_issue_title">Report Issue</string>
|
||||
<!-- Settings item that opens issue tracker -->
|
||||
<string name="report_issue_title">Report Issue</string>
|
||||
|
||||
<!-- Summary for the issue tracker settings item -->
|
||||
<string name="report_issue_summary">Open the Syncthing-Android issue tracker</string>
|
||||
<!-- Summary for the issue tracker settings item -->
|
||||
<string name="report_issue_summary">Open the Syncthing-Android issue tracker</string>
|
||||
|
||||
<!-- URL of the issue tracker -->
|
||||
<string name="issue_tracker_url" translatable="false">https://github.com/Nutomic/syncthing-android/issues</string>
|
||||
<!-- URL of the issue tracker -->
|
||||
<string name="issue_tracker_url" translatable="false">https://github.com/Nutomic/syncthing-android/issues</string>
|
||||
|
||||
<!-- Title of the preference showing upstream version name -->
|
||||
<string name="syncthing_version_title">Syncthing Version</string>
|
||||
<!-- Title of the preference showing upstream version name -->
|
||||
<string name="syncthing_version_title">Syncthing Version</string>
|
||||
|
||||
<!-- FolderPickerAcitivity -->
|
||||
<!-- FolderPickerAcitivity -->
|
||||
|
||||
|
||||
<!-- Activity title -->
|
||||
<string name="folder_picker_title">Folder Picker</string>
|
||||
<!-- Activity title -->
|
||||
<string name="folder_picker_title">Folder Picker</string>
|
||||
|
||||
<!-- ListView empty text -->
|
||||
<string name="directory_empty">Directory is Empty</string>
|
||||
<!-- ListView empty text -->
|
||||
<string name="directory_empty">Directory is Empty</string>
|
||||
|
||||
<!-- Menu item to create folder -->
|
||||
<string name="create_folder">Create new Folder</string>
|
||||
<!-- Menu item to create folder -->
|
||||
<string name="create_folder">Create new Folder</string>
|
||||
|
||||
<!-- Menu item to select the current folder -->
|
||||
<string name="select_folder">Select Folder</string>
|
||||
<!-- Menu item to select the current folder -->
|
||||
<string name="select_folder">Select Folder</string>
|
||||
|
||||
<!-- SyncthingService -->
|
||||
<!-- SyncthingService -->
|
||||
|
||||
<!-- Title of the dialog shown when the syncthing binary returns an error -->
|
||||
<string name="binary_crashed_title">Syncthing Binary Crashed</string>
|
||||
<!-- Title of the dialog shown when the syncthing binary returns an error -->
|
||||
<string name="binary_crashed_title">Syncthing Binary Crashed</string>
|
||||
|
||||
|
||||
<!-- Message of the dialog shown when the syncthing binary returns an error -->
|
||||
<!-- Message of the dialog shown when the syncthing binary returns an error -->
|
||||
<string name="binary_crashed_message">The syncthing binary has exited with error code %1$d.\n\n
|
||||
If this error persists, try reinstalling the app and restarting your device.\n\n</string>
|
||||
|
||||
|
@ -238,43 +238,43 @@ If this error persists, try reinstalling the app and restarting your device.\n\n
|
|||
<!-- Message of the "syncthing disabled" dialog -->
|
||||
<string name="syncthing_disabled_message">Do you want to change your preferences?</string>
|
||||
|
||||
<!-- Button text on the "syncthing disabled" dialog -->
|
||||
<!-- Button text on the "syncthing disabled" dialog -->
|
||||
<string name="syncthing_disabled_change_settings">Change Settings</string>
|
||||
|
||||
<!-- Button text on the "syncthing disabled" dialog -->
|
||||
<string name="exit">Exit</string>
|
||||
<!-- Button text on the "syncthing disabled" dialog -->
|
||||
<string name="exit">Exit</string>
|
||||
|
||||
<!-- RestApi -->
|
||||
<!-- RestApi -->
|
||||
|
||||
|
||||
<!-- Title of the notification shown when a restart is needed -->
|
||||
<string name="restart_title">Restart Needed</string>
|
||||
<!-- Title of the notification shown when a restart is needed -->
|
||||
<string name="restart_title">Restart Needed</string>
|
||||
|
||||
<!-- Text of the notification shown when a restart is needed -->
|
||||
<string name="restart_notification_text">Click here to restart syncthing now</string>
|
||||
<!-- Text of the notification shown when a restart is needed -->
|
||||
<string name="restart_notification_text">Click here to restart syncthing now</string>
|
||||
|
||||
<!-- Text for the dismiss button of the restart Activity -->
|
||||
<string name="restart_later">Restart Later</string>
|
||||
<!-- Text for the dismiss button of the restart Activity -->
|
||||
<string name="restart_later">Restart Later</string>
|
||||
|
||||
<!-- Shown when a node ID is copied to the clipboard -->
|
||||
<string name="node_id_copied_to_clipboard">Node ID copied to clipboard</string>
|
||||
<!-- Shown when a node ID is copied to the clipboard -->
|
||||
<string name="node_id_copied_to_clipboard">Node ID copied to clipboard</string>
|
||||
|
||||
<!-- Strings representing units for file sizes, from smallest to largest -->
|
||||
<string-array name="file_size_units">
|
||||
<item>B</item>
|
||||
<item>KB</item>
|
||||
<item>MB</item>
|
||||
<item>GB</item>
|
||||
<item>TB</item>
|
||||
</string-array>
|
||||
<!-- Strings representing units for file sizes, from smallest to largest -->
|
||||
<string-array name="file_size_units">
|
||||
<item>B</item>
|
||||
<item>KB</item>
|
||||
<item>MB</item>
|
||||
<item>GB</item>
|
||||
<item>TB</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Strings representing units for transfer rates, from smallest to largest -->
|
||||
<string-array name="transfer_rate_units">
|
||||
<item>b/s</item>
|
||||
<item>Kb/s</item>
|
||||
<item>Mb/s</item>
|
||||
<item>Gb/s</item>
|
||||
<item>Tb/s</item>
|
||||
</string-array>
|
||||
<!-- Strings representing units for transfer rates, from smallest to largest -->
|
||||
<string-array name="transfer_rate_units">
|
||||
<item>b/s</item>
|
||||
<item>Kb/s</item>
|
||||
<item>Mb/s</item>
|
||||
<item>Gb/s</item>
|
||||
<item>Tb/s</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="AppTheme" parent="@style/Theme.AppCompat" />
|
||||
</resources>
|
||||
|
||||
<style name="AppTheme" parent="@style/Theme.AppCompat" />
|
||||
</resources>
|
||||
|
|
|
@ -1,106 +1,106 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="stop_sync_while_not_charging"
|
||||
android:title="@string/stop_sync_while_not_charging"
|
||||
android:defaultValue="true" />
|
||||
<CheckBoxPreference
|
||||
android:key="stop_sync_while_not_charging"
|
||||
android:title="@string/stop_sync_while_not_charging"
|
||||
android:defaultValue="true" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="stop_sync_on_mobile_data"
|
||||
android:title="@string/stop_sync_on_mobile_data"
|
||||
android:defaultValue="true" />
|
||||
<CheckBoxPreference
|
||||
android:key="stop_sync_on_mobile_data"
|
||||
android:title="@string/stop_sync_on_mobile_data"
|
||||
android:defaultValue="true" />
|
||||
|
||||
<PreferenceScreen
|
||||
android:key="syncthing_options"
|
||||
android:title="Syncthing Options"
|
||||
android:persistent="false" >
|
||||
<PreferenceScreen
|
||||
android:key="syncthing_options"
|
||||
android:title="Syncthing Options"
|
||||
android:persistent="false">
|
||||
|
||||
<EditTextPreference
|
||||
android:key="ListenAddress"
|
||||
android:title="Sync Protocol Listen Addresses"
|
||||
android:defaultValue="0.0.0.0:22000" />
|
||||
<EditTextPreference
|
||||
android:key="ListenAddress"
|
||||
android:title="Sync Protocol Listen Addresses"
|
||||
android:defaultValue="0.0.0.0:22000" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="MaxSendKbps"
|
||||
android:title="Outgoing Rate Limit (KiB/s)"
|
||||
android:numeric="integer" />
|
||||
<EditTextPreference
|
||||
android:key="MaxSendKbps"
|
||||
android:title="Outgoing Rate Limit (KiB/s)"
|
||||
android:numeric="integer" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="RescanIntervalS"
|
||||
android:title="Rescan Interval (s)"
|
||||
android:numeric="integer" />
|
||||
<EditTextPreference
|
||||
android:key="RescanIntervalS"
|
||||
android:title="Rescan Interval (s)"
|
||||
android:numeric="integer" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="ReconnectIntervalS"
|
||||
android:title="Reconnect Interval (s)"
|
||||
android:numeric="integer" />
|
||||
<EditTextPreference
|
||||
android:key="ReconnectIntervalS"
|
||||
android:title="Reconnect Interval (s)"
|
||||
android:numeric="integer" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="ParallelRequests"
|
||||
android:title="Max Outstanding Requests"
|
||||
android:numeric="integer" />
|
||||
<EditTextPreference
|
||||
android:key="ParallelRequests"
|
||||
android:title="Max Outstanding Requests"
|
||||
android:numeric="integer" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="MaxChangeKbps"
|
||||
android:title="Max File Change Rate (KiB/s)"
|
||||
android:numeric="integer" />
|
||||
<EditTextPreference
|
||||
android:key="MaxChangeKbps"
|
||||
android:title="Max File Change Rate (KiB/s)"
|
||||
android:numeric="integer" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="GlobalAnnEnabled"
|
||||
android:title="Global Discovery" />
|
||||
<CheckBoxPreference
|
||||
android:key="GlobalAnnEnabled"
|
||||
android:title="Global Discovery" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="LocalAnnEnabled"
|
||||
android:title="Local Discovery" />
|
||||
<CheckBoxPreference
|
||||
android:key="LocalAnnEnabled"
|
||||
android:title="Local Discovery" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="LocalAnnPort"
|
||||
android:title="Local Discovery Port"
|
||||
android:numeric="integer" />
|
||||
<EditTextPreference
|
||||
android:key="LocalAnnPort"
|
||||
android:title="Local Discovery Port"
|
||||
android:numeric="integer" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="UPnPEnabled"
|
||||
android:title="Enable UPnP" />
|
||||
<CheckBoxPreference
|
||||
android:key="UPnPEnabled"
|
||||
android:title="Enable UPnP" />
|
||||
|
||||
</PreferenceScreen>
|
||||
</PreferenceScreen>
|
||||
|
||||
<PreferenceScreen
|
||||
android:key="syncthing_gui"
|
||||
android:title="Syncthing GUI"
|
||||
android:persistent="false" >
|
||||
<PreferenceScreen
|
||||
android:key="syncthing_gui"
|
||||
android:title="Syncthing GUI"
|
||||
android:persistent="false">
|
||||
|
||||
<EditTextPreference
|
||||
android:key="Address"
|
||||
android:title="GUI Listen Addresses" />
|
||||
<EditTextPreference
|
||||
android:key="Address"
|
||||
android:title="GUI Listen Addresses" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="User"
|
||||
android:title="GUI Authentication User" />
|
||||
<EditTextPreference
|
||||
android:key="User"
|
||||
android:title="GUI Authentication User" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="Password"
|
||||
android:title="GUI Authentication Password"
|
||||
android:inputType="textPassword" />
|
||||
<EditTextPreference
|
||||
android:key="Password"
|
||||
android:title="GUI Authentication Password"
|
||||
android:inputType="textPassword" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="UseTLS"
|
||||
android:title="Use HTTPS for GUI"
|
||||
android:enabled="false" />
|
||||
<CheckBoxPreference
|
||||
android:key="UseTLS"
|
||||
android:title="Use HTTPS for GUI"
|
||||
android:enabled="false" />
|
||||
|
||||
</PreferenceScreen>
|
||||
</PreferenceScreen>
|
||||
|
||||
<Preference
|
||||
android:title="@string/report_issue_title"
|
||||
android:summary="@string/report_issue_summary" >
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="@string/issue_tracker_url" />
|
||||
</Preference>
|
||||
<Preference
|
||||
android:title="@string/report_issue_title"
|
||||
android:summary="@string/report_issue_summary">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="@string/issue_tracker_url" />
|
||||
</Preference>
|
||||
|
||||
<Preference
|
||||
android:key="syncthing_version"
|
||||
android:title="@string/syncthing_version_title"
|
||||
style="?android:preferenceInformationStyle" />
|
||||
<Preference
|
||||
android:key="syncthing_version"
|
||||
android:title="@string/syncthing_version_title"
|
||||
style="?android:preferenceInformationStyle" />
|
||||
|
||||
</PreferenceScreen>
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:persistent="false" >
|
||||
android:persistent="false">
|
||||
|
||||
<EditTextPreference
|
||||
android:key="node_id"
|
||||
android:title="@string/node_id"
|
||||
android:widgetLayout="@layout/scan_qr_code_widget" />
|
||||
<EditTextPreference
|
||||
android:key="node_id"
|
||||
android:title="@string/node_id"
|
||||
android:widgetLayout="@layout/scan_qr_code_widget" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="name"
|
||||
android:title="@string/name" />
|
||||
<EditTextPreference
|
||||
android:key="name"
|
||||
android:title="@string/name" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="addresses"
|
||||
android:title="@string/addresses" />
|
||||
<EditTextPreference
|
||||
android:key="addresses"
|
||||
android:title="@string/addresses" />
|
||||
|
||||
</PreferenceScreen>
|
||||
</PreferenceScreen>
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:persistent="false" >
|
||||
android:persistent="false">
|
||||
|
||||
<Preference
|
||||
android:key="node_id"
|
||||
android:title="@string/node_id"/>
|
||||
<Preference
|
||||
android:key="node_id"
|
||||
android:title="@string/node_id" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="name"
|
||||
android:title="@string/name" />
|
||||
<EditTextPreference
|
||||
android:key="name"
|
||||
android:title="@string/name" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="addresses"
|
||||
android:title="@string/addresses" />
|
||||
<EditTextPreference
|
||||
android:key="addresses"
|
||||
android:title="@string/addresses" />
|
||||
|
||||
<Preference
|
||||
android:key="version"
|
||||
android:title="@string/syncthing_version_title"
|
||||
style="?android:preferenceInformationStyle" />
|
||||
<Preference
|
||||
android:key="version"
|
||||
android:title="@string/syncthing_version_title"
|
||||
style="?android:preferenceInformationStyle" />
|
||||
|
||||
<Preference
|
||||
android:key="current_address"
|
||||
android:title="@string/current_address"
|
||||
style="?android:preferenceInformationStyle" />
|
||||
<Preference
|
||||
android:key="current_address"
|
||||
android:title="@string/current_address"
|
||||
style="?android:preferenceInformationStyle" />
|
||||
|
||||
</PreferenceScreen>
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:persistent="false" >
|
||||
android:persistent="false">
|
||||
|
||||
<EditTextPreference
|
||||
android:key="repo_id"
|
||||
android:title="@string/repo_id" />
|
||||
<EditTextPreference
|
||||
android:key="repo_id"
|
||||
android:title="@string/repo_id" />
|
||||
|
||||
<Preference
|
||||
android:key="directory"
|
||||
android:title="@string/directory" />
|
||||
<Preference
|
||||
android:key="directory"
|
||||
android:title="@string/directory" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="repo_master"
|
||||
android:title="@string/repo_master" />
|
||||
<CheckBoxPreference
|
||||
android:key="repo_master"
|
||||
android:title="@string/repo_master" />
|
||||
|
||||
<PreferenceScreen
|
||||
android:key="nodes"
|
||||
android:title="@string/nodes" />
|
||||
<PreferenceScreen
|
||||
android:key="nodes"
|
||||
android:title="@string/nodes" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="versioning"
|
||||
android:title="@string/file_versioning" />
|
||||
<CheckBoxPreference
|
||||
android:key="versioning"
|
||||
android:title="@string/file_versioning" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="versioning_keep"
|
||||
android:title="@string/keep_versions"
|
||||
android:inputType="numberDecimal" />
|
||||
<EditTextPreference
|
||||
android:key="versioning_keep"
|
||||
android:title="@string/keep_versions"
|
||||
android:inputType="numberDecimal" />
|
||||
|
||||
</PreferenceScreen>
|
||||
</PreferenceScreen>
|
||||
|
|
|
@ -1,34 +1,34 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:persistent="false" >
|
||||
android:persistent="false">
|
||||
|
||||
<EditTextPreference
|
||||
android:key="repo_id"
|
||||
android:title="@string/repo_id"
|
||||
android:enabled="false"
|
||||
style="?android:preferenceInformationStyle" />
|
||||
<EditTextPreference
|
||||
android:key="repo_id"
|
||||
android:title="@string/repo_id"
|
||||
android:enabled="false"
|
||||
style="?android:preferenceInformationStyle" />
|
||||
|
||||
<Preference
|
||||
android:key="directory"
|
||||
android:title="@string/directory"
|
||||
android:enabled="false"
|
||||
style="?android:preferenceInformationStyle" />
|
||||
<Preference
|
||||
android:key="directory"
|
||||
android:title="@string/directory"
|
||||
android:enabled="false"
|
||||
style="?android:preferenceInformationStyle" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="repo_master"
|
||||
android:title="@string/repo_master" />
|
||||
<CheckBoxPreference
|
||||
android:key="repo_master"
|
||||
android:title="@string/repo_master" />
|
||||
|
||||
<PreferenceScreen
|
||||
android:key="nodes"
|
||||
android:title="@string/nodes" />
|
||||
<PreferenceScreen
|
||||
android:key="nodes"
|
||||
android:title="@string/nodes" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="versioning"
|
||||
android:title="File Versioning" />
|
||||
<CheckBoxPreference
|
||||
android:key="versioning"
|
||||
android:title="File Versioning" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="versioning_keep"
|
||||
android:title="@string/keep_versions"
|
||||
android:inputType="numberDecimal" />
|
||||
<EditTextPreference
|
||||
android:key="versioning_keep"
|
||||
android:title="@string/keep_versions"
|
||||
android:inputType="numberDecimal" />
|
||||
|
||||
</PreferenceScreen>
|
||||
|
|
Loading…
Reference in a new issue