diff --git a/build.gradle b/build.gradle
index f8d79b67..701103fe 100644
--- a/build.gradle
+++ b/build.gradle
@@ -95,7 +95,7 @@ def getVersionCodeFromManifest() {
return Integer.parseInt(matcher.group(1))
}
-task buildNative(type:Exec) {
+task buildNative(type: Exec) {
outputs.upToDateWhen { false }
executable = './build-native.sh'
}
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index d7af018d..d7553221 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -1,32 +1,33 @@
-
+
-
+
-
+
-
+
-
@@ -34,7 +35,6 @@
android:name="android.support.PARENT_ACTIVITY"
android:value=".gui.MainActivity" />
-
@@ -47,19 +47,28 @@
+ android:theme="@style/DialogWhenLarge" >
-
+ android:theme="@style/DialogWhenLarge" >
-
+
+
+
+
-
+
+
diff --git a/src/main/java/com/nutomic/syncthingandroid/gui/FolderPickerActivity.java b/src/main/java/com/nutomic/syncthingandroid/gui/FolderPickerActivity.java
new file mode 100644
index 00000000..c40166b6
--- /dev/null
+++ b/src/main/java/com/nutomic/syncthingandroid/gui/FolderPickerActivity.java
@@ -0,0 +1,207 @@
+package com.nutomic.syncthingandroid.gui;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.IBinder;
+import android.support.v7.app.ActionBarActivity;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import com.nutomic.syncthingandroid.R;
+import com.nutomic.syncthingandroid.syncthing.SyncthingService;
+import com.nutomic.syncthingandroid.syncthing.SyncthingServiceBinder;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Stack;
+
+/**
+ * Activity that allows selecting a directory in the local file system.
+ */
+public class FolderPickerActivity extends ActionBarActivity
+ implements AdapterView.OnItemClickListener, SyncthingService.OnApiChangeListener {
+
+ private static final String TAG = "FolderPickerActivity";
+
+ public static final String EXTRA_INITIAL_DIRECTORY = "initial_directory";
+
+ public static final String EXTRA_RESULT_DIRECTORY = "result_directory";
+
+ private ListView mListView;
+
+ private FileAdapter mAdapter;
+
+ private File mLocation;
+
+ private SyncthingService mSyncthingService;
+
+ private final ServiceConnection mSyncthingServiceConnection = new ServiceConnection() {
+
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ SyncthingServiceBinder binder = (SyncthingServiceBinder) service;
+ mSyncthingService = binder.getService();
+ mSyncthingService.registerOnApiChangeListener(FolderPickerActivity.this);
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ mSyncthingService = null;
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ 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);
+
+ mLocation = new File(getIntent().getStringExtra(EXTRA_INITIAL_DIRECTORY));
+ refresh();
+
+ bindService(new Intent(this, SyncthingService.class),
+ mSyncthingServiceConnection, Context.BIND_AUTO_CREATE);
+ }
+
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.folder_picker, menu);
+ return true;
+ }
+
+ @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;
+ 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();
+ }
+
+ /**
+ * 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();
+ }
+
+ private class FileAdapter extends ArrayAdapter {
+
+ 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);
+ }
+
+ 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 onApiChange(boolean isAvailable) {
+ if (!isAvailable) {
+ setResult(Activity.RESULT_CANCELED);
+ finish();
+ }
+ }
+
+}
diff --git a/src/main/java/com/nutomic/syncthingandroid/gui/MainActivity.java b/src/main/java/com/nutomic/syncthingandroid/gui/MainActivity.java
index 86597da5..1fec1c32 100644
--- a/src/main/java/com/nutomic/syncthingandroid/gui/MainActivity.java
+++ b/src/main/java/com/nutomic/syncthingandroid/gui/MainActivity.java
@@ -16,7 +16,6 @@ import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
-import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;
import android.support.v4.widget.DrawerLayout;
@@ -24,14 +23,10 @@ import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBar.Tab;
import android.support.v7.app.ActionBar.TabListener;
import android.support.v7.app.ActionBarActivity;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
-import android.view.OrientationEventListener;
import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.ProgressBar;
import android.widget.TextView;
import com.nutomic.syncthingandroid.R;
@@ -243,7 +238,7 @@ public class MainActivity extends ActionBarActivity
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.main_menu, menu);
+ getMenuInflater().inflate(R.menu.main, menu);
return true;
}
diff --git a/src/main/java/com/nutomic/syncthingandroid/gui/NodeSettingsActivity.java b/src/main/java/com/nutomic/syncthingandroid/gui/NodeSettingsActivity.java
index 35a91530..9848dbd2 100644
--- a/src/main/java/com/nutomic/syncthingandroid/gui/NodeSettingsActivity.java
+++ b/src/main/java/com/nutomic/syncthingandroid/gui/NodeSettingsActivity.java
@@ -131,7 +131,7 @@ public class NodeSettingsActivity extends PreferenceActivity implements
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.node_settings_menu, menu);
+ getMenuInflater().inflate(R.menu.node_settings, menu);
return super.onCreateOptionsMenu(menu);
}
diff --git a/src/main/java/com/nutomic/syncthingandroid/gui/RepoSettingsActivity.java b/src/main/java/com/nutomic/syncthingandroid/gui/RepoSettingsActivity.java
index 37a4723f..cbb688ab 100644
--- a/src/main/java/com/nutomic/syncthingandroid/gui/RepoSettingsActivity.java
+++ b/src/main/java/com/nutomic/syncthingandroid/gui/RepoSettingsActivity.java
@@ -1,5 +1,6 @@
package com.nutomic.syncthingandroid.gui;
+import android.app.Activity;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
@@ -7,6 +8,7 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
+import android.os.Environment;
import android.os.IBinder;
import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
@@ -33,6 +35,8 @@ public class RepoSettingsActivity extends PreferenceActivity
implements Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener,
SyncthingService.OnApiChangeListener {
+ private static final int DIRECTORY_REQUEST_CODE = 234;
+
public static final String ACTION_CREATE = "create";
public static final String ACTION_EDIT = "edit";
@@ -60,7 +64,7 @@ public class RepoSettingsActivity extends PreferenceActivity
private EditTextPreference mRepoId;
- private EditTextPreference mDirectory;
+ private Preference mDirectory;
private CheckBoxPreference mRepoMaster;
@@ -85,8 +89,8 @@ public class RepoSettingsActivity extends PreferenceActivity
mRepoId = (EditTextPreference) findPreference("repo_id");
mRepoId.setOnPreferenceChangeListener(this);
- mDirectory = (EditTextPreference) findPreference("directory");
- mDirectory.setOnPreferenceChangeListener(this);
+ mDirectory = findPreference("directory");
+ mDirectory.setOnPreferenceClickListener(this);
mRepoMaster = (CheckBoxPreference) findPreference("repo_master");
mRepoMaster.setOnPreferenceChangeListener(this);
mNodes = (PreferenceScreen) findPreference("nodes");
@@ -131,7 +135,6 @@ public class RepoSettingsActivity extends PreferenceActivity
mRepoId.setText(mRepo.ID);
mRepoId.setSummary(mRepo.ID);
- mDirectory.setText(mRepo.Directory);
mDirectory.setSummary(mRepo.Directory);
mRepoMaster.setChecked(mRepo.ReadOnly);
List nodesList = mSyncthingService.getApi().getNodes();
@@ -162,7 +165,7 @@ public class RepoSettingsActivity extends PreferenceActivity
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.repo_settings_menu, menu);
+ getMenuInflater().inflate(R.menu.repo_settings, menu);
return super.onCreateOptionsMenu(menu);
}
@@ -262,7 +265,15 @@ public class RepoSettingsActivity extends PreferenceActivity
@Override
public boolean onPreferenceClick(Preference preference) {
- if (preference.equals(mDelete)) {
+ if (preference.equals(mDirectory)) {
+ Intent intent = new Intent(this, 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(mDelete)) {
new AlertDialog.Builder(this)
.setMessage(R.string.delete_repo_confirm)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
@@ -279,6 +290,15 @@ public class RepoSettingsActivity extends PreferenceActivity
return false;
}
+ @Override
+ protected 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 (getIntent().getAction().equals(ACTION_EDIT)) {
mSyncthingService.getApi().editRepo(mRepo, false);
diff --git a/src/main/java/com/nutomic/syncthingandroid/util/ConfigXml.java b/src/main/java/com/nutomic/syncthingandroid/util/ConfigXml.java
index 8f9467f9..476b739f 100644
--- a/src/main/java/com/nutomic/syncthingandroid/util/ConfigXml.java
+++ b/src/main/java/com/nutomic/syncthingandroid/util/ConfigXml.java
@@ -96,16 +96,25 @@ public class ConfigXml {
changed = true;
}
- // Set ignorePerms attribute.
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;
+ }
}
if (changed) {
diff --git a/src/main/java/com/nutomic/syncthingandroid/util/ReposAdapter.java b/src/main/java/com/nutomic/syncthingandroid/util/ReposAdapter.java
index d580597d..0a444117 100644
--- a/src/main/java/com/nutomic/syncthingandroid/util/ReposAdapter.java
+++ b/src/main/java/com/nutomic/syncthingandroid/util/ReposAdapter.java
@@ -23,7 +23,7 @@ public class ReposAdapter extends ArrayAdapter
private HashMap mModels = new HashMap();
public ReposAdapter(Context context) {
- super(context, R.layout.node_list_item);
+ super(context, R.layout.repo_list_item);
}
@Override
diff --git a/src/main/res/layout/folder_picker_activity.xml b/src/main/res/layout/folder_picker_activity.xml
new file mode 100644
index 00000000..83c003de
--- /dev/null
+++ b/src/main/res/layout/folder_picker_activity.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
diff --git a/src/main/res/menu/folder_picker.xml b/src/main/res/menu/folder_picker.xml
new file mode 100644
index 00000000..b6383bc8
--- /dev/null
+++ b/src/main/res/menu/folder_picker.xml
@@ -0,0 +1,13 @@
+
+
+
\ No newline at end of file
diff --git a/src/main/res/menu/main_menu.xml b/src/main/res/menu/main.xml
similarity index 100%
rename from src/main/res/menu/main_menu.xml
rename to src/main/res/menu/main.xml
diff --git a/src/main/res/menu/node_settings_menu.xml b/src/main/res/menu/node_settings.xml
similarity index 100%
rename from src/main/res/menu/node_settings_menu.xml
rename to src/main/res/menu/node_settings.xml
diff --git a/src/main/res/menu/repo_settings_menu.xml b/src/main/res/menu/repo_settings.xml
similarity index 100%
rename from src/main/res/menu/repo_settings_menu.xml
rename to src/main/res/menu/repo_settings.xml
diff --git a/src/main/res/values-large/styles.xml b/src/main/res/values-large/styles.xml
index 44272522..b7e42215 100644
--- a/src/main/res/values-large/styles.xml
+++ b/src/main/res/values-large/styles.xml
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 916143e2..f26383da 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -14,6 +14,7 @@
+
Add Repository
@@ -63,6 +64,7 @@
+
Download:\u0020
@@ -80,6 +82,7 @@
+
Repository ID
@@ -97,7 +100,6 @@
Keep Versions
-
Delete Repository
@@ -120,6 +122,7 @@
+
Node ID
@@ -152,6 +155,7 @@
+
Web GUI
@@ -171,11 +175,11 @@
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.
-
+Please report any problems you encounter.
+
Settings
@@ -190,8 +194,16 @@ Please report any problems you encounter.
Syncthing Version
+
+
+
+ Directory is Empty
+
+ Create new Folder
+
+
- B
@@ -210,4 +222,8 @@ Please report any problems you encounter.
- Tb/s
+ FolderPickerActivity
+ Hello world!
+ Settings
+
diff --git a/src/main/res/values/styles.xml b/src/main/res/values/styles.xml
index 161f6d2e..12ed96ab 100644
--- a/src/main/res/values/styles.xml
+++ b/src/main/res/values/styles.xml
@@ -1,6 +1,6 @@
-