mirror of
https://github.com/syncthing/syncthing-android.git
synced 2025-01-10 20:15:54 +00:00
Improvements for "save to Syncthing" (#939)
* Addressing #899 and #898. Added Subdirectory browsing The previously selected folder is remembered. The subdirectory is remembered for each syncthing folder. The saved subdirectory in the sharedpreferences is deleted when a folder is deleted. The root directory of the folderpicker activity is set to the synced folder, so the user can only choose a subfolder within the folder that is being synced. The folderpicker activity was modified inorder to allow for a custom root directroy to be set. * Addressing change requests. Spelling and formatting. * Addressing change requests. - The saved folder subdirectory is now deleted in RestApi.removeFolder(), this ensure that the data will be deleted no matter where removeFolder() is called from. - FolderPickerActivity.createIntentWithRootDir() removed and its functionality moved to FolderPickerActivity.createIntent() inorder to simplify the code. - getSharedPreference has been replaced with PreferenceManager.getDefaultSharedPreferences. - When passing the directory to CopyFileTask getSavedSubdirectory() is now used, instead of getting the text from the textview. This is cleaner and ensures that the same method us used to get the saved subdirectory everywhere in the ShareActivity. - File is used to combine the folder path and subdirectory path instead of strings. This ensures that the paths are properly combined. As a result of this CopyFilesTask has been modified so it accepts a File instead of a String. * Addressing change requests - Removed the preceding slash from the sub directory and added a trailing slash. - TextView now diplays a message when no sub directory is selected. - A separate browse button has been added. * Fixes UI for all screen sizes in the share activity and adds helper method for formatting file paths. If there is not space for the save and cancel buttons then the view becomes scrollable so the buttons can be reached.
This commit is contained in:
parent
3bec05f718
commit
d6ee33e48e
8 changed files with 285 additions and 78 deletions
|
@ -141,7 +141,7 @@ public class FolderActivity extends SyncthingActivity
|
|||
mEditIgnores = findViewById(R.id.edit_ignores);
|
||||
|
||||
mPathView.setOnClickListener(view ->
|
||||
startActivityForResult(FolderPickerActivity.createIntent(this, mFolder.path), FolderPickerActivity.DIRECTORY_REQUEST_CODE));
|
||||
startActivityForResult(FolderPickerActivity.createIntent(this, mFolder.path, null), FolderPickerActivity.DIRECTORY_REQUEST_CODE));
|
||||
|
||||
findViewById(R.id.versioningContainer).setOnClickListener(v -> showVersioningDialog());
|
||||
mEditIgnores.setOnClickListener(v -> editIgnores());
|
||||
|
|
|
@ -11,9 +11,12 @@ import android.os.Build;
|
|||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.IBinder;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
@ -30,6 +33,9 @@ import com.google.common.collect.Sets;
|
|||
import com.nutomic.syncthingandroid.R;
|
||||
import com.nutomic.syncthingandroid.SyncthingApp;
|
||||
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||
import com.nutomic.syncthingandroid.util.Util;
|
||||
|
||||
import org.w3c.dom.Text;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
@ -48,6 +54,9 @@ public class FolderPickerActivity extends SyncthingActivity
|
|||
private static final String EXTRA_INITIAL_DIRECTORY =
|
||||
"com.nutomic.syncthingandroid.activities.FolderPickerActivity.INITIAL_DIRECTORY";
|
||||
|
||||
public static final String EXTRA_ROOT_DIRECTORY =
|
||||
"com.nutomic.syncthingandroid.activities.FolderPickerActivity.ROOT_DIRECTORY";
|
||||
|
||||
public static final String EXTRA_RESULT_DIRECTORY =
|
||||
"com.nutomic.syncthingandroid.activities.FolderPickerActivity.RESULT_DIRECTORY";
|
||||
|
||||
|
@ -56,18 +65,21 @@ public class FolderPickerActivity extends SyncthingActivity
|
|||
private ListView mListView;
|
||||
private FileAdapter mFilesAdapter;
|
||||
private RootsAdapter mRootsAdapter;
|
||||
@Inject SharedPreferences mPreferences;
|
||||
|
||||
/**
|
||||
* Location of null means that the list of roots is displayed.
|
||||
*/
|
||||
private File mLocation;
|
||||
|
||||
public static Intent createIntent(Context context, String currentPath) {
|
||||
public static Intent createIntent(Context context, String initialDirectory, @Nullable String rootDirectory) {
|
||||
Intent intent = new Intent(context, FolderPickerActivity.class);
|
||||
|
||||
if (!TextUtils.isEmpty(currentPath)) {
|
||||
intent.putExtra(FolderPickerActivity.EXTRA_INITIAL_DIRECTORY, currentPath);
|
||||
if (!TextUtils.isEmpty(initialDirectory)) {
|
||||
intent.putExtra(EXTRA_INITIAL_DIRECTORY, initialDirectory);
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(rootDirectory)) {
|
||||
intent.putExtra(EXTRA_ROOT_DIRECTORY, rootDirectory);
|
||||
}
|
||||
|
||||
return intent;
|
||||
|
@ -101,7 +113,8 @@ public class FolderPickerActivity extends SyncthingActivity
|
|||
}
|
||||
|
||||
/**
|
||||
* Reads available storage devices/folders from various APIs and inserts them into
|
||||
* If a root directory is specified it is added to {@link #mRootsAdapter} otherwise
|
||||
* all available storage devices/folders from various APIs are inserted into
|
||||
* {@link #mRootsAdapter}.
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
|
@ -111,22 +124,28 @@ public class FolderPickerActivity extends SyncthingActivity
|
|||
roots.addAll(Arrays.asList(getExternalFilesDirs(null)));
|
||||
roots.remove(getExternalFilesDir(null));
|
||||
}
|
||||
roots.add(Environment.getExternalStorageDirectory());
|
||||
roots.add(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC));
|
||||
roots.add(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES));
|
||||
roots.add(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES));
|
||||
roots.add(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS));
|
||||
roots.add(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
roots.add(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS));
|
||||
}
|
||||
|
||||
// Add paths that might not be accessible to Syncthing.
|
||||
if (mPreferences.getBoolean("advanced_folder_picker", false)) {
|
||||
Collections.addAll(roots, new File("/storage/").listFiles());
|
||||
roots.add(new File("/"));
|
||||
}
|
||||
String rootDir = getIntent().getStringExtra(EXTRA_ROOT_DIRECTORY);
|
||||
if (getIntent().hasExtra(EXTRA_ROOT_DIRECTORY) && !TextUtils.isEmpty(rootDir)) {
|
||||
roots.add(new File(rootDir));
|
||||
} else {
|
||||
roots.add(Environment.getExternalStorageDirectory());
|
||||
roots.add(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC));
|
||||
roots.add(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES));
|
||||
roots.add(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES));
|
||||
roots.add(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS));
|
||||
roots.add(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
roots.add(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS));
|
||||
}
|
||||
|
||||
// Add paths that might not be accessible to Syncthing.
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
if (sp.getBoolean("advanced_folder_picker", false)) {
|
||||
Collections.addAll(roots, new File("/storage/").listFiles());
|
||||
roots.add(new File("/"));
|
||||
}
|
||||
}
|
||||
// Remove any invalid directories.
|
||||
Iterator<File> it = roots.iterator();
|
||||
while (it.hasNext()) {
|
||||
|
@ -135,6 +154,7 @@ public class FolderPickerActivity extends SyncthingActivity
|
|||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
mRootsAdapter.addAll(Sets.newTreeSet(roots));
|
||||
}
|
||||
|
||||
|
@ -179,7 +199,7 @@ public class FolderPickerActivity extends SyncthingActivity
|
|||
return true;
|
||||
case R.id.select:
|
||||
Intent intent = new Intent()
|
||||
.putExtra(EXTRA_RESULT_DIRECTORY, mLocation.getAbsolutePath());
|
||||
.putExtra(EXTRA_RESULT_DIRECTORY, Util.formatPath(mLocation.getAbsolutePath()));
|
||||
setResult(Activity.RESULT_OK, intent);
|
||||
finish();
|
||||
return true;
|
||||
|
@ -291,7 +311,7 @@ public class FolderPickerActivity extends SyncthingActivity
|
|||
|
||||
/**
|
||||
* Goes up a directory, up to the list of roots if there are multiple roots.
|
||||
*
|
||||
* <p>
|
||||
* If we already are in the list of roots, or if we are directly in the only
|
||||
* root folder, we cancel.
|
||||
*/
|
||||
|
|
|
@ -7,10 +7,13 @@ import android.database.Cursor;
|
|||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.MediaStore;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.webkit.MimeTypeMap;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
|
@ -37,7 +40,7 @@ import java.util.Map;
|
|||
|
||||
/**
|
||||
* Shares incoming files to syncthing folders.
|
||||
*
|
||||
* <p>
|
||||
* {@link #getDisplayNameForUri} and {@link #getDisplayNameFromContentResolver} are taken from
|
||||
* ownCloud Android {@see https://github.com/owncloud/android/blob/79664304fdb762b2e04f1ac505f50d0923ddd212/src/com/owncloud/android/utils/UriUtils.java#L193}
|
||||
*/
|
||||
|
@ -45,6 +48,13 @@ public class ShareActivity extends StateDialogActivity
|
|||
implements SyncthingActivity.OnServiceConnectedListener, SyncthingService.OnApiChangeListener {
|
||||
|
||||
private static final String TAG = "ShareActivity";
|
||||
private static final String PREF_PREVIOUSLY_SELECTED_SYNCTHING_FOLDER = "previously_selected_syncthing_folder";
|
||||
|
||||
public static final String PREF_FOLDER_SAVED_SUBDIRECTORY = "saved_sub_directory_";
|
||||
|
||||
private TextView mSubDirectoryTextView;
|
||||
|
||||
private Spinner mFoldersSpinner;
|
||||
|
||||
@Override
|
||||
public void onApiChange(SyncthingService.State currentState) {
|
||||
|
@ -53,12 +63,24 @@ public class ShareActivity extends StateDialogActivity
|
|||
|
||||
List<Folder> folders = getApi().getFolders();
|
||||
|
||||
// Get the index of the previously selected folder.
|
||||
int folderIndex = 0;
|
||||
String savedFolderId = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
.getString(PREF_PREVIOUSLY_SELECTED_SYNCTHING_FOLDER, "");
|
||||
for (Folder folder : folders) {
|
||||
if (folder.id.equals(savedFolderId)) {
|
||||
folderIndex = folders.indexOf(folder);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ArrayAdapter<Folder> adapter = new ArrayAdapter<>(
|
||||
this, android.R.layout.simple_spinner_item, folders);
|
||||
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
Spinner sItems = findViewById(R.id.folders);
|
||||
sItems.setAdapter(adapter);
|
||||
sItems.setSelection(folderIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -81,12 +103,15 @@ public class ShareActivity extends StateDialogActivity
|
|||
|
||||
registerOnServiceConnectedListener(this);
|
||||
|
||||
Spinner mFoldersSpinner = findViewById(R.id.folders);
|
||||
Button mShareButton = findViewById(R.id.share_button);
|
||||
Button mCancelButton = findViewById(R.id.cancel_button);
|
||||
Button browseButton = findViewById(R.id.browse_button);
|
||||
EditText mShareName = findViewById(R.id.name);
|
||||
TextView mShareTitle = findViewById(R.id.namesTitle);
|
||||
|
||||
mSubDirectoryTextView = findViewById(R.id.sub_directory_Textview);
|
||||
mFoldersSpinner = findViewById(R.id.folders);
|
||||
|
||||
// TODO: add support for EXTRA_TEXT (notes, memos sharing)
|
||||
ArrayList<Uri> extrasToCopy = new ArrayList<>();
|
||||
if (getIntent().getAction().equals(Intent.ACTION_SEND)) {
|
||||
|
@ -124,9 +149,32 @@ public class ShareActivity extends StateDialogActivity
|
|||
if (files.size() == 1)
|
||||
files.entrySet().iterator().next().setValue(mShareName.getText().toString());
|
||||
Folder folder = (Folder) mFoldersSpinner.getSelectedItem();
|
||||
new CopyFilesTask(files, folder).execute();
|
||||
File directory = new File(folder.path, getSavedSubDirectory());
|
||||
new CopyFilesTask(files, folder, directory).execute();
|
||||
});
|
||||
|
||||
mFoldersSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
mSubDirectoryTextView.setText(getSavedSubDirectory());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
browseButton.setOnClickListener(view -> {
|
||||
Folder folder = (Folder) mFoldersSpinner.getSelectedItem();
|
||||
File initialDirectory = new File(folder.path, getSavedSubDirectory());
|
||||
startActivityForResult(FolderPickerActivity.createIntent(getApplicationContext(),
|
||||
initialDirectory.getAbsolutePath(), folder.path),
|
||||
FolderPickerActivity.DIRECTORY_REQUEST_CODE);
|
||||
});
|
||||
|
||||
mCancelButton.setOnClickListener(view -> finish());
|
||||
mSubDirectoryTextView.setText(getSavedSubDirectory());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -209,15 +257,32 @@ public class ShareActivity extends StateDialogActivity
|
|||
return displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the previously selected sub directory for the currently selected Syncthing folder.
|
||||
*/
|
||||
private String getSavedSubDirectory() {
|
||||
Folder selectedFolder = (Folder) mFoldersSpinner.getSelectedItem();
|
||||
String savedSubDirectory = "";
|
||||
|
||||
if (selectedFolder != null) {
|
||||
savedSubDirectory = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
.getString(PREF_FOLDER_SAVED_SUBDIRECTORY + selectedFolder.id, "");
|
||||
}
|
||||
|
||||
return savedSubDirectory;
|
||||
}
|
||||
|
||||
private class CopyFilesTask extends AsyncTask<Void, Void, Boolean> {
|
||||
private ProgressDialog mProgress;
|
||||
private final Map<Uri, String> mFiles;
|
||||
private final Folder mFolder;
|
||||
private Map<Uri, String> mFiles;
|
||||
private Folder mFolder;
|
||||
private File mDirectory;
|
||||
private int mCopied = 0, mIgnored = 0;
|
||||
|
||||
CopyFilesTask(Map<Uri, String> files, Folder folder) {
|
||||
CopyFilesTask(Map<Uri, String> files, Folder folder, File directory) {
|
||||
this.mFiles = files;
|
||||
this.mFolder = folder;
|
||||
this.mDirectory = directory;
|
||||
}
|
||||
|
||||
protected void onPreExecute() {
|
||||
|
@ -230,7 +295,7 @@ public class ShareActivity extends StateDialogActivity
|
|||
for (Map.Entry<Uri, String> entry : mFiles.entrySet()) {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
File outFile = new File(mFolder.path, entry.getValue());
|
||||
File outFile = new File(mDirectory, entry.getValue());
|
||||
if (outFile.isFile()) {
|
||||
mIgnored++;
|
||||
continue;
|
||||
|
@ -261,10 +326,10 @@ public class ShareActivity extends StateDialogActivity
|
|||
protected void onPostExecute(Boolean isError) {
|
||||
Util.dismissDialogSafe(mProgress, ShareActivity.this);
|
||||
Toast.makeText(ShareActivity.this, mIgnored > 0 ?
|
||||
getResources().getQuantityString(R.plurals.copy_success_partially, mCopied,
|
||||
mCopied, mFolder.label, mIgnored) :
|
||||
getResources().getQuantityString(R.plurals.copy_success, mCopied, mCopied,
|
||||
mFolder.label),
|
||||
getResources().getQuantityString(R.plurals.copy_success_partially, mCopied,
|
||||
mCopied, mFolder.label, mIgnored) :
|
||||
getResources().getQuantityString(R.plurals.copy_success, mCopied, mCopied,
|
||||
mFolder.label),
|
||||
Toast.LENGTH_LONG).show();
|
||||
if (isError) {
|
||||
Toast.makeText(ShareActivity.this, getString(R.string.copy_exception),
|
||||
|
@ -273,4 +338,32 @@ public class ShareActivity extends StateDialogActivity
|
|||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
if (mFoldersSpinner.getSelectedItem() != null) {
|
||||
Folder selectedFolder = (Folder) mFoldersSpinner.getSelectedItem();
|
||||
PreferenceManager.getDefaultSharedPreferences(this).edit()
|
||||
.putString(PREF_PREVIOUSLY_SELECTED_SYNCTHING_FOLDER, selectedFolder.id)
|
||||
.apply();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode == FolderPickerActivity.DIRECTORY_REQUEST_CODE && resultCode == RESULT_OK) {
|
||||
Folder selectedFolder = (Folder) mFoldersSpinner.getSelectedItem();
|
||||
String folderDirectory = Util.formatPath(selectedFolder.path);
|
||||
String subDirectory = data.getStringExtra(FolderPickerActivity.EXTRA_RESULT_DIRECTORY);
|
||||
//Remove the parent directory from the string, so it is only the Sub directory that is displayed to the user.
|
||||
subDirectory = subDirectory.replace(folderDirectory, "");
|
||||
mSubDirectoryTextView.setText(subDirectory);
|
||||
|
||||
PreferenceManager.getDefaultSharedPreferences(this)
|
||||
.edit().putString(PREF_FOLDER_SAVED_SUBDIRECTORY + selectedFolder.id, subDirectory)
|
||||
.apply();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ public class StaggeredVersioningFragment extends Fragment {
|
|||
|
||||
mPathView.setText(currentPath);
|
||||
mPathView.setOnClickListener(view ->
|
||||
startActivityForResult(FolderPickerActivity.createIntent(getContext(), currentPath), FolderPickerActivity.DIRECTORY_REQUEST_CODE));
|
||||
startActivityForResult(FolderPickerActivity.createIntent(getContext(), currentPath, null), FolderPickerActivity.DIRECTORY_REQUEST_CODE));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.nutomic.syncthingandroid.service;
|
|||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
|
@ -18,6 +19,7 @@ import com.google.gson.JsonParser;
|
|||
import com.nutomic.syncthingandroid.BuildConfig;
|
||||
import com.nutomic.syncthingandroid.SyncthingApp;
|
||||
import com.nutomic.syncthingandroid.activities.RestartActivity;
|
||||
import com.nutomic.syncthingandroid.activities.ShareActivity;
|
||||
import com.nutomic.syncthingandroid.http.GetRequest;
|
||||
import com.nutomic.syncthingandroid.http.PostConfigRequest;
|
||||
import com.nutomic.syncthingandroid.http.PostScanRequest;
|
||||
|
@ -228,6 +230,10 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener,
|
|||
public void removeFolder(String id) {
|
||||
removeFolderInternal(id);
|
||||
sendConfig();
|
||||
// Remove saved data from share activity for this folder.
|
||||
PreferenceManager.getDefaultSharedPreferences(mContext).edit()
|
||||
.remove(ShareActivity.PREF_FOLDER_SAVED_SUBDIRECTORY+id)
|
||||
.apply();
|
||||
}
|
||||
|
||||
private void removeFolderInternal(String id) {
|
||||
|
|
|
@ -15,6 +15,7 @@ import com.nutomic.syncthingandroid.R;
|
|||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.File;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import eu.chainfire.libsuperuser.Shell;
|
||||
|
@ -42,7 +43,7 @@ public class Util {
|
|||
|
||||
/**
|
||||
* Converts a number of bytes to a human readable file size (eg 3.5 GiB).
|
||||
*
|
||||
* <p>
|
||||
* Based on http://stackoverflow.com/a/5599842
|
||||
*/
|
||||
public static String readableFileSize(Context context, long bytes) {
|
||||
|
@ -56,7 +57,7 @@ public class Util {
|
|||
/**
|
||||
* Converts a number of bytes to a human readable transfer rate in bytes per second
|
||||
* (eg 100 KiB/s).
|
||||
*
|
||||
* <p>
|
||||
* Based on http://stackoverflow.com/a/5599842
|
||||
*/
|
||||
public static String readableTransferRate(Context context, long bits) {
|
||||
|
@ -69,13 +70,14 @@ public class Util {
|
|||
}
|
||||
|
||||
/**
|
||||
* <<<<<<< HEAD
|
||||
* Normally an application's data directory is only accessible by the corresponding application.
|
||||
* Therefore, every file and directory is owned by an application's user and group. When running Syncthing as root,
|
||||
* it writes to the application's data directory. This leaves files and directories behind which are owned by root having 0600.
|
||||
* Moreover, those acitons performed as root changes a file's type in terms of SELinux.
|
||||
* A subsequent start of Syncthing will fail due to insufficient permissions.
|
||||
* Hence, this method fixes the owner, group and the files' type of the data directory.
|
||||
*
|
||||
*
|
||||
* @return true if the operation was successfully performed. False otherwise.
|
||||
*/
|
||||
public static boolean fixAppDataPermissions(Context context) {
|
||||
|
@ -136,4 +138,14 @@ public class Util {
|
|||
|
||||
dialog.dismiss();
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a path properly.
|
||||
*
|
||||
* @param path String containing the path that needs formatting.
|
||||
* @return formatted file path as a string.
|
||||
*/
|
||||
public static String formatPath(String path) {
|
||||
return new File(path).toURI().normalize().getPath();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context="com.nutomic.syncthingandroid.activities.ShareActivity"
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true"
|
||||
android:orientation="vertical"
|
||||
tools:context="com.nutomic.syncthingandroid.activities.ShareActivity">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include layout="@layout/widget_toolbar" />
|
||||
|
||||
<RelativeLayout
|
||||
<android.support.constraint.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
|
@ -23,69 +26,137 @@
|
|||
android:paddingTop="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/namesTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/namesTitle"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_marginTop="8dp" />
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<EditText
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ems="10"
|
||||
android:id="@+id/name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:ems="10"
|
||||
android:inputType="text|textMultiLine"
|
||||
android:layout_below="@+id/namesTitle"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true" />
|
||||
app:layout_constraintBottom_toTopOf="@+id/folders"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/namesTitle"
|
||||
app:layout_constraintVertical_bias="0.0" />
|
||||
|
||||
<TextView
|
||||
android:text="@string/folder_title"
|
||||
android:id="@+id/folder_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/folder_title"
|
||||
android:layout_below="@+id/name"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_marginTop="8dp" />
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="7dp"
|
||||
android:text="@string/folder_title"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/name" />
|
||||
|
||||
<Spinner
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/folders"
|
||||
android:layout_below="@+id/folder_title"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_marginTop="8dp" />
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/folder_title" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/share_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/save_title"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginRight="-8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:minWidth="60dip"
|
||||
android:text="@string/save_title"
|
||||
android:textColor="@color/accent"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:textSize="14sp"
|
||||
android:minWidth="60dip" />
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/browse_button"
|
||||
app:layout_constraintVertical_bias="0.965" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/cancel_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/cancel_title"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:textColor="@color/accent"
|
||||
android:minWidth="50dip"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_toLeftOf="@+id/share_button"
|
||||
android:layout_toStartOf="@+id/share_button"
|
||||
android:layout_marginRight="14dp"
|
||||
android:layout_marginEnd="14dp" />
|
||||
android:text="@string/cancel_title"
|
||||
android:textColor="@color/accent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.951"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@+id/share_button"
|
||||
app:layout_constraintTop_toBottomOf="@+id/sub_directory_Textview"
|
||||
app:layout_constraintVertical_bias="0.964" />
|
||||
|
||||
</RelativeLayout>
|
||||
<TextView
|
||||
android:id="@+id/sub_folder_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/sub_folder"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/folders" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sub_directory_Textview"
|
||||
style="@style/Widget.Syncthing.TextView.Label.Details"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:drawableLeft="@drawable/ic_folder_black_24dp"
|
||||
android:drawableStart="@drawable/ic_folder_black_24dp"
|
||||
android:focusable="true"
|
||||
android:hint="@string/no_sub_folder_is_selected"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@+id/browse_button"
|
||||
app:layout_constraintTop_toBottomOf="@+id/sub_folder_title" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/browse_button"
|
||||
android:layout_width="88dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:text="@string/browse"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/sub_directory_Textview"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/sub_directory_Textview" />
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
</LinearLayout>
|
||||
</android.support.v4.widget.DrawerLayout>
|
||||
</ScrollView>
|
||||
|
|
|
@ -497,6 +497,9 @@ Please report any problems you encounter via Github.</string>
|
|||
<item quantity="other">Files List</item>
|
||||
</plurals>
|
||||
|
||||
<!-- Sub Folder title -->
|
||||
<string name="sub_folder">Sub folder</string>
|
||||
|
||||
<!-- SyncthingService -->
|
||||
|
||||
|
||||
|
@ -620,5 +623,7 @@ Please report any problems you encounter via Github.</string>
|
|||
|
||||
<!-- error message if the deviceID/QRCode dialog for some reason cannot be displayed.-->
|
||||
<string name="could_not_access_deviceid">Could not access device ID.</string>
|
||||
<string name="browse">Browse</string>
|
||||
<string name="no_sub_folder_is_selected">No sub folder is selected</string>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue