diff options
Diffstat (limited to 'app/src/main/java/it/niedermann/owncloud')
9 files changed, 87 insertions, 29 deletions
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherDialog.java b/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherDialog.java index b15f6308..7d088afe 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherDialog.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherDialog.java @@ -1,5 +1,7 @@ package it.niedermann.owncloud.notes.accountswitcher; +import static it.niedermann.owncloud.notes.branding.BrandingUtil.applyBrandToLayerDrawable; + import android.app.Dialog; import android.content.Context; import android.content.Intent; @@ -8,14 +10,11 @@ import android.net.Uri; import android.os.Bundle; import androidx.annotation.NonNull; -import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.DialogFragment; -import androidx.lifecycle.LiveData; import com.bumptech.glide.Glide; import com.bumptech.glide.request.RequestOptions; - -import java.util.List; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import it.niedermann.owncloud.notes.R; import it.niedermann.owncloud.notes.branding.BrandedDialogFragment; @@ -24,8 +23,6 @@ import it.niedermann.owncloud.notes.manageaccounts.ManageAccountsActivity; import it.niedermann.owncloud.notes.persistence.NotesRepository; import it.niedermann.owncloud.notes.persistence.entity.Account; -import static it.niedermann.owncloud.notes.branding.BrandingUtil.applyBrandToLayerDrawable; - /** * Displays all available {@link Account} entries and provides basic operations for them, like adding or switching */ @@ -104,7 +101,7 @@ public class AccountSwitcherDialog extends BrandedDialogFragment { dismiss(); }); - return new AlertDialog.Builder(requireContext()) + return new MaterialAlertDialogBuilder(requireContext()) .setView(binding.getRoot()) .create(); } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedAlertDialogBuilder.java b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedAlertDialogBuilder.java index c48e6298..a30c176f 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedAlertDialogBuilder.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedAlertDialogBuilder.java @@ -1,5 +1,7 @@ package it.niedermann.owncloud.notes.branding; +import static it.niedermann.owncloud.notes.branding.BrandingUtil.getSecondaryForegroundColorDependingOnTheme; + import android.content.Context; import android.content.DialogInterface; import android.widget.Button; @@ -9,9 +11,9 @@ import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; -import static it.niedermann.owncloud.notes.branding.BrandingUtil.getSecondaryForegroundColorDependingOnTheme; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; -public class BrandedAlertDialogBuilder extends AlertDialog.Builder implements Branded { +public class BrandedAlertDialogBuilder extends MaterialAlertDialogBuilder implements Branded { protected AlertDialog dialog; diff --git a/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedSnackbar.java b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedSnackbar.java index 8e3a4d9f..1c0ebf11 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedSnackbar.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedSnackbar.java @@ -1,28 +1,46 @@ package it.niedermann.owncloud.notes.branding; +import static it.niedermann.owncloud.notes.NotesApplication.isDarkThemeActive; +import static it.niedermann.owncloud.notes.branding.BrandingUtil.getAttribute; +import static it.niedermann.owncloud.notes.branding.BrandingUtil.readBrandMainColor; +import static it.niedermann.owncloud.notes.shared.util.NotesColorUtil.contrastRatioIsSufficient; + import android.graphics.Color; import android.view.View; +import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.StringRes; +import com.google.android.material.snackbar.BaseTransientBottomBar; import com.google.android.material.snackbar.Snackbar; -import it.niedermann.android.util.ColorUtil; +import it.niedermann.owncloud.notes.R; public class BrandedSnackbar { @NonNull - public static Snackbar make(@NonNull View view, @NonNull CharSequence text, @Snackbar.Duration int duration) { + public static Snackbar make(@NonNull View view, @NonNull CharSequence text, @BaseTransientBottomBar.Duration int duration) { final var snackbar = Snackbar.make(view, text, duration); - final int color = BrandingUtil.readBrandMainColor(view.getContext()); - snackbar.setActionTextColor(ColorUtil.INSTANCE.isColorDark(color) ? Color.WHITE : color); + + @ColorInt final int backgroundColor = getAttribute(view.getContext(), R.attr.colorSurfaceInverse); + @ColorInt final int color = readBrandMainColor(view.getContext()); + + if (contrastRatioIsSufficient(backgroundColor, color)) { + snackbar.setActionTextColor(color); + } else { + if (isDarkThemeActive(view.getContext())) { + snackbar.setActionTextColor(Color.BLACK); + } else { + snackbar.setActionTextColor(Color.WHITE); + } + } + return snackbar; } @NonNull - public static Snackbar make(@NonNull View view, @StringRes int resId, @Snackbar.Duration int duration) { + public static Snackbar make(@NonNull View view, @StringRes int resId, @BaseTransientBottomBar.Duration int duration) { return make(view, view.getResources().getText(resId), duration); } - }
\ No newline at end of file diff --git a/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandingUtil.java b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandingUtil.java index af2b4a43..44b34eb7 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandingUtil.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandingUtil.java @@ -7,9 +7,11 @@ import android.graphics.Color; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.util.Log; +import android.util.TypedValue; import android.view.MenuItem; import android.widget.EditText; +import androidx.annotation.AttrRes; import androidx.annotation.ColorInt; import androidx.annotation.IdRes; import androidx.annotation.NonNull; @@ -161,4 +163,11 @@ public class BrandingUtil { DrawableCompat.setTint(drawable, mainColor); } } + + @ColorInt + public static int getAttribute(@NonNull Context context, @AttrRes int id) { + final var typedValue = new TypedValue(); + context.getTheme().resolveAttribute(id, typedValue, true); + return typedValue.data; + } } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/edit/title/EditTitleDialogFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/edit/title/EditTitleDialogFragment.java index d372cdcb..4d2a770a 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/edit/title/EditTitleDialogFragment.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/edit/title/EditTitleDialogFragment.java @@ -1,6 +1,5 @@ package it.niedermann.owncloud.notes.edit.title; -import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.os.Bundle; @@ -13,6 +12,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; + import it.niedermann.owncloud.notes.R; import it.niedermann.owncloud.notes.databinding.DialogEditTitleBinding; @@ -53,7 +54,7 @@ public class EditTitleDialogFragment extends DialogFragment { binding.title.setText(oldTitle); } - return new AlertDialog.Builder(getActivity()) + return new MaterialAlertDialogBuilder(requireActivity()) .setTitle(R.string.change_note_title) .setView(dialogView) .setCancelable(true) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/exception/ExceptionDialogFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/exception/ExceptionDialogFragment.java index cfaa543d..ca242a7f 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/exception/ExceptionDialogFragment.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/exception/ExceptionDialogFragment.java @@ -10,6 +10,8 @@ import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatDialogFragment; import androidx.fragment.app.DialogFragment; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; + import java.util.ArrayList; import it.niedermann.android.util.ClipboardUtil; @@ -62,7 +64,7 @@ public class ExceptionDialogFragment extends AppCompatDialogFragment { adapter.setThrowables(throwables); - return new AlertDialog.Builder(requireActivity()) + return new MaterialAlertDialogBuilder(requireActivity()) .setView(binding.getRoot()) .setTitle(R.string.error_dialog_title) .setPositiveButton(android.R.string.copy, (a, b) -> ClipboardUtil.INSTANCE.copyToClipboard(requireContext(), getString(R.string.simple_exception), "```\n" + debugInfos + "\n```")) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java index 1c901c21..046f0e7d 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java @@ -29,7 +29,6 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBarDrawerToggle; -import androidx.appcompat.app.AlertDialog; import androidx.appcompat.view.ActionMode; import androidx.appcompat.widget.SearchView; import androidx.coordinatorlayout.widget.CoordinatorLayout; @@ -48,6 +47,7 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import com.bumptech.glide.Glide; import com.bumptech.glide.request.RequestOptions; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.snackbar.Snackbar; import com.nextcloud.android.sso.AccountImporter; @@ -175,7 +175,7 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A runOnUiThread(() -> mainViewModel.postCurrentAccount(account)); } catch (NextcloudFilesAppAccountNotFoundException e) { // Verbose log output for https://github.com/stefan-niedermann/nextcloud-notes/issues/1256 - runOnUiThread(() -> new AlertDialog.Builder(this) + runOnUiThread(() -> new MaterialAlertDialogBuilder(this) .setTitle(NextcloudFilesAppAccountNotFoundException.class.getSimpleName()) .setMessage(R.string.backup) .setPositiveButton(R.string.simple_backup, (a, b) -> executor.submit(() -> { @@ -218,6 +218,7 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A mainViewModel.getSyncErrors().observe(this, exceptions -> { if (mainViewModel.containsNonInfrastructureRelatedItems(exceptions)) { BrandedSnackbar.make(coordinatorLayout, R.string.error_synchronization, Snackbar.LENGTH_LONG) + .setAnchorView(binding.activityNotesListView.fabCreate) .setAction(R.string.simple_more, v -> ExceptionDialogFragment.newInstance(exceptions) .show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName())) .show(); @@ -325,11 +326,14 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A if (t instanceof IntendedOfflineException) { Log.i(TAG, "Capabilities and notes not updated because " + nextAccount.getAccountName() + " is offline by intention."); } else if (t instanceof NetworkErrorException) { - BrandedSnackbar.make(coordinatorLayout, getString(R.string.error_sync, getString(R.string.error_no_network)), Snackbar.LENGTH_LONG).show(); + BrandedSnackbar.make(coordinatorLayout, getString(R.string.error_sync, getString(R.string.error_no_network)), Snackbar.LENGTH_LONG) + .setAnchorView(binding.activityNotesListView.fabCreate) + .show(); } else { BrandedSnackbar.make(coordinatorLayout, R.string.error_synchronization, Snackbar.LENGTH_LONG) .setAction(R.string.simple_more, v -> ExceptionDialogFragment.newInstance(t) .show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName())) + .setAnchorView(binding.activityNotesListView.fabCreate) .show(); } }); @@ -477,13 +481,18 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A if (t instanceof IntendedOfflineException) { Log.i(TAG, "Capabilities and notes not updated because " + currentAccount.getAccountName() + " is offline by intention."); } else if (t instanceof NextcloudHttpRequestFailedException && ((NextcloudHttpRequestFailedException) t).getStatusCode() == HttpURLConnection.HTTP_UNAVAILABLE) { - BrandedSnackbar.make(coordinatorLayout, R.string.error_maintenance_mode, Snackbar.LENGTH_LONG).show(); + BrandedSnackbar.make(coordinatorLayout, R.string.error_maintenance_mode, Snackbar.LENGTH_LONG) + .setAnchorView(binding.activityNotesListView.fabCreate) + .show(); } else if (t instanceof NetworkErrorException) { - BrandedSnackbar.make(coordinatorLayout, getString(R.string.error_sync, getString(R.string.error_no_network)), Snackbar.LENGTH_LONG).show(); + BrandedSnackbar.make(coordinatorLayout, getString(R.string.error_sync, getString(R.string.error_no_network)), Snackbar.LENGTH_LONG) + .setAnchorView(binding.activityNotesListView.fabCreate) + .show(); } else { BrandedSnackbar.make(coordinatorLayout, R.string.error_synchronization, Snackbar.LENGTH_LONG) .setAction(R.string.simple_more, v -> ExceptionDialogFragment.newInstance(t) .show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName())) + .setAnchorView(binding.activityNotesListView.fabCreate) .show(); } }); @@ -500,7 +509,7 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A public void onSelectionChanged() { super.onSelectionChanged(); if (tracker.hasSelection() && mActionMode == null) { - mActionMode = startSupportActionMode(new MultiSelectedActionModeCallback(MainActivity.this, coordinatorLayout, mainViewModel, MainActivity.this, canMoveNoteToAnotherAccounts, tracker, getSupportFragmentManager())); + mActionMode = startSupportActionMode(new MultiSelectedActionModeCallback(MainActivity.this, coordinatorLayout, binding.activityNotesListView.fabCreate, mainViewModel, MainActivity.this, canMoveNoteToAnotherAccounts, tracker, getSupportFragmentManager())); } if (mActionMode != null) { if (tracker.hasSelection()) { @@ -515,7 +524,7 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A } ); - itemTouchHelper = new NotesListViewItemTouchHelper(this, mainViewModel, this, tracker, adapter, swipeRefreshLayout, coordinatorLayout, gridView); + itemTouchHelper = new NotesListViewItemTouchHelper(this, mainViewModel, this, tracker, adapter, swipeRefreshLayout, coordinatorLayout, binding.activityNotesListView.fabCreate, gridView); itemTouchHelper.attachToRecyclerView(listView); } @@ -673,7 +682,8 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A AccountImporter.onActivityResult(requestCode, resultCode, data, this, (ssoAccount) -> { CapabilitiesWorker.update(this); executor.submit(() -> { - final var importSnackbar = BrandedSnackbar.make(coordinatorLayout, R.string.progress_import_indeterminate, Snackbar.LENGTH_INDEFINITE); + final var importSnackbar = BrandedSnackbar.make(coordinatorLayout, R.string.progress_import_indeterminate, Snackbar.LENGTH_INDEFINITE) + .setAnchorView(binding.activityNotesListView.fabCreate); Log.i(TAG, "Added account: " + "name:" + ssoAccount.name + ", " + ssoAccount.url + ", userId" + ssoAccount.userId); try { Log.i(TAG, "Refreshing capabilities for " + ssoAccount.name); @@ -715,11 +725,15 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A runOnUiThread(() -> { mainViewModel.postCurrentAccount(mainViewModel.getLocalAccountByAccountName(ssoAccount.name)); // TODO there is already a sync in progress and results in displaying a TokenMissMatchException snackbar which conflicts with this one - coordinatorLayout.post(() -> BrandedSnackbar.make(coordinatorLayout, R.string.account_already_imported, Snackbar.LENGTH_LONG).show()); + coordinatorLayout.post(() -> BrandedSnackbar.make(coordinatorLayout, R.string.account_already_imported, Snackbar.LENGTH_LONG) + .setAnchorView(binding.activityNotesListView.fabCreate) + .show()); }); } else if (e instanceof UnknownErrorException && e.getMessage() != null && e.getMessage().contains("No address associated with hostname")) { // https://github.com/stefan-niedermann/nextcloud-notes/issues/1014 - runOnUiThread(() -> Snackbar.make(coordinatorLayout, R.string.you_have_to_be_connected_to_the_internet_in_order_to_add_an_account, Snackbar.LENGTH_LONG).show()); + runOnUiThread(() -> Snackbar.make(coordinatorLayout, R.string.you_have_to_be_connected_to_the_internet_in_order_to_add_an_account, Snackbar.LENGTH_LONG) + .setAnchorView(binding.activityNotesListView.fabCreate) + .show()); } else { e.printStackTrace(); runOnUiThread(() -> { diff --git a/app/src/main/java/it/niedermann/owncloud/notes/main/MultiSelectedActionModeCallback.java b/app/src/main/java/it/niedermann/owncloud/notes/main/MultiSelectedActionModeCallback.java index a76b2068..194dcbc8 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/main/MultiSelectedActionModeCallback.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/main/MultiSelectedActionModeCallback.java @@ -42,6 +42,8 @@ public class MultiSelectedActionModeCallback implements Callback { @NonNull private final View view; @NonNull + private final View anchorView; + @NonNull private final MainViewModel mainViewModel; @NonNull private final LifecycleOwner lifecycleOwner; @@ -52,9 +54,17 @@ public class MultiSelectedActionModeCallback implements Callback { private final FragmentManager fragmentManager; public MultiSelectedActionModeCallback( - @NonNull Context context, @NonNull View view, @NonNull MainViewModel mainViewModel, @NonNull LifecycleOwner lifecycleOwner, boolean canMoveNoteToAnotherAccounts, @NonNull SelectionTracker<Long> tracker, @NonNull FragmentManager fragmentManager) { + @NonNull Context context, + @NonNull View view, + @NonNull View anchorView, + @NonNull MainViewModel mainViewModel, + @NonNull LifecycleOwner lifecycleOwner, + boolean canMoveNoteToAnotherAccounts, + @NonNull SelectionTracker<Long> tracker, + @NonNull FragmentManager fragmentManager) { this.context = context; this.view = view; + this.anchorView = anchorView; this.mainViewModel = mainViewModel; this.lifecycleOwner = lifecycleOwner; this.canMoveNoteToAnotherAccounts = canMoveNoteToAnotherAccounts; @@ -110,6 +120,7 @@ public class MultiSelectedActionModeCallback implements Callback { ? context.getString(R.string.action_note_deleted, fullNotes.get(0).getTitle()) : context.getResources().getQuantityString(R.plurals.bulk_notes_deleted, fullNotes.size(), fullNotes.size()); BrandedSnackbar.make(view, deletedSnackbarTitle, Snackbar.LENGTH_LONG) + .setAnchorView(anchorView) .setAction(R.string.action_undo, (View v) -> { for (final var deletedNote : fullNotes) { final var undoLiveData = mainViewModel.addNoteAndSync(deletedNote); @@ -119,6 +130,7 @@ public class MultiSelectedActionModeCallback implements Callback { ? context.getString(R.string.action_note_restored, fullNotes.get(0).getTitle()) : context.getResources().getQuantityString(R.plurals.bulk_notes_restored, fullNotes.size(), fullNotes.size()); BrandedSnackbar.make(view, restoreSnackbarTitle, Snackbar.LENGTH_SHORT) + .setAnchorView(anchorView) .show(); }) .show(); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/main/items/list/NotesListViewItemTouchHelper.java b/app/src/main/java/it/niedermann/owncloud/notes/main/items/list/NotesListViewItemTouchHelper.java index d31bb2f3..bb93b7b7 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/main/items/list/NotesListViewItemTouchHelper.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/main/items/list/NotesListViewItemTouchHelper.java @@ -38,6 +38,7 @@ public class NotesListViewItemTouchHelper extends ItemTouchHelper { @NonNull ItemAdapter adapter, @NonNull SwipeRefreshLayout swipeRefreshLayout, @NonNull View view, + @NonNull View anchorView, boolean gridView) { super(new SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) { private boolean swipeRefreshLayoutEnabled; @@ -81,10 +82,12 @@ public class NotesListViewItemTouchHelper extends ItemTouchHelper { deleteLiveData.observe(lifecycleOwner, (next) -> deleteLiveData.removeObservers(lifecycleOwner)); Log.v(TAG, "Item deleted through swipe ----------------------------------------------"); BrandedSnackbar.make(view, context.getString(R.string.action_note_deleted, dbNote.getTitle()), UNDO_DURATION) + .setAnchorView(anchorView) .setAction(R.string.action_undo, (View v) -> { final var undoLiveData = mainViewModel.addNoteAndSync(dbNote); undoLiveData.observe(lifecycleOwner, (o) -> undoLiveData.removeObservers(lifecycleOwner)); BrandedSnackbar.make(view, context.getString(R.string.action_note_restored, dbNote.getTitle()), Snackbar.LENGTH_SHORT) + .setAnchorView(anchorView) .show(); }) .show(); |