diff --git a/app/src/main/java/com/nutomic/syncthingandroid/activities/DeviceActivity.java b/app/src/main/java/com/nutomic/syncthingandroid/activities/DeviceActivity.java index 2aabb36ca..0b67bc744 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/activities/DeviceActivity.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/activities/DeviceActivity.java @@ -57,7 +57,7 @@ public class DeviceActivity extends SyncthingActivity implements View.OnClickLis private static final String TAG = "DeviceSettingsFragment"; private static final String IS_SHOWING_DISCARD_DIALOG = "DISCARD_FOLDER_DIALOG_STATE"; private static final String IS_SHOWING_COMPRESSION_DIALOG = "COMPRESSION_FOLDER_DIALOG_STATE"; - private static final String IS_SHOWING_DELETE_DIALOG = "DELETE_FOLDER_DIALOG_STATE"; + private static final String IS_SHOW_DELETE_DIALOG = "DELETE_FOLDER_DIALOG_STATE"; private static final int QR_SCAN_REQUEST_CODE = 777; private static final List DYNAMIC_ADDRESS = Collections.singletonList("dynamic"); @@ -170,7 +170,7 @@ private void restoreDialogStates(Bundle savedInstanceState) { showCompressionDialog(); } - if (savedInstanceState.getBoolean(IS_SHOWING_DELETE_DIALOG)){ + if (savedInstanceState.getBoolean(IS_SHOW_DELETE_DIALOG)){ showDeleteDialog(); } @@ -220,7 +220,7 @@ public void onSaveInstanceState(Bundle outState) { outState.putBoolean(IS_SHOWING_COMPRESSION_DIALOG, mCompressionDialog != null && mCompressionDialog.isShowing()); Util.dismissDialogSafe(mCompressionDialog, this); - outState.putBoolean(IS_SHOWING_DELETE_DIALOG, mDeleteDialog != null && mDeleteDialog.isShowing()); + outState.putBoolean(IS_SHOW_DELETE_DIALOG, mDeleteDialog != null && mDeleteDialog.isShowing()); Util.dismissDialogSafe(mDeleteDialog, this); } diff --git a/app/src/main/java/com/nutomic/syncthingandroid/activities/FolderActivity.java b/app/src/main/java/com/nutomic/syncthingandroid/activities/FolderActivity.java index 3210ac35b..7a0155456 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/activities/FolderActivity.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/activities/FolderActivity.java @@ -30,6 +30,7 @@ import com.nutomic.syncthingandroid.databinding.FragmentFolderBinding; import com.nutomic.syncthingandroid.model.Device; import com.nutomic.syncthingandroid.model.Folder; +import com.nutomic.syncthingandroid.model.FolderStatus; import com.nutomic.syncthingandroid.service.Constants; import com.nutomic.syncthingandroid.service.RestApi; import com.nutomic.syncthingandroid.service.SyncthingService; @@ -65,13 +66,16 @@ public class FolderActivity extends SyncthingActivity "com.nutomic.syncthingandroid.activities.FolderActivity.FOLDER_ID"; public static final String EXTRA_FOLDER_LABEL = "com.nutomic.syncthingandroid.activities.FolderActivity.FOLDER_LABEL"; + public static final String EXTRA_FOLDER_OVERRIDABLE_CHANGES = + "com.nutomic.syncthingandroid.activities.FolderActivity.FOLDER_OVERRIDABLE_CHANGES"; public static final String EXTRA_DEVICE_ID = "com.nutomic.syncthingandroid.activities.FolderActivity.DEVICE_ID"; private static final String TAG = "FolderActivity"; - private static final String IS_SHOWING_DELETE_DIALOG = "DELETE_FOLDER_DIALOG_STATE"; + private static final String IS_SHOW_DELETE_DIALOG = "DELETE_FOLDER_DIALOG_STATE"; private static final String IS_SHOW_DISCARD_DIALOG = "DISCARD_FOLDER_DIALOG_STATE"; + private static final String IS_SHOW_OVERRIDE_REMOTES_DIALOG = "OVERRIDE_REMOTES_DIALOG_STATE"; private static final int FILE_VERSIONING_DIALOG_REQUEST = 3454; private static final int PULL_ORDER_DIALOG_REQUEST = 3455; @@ -93,6 +97,7 @@ public class FolderActivity extends SyncthingActivity private Dialog mDeleteDialog; private Dialog mDiscardDialog; + private Dialog mOverrideChangesDialog; private Folder.Versioning mVersioning; @@ -148,6 +153,7 @@ public void onCreate(Bundle savedInstanceState) { findViewById(R.id.pullOrderContainer).setOnClickListener(v -> showPullOrderDialog()); findViewById(R.id.versioningContainer).setOnClickListener(v -> showVersioningDialog()); binding.editIgnores.setOnClickListener(v -> editIgnores()); + binding.overrideChangesContainer.setOnClickListener(v -> showOverrideChangesDialog()); if (mIsCreateMode) { if (savedInstanceState != null) { @@ -162,6 +168,7 @@ public void onCreate(Bundle savedInstanceState) { // Open keyboard on label view in edit mode. binding.label.requestFocus(); binding.editIgnores.setEnabled(false); + setOverrideChangesContainerEnabled(false); } else { // Prepare edit mode. @@ -169,19 +176,32 @@ public void onCreate(Bundle savedInstanceState) { binding.id.setFocusable(false); binding.id.setEnabled(false); binding.directoryTextView.setEnabled(false); + + // overridable remotes button + setOverrideChangesContainerEnabled( + getIntent().hasExtra(EXTRA_FOLDER_OVERRIDABLE_CHANGES) + && getIntent().getBooleanExtra(EXTRA_FOLDER_OVERRIDABLE_CHANGES, false) + ); } if (savedInstanceState != null){ - if (savedInstanceState.getBoolean(IS_SHOWING_DELETE_DIALOG)){ + if (savedInstanceState.getBoolean(IS_SHOW_DELETE_DIALOG)){ showDeleteDialog(); } } if (savedInstanceState != null){ - if (savedInstanceState.getBoolean(IS_SHOWING_DELETE_DIALOG)){ + if (savedInstanceState.getBoolean(IS_SHOW_DELETE_DIALOG)){ showDeleteDialog(); } } + + if (savedInstanceState != null) { + if (savedInstanceState.getBoolean(IS_SHOW_OVERRIDE_REMOTES_DIALOG)){ + showOverrideChangesDialog(); + } + } + } /** @@ -304,12 +324,18 @@ public void onPause() { @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); - outState.putBoolean(IS_SHOWING_DELETE_DIALOG, mDeleteDialog != null && mDeleteDialog.isShowing()); + outState.putBoolean(IS_SHOW_DELETE_DIALOG, mDeleteDialog != null && mDeleteDialog.isShowing()); Util.dismissDialogSafe(mDeleteDialog, this); + outState.putBoolean(IS_SHOW_OVERRIDE_REMOTES_DIALOG, mOverrideChangesDialog != null && mOverrideChangesDialog.isShowing()); + Util.dismissDialogSafe(mOverrideChangesDialog, this); + if (mIsCreateMode){ outState.putBoolean(IS_SHOW_DISCARD_DIALOG, mDiscardDialog != null && mDiscardDialog.isShowing()); Util.dismissDialogSafe(mDiscardDialog, this); + + outState.putBoolean(IS_SHOW_OVERRIDE_REMOTES_DIALOG, mOverrideChangesDialog != null && mOverrideChangesDialog.isShowing()); + Util.dismissDialogSafe(mOverrideChangesDialog, this); } } @@ -778,4 +804,34 @@ private void setVersioningDescription(String type, String description) { binding.versioningType.setText(type); binding.versioningDescription.setText(description); } + + private void setOverrideChangesContainerEnabled(boolean state) { + LinearLayout container = (LinearLayout) findViewById(R.id.overrideChangesContainer); + binding.overrideChangesContainer.setEnabled(state); + for ( int i = 0; i < container.getChildCount(); i++ ) { + container.getChildAt(i).setEnabled(state); + } + } + + private void showOverrideChangesDialog(){ + mOverrideChangesDialog = createOverrideChangesDialog(); + mOverrideChangesDialog.show(); + } + + private Dialog createOverrideChangesDialog(){ + return Util.getAlertDialogBuilder(this) + .setIcon(R.drawable.outline_arrow_circle_up_24) + .setTitle(R.string.override_changes) + .setMessage(R.string.override_changes_are_you_sure) + .setNegativeButton(android.R.string.cancel, null) + .setPositiveButton(android.R.string.yes, (dialogInterface, i) -> { + RestApi restApi = getApi(); + if (restApi != null) { + restApi.overrideChanges(mFolder.id); + mFolderNeedsToUpdate = true; + } + finish(); + }) + .create(); + } } diff --git a/app/src/main/java/com/nutomic/syncthingandroid/fragments/FolderListFragment.java b/app/src/main/java/com/nutomic/syncthingandroid/fragments/FolderListFragment.java index 8da44b77a..fa165d772 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/fragments/FolderListFragment.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/fragments/FolderListFragment.java @@ -13,6 +13,7 @@ import com.nutomic.syncthingandroid.activities.FolderActivity; import com.nutomic.syncthingandroid.activities.SyncthingActivity; import com.nutomic.syncthingandroid.model.Folder; +import com.nutomic.syncthingandroid.model.FolderStatus; import com.nutomic.syncthingandroid.service.Constants; import com.nutomic.syncthingandroid.service.RestApi; import com.nutomic.syncthingandroid.service.SyncthingService; @@ -101,9 +102,15 @@ private void updateList() { @Override public void onItemClick(AdapterView adapterView, View view, int i, long l) { + Folder folder = mAdapter.getItem(i); + FolderStatus folderStatus = mAdapter.mLocalFolderStatuses.get(folder.id); + boolean overridableChanges = folder.type.equals(Constants.FOLDER_TYPE_SEND_ONLY) + && folderStatus.isNeedsItems() + && folderStatus.isOutOfSync(); Intent intent = new Intent(getActivity(), FolderActivity.class) .putExtra(FolderActivity.EXTRA_IS_CREATE, false) - .putExtra(FolderActivity.EXTRA_FOLDER_ID, mAdapter.getItem(i).id); + .putExtra(FolderActivity.EXTRA_FOLDER_ID, mAdapter.getItem(i).id) + .putExtra(FolderActivity.EXTRA_FOLDER_OVERRIDABLE_CHANGES, overridableChanges); startActivity(intent); } diff --git a/app/src/main/java/com/nutomic/syncthingandroid/model/FolderStatus.java b/app/src/main/java/com/nutomic/syncthingandroid/model/FolderStatus.java index 2f5f4d624..c3df2976b 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/model/FolderStatus.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/model/FolderStatus.java @@ -27,4 +27,12 @@ public class FolderStatus { public long version; public String error; public String watchError; + + public boolean isNeedsItems() { + return needFiles + needDirectories + needSymlinks + needDeletes > 0; + } + + public boolean isOutOfSync() { + return state.equals("idle") && isNeedsItems(); + } } diff --git a/app/src/main/java/com/nutomic/syncthingandroid/views/FoldersAdapter.java b/app/src/main/java/com/nutomic/syncthingandroid/views/FoldersAdapter.java index 4605f7d96..b9895c243 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/views/FoldersAdapter.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/views/FoldersAdapter.java @@ -40,7 +40,7 @@ public class FoldersAdapter extends ArrayAdapter { private static final String TAG = "FoldersAdapter"; - private final HashMap mLocalFolderStatuses = new HashMap<>(); + public final HashMap mLocalFolderStatuses = new HashMap<>(); private final Context mContext; @@ -59,13 +59,6 @@ public View getView(int position, View convertView, @NonNull ViewGroup parent) { Folder folder = getItem(position); binding.label.setText(TextUtils.isEmpty(folder.label) ? folder.id : folder.label); binding.directory.setText(folder.path); - binding.override.setOnClickListener(v -> { - // Send "Override changes" through our service to the REST API. - Intent intent = new Intent(mContext, SyncthingService.class) - .putExtra(SyncthingService.EXTRA_FOLDER_ID, folder.id); - intent.setAction(SyncthingService.ACTION_OVERRIDE_CHANGES); - mContext.startService(intent); - }); binding.openFolder.setOnClickListener(v -> { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(new File(folder.path)), "resource/folder"); @@ -94,17 +87,12 @@ private void updateFolderStatusView(ItemFolderListBinding binding, Folder folder FolderStatus folderStatus = mLocalFolderStatuses.get(folder.id); if (folderStatus == null) { binding.items.setVisibility(GONE); - binding.override.setVisibility(GONE); binding.size.setVisibility(GONE); setTextOrHide(binding.invalid, folder.invalid); return; } - long neededItems = folderStatus.needFiles + folderStatus.needDirectories + folderStatus.needSymlinks + folderStatus.needDeletes; - boolean outOfSync = folderStatus.state.equals("idle") && neededItems > 0; - boolean overrideButtonVisible = folder.type.equals(Constants.FOLDER_TYPE_SEND_ONLY) && outOfSync; - binding.override.setVisibility(overrideButtonVisible ? VISIBLE : GONE); - if (outOfSync) { + if (folderStatus.isOutOfSync()) { binding.state.setText(mContext.getString(R.string.status_outofsync)); binding.state.setTextColor(ContextCompat.getColor(mContext, R.color.text_red)); } else { @@ -185,5 +173,4 @@ private void setTextOrHide(TextView view, String text) { view.setVisibility(VISIBLE); } } - } diff --git a/app/src/main/res/drawable/outline_arrow_circle_up_24.xml b/app/src/main/res/drawable/outline_arrow_circle_up_24.xml new file mode 100644 index 000000000..d37ba61dc --- /dev/null +++ b/app/src/main/res/drawable/outline_arrow_circle_up_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/fragment_folder.xml b/app/src/main/res/layout/fragment_folder.xml index 963a7c04c..6cb3622b5 100644 --- a/app/src/main/res/layout/fragment_folder.xml +++ b/app/src/main/res/layout/fragment_folder.xml @@ -217,6 +217,16 @@ android:textAppearance="@style/TextAppearance.AppCompat.Caption" android:layout_marginBottom="10dp" /> + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/item_folder_list.xml b/app/src/main/res/layout/item_folder_list.xml index e5fad950e..0965de2a9 100644 --- a/app/src/main/res/layout/item_folder_list.xml +++ b/app/src/main/res/layout/item_folder_list.xml @@ -44,26 +44,11 @@ android:ellipsize="end" android:textAppearance="?textAppearanceListItemSecondary" /> -