Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/stefan-niedermann/nextcloud-notes.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Niedermann <info@niedermann.it>2020-06-13 14:01:24 +0300
committerStefan Niedermann <info@niedermann.it>2020-06-13 14:01:24 +0300
commitc3630231d4d9d27d65414d11e3fd4b08572b4f9d (patch)
treee2d9ead4d2cdab74afb90e780b90c7f9b14503bb
parentf0b4c24aa941be2a3c423efe61d4e1b6505f6b04 (diff)
parent0e6afd42e37166c1f70e57d19d60d8e06f00b966 (diff)
Merge branch 'master' into 603-sorting-method
# Conflicts: # app/src/androidTest/java/it/niedermann/owncloud/notes/persistence/NotesDatabaseTest.java # app/src/main/java/it/niedermann/owncloud/notes/android/activity/NotesListViewActivity.java # app/src/main/java/it/niedermann/owncloud/notes/persistence/AbstractNotesDatabase.java # app/src/main/java/it/niedermann/owncloud/notes/persistence/LoadNotesListTask.java # app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesDatabase.java # app/src/main/res/layout/activity_notes_list_view.xml # app/src/main/res/menu/menu_list_view.xml
-rw-r--r--README.md4
-rw-r--r--app/build.gradle14
-rw-r--r--app/src/androidTest/java/it/niedermann/nextcloud/deck/util/ColorUtilTest.java25
-rw-r--r--app/src/androidTest/java/it/niedermann/owncloud/notes/persistence/NotesDatabaseTest.java31
-rw-r--r--app/src/main/AndroidManifest.xml12
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherAdapter.java54
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherDialog.java115
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherListener.java11
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherViewHolder.java36
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/MultiSelectedActionModeCallback.java47
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/NotesListViewItemTouchHelper.java23
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/activity/AboutActivity.java12
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/activity/AppendToNoteActivity.java11
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/activity/EditNoteActivity.java12
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/activity/LockedActivity.java4
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/activity/NoteListWidgetConfigurationActivity.java35
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/activity/NotesListViewActivity.java548
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/activity/PreferencesActivity.java9
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidget.java183
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidgetFactory.java43
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/SingleNoteWidget.java15
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/fragment/AccountChooserAdapter.java12
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/fragment/BaseNoteFragment.java124
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/fragment/CategoryAdapter.java10
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/fragment/CategoryDialogFragment.java23
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/fragment/MoveAccountDialogFragment.java (renamed from app/src/main/java/it/niedermann/owncloud/notes/android/fragment/AccountChooserDialogFragment.java)26
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/fragment/NoteEditFragment.java29
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/fragment/NotePreviewFragment.java18
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/fragment/NoteReadonlyFragment.java13
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/fragment/PreferencesFragment.java79
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/fragment/SearchableBaseNoteFragment.java42
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/android/fragment/about/AboutFragmentLicenseTab.java20
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/branding/Branded.java9
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedActivity.java67
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedAlertDialogBuilder.java48
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedDeleteAlertDialogBuilder.java26
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedDialogFragment.java24
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedFragment.java49
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedPreferenceCategory.java46
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedSnackbar.java31
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedSwitchPreference.java116
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/branding/BrandingUtil.java133
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/formattinghelp/FormattingHelpActivity.java252
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/glide/SingleSignOnStreamFetcher.java88
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/glide/SingleSignOnUrlLoader.java34
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountAdapter.java80
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountViewHolder.java53
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountsActivity.java74
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/model/AbstractWidgetData.java42
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/model/DBNote.java12
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/model/GridItemDecoration.java53
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/model/ItemAdapter.java224
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/model/NavigationAdapter.java32
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/model/NoteClickListener.java11
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/model/NoteListsWidgetData.java40
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/model/NoteViewGridHolder.java55
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/model/NoteViewGridHolderOnlyTitle.java47
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/model/NoteViewHolder.java127
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/model/NoteViewHolderWithExcerpt.java44
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/model/NoteViewHolderWithoutExcerpt.java41
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/model/SectionItem.java2
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/model/SectionItemDecoration.java39
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/model/SectionViewHolder.java19
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/model/SingleNoteWidgetData.java32
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/AbstractNotesDatabase.java380
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/LoadNotesListTask.java44
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/NoteServerSyncHelper.java5
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesDatabase.java197
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_10_11.java31
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_11_12.java21
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_12_13.java20
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_13_14.java78
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_14_15.java83
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_15_16.java103
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_16_17.java15
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_4_5.java18
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_5_6.java14
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_6_7.java19
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_7_8.java28
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_8_9.java127
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_9_10.java26
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/util/ColorUtil.java44
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/util/DisplayUtils.java64
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/util/MarkDownUtil.java6
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/util/NoteUtil.java21
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/util/Notes.java13
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/util/SSOUtil.java4
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/util/ShareUtil.java20
-rw-r--r--app/src/main/res/animator/appbar_elevation_off.xml9
-rw-r--r--app/src/main/res/animator/appbar_elevation_on.xml11
-rw-r--r--app/src/main/res/drawable-night/border.xml10
-rw-r--r--app/src/main/res/drawable-v21/grid_item_background_selector.xml19
-rw-r--r--app/src/main/res/drawable-v21/list_item_background_selector.xml2
-rw-r--r--app/src/main/res/drawable/border.xml12
-rw-r--r--app/src/main/res/drawable/check.xml12
-rw-r--r--app/src/main/res/drawable/grid_item_background_selector.xml6
-rw-r--r--app/src/main/res/drawable/ic_arrow_back_grey600_24dp.xml (renamed from app/src/main/res/drawable/ic_arrow_back_white_24dp.xml)2
-rw-r--r--app/src/main/res/drawable/ic_baseline_dashboard_24.xml5
-rw-r--r--app/src/main/res/drawable/ic_baseline_help_outline_24.xml5
-rw-r--r--app/src/main/res/drawable/ic_baseline_menu_24.xml5
-rw-r--r--app/src/main/res/drawable/ic_check_white_24dp.xml5
-rw-r--r--app/src/main/res/drawable/ic_color_lens_grey600_24dp.xml5
-rw-r--r--app/src/main/res/drawable/ic_delete_white_24dp.xml5
-rw-r--r--app/src/main/res/drawable/ic_edit_grey600_24dp.xml (renamed from app/src/main/res/drawable/ic_edit_white_24dp.xml)2
-rw-r--r--app/src/main/res/drawable/ic_eye_grey600_24dp.xml (renamed from app/src/main/res/drawable/ic_eye_white_24dp.xml)2
-rw-r--r--app/src/main/res/drawable/ic_launcher_foreground_full.xml13
-rw-r--r--app/src/main/res/drawable/ic_remove_red_eye_grey_24dp.xml10
-rw-r--r--app/src/main/res/drawable/ic_search_grey600_24dp.xml9
-rw-r--r--app/src/main/res/drawable/ic_search_white_24dp.xml5
-rw-r--r--app/src/main/res/drawable/ic_send_grey600_24dp.xml (renamed from app/src/main/res/drawable/ic_send_white_24dp.xml)2
-rw-r--r--app/src/main/res/drawable/splashscreen.xml2
-rw-r--r--app/src/main/res/layout/activity_about.xml40
-rw-r--r--app/src/main/res/layout/activity_edit.xml26
-rw-r--r--app/src/main/res/layout/activity_exception.xml17
-rw-r--r--app/src/main/res/layout/activity_formatting_help.xml43
-rw-r--r--app/src/main/res/layout/activity_manage_accounts.xml32
-rw-r--r--app/src/main/res/layout/activity_note_list_configuration.xml1
-rw-r--r--app/src/main/res/layout/activity_notes_list_view.xml99
-rw-r--r--app/src/main/res/layout/activity_preferences.xml26
-rw-r--r--app/src/main/res/layout/dialog_account_switcher.xml139
-rw-r--r--app/src/main/res/layout/dialog_change_category.xml19
-rw-r--r--app/src/main/res/layout/dialog_exception.xml2
-rw-r--r--app/src/main/res/layout/drawer_layout.xml133
-rw-r--r--app/src/main/res/layout/fragment_about_license_tab.xml9
-rw-r--r--app/src/main/res/layout/fragment_note_edit.xml19
-rw-r--r--app/src/main/res/layout/fragment_note_preview.xml10
-rw-r--r--app/src/main/res/layout/item_account.xml4
-rw-r--r--app/src/main/res/layout/item_account_choose.xml62
-rw-r--r--app/src/main/res/layout/item_category.xml10
-rw-r--r--app/src/main/res/layout/item_navigation.xml44
-rw-r--r--app/src/main/res/layout/item_notes_list_note_item_grid.xml106
-rw-r--r--app/src/main/res/layout/item_notes_list_note_item_grid_only_title.xml61
-rw-r--r--app/src/main/res/layout/item_notes_list_note_item_with_excerpt.xml (renamed from app/src/main/res/layout/item_notes_list_note_item.xml)82
-rw-r--r--app/src/main/res/layout/item_notes_list_note_item_without_excerpt.xml99
-rw-r--r--app/src/main/res/layout/item_notes_list_section_item.xml43
-rw-r--r--app/src/main/res/layout/item_pref.xml5
-rw-r--r--app/src/main/res/layout/item_preference_category.xml12
-rw-r--r--app/src/main/res/layout/widget_create_note.xml20
-rw-r--r--app/src/main/res/layout/widget_entry.xml2
-rw-r--r--app/src/main/res/layout/widget_entry_dark.xml2
-rw-r--r--app/src/main/res/layout/widget_note_list.xml15
-rw-r--r--app/src/main/res/layout/widget_note_list_dark.xml5
-rw-r--r--app/src/main/res/menu/menu_list_context_multiple.xml11
-rw-r--r--app/src/main/res/menu/menu_list_view.xml17
-rw-r--r--app/src/main/res/menu/menu_note_activity.xml4
-rw-r--r--app/src/main/res/menu/menu_note_fragment.xml9
-rw-r--r--app/src/main/res/values-ca/strings.xml5
-rw-r--r--app/src/main/res/values-cs-rCZ/strings.xml56
-rw-r--r--app/src/main/res/values-da/strings.xml12
-rw-r--r--app/src/main/res/values-de/strings.xml56
-rw-r--r--app/src/main/res/values-el/strings.xml56
-rw-r--r--app/src/main/res/values-es/strings.xml16
-rw-r--r--app/src/main/res/values-eu/strings.xml14
-rw-r--r--app/src/main/res/values-fa/strings.xml5
-rw-r--r--app/src/main/res/values-fi-rFI/strings.xml5
-rw-r--r--app/src/main/res/values-fr/strings.xml29
-rw-r--r--app/src/main/res/values-gl/strings.xml25
-rw-r--r--app/src/main/res/values-he/strings.xml7
-rw-r--r--app/src/main/res/values-hr/strings.xml13
-rw-r--r--app/src/main/res/values-hu-rHU/strings.xml6
-rw-r--r--app/src/main/res/values-it/strings.xml56
-rw-r--r--app/src/main/res/values-ja-rJP/strings.xml12
-rw-r--r--app/src/main/res/values-lt-rLT/strings.xml5
-rw-r--r--app/src/main/res/values-night/booleans.xml4
-rw-r--r--app/src/main/res/values-night/colors.xml10
-rw-r--r--app/src/main/res/values-nl/strings.xml16
-rw-r--r--app/src/main/res/values-pl/strings.xml49
-rw-r--r--app/src/main/res/values-pt-rBR/strings.xml16
-rw-r--r--app/src/main/res/values-ru/strings.xml15
-rw-r--r--app/src/main/res/values-sk-rSK/strings.xml47
-rw-r--r--app/src/main/res/values-sl/strings.xml19
-rw-r--r--app/src/main/res/values-sr/strings.xml16
-rw-r--r--app/src/main/res/values-sv/strings.xml6
-rw-r--r--app/src/main/res/values-tr/strings.xml56
-rw-r--r--app/src/main/res/values-v23/styles.xml14
-rw-r--r--app/src/main/res/values-v27/styles.xml18
-rw-r--r--app/src/main/res/values-w1280dp/integers.xml4
-rw-r--r--app/src/main/res/values-w320dp/integers.xml4
-rw-r--r--app/src/main/res/values-w600dp/integers.xml4
-rw-r--r--app/src/main/res/values-w800dp/integers.xml4
-rw-r--r--app/src/main/res/values-zh-rCN/strings.xml5
-rw-r--r--app/src/main/res/values-zh-rTW/strings.xml4
-rw-r--r--app/src/main/res/values/booleans.xml4
-rw-r--r--app/src/main/res/values/colors.xml15
-rw-r--r--app/src/main/res/values/dimens.xml7
-rw-r--r--app/src/main/res/values/integers.xml4
-rw-r--r--app/src/main/res/values/strings.xml83
-rw-r--r--app/src/main/res/values/styles.xml15
-rw-r--r--app/src/main/res/xml/preferences.xml146
-rw-r--r--fastlane/metadata/android/de-DE/changelogs/39.txt6
-rw-r--r--fastlane/metadata/android/de-DE/changelogs/40.txt1
-rw-r--r--fastlane/metadata/android/de-DE/changelogs/41.txt1
-rw-r--r--fastlane/metadata/android/de-DE/changelogs/42.txt1
-rw-r--r--fastlane/metadata/android/de-DE/changelogs/43.txt1
-rw-r--r--fastlane/metadata/android/de-DE/full_description.txt28
-rw-r--r--fastlane/metadata/android/de-DE/images/icon.pngbin34307 -> 0 bytes
-rw-r--r--fastlane/metadata/android/de-DE/images/phoneScreenshots/1.pngbin323471 -> 0 bytes
-rw-r--r--fastlane/metadata/android/de-DE/images/phoneScreenshots/2.pngbin381103 -> 0 bytes
-rw-r--r--fastlane/metadata/android/de-DE/images/phoneScreenshots/3.pngbin361636 -> 0 bytes
-rw-r--r--fastlane/metadata/android/de-DE/images/phoneScreenshots/4.pngbin342165 -> 0 bytes
-rw-r--r--fastlane/metadata/android/de-DE/images/phoneScreenshots/5.pngbin392268 -> 0 bytes
-rw-r--r--fastlane/metadata/android/de-DE/short_description.txt1
-rw-r--r--fastlane/metadata/android/de-DE/title.txt1
-rw-r--r--fastlane/metadata/android/en-US/changelogs/2012002.txt5
-rw-r--r--fastlane/metadata/android/en-US/changelogs/2013000.txt8
-rw-r--r--fastlane/metadata/android/en-US/changelogs/2013001.txt6
-rw-r--r--fastlane/metadata/android/en-US/changelogs/2013002.txt6
-rw-r--r--fastlane/metadata/android/en-US/changelogs/2013003.txt6
-rw-r--r--fastlane/metadata/android/en-US/changelogs/2014000.txt4
-rw-r--r--fastlane/metadata/android/en-US/changelogs/2014001.txt2
-rw-r--r--fastlane/metadata/android/en-US/changelogs/2015000.txt15
-rw-r--r--fastlane/metadata/android/en-US/images/icon.pngbin34307 -> 17774 bytes
-rw-r--r--fastlane/metadata/android/en-US/images/phoneScreenshots/1.pngbin319340 -> 303719 bytes
-rw-r--r--fastlane/metadata/android/en-US/images/phoneScreenshots/2.pngbin369476 -> 324422 bytes
-rw-r--r--fastlane/metadata/android/en-US/images/phoneScreenshots/3.pngbin350017 -> 349766 bytes
-rw-r--r--fastlane/metadata/android/en-US/images/phoneScreenshots/4.pngbin305218 -> 332753 bytes
-rw-r--r--fastlane/metadata/android/en-US/images/phoneScreenshots/5.pngbin390115 -> 339575 bytes
-rw-r--r--fastlane/metadata/android/en-US/images/phoneScreenshots/6.pngbin351473 -> 0 bytes
-rw-r--r--fastlane/metadata/android/en-US/title.txt2
219 files changed, 5758 insertions, 1656 deletions
diff --git a/README.md b/README.md
index 0488dc4c..87365623 100644
--- a/README.md
+++ b/README.md
@@ -27,9 +27,9 @@ An android client for [Nextcloud Notes App](https://github.com/nextcloud/notes/)
## :eyes: Screenshots
-| Navi | List View | Edit Mode |
+| List View | Edit Mode | Preview |
| :--: | :--: | :--: |
-| ![Screenshot of categories in sidebar](/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png) | ![Screenshot of list view](/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png) | ![Screenshot of edit view](/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png) |
+| ![Screenshot of list view](/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png) | ![Screenshot of edit mode](/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png) | ![Screenshot of preview](/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png) |
## :rocket: Features
* Multiple accounts
diff --git a/app/build.gradle b/app/build.gradle
index 65f46fb2..38e4542c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -11,10 +11,10 @@ android {
defaultConfig {
applicationId "it.niedermann.owncloud.notes"
- minSdkVersion 16
+ minSdkVersion 17
targetSdkVersion 29
- versionCode 2012001
- versionName "2.12.1"
+ versionCode 2015000
+ versionName "2.15.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -56,19 +56,19 @@ android {
dependencies {
// Nextcloud SSO
- implementation "com.github.nextcloud:Android-SingleSignOn:0.5.0"
+ implementation "com.github.nextcloud:Android-SingleSignOn:0.5.1"
// Markdown
implementation 'com.yydcdut:markdown-processor:0.1.3'
implementation 'com.yydcdut:rxmarkdown-wrapper:0.1.3'
// Glide
- implementation 'com.github.bumptech.glide:glide:4.10.0'
- annotationProcessor 'com.github.bumptech.glide:compiler:4.10.0'
+ implementation 'com.github.bumptech.glide:glide:4.11.0'
+ annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
// Android X
implementation "androidx.appcompat:appcompat:1.1.0"
- implementation "androidx.fragment:fragment:1.2.4"
+ implementation "androidx.fragment:fragment:1.2.5"
implementation "androidx.preference:preference:1.1.1"
implementation "androidx.recyclerview:recyclerview:1.1.0"
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'
diff --git a/app/src/androidTest/java/it/niedermann/nextcloud/deck/util/ColorUtilTest.java b/app/src/androidTest/java/it/niedermann/nextcloud/deck/util/ColorUtilTest.java
index bde7ef68..2977c08b 100644
--- a/app/src/androidTest/java/it/niedermann/nextcloud/deck/util/ColorUtilTest.java
+++ b/app/src/androidTest/java/it/niedermann/nextcloud/deck/util/ColorUtilTest.java
@@ -6,7 +6,9 @@ import androidx.annotation.ColorInt;
import androidx.core.util.Pair;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import java.util.ArrayList;
@@ -98,4 +100,27 @@ public class ColorUtilTest {
);
}
}
+
+ @Rule
+ public final ExpectedException exception = ExpectedException.none();
+
+ @Test
+ public void testGetCleanHexaColorString() {
+ final List<Pair<String, String>> validColors = new ArrayList<>();
+ validColors.add(new Pair<>("#0082C9", "#0082C9"));
+ validColors.add(new Pair<>("0082C9", "#0082C9"));
+ validColors.add(new Pair<>("#CCC", "#CCCCCC"));
+ validColors.add(new Pair<>("ccc", "#cccccc"));
+ validColors.add(new Pair<>("af0", "#aaff00"));
+ validColors.add(new Pair<>("#af0", "#aaff00"));
+ for (Pair<String, String> color : validColors) {
+ assertEquals("Expect " + color.first + " to be cleaned up to " + color.second, color.second, ColorUtil.formatColorToParsableHexString(color.first));
+ }
+
+ final String[] invalidColors = new String[]{null, "", "cc", "c", "#a", "#55L", "55L"};
+ for (String color : invalidColors) {
+ exception.expect(IllegalArgumentException.class);
+ ColorUtil.formatColorToParsableHexString(color);
+ }
+ }
}
diff --git a/app/src/androidTest/java/it/niedermann/owncloud/notes/persistence/NotesDatabaseTest.java b/app/src/androidTest/java/it/niedermann/owncloud/notes/persistence/NotesDatabaseTest.java
index e8fad4cc..ef7e5f65 100644
--- a/app/src/androidTest/java/it/niedermann/owncloud/notes/persistence/NotesDatabaseTest.java
+++ b/app/src/androidTest/java/it/niedermann/owncloud/notes/persistence/NotesDatabaseTest.java
@@ -1,6 +1,5 @@
package it.niedermann.owncloud.notes.persistence;
-import it.niedermann.owncloud.notes.R;
import it.niedermann.owncloud.notes.model.Capabilities;
import it.niedermann.owncloud.notes.model.Category;
import it.niedermann.owncloud.notes.model.CloudNote;
@@ -8,14 +7,11 @@ import it.niedermann.owncloud.notes.model.DBNote;
import it.niedermann.owncloud.notes.model.DBStatus;
import it.niedermann.owncloud.notes.model.LocalAccount;
import it.niedermann.owncloud.notes.model.NavigationAdapter;
-import it.niedermann.owncloud.notes.persistence.NotesDatabase;
import it.niedermann.owncloud.notes.util.CategorySortingMethod;
import it.niedermann.owncloud.notes.util.NoteUtil;
import android.content.Context;
import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import androidx.preference.PreferenceManager;
@@ -30,18 +26,21 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
-import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
-import java.util.Collections;
import java.util.Date;
import java.util.List;
-import java.util.ArrayList;
import java.util.TimeZone;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
/**
@@ -151,7 +150,7 @@ public class NotesDatabaseTest {
String newContent = getCurDate() + " This is a even greater day my friend.";
DBNote dbNote = new DBNote(newNoteID, 1, Calendar.getInstance(), "A Greater Day",
newContent, true, "Best Friend's Record", null, DBStatus.VOID,
- accountID, NoteUtil.generateNoteExcerpt(newContent));
+ accountID, NoteUtil.generateNoteExcerpt(newContent), 0);
// Add a new note
long noteID = db.addNote(accountID, dbNote);
@@ -166,7 +165,7 @@ public class NotesDatabaseTest {
newContent = getCurDate() + " This is a even greater day my friend.";
dbNote = new DBNote(0, 1, Calendar.getInstance(), "An Even Greater Day",
newContent, true, "Sincere Friend's Record", null, DBStatus.VOID,
- accountID, NoteUtil.generateNoteExcerpt(newContent));
+ accountID, NoteUtil.generateNoteExcerpt(newContent), 0);
// Add a new note
noteID = db.addNote(accountID, dbNote);
// Check if this note is added successfully
@@ -211,7 +210,7 @@ public class NotesDatabaseTest {
@Test
public void test_04_getCategories() {
- List<NavigationAdapter.NavigationItem> categories = db.getCategories(account.getId());
+ List<NavigationAdapter.CategoryNavigationItem> categories = db.getCategories(account.getId());
boolean exitFlag = false;
for (NavigationAdapter.NavigationItem categoryItem : categories) {
Log.i("Test_04_getCategories_Item", String.format("%s | %s | %d | %d", categoryItem.id, categoryItem.label, categoryItem.count, categoryItem.icon));
@@ -224,7 +223,7 @@ public class NotesDatabaseTest {
@Test
public void test_05_searchCategories() {
- List<NavigationAdapter.NavigationItem> categories = db.searchCategories(account.getId(), "Dia");
+ List<NavigationAdapter.CategoryNavigationItem> categories = db.searchCategories(account.getId(), "Dia");
boolean exitFlag = false;
for (NavigationAdapter.NavigationItem categoryItem : categories) {
Log.i("Test_05_searchCategories_Dia", String.format("%s | %s | %d | %d", categoryItem.id, categoryItem.label, categoryItem.count, categoryItem.icon));
@@ -360,7 +359,7 @@ public class NotesDatabaseTest {
@Test
public void test_09_multiGetCategories() {
- List<NavigationAdapter.NavigationItem> categories = db.getCategories(account.getId());
+ List<NavigationAdapter.CategoryNavigationItem> categories = db.getCategories(account.getId());
int count = 0;
for (NavigationAdapter.NavigationItem categoryItem : categories) {
Log.i("Test_09_multiGetCategories_Item", String.format("%s | %s | %d | %d", categoryItem.id, categoryItem.label, categoryItem.count, categoryItem.icon));
@@ -373,7 +372,7 @@ public class NotesDatabaseTest {
@Test
public void test_10_multiSearchCategories() {
- List<NavigationAdapter.NavigationItem> categories = db.searchCategories(account.getId(), "M");
+ List<NavigationAdapter.CategoryNavigationItem> categories = db.searchCategories(account.getId(), "M");
int count = 0;
for (NavigationAdapter.NavigationItem categoryItem : categories) {
Log.i("Test_10_multiSearchCategories_Item", String.format("%s | %s | %d | %d", categoryItem.id, categoryItem.label, categoryItem.count, categoryItem.icon));
@@ -482,7 +481,7 @@ public class NotesDatabaseTest {
Log.i("Test_12_Chinese", "Size: " + notes.size());
assertEquals(1, notes.size());
- List<NavigationAdapter.NavigationItem> categories = db.getCategories(account.getId());
+ List<NavigationAdapter.CategoryNavigationItem> categories = db.getCategories(account.getId());
boolean exitFlag = false;
for (NavigationAdapter.NavigationItem categoryItem : categories) {
Log.i("Test_12_Chinese_Item", String.format("%s | %s | %d | %d", categoryItem.id, categoryItem.label, categoryItem.count, categoryItem.icon));
@@ -524,7 +523,7 @@ public class NotesDatabaseTest {
String.class);
method.setAccessible(true);
- List<NavigationAdapter.NavigationItem> categories = db.getCategories(account.getId());
+ List<NavigationAdapter.CategoryNavigationItem> categories = db.getCategories(account.getId());
int count = 0;
for (NavigationAdapter.NavigationItem categoryItem : categories) {
Log.i("Test_13_getCategoryIdByTitle", String.format("%s | %s | %d | %d",
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 6180a1a6..f3117ead 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -63,6 +63,18 @@
android:label="@string/app_name" />
<activity
+ android:name=".formattinghelp.FormattingHelpActivity"
+ android:label="@string/action_formatting_help"
+ android:parentActivityName=".android.activity.NotesListViewActivity"
+ android:windowSoftInputMode="stateHidden" />
+
+ <activity
+ android:name=".manageaccounts.ManageAccountsActivity"
+ android:label="@string/manage_accounts"
+ android:parentActivityName=".android.activity.NotesListViewActivity"
+ android:windowSoftInputMode="stateHidden" />
+
+ <activity
android:name=".android.activity.PreferencesActivity"
android:label="@string/action_settings"
android:parentActivityName=".android.activity.NotesListViewActivity"
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherAdapter.java b/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherAdapter.java
new file mode 100644
index 00000000..0223a53f
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherAdapter.java
@@ -0,0 +1,54 @@
+package it.niedermann.owncloud.notes.accountswitcher;
+
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.core.util.Consumer;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import it.niedermann.owncloud.notes.R;
+import it.niedermann.owncloud.notes.model.LocalAccount;
+
+public class AccountSwitcherAdapter extends RecyclerView.Adapter<AccountSwitcherViewHolder> {
+
+ @NonNull
+ private final List<LocalAccount> localAccounts = new ArrayList<>();
+ @NonNull
+ private final Consumer<LocalAccount> onAccountClick;
+
+ public AccountSwitcherAdapter(@NonNull Consumer<LocalAccount> onAccountClick) {
+ this.onAccountClick = onAccountClick;
+ setHasStableIds(true);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return localAccounts.get(position).getId();
+ }
+
+ @NonNull
+ @Override
+ public AccountSwitcherViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ return new AccountSwitcherViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_account_choose, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull AccountSwitcherViewHolder holder, int position) {
+ holder.bind(localAccounts.get(position), onAccountClick);
+ }
+
+ @Override
+ public int getItemCount() {
+ return localAccounts.size();
+ }
+
+ public void setLocalAccounts(@NonNull List<LocalAccount> localAccounts) {
+ this.localAccounts.clear();
+ this.localAccounts.addAll(localAccounts);
+ notifyDataSetChanged();
+ }
+}
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
new file mode 100644
index 00000000..249d2c3d
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherDialog.java
@@ -0,0 +1,115 @@
+package it.niedermann.owncloud.notes.accountswitcher;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.LayerDrawable;
+import android.net.Uri;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.DialogFragment;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.RequestOptions;
+
+import java.util.List;
+
+import it.niedermann.owncloud.notes.R;
+import it.niedermann.owncloud.notes.branding.BrandedDialogFragment;
+import it.niedermann.owncloud.notes.databinding.DialogAccountSwitcherBinding;
+import it.niedermann.owncloud.notes.manageaccounts.ManageAccountsActivity;
+import it.niedermann.owncloud.notes.model.LocalAccount;
+import it.niedermann.owncloud.notes.persistence.NotesDatabase;
+
+import static it.niedermann.owncloud.notes.android.activity.NotesListViewActivity.manage_account;
+import static it.niedermann.owncloud.notes.branding.BrandingUtil.applyBrandToLayerDrawable;
+
+public class AccountSwitcherDialog extends BrandedDialogFragment {
+
+ private static final String KEY_CURRENT_ACCOUNT_ID = "current_account_id";
+
+ private NotesDatabase db;
+ private DialogAccountSwitcherBinding binding;
+ private AccountSwitcherListener accountSwitcherListener;
+ private long currentAccountId;
+
+ @Override
+ public void onAttach(@NonNull Context context) {
+ super.onAttach(context);
+ if (context instanceof AccountSwitcherListener) {
+ this.accountSwitcherListener = (AccountSwitcherListener) context;
+ } else {
+ throw new ClassCastException("Caller must implement " + AccountSwitcherListener.class.getSimpleName());
+ }
+
+ final Bundle args = getArguments();
+
+ if (args == null || !args.containsKey(KEY_CURRENT_ACCOUNT_ID)) {
+ throw new IllegalArgumentException("Please provide at least " + KEY_CURRENT_ACCOUNT_ID);
+ } else {
+ this.currentAccountId = args.getLong(KEY_CURRENT_ACCOUNT_ID);
+ }
+
+ db = NotesDatabase.getInstance(getActivity());
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ binding = DialogAccountSwitcherBinding.inflate(requireActivity().getLayoutInflater());
+
+ LocalAccount currentLocalAccount = db.getAccount(currentAccountId);
+ binding.accountItemLabel.setText(currentLocalAccount.getAccountName());
+ Glide.with(requireContext())
+ .load(currentLocalAccount.getUrl() + "/index.php/avatar/" + Uri.encode(currentLocalAccount.getUserName()) + "/64")
+ .error(R.drawable.ic_account_circle_grey_24dp)
+ .apply(RequestOptions.circleCropTransform())
+ .into(binding.currentAccountItemAvatar);
+ binding.accountLayout.setOnClickListener((v) -> dismiss());
+
+ AccountSwitcherAdapter adapter = new AccountSwitcherAdapter((localAccount -> {
+ accountSwitcherListener.onAccountChosen(localAccount);
+ dismiss();
+ }));
+ binding.accountsList.setAdapter(adapter);
+ List<LocalAccount> localAccounts = db.getAccounts();
+ for (LocalAccount localAccount : localAccounts) {
+ if (localAccount.getId() == currentLocalAccount.getId()) {
+ localAccounts.remove(localAccount);
+ break;
+ }
+ }
+ adapter.setLocalAccounts(localAccounts);
+
+ binding.addAccount.setOnClickListener((v) -> {
+ accountSwitcherListener.addAccount();
+ dismiss();
+ });
+
+ binding.manageAccounts.setOnClickListener((v) -> {
+ requireActivity().startActivityForResult(new Intent(requireContext(), ManageAccountsActivity.class), manage_account);
+ dismiss();
+ });
+
+ return new AlertDialog.Builder(requireContext())
+ .setView(binding.getRoot())
+ .create();
+ }
+
+ public static DialogFragment newInstance(long currentAccountId) {
+ DialogFragment dialog = new AccountSwitcherDialog();
+
+ Bundle args = new Bundle();
+ args.putLong(KEY_CURRENT_ACCOUNT_ID, currentAccountId);
+ dialog.setArguments(args);
+
+ return dialog;
+ }
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ applyBrandToLayerDrawable((LayerDrawable) binding.check.getDrawable(), R.id.area, mainColor);
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherListener.java b/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherListener.java
new file mode 100644
index 00000000..2e26277f
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherListener.java
@@ -0,0 +1,11 @@
+package it.niedermann.owncloud.notes.accountswitcher;
+
+import it.niedermann.owncloud.notes.model.LocalAccount;
+
+public interface AccountSwitcherListener {
+ void addAccount();
+
+ void onAccountChosen(LocalAccount localAccount);
+
+ void onAccountDeleted(LocalAccount localAccount);
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherViewHolder.java b/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherViewHolder.java
new file mode 100644
index 00000000..7093e651
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/accountswitcher/AccountSwitcherViewHolder.java
@@ -0,0 +1,36 @@
+package it.niedermann.owncloud.notes.accountswitcher;
+
+import android.net.Uri;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.core.util.Consumer;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.RequestOptions;
+
+import it.niedermann.owncloud.notes.R;
+import it.niedermann.owncloud.notes.databinding.ItemAccountChooseBinding;
+import it.niedermann.owncloud.notes.model.LocalAccount;
+
+public class AccountSwitcherViewHolder extends RecyclerView.ViewHolder {
+
+ ItemAccountChooseBinding binding;
+
+ public AccountSwitcherViewHolder(@NonNull View itemView) {
+ super(itemView);
+ binding = ItemAccountChooseBinding.bind(itemView);
+ }
+
+ public void bind(@NonNull LocalAccount localAccount, @NonNull Consumer<LocalAccount> onAccountClick) {
+ binding.accountItemLabel.setText(localAccount.getAccountName());
+ Glide.with(itemView.getContext())
+ .load(localAccount.getUrl() + "/index.php/avatar/" + Uri.encode(localAccount.getUserName()) + "/64")
+ .error(R.drawable.ic_account_circle_grey_24dp)
+ .apply(RequestOptions.circleCropTransform())
+ .into(binding.accountItemAvatar);
+ itemView.setOnClickListener((v) -> onAccountClick.accept(localAccount));
+ binding.delete.setVisibility(View.GONE);
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/MultiSelectedActionModeCallback.java b/app/src/main/java/it/niedermann/owncloud/notes/android/MultiSelectedActionModeCallback.java
index c9c3a59d..b90be5d7 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/MultiSelectedActionModeCallback.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/MultiSelectedActionModeCallback.java
@@ -1,13 +1,18 @@
package it.niedermann.owncloud.notes.android;
import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
+import androidx.annotation.ColorInt;
import androidx.appcompat.view.ActionMode;
import androidx.appcompat.view.ActionMode.Callback;
import androidx.appcompat.widget.SearchView;
+import androidx.core.graphics.drawable.DrawableCompat;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -22,14 +27,19 @@ import java.util.List;
import it.niedermann.owncloud.notes.R;
import it.niedermann.owncloud.notes.android.activity.NotesListViewActivity;
-import it.niedermann.owncloud.notes.android.fragment.AccountChooserDialogFragment;
+import it.niedermann.owncloud.notes.android.fragment.MoveAccountDialogFragment;
+import it.niedermann.owncloud.notes.branding.BrandedSnackbar;
import it.niedermann.owncloud.notes.model.DBNote;
import it.niedermann.owncloud.notes.model.ItemAdapter;
import it.niedermann.owncloud.notes.persistence.NoteServerSyncHelper.ViewProvider;
import it.niedermann.owncloud.notes.persistence.NotesDatabase;
+import it.niedermann.owncloud.notes.util.ShareUtil;
public class MultiSelectedActionModeCallback implements Callback {
+ @ColorInt
+ private int colorAccent;
+
private final Context context;
private final ViewProvider viewProvider;
private final NotesDatabase db;
@@ -49,12 +59,24 @@ public class MultiSelectedActionModeCallback implements Callback {
this.refreshLists = refreshLists;
this.fragmentManager = fragmentManager;
this.searchView = searchView;
+
+ final TypedValue typedValue = new TypedValue();
+ context.getTheme().resolveAttribute(R.attr.colorAccent, typedValue, true);
+ colorAccent = typedValue.data;
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// inflate contextual menu
mode.getMenuInflater().inflate(R.menu.menu_list_context_multiple, menu);
+ for (int i = 0; i < menu.size(); i++) {
+ Drawable drawable = menu.getItem(i).getIcon();
+ if (drawable != null) {
+ drawable = DrawableCompat.wrap(drawable);
+ DrawableCompat.setTint(drawable, colorAccent);
+ menu.getItem(i).setIcon(drawable);
+ }
+ }
return true;
}
@@ -88,7 +110,7 @@ public class MultiSelectedActionModeCallback implements Callback {
String deletedSnackbarTitle = deletedNotes.size() == 1
? context.getString(R.string.action_note_deleted, deletedNotes.get(0).getTitle())
: context.getString(R.string.bulk_notes_deleted, deletedNotes.size());
- Snackbar.make(viewProvider.getView(), deletedSnackbarTitle, Snackbar.LENGTH_LONG)
+ BrandedSnackbar.make(viewProvider.getView(), deletedSnackbarTitle, Snackbar.LENGTH_LONG)
.setAction(R.string.action_undo, (View v) -> {
db.getNoteServerSyncHelper().addCallbackPush(ssoAccount, refreshLists::run);
for (DBNote deletedNote : deletedNotes) {
@@ -98,7 +120,7 @@ public class MultiSelectedActionModeCallback implements Callback {
String restoreSnackbarTitle = deletedNotes.size() == 1
? context.getString(R.string.action_note_restored, deletedNotes.get(0).getTitle())
: context.getString(R.string.bulk_notes_restored, deletedNotes.size());
- Snackbar.make(viewProvider.getView(), restoreSnackbarTitle, Snackbar.LENGTH_SHORT)
+ BrandedSnackbar.make(viewProvider.getView(), restoreSnackbarTitle, Snackbar.LENGTH_SHORT)
.show();
})
.show();
@@ -107,7 +129,24 @@ public class MultiSelectedActionModeCallback implements Callback {
}
return true;
case R.id.menu_move:
- AccountChooserDialogFragment.newInstance().show(fragmentManager, NotesListViewActivity.class.getSimpleName());
+ MoveAccountDialogFragment.newInstance().show(fragmentManager, NotesListViewActivity.class.getSimpleName());
+ return true;
+ case R.id.menu_share:
+ final String subject = (adapter.getSelected().size() == 1)
+ ? ((DBNote) adapter.getItem(adapter.getSelected().get(0))).getTitle()
+ : context.getString(R.string.share_multiple, adapter.getSelected().size());
+ final StringBuilder noteContents = new StringBuilder();
+ for (Integer i : adapter.getSelected()) {
+ final DBNote noteWithoutContent = (DBNote) adapter.getItem(i);
+ final String tempFullNote = db.getNote(noteWithoutContent.getAccountId(), noteWithoutContent.getId()).getContent();
+ if (!TextUtils.isEmpty(tempFullNote)) {
+ if (noteContents.length() > 0) {
+ noteContents.append("\n\n");
+ }
+ noteContents.append(tempFullNote);
+ }
+ }
+ ShareUtil.openShareDialog(context, subject, noteContents.toString());
return true;
default:
return false;
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/NotesListViewItemTouchHelper.java b/app/src/main/java/it/niedermann/owncloud/notes/android/NotesListViewItemTouchHelper.java
index ccb3cd9c..ed3cc8c2 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/NotesListViewItemTouchHelper.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/NotesListViewItemTouchHelper.java
@@ -16,9 +16,12 @@ import com.google.android.material.snackbar.Snackbar;
import com.nextcloud.android.sso.model.SingleSignOnAccount;
import it.niedermann.owncloud.notes.R;
+import it.niedermann.owncloud.notes.branding.BrandedSnackbar;
import it.niedermann.owncloud.notes.model.DBNote;
import it.niedermann.owncloud.notes.model.ISyncCallback;
import it.niedermann.owncloud.notes.model.ItemAdapter;
+import it.niedermann.owncloud.notes.model.NoteViewHolder;
+import it.niedermann.owncloud.notes.model.SectionViewHolder;
import it.niedermann.owncloud.notes.persistence.NoteServerSyncHelper.ViewProvider;
import it.niedermann.owncloud.notes.persistence.NotesDatabase;
@@ -34,8 +37,8 @@ public class NotesListViewItemTouchHelper extends ItemTouchHelper {
@NonNull ISyncCallback syncCallBack,
@NonNull Runnable refreshLists,
@Nullable SwipeRefreshLayout swipeRefreshLayout,
- @Nullable ViewProvider viewProvider
- ) {
+ @Nullable ViewProvider viewProvider,
+ boolean gridView) {
super(new SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
private boolean swipeRefreshLayoutEnabled;
@@ -45,15 +48,15 @@ public class NotesListViewItemTouchHelper extends ItemTouchHelper {
}
/**
- * Disable swipe on sections
+ * Disable swipe on sections and if grid view is enabled
*
* @param recyclerView RecyclerView
* @param viewHolder RecyclerView.ViewHoler
- * @return 0 if section, otherwise super()
+ * @return 0 if viewHolder is section or grid view is enabled, otherwise super()
*/
@Override
public int getSwipeDirs(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
- if (viewHolder instanceof ItemAdapter.SectionViewHolder) return 0;
+ if (gridView || viewHolder instanceof SectionViewHolder) return 0;
return super.getSwipeDirs(recyclerView, viewHolder);
}
@@ -76,12 +79,12 @@ public class NotesListViewItemTouchHelper extends ItemTouchHelper {
if (viewProvider == null) {
Toast.makeText(context, context.getString(R.string.action_note_deleted, dbNote.getTitle()), Toast.LENGTH_LONG).show();
} else {
- Snackbar.make(viewProvider.getView(), context.getString(R.string.action_note_deleted, dbNote.getTitle()), Snackbar.LENGTH_LONG)
+ BrandedSnackbar.make(viewProvider.getView(), context.getString(R.string.action_note_deleted, dbNote.getTitle()), Snackbar.LENGTH_LONG)
.setAction(R.string.action_undo, (View v) -> {
db.getNoteServerSyncHelper().addCallbackPush(ssoAccount, refreshLists::run);
db.addNoteAndSync(ssoAccount, dbNote.getAccountId(), dbNote);
refreshLists.run();
- Snackbar.make(viewProvider.getView(), context.getString(R.string.action_note_restored, dbNote.getTitle()), Snackbar.LENGTH_SHORT)
+ BrandedSnackbar.make(viewProvider.getView(), context.getString(R.string.action_note_restored, dbNote.getTitle()), Snackbar.LENGTH_SHORT)
.show();
})
.show();
@@ -99,11 +102,11 @@ public class NotesListViewItemTouchHelper extends ItemTouchHelper {
@Override
public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
- ItemAdapter.NoteViewHolder noteViewHolder = (ItemAdapter.NoteViewHolder) viewHolder;
+ NoteViewHolder noteViewHolder = (NoteViewHolder) viewHolder;
// show swipe icon on the side
noteViewHolder.showSwipe(dX > 0);
// move only swipeable part of item (not leave-behind)
- getDefaultUIUtil().onDraw(c, recyclerView, noteViewHolder.noteSwipeable, dX, dY, actionState, isCurrentlyActive);
+ getDefaultUIUtil().onDraw(c, recyclerView, noteViewHolder.getNoteSwipeable(), dX, dY, actionState, isCurrentlyActive);
}
@Override
@@ -122,7 +125,7 @@ public class NotesListViewItemTouchHelper extends ItemTouchHelper {
if (swipeRefreshLayout != null) {
swipeRefreshLayout.setEnabled(swipeRefreshLayoutEnabled);
}
- getDefaultUIUtil().clearView(((ItemAdapter.NoteViewHolder) viewHolder).noteSwipeable);
+ getDefaultUIUtil().clearView(((NoteViewHolder) viewHolder).getNoteSwipeable());
}
@Override
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/AboutActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/AboutActivity.java
index 0334ba64..d6cd1c39 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/AboutActivity.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/AboutActivity.java
@@ -2,6 +2,7 @@ package it.niedermann.owncloud.notes.android.activity;
import android.os.Bundle;
+import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
@@ -11,15 +12,18 @@ import it.niedermann.owncloud.notes.R;
import it.niedermann.owncloud.notes.android.fragment.about.AboutFragmentContributingTab;
import it.niedermann.owncloud.notes.android.fragment.about.AboutFragmentCreditsTab;
import it.niedermann.owncloud.notes.android.fragment.about.AboutFragmentLicenseTab;
+import it.niedermann.owncloud.notes.branding.BrandingUtil;
import it.niedermann.owncloud.notes.databinding.ActivityAboutBinding;
public class AboutActivity extends LockedActivity {
+ private ActivityAboutBinding binding;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- ActivityAboutBinding binding = ActivityAboutBinding.inflate(getLayoutInflater());
+ binding = ActivityAboutBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
@@ -27,6 +31,12 @@ public class AboutActivity extends LockedActivity {
binding.tabs.setupWithViewPager(binding.pager);
}
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ @ColorInt int finalMainColor = BrandingUtil.getSecondaryForegroundColorDependingOnTheme(this, mainColor);
+ binding.tabs.setSelectedTabIndicatorColor(finalMainColor);
+ }
+
private class TabsPagerAdapter extends FragmentPagerAdapter {
TabsPagerAdapter(FragmentManager fragmentManager) {
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/AppendToNoteActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/AppendToNoteActivity.java
index 3f286c1c..2cc72aea 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/AppendToNoteActivity.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/AppendToNoteActivity.java
@@ -2,9 +2,13 @@ package it.niedermann.owncloud.notes.android.activity;
import android.content.Intent;
import android.os.Bundle;
+import android.util.Log;
import android.view.View;
import android.widget.Toast;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.ActionBar;
+
import it.niedermann.owncloud.notes.R;
import it.niedermann.owncloud.notes.model.DBNote;
@@ -20,7 +24,12 @@ public class AppendToNoteActivity extends NotesListViewActivity {
super.onCreate(savedInstanceState);
final Intent receivedIntent = getIntent();
receivedText = receivedIntent.getStringExtra(Intent.EXTRA_TEXT);
- binding.activityNotesListView.toolbar.setTitle(R.string.append_to_note);
+ @Nullable final ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ getSupportActionBar().setTitle(R.string.append_to_note);
+ } else {
+ Log.e(TAG, "SupportActioBar is null. Expected toolbar to be present to set a title.");
+ }
binding.activityNotesListView.toolbar.setSubtitle(receivedText);
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/EditNoteActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/EditNoteActivity.java
index d9e9fb7d..6e6fc2e6 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/EditNoteActivity.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/EditNoteActivity.java
@@ -29,9 +29,9 @@ import it.niedermann.owncloud.notes.model.DBNote;
import it.niedermann.owncloud.notes.model.LocalAccount;
import it.niedermann.owncloud.notes.util.NoteUtil;
-import static it.niedermann.owncloud.notes.android.fragment.AccountChooserAdapter.AccountChooserListener;
+import static it.niedermann.owncloud.notes.android.fragment.AccountChooserAdapter.MoveAccountListener;
-public class EditNoteActivity extends LockedActivity implements BaseNoteFragment.NoteFragmentListener, AccountChooserListener {
+public class EditNoteActivity extends LockedActivity implements BaseNoteFragment.NoteFragmentListener, MoveAccountListener {
private static final String TAG = EditNoteActivity.class.getSimpleName();
@@ -54,6 +54,7 @@ public class EditNoteActivity extends LockedActivity implements BaseNoteFragment
binding = ActivityEditBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
+ setSupportActionBar(binding.toolbar);
if (savedInstanceState == null) {
launchNoteFragment();
@@ -267,7 +268,12 @@ public class EditNoteActivity extends LockedActivity implements BaseNoteFragment
}
@Override
- public void onAccountChosen(LocalAccount account) {
+ public void moveToAccount(LocalAccount account) {
fragment.moveNote(account);
}
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ applyBrandToPrimaryToolbar(binding.toolbar);
+ }
} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/LockedActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/LockedActivity.java
index 0b0ca7c1..07a544df 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/LockedActivity.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/LockedActivity.java
@@ -8,13 +8,13 @@ import android.os.Bundle;
import android.util.Log;
import androidx.annotation.Nullable;
-import androidx.appcompat.app.AppCompatActivity;
import it.niedermann.owncloud.notes.ExceptionHandler;
import it.niedermann.owncloud.notes.R;
+import it.niedermann.owncloud.notes.branding.BrandedActivity;
import it.niedermann.owncloud.notes.util.Notes;
-public abstract class LockedActivity extends AppCompatActivity {
+public abstract class LockedActivity extends BrandedActivity {
private static final String TAG = LockedActivity.class.getSimpleName();
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/NoteListWidgetConfigurationActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/NoteListWidgetConfigurationActivity.java
index 2f50999b..92f20c4b 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/NoteListWidgetConfigurationActivity.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/NoteListWidgetConfigurationActivity.java
@@ -3,14 +3,12 @@ package it.niedermann.owncloud.notes.android.activity;
import android.app.Activity;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.Nullable;
-import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -26,6 +24,8 @@ import it.niedermann.owncloud.notes.R;
import it.niedermann.owncloud.notes.android.appwidget.NoteListWidget;
import it.niedermann.owncloud.notes.model.LocalAccount;
import it.niedermann.owncloud.notes.model.NavigationAdapter;
+import it.niedermann.owncloud.notes.model.NavigationAdapter.CategoryNavigationItem;
+import it.niedermann.owncloud.notes.model.NoteListsWidgetData;
import it.niedermann.owncloud.notes.persistence.NotesDatabase;
import it.niedermann.owncloud.notes.util.Notes;
@@ -57,6 +57,7 @@ public class NoteListWidgetConfigurationActivity extends LockedActivity {
// TODO Present user with app login screen
Log.w(TAG, "onCreate: user not logged in");
finish();
+ return;
}
final Bundle extras = getIntent().getExtras();
@@ -81,27 +82,33 @@ public class NoteListWidgetConfigurationActivity extends LockedActivity {
RecyclerView recyclerView;
RecyclerView.LayoutManager layoutManager;
- adapterCategories = new NavigationAdapter(new NavigationAdapter.ClickListener() {
+ adapterCategories = new NavigationAdapter(this, new NavigationAdapter.ClickListener() {
@Override
public void onItemClick(NavigationAdapter.NavigationItem item) {
- SharedPreferences.Editor sp = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).edit();
+ NoteListsWidgetData data = new NoteListsWidgetData();
+ data.setAppWidgetId(appWidgetId);
if (itemRecent.equals(item)) {
- sp.putInt(NoteListWidget.WIDGET_MODE_KEY + appWidgetId, NoteListWidget.NLW_DISPLAY_ALL);
+ data.setMode(NoteListsWidgetData.MODE_DISPLAY_ALL);
} else if (itemFavorites.equals(item)) {
- sp.putInt(NoteListWidget.WIDGET_MODE_KEY + appWidgetId, NoteListWidget.NLW_DISPLAY_STARRED);
+ data.setMode(NoteListsWidgetData.MODE_DISPLAY_STARRED);
} else {
String category = "";
if (!item.label.equals(getString(R.string.action_uncategorized))) {
category = item.label;
}
- sp.putInt(NoteListWidget.WIDGET_MODE_KEY + appWidgetId, NoteListWidget.NLW_DISPLAY_CATEGORY);
- sp.putString(NoteListWidget.WIDGET_CATEGORY_KEY + appWidgetId, category);
+ data.setMode(NoteListsWidgetData.MODE_DISPLAY_CATEGORY);
+ if (item instanceof CategoryNavigationItem) {
+ data.setCategoryId(((CategoryNavigationItem) item).categoryId);
+ } else {
+ throw new IllegalStateException("Tried to choose a category, but ");
+ }
}
- sp.putLong(NoteListWidget.ACCOUNT_ID_KEY + appWidgetId, localAccount.getId());
- sp.putString(NoteListWidget.DARK_THEME_KEY + appWidgetId, Notes.getAppTheme(getApplicationContext()).name());
- sp.apply();
+ data.setAccountId(localAccount.getId());
+ data.setThemeMode(Notes.getAppTheme(getApplicationContext()).getModeId());
+
+ db.createOrUpdateNoteListWidgetData(data);
Intent updateIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE, null,
getApplicationContext(), NoteListWidget.class);
@@ -129,6 +136,10 @@ public class NoteListWidgetConfigurationActivity extends LockedActivity {
new LoadCategoryListTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ }
+
private class LoadCategoryListTask extends AsyncTask<Void, Void, List<NavigationAdapter.NavigationItem>> {
@Override
protected List<NavigationAdapter.NavigationItem> doInBackground(Void... voids) {
@@ -136,7 +147,7 @@ public class NoteListWidgetConfigurationActivity extends LockedActivity {
return new ArrayList<>();
}
NavigationAdapter.NavigationItem itemUncategorized;
- List<NavigationAdapter.NavigationItem> categories = db.getCategories(localAccount.getId());
+ List<CategoryNavigationItem> categories = db.getCategories(localAccount.getId());
if (!categories.isEmpty() && categories.get(0).label.isEmpty()) {
itemUncategorized = categories.get(0);
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/NotesListViewActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/NotesListViewActivity.java
index d8b2927c..51630d59 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/NotesListViewActivity.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/NotesListViewActivity.java
@@ -1,34 +1,35 @@
package it.niedermann.owncloud.notes.android.activity;
+import android.animation.AnimatorInflater;
+import android.annotation.SuppressLint;
import android.app.SearchManager;
import android.content.Intent;
-import android.content.res.Configuration;
-import android.database.sqlite.SQLiteConstraintException;
+import android.database.sqlite.SQLiteException;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.text.TextUtils;
import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
import android.view.View;
import android.view.ViewTreeObserver;
-import android.widget.ImageView;
import android.widget.LinearLayout;
-import android.widget.TextView;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.view.ActionMode;
-import androidx.appcompat.widget.AppCompatImageView;
import androidx.appcompat.widget.SearchView;
-import androidx.appcompat.widget.Toolbar;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
+import androidx.core.content.ContextCompat;
+import androidx.core.graphics.drawable.DrawableCompat;
import androidx.core.view.GravityCompat;
+import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.bumptech.glide.Glide;
@@ -40,6 +41,7 @@ import com.nextcloud.android.sso.exceptions.AccountImportCancelledException;
import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException;
import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException;
import com.nextcloud.android.sso.exceptions.NoCurrentAccountSelectedException;
+import com.nextcloud.android.sso.exceptions.TokenMismatchException;
import com.nextcloud.android.sso.helper.SingleAccountHelper;
import com.nextcloud.android.sso.model.SingleSignOnAccount;
@@ -49,35 +51,55 @@ import java.util.List;
import java.util.Map;
import it.niedermann.owncloud.notes.R;
+import it.niedermann.owncloud.notes.accountswitcher.AccountSwitcherDialog;
+import it.niedermann.owncloud.notes.accountswitcher.AccountSwitcherListener;
import it.niedermann.owncloud.notes.android.MultiSelectedActionModeCallback;
import it.niedermann.owncloud.notes.android.NotesListViewItemTouchHelper;
-import it.niedermann.owncloud.notes.android.fragment.AccountChooserAdapter.AccountChooserListener;
+import it.niedermann.owncloud.notes.android.fragment.AccountChooserAdapter.MoveAccountListener;
import it.niedermann.owncloud.notes.android.fragment.ExceptionDialogFragment;
+import it.niedermann.owncloud.notes.branding.BrandedSnackbar;
+import it.niedermann.owncloud.notes.branding.BrandingUtil;
+import it.niedermann.owncloud.notes.databinding.ActivityNotesListViewBinding;
import it.niedermann.owncloud.notes.databinding.DrawerLayoutBinding;
+import it.niedermann.owncloud.notes.formattinghelp.FormattingHelpActivity;
import it.niedermann.owncloud.notes.model.Capabilities;
import it.niedermann.owncloud.notes.model.Category;
import it.niedermann.owncloud.notes.model.DBNote;
+import it.niedermann.owncloud.notes.model.GridItemDecoration;
import it.niedermann.owncloud.notes.model.ISyncCallback;
import it.niedermann.owncloud.notes.model.Item;
import it.niedermann.owncloud.notes.model.ItemAdapter;
import it.niedermann.owncloud.notes.model.LocalAccount;
import it.niedermann.owncloud.notes.model.NavigationAdapter;
+import it.niedermann.owncloud.notes.model.NavigationAdapter.CategoryNavigationItem;
import it.niedermann.owncloud.notes.model.NavigationAdapter.NavigationItem;
+import it.niedermann.owncloud.notes.model.NoteClickListener;
+import it.niedermann.owncloud.notes.model.SectionItemDecoration;
import it.niedermann.owncloud.notes.persistence.CapabilitiesClient;
import it.niedermann.owncloud.notes.persistence.CapabilitiesWorker;
import it.niedermann.owncloud.notes.persistence.LoadNotesListTask;
import it.niedermann.owncloud.notes.persistence.LoadNotesListTask.NotesLoadedListener;
import it.niedermann.owncloud.notes.persistence.NoteServerSyncHelper;
+import it.niedermann.owncloud.notes.persistence.NoteServerSyncHelper.ViewProvider;
import it.niedermann.owncloud.notes.persistence.NotesDatabase;
import it.niedermann.owncloud.notes.util.CategorySortingMethod;
import it.niedermann.owncloud.notes.util.NoteUtil;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+import static it.niedermann.owncloud.notes.branding.BrandingUtil.getSecondaryForegroundColorDependingOnTheme;
+import static it.niedermann.owncloud.notes.util.ColorUtil.contrastRatioIsSufficient;
+import static it.niedermann.owncloud.notes.util.Notes.isDarkThemeActive;
+import static it.niedermann.owncloud.notes.util.Notes.isGridViewEnabled;
import static it.niedermann.owncloud.notes.util.SSOUtil.askForNewAccount;
+import static java.util.Arrays.asList;
-public class NotesListViewActivity extends LockedActivity implements ItemAdapter.NoteClickListener, NoteServerSyncHelper.ViewProvider, AccountChooserListener {
+public class NotesListViewActivity extends LockedActivity implements NoteClickListener, ViewProvider, MoveAccountListener, AccountSwitcherListener {
private static final String TAG = NotesListViewActivity.class.getSimpleName();
+ private boolean gridView = true;
+
public static final String CREATED_NOTE = "it.niedermann.owncloud.notes.created_notes";
public static final String ADAPTER_KEY_RECENT = "recent";
public static final String ADAPTER_KEY_STARRED = "starred";
@@ -92,6 +114,7 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
private final static int show_single_note_cmd = 1;
private final static int server_settings = 2;
private final static int about = 3;
+ public final static int manage_account = 4;
/**
* Used to detect the onResume() call after the import dialog has been displayed.
@@ -103,26 +126,26 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
protected LocalAccount localAccount;
protected DrawerLayoutBinding binding;
+ protected ActivityNotesListViewBinding activityBinding;
private CoordinatorLayout coordinatorLayout;
private SwipeRefreshLayout swipeRefreshLayout;
protected FloatingActionButton fabCreate;
private RecyclerView listView;
- protected ItemAdapter adapter = null;
+ protected ItemAdapter adapter;
private Menu currentMenu;
protected NotesDatabase db = null;
- private ActionBarDrawerToggle drawerToggle;
private NavigationAdapter adapterCategories;
private NavigationItem itemRecent;
private NavigationItem itemFavorites;
private NavigationItem itemUncategorized;
+ @NonNull
private Category navigationSelection = new Category(null, null);
private String navigationOpen = "";
private ActionMode mActionMode;
- private SearchView searchView = null;
private final ISyncCallback syncCallBack = () -> {
adapter.clearSelection(listView);
if (mActionMode != null) {
@@ -131,7 +154,6 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
refreshLists();
swipeRefreshLayout.setRefreshing(false);
};
- private boolean accountChooserActive;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -139,7 +161,10 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
CapabilitiesWorker.update(this);
binding = DrawerLayoutBinding.inflate(getLayoutInflater());
+ activityBinding = ActivityNotesListViewBinding.bind(binding.activityNotesListView.getRoot());
+
setContentView(binding.getRoot());
+
this.coordinatorLayout = binding.activityNotesListView.activityNotesListView;
this.swipeRefreshLayout = binding.activityNotesListView.swiperefreshlayout;
this.fabCreate = binding.activityNotesListView.fabCreate;
@@ -154,15 +179,22 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
navigationSelection = new Category(null, true);
}
} else {
- navigationSelection = (Category) savedInstanceState.getSerializable(SAVED_STATE_NAVIGATION_SELECTION);
+ Object savedCategory = savedInstanceState.getSerializable(SAVED_STATE_NAVIGATION_SELECTION);
+ if (savedCategory != null) {
+ navigationSelection = (Category) savedCategory;
+ }
navigationOpen = savedInstanceState.getString(SAVED_STATE_NAVIGATION_OPEN);
categoryAdapterSelectedItem = savedInstanceState.getString(SAVED_STATE_NAVIGATION_ADAPTER_SLECTION);
}
db = NotesDatabase.getInstance(this);
- setupHeader();
- setupActionBar();
+ gridView = isGridViewEnabled();
+ if (!gridView || isDarkThemeActive(this)) {
+ activityBinding.activityNotesListView.setBackgroundColor(ContextCompat.getColor(this, R.color.primary));
+ }
+
+ setupToolbars();
setupNavigationList(categoryAdapterSelectedItem);
setupNavigationMenu();
setupNotesList();
@@ -197,18 +229,6 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
}
@Override
- protected void onPostCreate(@Nullable Bundle savedInstanceState) {
- super.onPostCreate(savedInstanceState);
- drawerToggle.syncState();
- }
-
- @Override
- public void onConfigurationChanged(@NonNull Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- drawerToggle.syncState();
- }
-
- @Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
if (localAccount != null) {
@@ -224,8 +244,10 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
localAccount = db.getLocalAccountByAccountName(accountName);
if (localAccount != null) {
try {
+ BrandingUtil.saveBrandColors(this, localAccount.getColor(), localAccount.getTextColor());
ssoAccount = SingleAccountHelper.getCurrentSingleSignOnAccount(getApplicationContext());
- new NotesListViewItemTouchHelper(ssoAccount, this, db, adapter, syncCallBack, this::refreshLists, swipeRefreshLayout, this).attachToRecyclerView(listView);
+ new NotesListViewItemTouchHelper(ssoAccount, this, db, adapter, syncCallBack, this::refreshLists, swipeRefreshLayout, this, gridView)
+ .attachToRecyclerView(listView);
synchronize();
} catch (NextcloudFilesAppAccountNotFoundException | NoCurrentAccountSelectedException e) {
Log.i(TAG, "Tried to select account, but got an " + e.getClass().getSimpleName() + ". Asking for importing an account...");
@@ -233,14 +255,21 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
}
refreshLists();
fabCreate.show();
- setupHeader();
+ activityBinding.launchAccountSwitcher.setOnClickListener((v) -> {
+ if (localAccount == null) {
+ handleNotAuthorizedAccount();
+ } else {
+ AccountSwitcherDialog.newInstance(localAccount.getId()).show(getSupportFragmentManager(), AccountSwitcherDialog.class.getSimpleName());
+ }
+ });
setupNavigationList(ADAPTER_KEY_RECENT);
- updateUsernameInDrawer();
} else {
if (!notAuthorizedAccountHandled) {
handleNotAuthorizedAccount();
}
+ binding.navigationList.setAdapter(null);
}
+ updateCurrentAccountAvatar();
}
private void handleNotAuthorizedAccount() {
@@ -250,59 +279,63 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
notAuthorizedAccountHandled = true;
}
- private void setupHeader() {
- binding.accountChooser.removeAllViews();
- for (LocalAccount localAccount : db.getAccounts()) {
- View v = View.inflate(this, R.layout.item_account, null);
- ((TextView) v.findViewById(R.id.accountItemLabel)).setText(localAccount.getAccountName());
- Glide
- .with(this)
- .load(localAccount.getUrl() + "/index.php/avatar/" + Uri.encode(localAccount.getUserName()) + "/64")
- .error(R.drawable.ic_account_circle_grey_24dp)
- .apply(RequestOptions.circleCropTransform())
- .into(((ImageView) v.findViewById(R.id.accountItemAvatar)));
- v.setOnClickListener(clickedView -> {
- clickHeader();
- binding.drawerLayout.closeDrawer(GravityCompat.START);
- selectAccount(localAccount.getAccountName());
- });
- v.findViewById(R.id.delete).setOnClickListener(clickedView -> {
- db.deleteAccount(localAccount);
- if (localAccount.getId() == this.localAccount.getId()) {
- List<LocalAccount> remainingAccounts = db.getAccounts();
- if (remainingAccounts.size() > 0) {
- this.localAccount = remainingAccounts.get(0);
- selectAccount(this.localAccount.getAccountName());
+ private void setupToolbars() {
+ setSupportActionBar(binding.activityNotesListView.toolbar);
+ updateCurrentAccountAvatar();
+ activityBinding.homeToolbar.setOnClickListener((v) -> {
+ if (activityBinding.toolbar.getVisibility() == GONE) {
+ updateToolbars(false);
+ }
+ });
+
+ activityBinding.launchAccountSwitcher.setOnClickListener((v) -> askForNewAccount(this));
+ activityBinding.menuButton.setOnClickListener((v) -> binding.drawerLayout.openDrawer(GravityCompat.START));
+
+ final LinearLayout searchEditFrame = activityBinding.searchView.findViewById(R.id
+ .search_edit_frame);
+
+ searchEditFrame.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+ int oldVisibility = -1;
+
+ @Override
+ public void onGlobalLayout() {
+ int currentVisibility = searchEditFrame.getVisibility();
+
+ if (currentVisibility != oldVisibility) {
+ if (currentVisibility == VISIBLE) {
+ fabCreate.hide();
} else {
- selectAccount(null);
- askForNewAccount(this);
+ new Handler().postDelayed(() -> fabCreate.show(), 150);
}
+
+ oldVisibility = currentVisibility;
}
- setupHeader();
- clickHeader();
- binding.drawerLayout.closeDrawer(GravityCompat.START);
- });
- binding.accountChooser.addView(v);
- }
- View addButton = View.inflate(this, R.layout.item_account, null);
- ((TextView) addButton.findViewById(R.id.accountItemLabel)).setText(getString(R.string.add_account));
- ((AppCompatImageView) addButton.findViewById(R.id.accountItemAvatar)).setImageResource(R.drawable.ic_person_add_grey600_24dp);
- addButton.setOnClickListener((btn) -> askForNewAccount(this));
- addButton.findViewById(R.id.delete).setVisibility(View.GONE);
- binding.accountChooser.addView(addButton);
- binding.headerView.setOnClickListener(view -> clickHeader());
- }
+ }
+
+ });
+ activityBinding.searchView.setOnCloseListener(() -> {
+ if (activityBinding.toolbar.getVisibility() == VISIBLE && TextUtils.isEmpty(activityBinding.searchView.getQuery())) {
+ updateToolbars(true);
+ return true;
+ }
+ return false;
+ });
+ activityBinding.searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String query) {
+ return false;
+ }
- private void setupActionBar() {
- Toolbar toolbar = binding.activityNotesListView.toolbar;
- setSupportActionBar(toolbar);
- drawerToggle = new ActionBarDrawerToggle(this, binding.drawerLayout, toolbar, R.string.action_drawer_open, R.string.action_drawer_close);
- drawerToggle.setDrawerIndicatorEnabled(true);
- binding.drawerLayout.addDrawerListener(drawerToggle);
+ @Override
+ public boolean onQueryTextChange(String newText) {
+ refreshLists();
+ return true;
+ }
+ });
}
private void setupNotesList() {
- initList();
+ initRecyclerView();
((RecyclerView) findViewById(R.id.recycler_view)).addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
@@ -333,6 +366,9 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
db.updateCapabilitiesETag(localAccount.getId(), capabilities.getETag());
db.updateBrand(localAccount.getId(), capabilities);
db.updateBrand(localAccount.getId(), capabilities);
+ localAccount.setColor(Color.parseColor(capabilities.getColor()));
+ localAccount.setTextColor(Color.parseColor(capabilities.getTextColor()));
+ BrandingUtil.saveBrandColors(this, localAccount.getColor(), localAccount.getTextColor());
db.updateApiVersion(localAccount.getId(), capabilities.getApiVersion());
Log.i(TAG, capabilities.toString());
} catch (Exception e) {
@@ -353,8 +389,8 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
fabCreate.setOnClickListener((View view) -> {
Intent createIntent = new Intent(getApplicationContext(), EditNoteActivity.class);
createIntent.putExtra(EditNoteActivity.PARAM_CATEGORY, navigationSelection);
- if (searchView != null && !searchView.isIconified() && searchView.getQuery().length() > 0) {
- createIntent.putExtra(EditNoteActivity.PARAM_CONTENT, searchView.getQuery().toString());
+ if (activityBinding.searchView.getQuery().length() > 0) {
+ createIntent.putExtra(EditNoteActivity.PARAM_CONTENT, activityBinding.searchView.getQuery().toString());
invalidateOptionsMenu();
}
startActivityForResult(createIntent, create_note_cmd);
@@ -364,7 +400,7 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
private void setupNavigationList(final String selectedItem) {
itemRecent = new NavigationItem(ADAPTER_KEY_RECENT, getString(R.string.label_all_notes), null, R.drawable.ic_access_time_grey600_24dp);
itemFavorites = new NavigationItem(ADAPTER_KEY_STARRED, getString(R.string.label_favorites), null, R.drawable.ic_star_yellow_24dp);
- adapterCategories = new NavigationAdapter(new NavigationAdapter.ClickListener() {
+ adapterCategories = new NavigationAdapter(this, new NavigationAdapter.ClickListener() {
@Override
public void onItemClick(NavigationItem item) {
selectItem(item, true);
@@ -416,21 +452,40 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
binding.navigationList.setAdapter(adapterCategories);
}
- private void clickHeader() {
- if (this.accountChooserActive) {
- binding.accountChooser.setVisibility(View.GONE);
- binding.accountNavigation.setVisibility(View.VISIBLE);
- } else {
- binding.accountChooser.setVisibility(View.VISIBLE);
- binding.accountNavigation.setVisibility(View.GONE);
+ @Override
+ public CoordinatorLayout getView() {
+ return this.coordinatorLayout;
+ }
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ applyBrandToPrimaryToolbar(activityBinding.toolbar);
+ applyBrandToFAB(mainColor, textColor, activityBinding.fabCreate);
+
+ binding.headerView.setBackgroundColor(mainColor);
+ binding.appName.setTextColor(textColor);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ activityBinding.progressCircular.getIndeterminateDrawable().setColorFilter(getSecondaryForegroundColorDependingOnTheme(this, mainColor), PorterDuff.Mode.SRC_IN);
}
- this.accountChooserActive = !this.accountChooserActive;
+
+ // TODO We assume, that the background of the spinner is always white
+ activityBinding.swiperefreshlayout.setColorSchemeColors(contrastRatioIsSufficient(Color.WHITE, mainColor) ? mainColor : Color.BLACK);
+ binding.appName.setTextColor(textColor);
+ DrawableCompat.setTint(binding.logo.getDrawable(), textColor);
+
+ adapter.applyBrand(mainColor, textColor);
+ adapterCategories.applyBrand(mainColor, textColor);
+ invalidateOptionsMenu();
}
@Override
- public CoordinatorLayout getView() {
- return this.coordinatorLayout;
+ public boolean onSupportNavigateUp() {
+ if (activityBinding.toolbar.getVisibility() == VISIBLE) {
+ updateToolbars(true);
+ return true;
+ } else {
+ return super.onSupportNavigateUp();
+ }
}
private class LoadCategoryListTask extends AsyncTask<Void, Void, List<NavigationItem>> {
@@ -439,7 +494,7 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
if (localAccount == null) {
return new ArrayList<>();
}
- List<NavigationItem> categories = db.getCategories(localAccount.getId());
+ List<CategoryNavigationItem> categories = db.getCategories(localAccount.getId());
if (!categories.isEmpty() && categories.get(0).label.isEmpty()) {
itemUncategorized = categories.get(0);
itemUncategorized.label = getString(R.string.action_uncategorized);
@@ -519,19 +574,18 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
}
private void setupNavigationMenu() {
+ final NavigationItem itemFormattingHelp = new NavigationItem("formattingHelp", getString(R.string.action_formatting_help), null, R.drawable.ic_baseline_help_outline_24);
final NavigationItem itemTrashbin = new NavigationItem("trashbin", getString(R.string.action_trashbin), null, R.drawable.ic_delete_grey600_24dp);
final NavigationItem itemSettings = new NavigationItem("settings", getString(R.string.action_settings), null, R.drawable.ic_settings_grey600_24dp);
final NavigationItem itemAbout = new NavigationItem("about", getString(R.string.simple_about), null, R.drawable.ic_info_outline_grey600_24dp);
- ArrayList<NavigationItem> itemsMenu = new ArrayList<>();
- itemsMenu.add(itemTrashbin);
- itemsMenu.add(itemSettings);
- itemsMenu.add(itemAbout);
-
- NavigationAdapter adapterMenu = new NavigationAdapter(new NavigationAdapter.ClickListener() {
+ NavigationAdapter adapterMenu = new NavigationAdapter(this, new NavigationAdapter.ClickListener() {
@Override
public void onItemClick(NavigationItem item) {
- if (itemSettings.equals(item)) {
+ if (itemFormattingHelp.equals(item)) {
+ Intent formattingHelpIntent = new Intent(getApplicationContext(), FormattingHelpActivity.class);
+ startActivity(formattingHelpIntent);
+ } else if (itemSettings.equals(item)) {
Intent settingsIntent = new Intent(getApplicationContext(), PreferencesActivity.class);
startActivityForResult(settingsIntent, server_settings);
} else if (itemAbout.equals(item)) {
@@ -547,17 +601,35 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
onItemClick(item);
}
});
-
-
- this.updateUsernameInDrawer();
- adapterMenu.setItems(itemsMenu);
+ adapterMenu.setItems(asList(itemFormattingHelp, itemTrashbin, itemSettings, itemAbout));
binding.navigationMenu.setAdapter(adapterMenu);
}
- public void initList() {
- adapter = new ItemAdapter(this);
+ private void initRecyclerView() {
+ adapter = new ItemAdapter(this, gridView);
listView.setAdapter(adapter);
- listView.setLayoutManager(new LinearLayoutManager(this));
+
+ if (gridView) {
+ int spanCount = getResources().getInteger(R.integer.grid_view_span_count);
+ StaggeredGridLayoutManager gridLayoutManager = new StaggeredGridLayoutManager(spanCount, StaggeredGridLayoutManager.VERTICAL);
+ listView.setLayoutManager(gridLayoutManager);
+ listView.addItemDecoration(new GridItemDecoration(adapter, spanCount,
+ getResources().getDimensionPixelSize(R.dimen.spacer_3x),
+ getResources().getDimensionPixelSize(R.dimen.spacer_5x),
+ getResources().getDimensionPixelSize(R.dimen.spacer_3x),
+ getResources().getDimensionPixelSize(R.dimen.spacer_1x),
+ getResources().getDimensionPixelSize(R.dimen.spacer_1x)
+ ));
+ } else {
+ LinearLayoutManager layoutManager = new LinearLayoutManager(this);
+ listView.setLayoutManager(layoutManager);
+ listView.addItemDecoration(new SectionItemDecoration(adapter,
+ getResources().getDimensionPixelSize(R.dimen.spacer_6x),
+ getResources().getDimensionPixelSize(R.dimen.spacer_5x),
+ getResources().getDimensionPixelSize(R.dimen.spacer_1x),
+ 0
+ ));
+ }
}
private void refreshLists() {
@@ -571,35 +643,36 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
return;
}
View emptyContentView = binding.activityNotesListView.emptyContentView.getRoot();
- emptyContentView.setVisibility(View.GONE);
- binding.activityNotesListView.progressCircular.setVisibility(View.VISIBLE);
+ emptyContentView.setVisibility(GONE);
+ binding.activityNotesListView.progressCircular.setVisibility(VISIBLE);
fabCreate.show();
String subtitle;
if (navigationSelection.category != null) {
if (navigationSelection.category.isEmpty()) {
- subtitle = getString(R.string.action_uncategorized);
+ subtitle = getString(R.string.search_in_category, getString(R.string.action_uncategorized));
} else {
- subtitle = NoteUtil.extendCategory(navigationSelection.category);
+ subtitle = getString(R.string.search_in_category, NoteUtil.extendCategory(navigationSelection.category));
}
} else if (navigationSelection.favorite != null && navigationSelection.favorite) {
- subtitle = getString(R.string.label_favorites);
+ subtitle = getString(R.string.search_in_category, getString(R.string.label_favorites));
} else {
- subtitle = getString(R.string.app_name);
+ subtitle = getString(R.string.search_in_all);
}
- setTitle(subtitle);
+ activityBinding.searchText.setText(subtitle);
CharSequence query = null;
- if (searchView != null && !searchView.isIconified() && searchView.getQuery().length() != 0) {
- query = searchView.getQuery();
+ if (activityBinding.searchView.getQuery().length() != 0) {
+ query = activityBinding.searchView.getQuery();
}
- NotesLoadedListener callback = (List<Item> notes, boolean showCategory) -> {
+ NotesLoadedListener callback = (List<Item> notes, boolean showCategory, CharSequence searchQuery) -> {
adapter.setShowCategory(showCategory);
+ adapter.setHighlightSearchQuery(searchQuery);
adapter.setItemList(notes);
- binding.activityNotesListView.progressCircular.setVisibility(View.GONE);
+ binding.activityNotesListView.progressCircular.setVisibility(GONE);
if (notes.size() > 0) {
- emptyContentView.setVisibility(View.GONE);
+ emptyContentView.setVisibility(GONE);
} else {
- emptyContentView.setVisibility(View.VISIBLE);
+ emptyContentView.setVisibility(VISIBLE);
}
if (scrollToTop) {
listView.scrollToPosition(0);
@@ -675,52 +748,13 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_list_view, menu);
- // Associate searchable configuration with the SearchView
- final MenuItem item = menu.findItem(R.id.search);
- searchView = (SearchView) item.getActionView();
-
- final LinearLayout searchEditFrame = searchView.findViewById(R.id
- .search_edit_frame);
-
- searchEditFrame.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
- int oldVisibility = -1;
-
- @Override
- public void onGlobalLayout() {
- int currentVisibility = searchEditFrame.getVisibility();
-
- if (currentVisibility != oldVisibility) {
- if (currentVisibility == View.VISIBLE) {
- fabCreate.hide();
- } else {
- new Handler().postDelayed(() -> fabCreate.show(), 150);
- }
-
- oldVisibility = currentVisibility;
- }
- }
-
- });
-
- searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
- @Override
- public boolean onQueryTextSubmit(String query) {
- return false;
- }
-
- @Override
- public boolean onQueryTextChange(String newText) {
- refreshLists();
- return true;
- }
- });
return true;
}
@Override
protected void onNewIntent(Intent intent) {
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
- searchView.setQuery(intent.getStringExtra(SearchManager.QUERY), true);
+ activityBinding.searchView.setQuery(intent.getStringExtra(SearchManager.QUERY), true);
}
super.onNewIntent(intent);
}
@@ -742,98 +776,99 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
- // Check which request we're responding to
- if (requestCode == create_note_cmd) {
- // Make sure the request was successful
- if (resultCode == RESULT_OK) {
- //not need because of db.synchronisation in createActivity
-
- Bundle bundle = data.getExtras();
- if (bundle != null && bundle.containsKey(CREATED_NOTE)) {
- DBNote createdNote = (DBNote) bundle.getSerializable(CREATED_NOTE);
- if (createdNote != null) {
- adapter.add(createdNote);
+ switch (requestCode) {
+ case create_note_cmd: {
+ // Make sure the request was successful
+ if (resultCode == RESULT_OK) {
+ //not need because of db.synchronisation in createActivity
+
+ Bundle bundle = data.getExtras();
+ if (bundle != null && bundle.containsKey(CREATED_NOTE)) {
+ DBNote createdNote = (DBNote) bundle.getSerializable(CREATED_NOTE);
+ if (createdNote != null) {
+ adapter.add(createdNote);
+ } else {
+ Log.w(TAG, "createdNote must not be null");
+ }
} else {
- Log.w(TAG, "createdNote must not be null");
+ Log.w(TAG, "Provide at least " + CREATED_NOTE);
}
- } else {
- Log.w(TAG, "Provide at least " + CREATED_NOTE);
}
+ listView.scrollToPosition(0);
+ break;
}
- listView.scrollToPosition(0);
- } else if (requestCode == server_settings) {
- // Recreate activity completely, because theme switching makes problems when only invalidating the views.
- // @see https://github.com/stefan-niedermann/nextcloud-notes/issues/529
- recreate();
- } else {
- try {
- AccountImporter.onActivityResult(requestCode, resultCode, data, this, (ssoAccount) -> {
- CapabilitiesWorker.update(this);
- new Thread(() -> {
- Log.i(TAG, "Added account: " + "name:" + ssoAccount.name + ", " + ssoAccount.url + ", userId" + ssoAccount.userId);
- try {
- Log.i(TAG, "Refreshing capabilities for " + ssoAccount.name);
- final Capabilities capabilities = CapabilitiesClient.getCapabilities(getApplicationContext(), ssoAccount, null);
- db.addAccount(ssoAccount.url, ssoAccount.userId, ssoAccount.name, capabilities);
- Log.i(TAG, capabilities.toString());
- runOnUiThread(() -> {
- selectAccount(ssoAccount.name);
- this.accountChooserActive = false;
- binding.accountChooser.setVisibility(View.GONE);
- binding.accountNavigation.setVisibility(View.VISIBLE);
- binding.drawerLayout.closeDrawer(GravityCompat.START);
- });
- } catch (SQLiteConstraintException e) {
- if (db.getAccounts().size() > 1) { // TODO ideally only show snackbar when this is a not migrated account
- runOnUiThread(() -> {
- Snackbar.make(coordinatorLayout, R.string.account_already_imported, Snackbar.LENGTH_LONG).show();
- selectAccount(ssoAccount.name);
- this.accountChooserActive = false;
- binding.accountChooser.setVisibility(View.GONE);
- binding.accountNavigation.setVisibility(View.VISIBLE);
- binding.drawerLayout.closeDrawer(GravityCompat.START);
- });
+ case server_settings: {
+ // Recreate activity completely, because theme switching makes problems when only invalidating the views.
+ // @see https://github.com/stefan-niedermann/nextcloud-notes/issues/529
+ recreate();
+ break;
+ }
+ case manage_account: {
+ if (resultCode == RESULT_FIRST_USER) {
+ selectAccount(null);
+ }
+ break;
+ }
+ default: {
+ try {
+ AccountImporter.onActivityResult(requestCode, resultCode, data, this, (ssoAccount) -> {
+ CapabilitiesWorker.update(this);
+ new Thread(() -> {
+ Log.i(TAG, "Added account: " + "name:" + ssoAccount.name + ", " + ssoAccount.url + ", userId" + ssoAccount.userId);
+ try {
+ Log.i(TAG, "Refreshing capabilities for " + ssoAccount.name);
+ final Capabilities capabilities = CapabilitiesClient.getCapabilities(getApplicationContext(), ssoAccount, null);
+ db.addAccount(ssoAccount.url, ssoAccount.userId, ssoAccount.name, capabilities);
+ Log.i(TAG, capabilities.toString());
+ runOnUiThread(() -> selectAccount(ssoAccount.name));
+ } catch (SQLiteException e) {
+ // Happens when upgrading from version ≤ 1.0.1 and importing the account
+ runOnUiThread(() -> selectAccount(ssoAccount.name));
+ } catch (Exception e) {
+ // Happens when importing an already existing account the second time
+ if (e instanceof TokenMismatchException && db.getLocalAccountByAccountName(ssoAccount.name) != null) {
+ Log.w(TAG, "Received " + TokenMismatchException.class.getSimpleName() + " and the given ssoAccount.name (" + ssoAccount.name + ") does already exist in the database. Assume that this account has already been imported.");
+ runOnUiThread(() -> {
+ selectAccount(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());
+ });
+ } else {
+ e.printStackTrace();
+ runOnUiThread(() -> {
+ binding.activityNotesListView.progressCircular.setVisibility(GONE);
+ ExceptionDialogFragment.newInstance(e).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName());
+ });
+ }
}
- } catch (Exception e) {
- e.printStackTrace();
- runOnUiThread(() -> {
- this.accountChooserActive = true;
- binding.accountChooser.setVisibility(View.VISIBLE);
- binding.accountNavigation.setVisibility(View.GONE);
- binding.drawerLayout.openDrawer(GravityCompat.START);
- binding.activityNotesListView.progressCircular.setVisibility(View.GONE);
- ExceptionDialogFragment.newInstance(e).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName());
- });
- }
- }).start();
- });
- } catch (AccountImportCancelledException e) {
- Log.i(TAG, "AccountImport has been cancelled.");
+ }).start();
+ });
+ } catch (AccountImportCancelledException e) {
+ Log.i(TAG, "AccountImport has been cancelled.");
+ }
}
}
}
- private void updateUsernameInDrawer() {
+ private void updateCurrentAccountAvatar() {
try {
String url = localAccount.getUrl();
if (url != null) {
- binding.account.setText(localAccount.getAccountName());
Glide
.with(this)
.load(url + "/index.php/avatar/" + Uri.encode(localAccount.getUserName()) + "/64")
- .error(R.mipmap.ic_launcher)
+ .error(R.drawable.ic_account_circle_grey_24dp)
.apply(RequestOptions.circleCropTransform())
- .into(binding.currentAccountImage);
+ .into(activityBinding.launchAccountSwitcher);
} else {
Log.w(TAG, "url is null");
}
} catch (NullPointerException e) { // No local account - show generic header
- binding.account.setText(R.string.app_name_long);
Glide
.with(this)
- .load(R.mipmap.ic_launcher)
+ .load(R.drawable.ic_account_circle_grey_24dp)
.apply(RequestOptions.circleCropTransform())
- .into(binding.currentAccountImage);
+ .into(activityBinding.launchAccountSwitcher);
Log.w(TAG, "Tried to update username in drawer, but localAccount was null");
}
}
@@ -859,7 +894,6 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
Intent intent = new Intent(getApplicationContext(), EditNoteActivity.class);
intent.putExtra(EditNoteActivity.PARAM_NOTE_ID, note.getId());
startActivityForResult(intent, show_single_note_cmd);
-
}
}
@@ -878,7 +912,7 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
if (selected) {
v.setSelected(true);
mActionMode = startSupportActionMode(new MultiSelectedActionModeCallback(
- this, this, db, mActionMode, adapter, listView, this::refreshLists, getSupportFragmentManager(), searchView
+ this, this, db, mActionMode, adapter, listView, this::refreshLists, getSupportFragmentManager(), activityBinding.searchView
));
int checkedItemCount = adapter.getSelected().size();
mActionMode.setTitle(getResources().getQuantityString(R.plurals.ab_selected, checkedItemCount, checkedItemCount));
@@ -888,11 +922,27 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
@Override
public void onBackPressed() {
- if (searchView == null || searchView.isIconified()) {
+ if (activityBinding.toolbar.getVisibility() == VISIBLE) {
+ updateToolbars(true);
+ } else {
super.onBackPressed();
+ }
+ }
+
+ @SuppressLint("PrivateResource")
+ private void updateToolbars(boolean disableSearch) {
+ activityBinding.homeToolbar.setVisibility(disableSearch ? VISIBLE : GONE);
+ activityBinding.toolbar.setVisibility(disableSearch ? GONE : VISIBLE);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ activityBinding.appBar.setStateListAnimator(AnimatorInflater.loadStateListAnimator(activityBinding.appBar.getContext(),
+ disableSearch ? R.animator.appbar_elevation_off : R.animator.appbar_elevation_on));
} else {
- invalidateOptionsMenu();
+ ViewCompat.setElevation(activityBinding.appBar, disableSearch ? 0 : getResources().getDimension(R.dimen.design_appbar_elevation));
}
+ if (disableSearch) {
+ activityBinding.searchView.setQuery(null, true);
+ }
+ activityBinding.searchView.setIconified(disableSearch);
}
private void synchronize() {
@@ -907,14 +957,39 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
Log.d(TAG, "Network is connected, but sync is not possible");
} else {
Log.d(TAG, "Sync is not possible, because network is not connected");
- Snackbar.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).show();
}
}
}
+ @Override
+ public void addAccount() {
+ askForNewAccount(this);
+ }
+
+ @Override
+ public void onAccountChosen(LocalAccount localAccount) {
+ binding.drawerLayout.closeDrawer(GravityCompat.START);
+ selectAccount(localAccount.getAccountName());
+ }
+
+ @Override
+ public void onAccountDeleted(LocalAccount localAccount) {
+ db.deleteAccount(localAccount);
+ if (localAccount.getId() == this.localAccount.getId()) {
+ List<LocalAccount> remainingAccounts = db.getAccounts();
+ if (remainingAccounts.size() > 0) {
+ this.localAccount = remainingAccounts.get(0);
+ selectAccount(this.localAccount.getAccountName());
+ } else {
+ selectAccount(null);
+ askForNewAccount(this);
+ }
+ }
+ }
@Override
- public void onAccountChosen(LocalAccount account) {
+ public void moveToAccount(LocalAccount account) {
List<Integer> selection = new ArrayList<>(adapter.getSelected());
adapter.deselect(0);
@@ -930,7 +1005,6 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
}
mActionMode.finish();
- searchView.setIconified(true);
refreshLists();
}
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/PreferencesActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/PreferencesActivity.java
index 3efc1ad5..ec1566b2 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/PreferencesActivity.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/PreferencesActivity.java
@@ -14,11 +14,13 @@ import it.niedermann.owncloud.notes.databinding.ActivityPreferencesBinding;
public class PreferencesActivity extends LockedActivity {
+ private ActivityPreferencesBinding binding;
+
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- ActivityPreferencesBinding binding = ActivityPreferencesBinding.inflate(getLayoutInflater());
+ binding = ActivityPreferencesBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
@@ -27,4 +29,9 @@ public class PreferencesActivity extends LockedActivity {
.replace(R.id.fragment_container_view, new PreferencesFragment())
.commit();
}
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ applyBrandToPrimaryToolbar(binding.toolbar);
+ }
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidget.java b/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidget.java
index 5a2f83ef..2a59aaa8 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidget.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidget.java
@@ -6,105 +6,127 @@ import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
+import android.graphics.Color;
import android.net.Uri;
import android.util.Log;
import android.widget.RemoteViews;
-import androidx.preference.PreferenceManager;
+import java.util.NoSuchElementException;
import it.niedermann.owncloud.notes.R;
import it.niedermann.owncloud.notes.android.DarkModeSetting;
import it.niedermann.owncloud.notes.android.activity.EditNoteActivity;
import it.niedermann.owncloud.notes.android.activity.NotesListViewActivity;
+import it.niedermann.owncloud.notes.branding.BrandingUtil;
import it.niedermann.owncloud.notes.model.Category;
+import it.niedermann.owncloud.notes.model.LocalAccount;
+import it.niedermann.owncloud.notes.model.NoteListsWidgetData;
+import it.niedermann.owncloud.notes.persistence.NotesDatabase;
import it.niedermann.owncloud.notes.util.Notes;
import static it.niedermann.owncloud.notes.android.activity.EditNoteActivity.PARAM_CATEGORY;
+import static it.niedermann.owncloud.notes.model.NoteListsWidgetData.MODE_DISPLAY_ALL;
+import static it.niedermann.owncloud.notes.model.NoteListsWidgetData.MODE_DISPLAY_CATEGORY;
+import static it.niedermann.owncloud.notes.model.NoteListsWidgetData.MODE_DISPLAY_STARRED;
public class NoteListWidget extends AppWidgetProvider {
private static final String TAG = NoteListWidget.class.getSimpleName();
- public static final String WIDGET_MODE_KEY = "NLW_mode";
- public static final String WIDGET_CATEGORY_KEY = "NLW_cat";
- public static final String ACCOUNT_ID_KEY = "NLW_account";
- public static final String DARK_THEME_KEY = "NLW_darkTheme";
- public static final int NLW_DISPLAY_ALL = 0;
- public static final int NLW_DISPLAY_STARRED = 1;
- public static final int NLW_DISPLAY_CATEGORY = 2;
public static final int PENDING_INTENT_NEW_NOTE_RQ = 0;
public static final int PENDING_INTENT_EDIT_NOTE_RQ = 1;
public static final int PENDING_INTENT_OPEN_APP_RQ = 2;
static void updateAppWidget(Context context, AppWidgetManager awm, int[] appWidgetIds) {
+ final NotesDatabase db = NotesDatabase.getInstance(context);
+
RemoteViews views;
DarkModeSetting darkTheme;
for (int appWidgetId : appWidgetIds) {
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
- int displayMode = sp.getInt(NoteListWidget.WIDGET_MODE_KEY + appWidgetId, -1);
-
- // onUpdate has been triggered before the user finished configuring the widget
- if (displayMode == -1) {
- return;
- }
+ try {
+ final NoteListsWidgetData data = db.getNoteListWidgetData(appWidgetId);
+ final LocalAccount localAccount = db.getAccount(data.getAccountId());
- String category = sp.getString(NoteListWidget.WIDGET_CATEGORY_KEY + appWidgetId, null);
- darkTheme = NoteWidgetHelper.getDarkThemeSetting(sp, DARK_THEME_KEY, appWidgetId);
-
- Intent serviceIntent = new Intent(context, NoteListWidgetService.class);
- serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
- serviceIntent.putExtra(NoteListWidget.WIDGET_MODE_KEY + appWidgetId, displayMode);
- serviceIntent.putExtra(NoteListWidget.DARK_THEME_KEY + appWidgetId, darkTheme.name());
- serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME)));
+ String category = null;
+ if (data.getCategoryId() != null) {
+ category = db.getCategoryTitleById(data.getAccountId(), data.getCategoryId());
+ }
- if (displayMode == NLW_DISPLAY_CATEGORY) {
- serviceIntent.putExtra(NoteListWidget.WIDGET_CATEGORY_KEY + appWidgetId, category);
- }
+ darkTheme = DarkModeSetting.fromModeID(data.getThemeMode());
+
+ Intent serviceIntent = new Intent(context, NoteListWidgetService.class);
+ serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+ serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME)));
+
+ // Launch application when user taps the header icon or app title
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setComponent(new ComponentName(context.getPackageName(),
+ NotesListViewActivity.class.getName()));
+
+ // Open the main app if the user taps the widget header
+ PendingIntent openAppI = PendingIntent.getActivity(context, PENDING_INTENT_OPEN_APP_RQ,
+ intent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+
+ // Launch create note activity if user taps "+" icon on header
+ PendingIntent newNoteI = PendingIntent.getActivity(context, (PENDING_INTENT_NEW_NOTE_RQ + appWidgetId),
+ new Intent(context, EditNoteActivity.class).putExtra(PARAM_CATEGORY, new Category(category, data.getMode() == MODE_DISPLAY_STARRED)),
+ PendingIntent.FLAG_UPDATE_CURRENT);
+
+ PendingIntent templatePI = PendingIntent.getActivity(context, PENDING_INTENT_EDIT_NOTE_RQ,
+ new Intent(context, EditNoteActivity.class),
+ PendingIntent.FLAG_UPDATE_CURRENT);
+
+ Log.v(TAG, "-- data - " + data);
+
+ if (Notes.isDarkThemeActive(context, darkTheme)) {
+ views = new RemoteViews(context.getPackageName(), R.layout.widget_note_list_dark);
+ views.setTextViewText(R.id.widget_note_list_title_tv_dark, getWidgetTitle(context, data.getMode(), category));
+ views.setOnClickPendingIntent(R.id.widget_note_header_icon_dark, openAppI);
+ views.setOnClickPendingIntent(R.id.widget_note_list_title_tv_dark, openAppI);
+ views.setOnClickPendingIntent(R.id.widget_note_list_create_icon_dark, newNoteI);
+ views.setPendingIntentTemplate(R.id.note_list_widget_lv_dark, templatePI);
+ views.setRemoteAdapter(appWidgetId, R.id.note_list_widget_lv_dark, serviceIntent);
+ views.setEmptyView(R.id.note_list_widget_lv_dark, R.id.widget_note_list_placeholder_tv_dark);
+ awm.notifyAppWidgetViewDataChanged(appWidgetId, R.id.note_list_widget_lv_dark);
+ if (BrandingUtil.isBrandingEnabled(context)) {
+ views.setInt(R.id.widget_note_header_dark, "setBackgroundColor", localAccount.getColor());
+ views.setInt(R.id.widget_note_header_icon_dark, "setColorFilter", localAccount.getTextColor());
+ views.setInt(R.id.widget_note_list_create_icon_dark, "setColorFilter", localAccount.getTextColor());
+ views.setTextColor(R.id.widget_note_list_title_tv_dark, localAccount.getTextColor());
+ } else {
+ views.setInt(R.id.widget_note_header_dark, "setBackgroundColor", context.getResources().getColor(R.color.defaultBrand));
+ views.setInt(R.id.widget_note_header_icon_dark, "setColorFilter", Color.WHITE);
+ views.setInt(R.id.widget_note_list_create_icon_dark, "setColorFilter", Color.WHITE);
+ views.setTextColor(R.id.widget_note_list_title_tv_dark, Color.WHITE);
+ }
+ } else {
+ views = new RemoteViews(context.getPackageName(), R.layout.widget_note_list);
+ views.setTextViewText(R.id.widget_note_list_title_tv, getWidgetTitle(context, data.getMode(), category));
+ views.setOnClickPendingIntent(R.id.widget_note_header_icon, openAppI);
+ views.setOnClickPendingIntent(R.id.widget_note_list_title_tv, openAppI);
+ views.setOnClickPendingIntent(R.id.widget_note_list_create_icon, newNoteI);
+ views.setPendingIntentTemplate(R.id.note_list_widget_lv, templatePI);
+ views.setRemoteAdapter(appWidgetId, R.id.note_list_widget_lv, serviceIntent);
+ views.setEmptyView(R.id.note_list_widget_lv, R.id.widget_note_list_placeholder_tv);
+ awm.notifyAppWidgetViewDataChanged(appWidgetId, R.id.note_list_widget_lv);
+ if (BrandingUtil.isBrandingEnabled(context)) {
+ views.setInt(R.id.widget_note_header, "setBackgroundColor", localAccount.getColor());
+ views.setInt(R.id.widget_note_header_icon, "setColorFilter", localAccount.getTextColor());
+ views.setInt(R.id.widget_note_list_create_icon, "setColorFilter", localAccount.getTextColor());
+ views.setTextColor(R.id.widget_note_list_title_tv, localAccount.getTextColor());
+ } else {
+ views.setInt(R.id.widget_note_header, "setBackgroundColor", context.getResources().getColor(R.color.defaultBrand));
+ views.setInt(R.id.widget_note_header_icon, "setColorFilter", Color.WHITE);
+ views.setInt(R.id.widget_note_list_create_icon, "setColorFilter", Color.WHITE);
+ views.setTextColor(R.id.widget_note_list_title_tv, Color.WHITE);
+ }
+ }
- // Launch application when user taps the header icon or app title
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.setComponent(new ComponentName(context.getPackageName(),
- NotesListViewActivity.class.getName()));
-
- // Open the main app if the user taps the widget header
- PendingIntent openAppI = PendingIntent.getActivity(context, PENDING_INTENT_OPEN_APP_RQ,
- intent,
- PendingIntent.FLAG_UPDATE_CURRENT);
-
- // Launch create note activity if user taps "+" icon on header
- PendingIntent newNoteI = PendingIntent.getActivity(context, PENDING_INTENT_NEW_NOTE_RQ,
- new Intent(context, EditNoteActivity.class).putExtra(PARAM_CATEGORY, new Category(category, displayMode == NLW_DISPLAY_STARRED)),
- PendingIntent.FLAG_UPDATE_CURRENT);
-
-
- PendingIntent templatePI = PendingIntent.getActivity(context, PENDING_INTENT_EDIT_NOTE_RQ,
- new Intent(context, EditNoteActivity.class),
- PendingIntent.FLAG_UPDATE_CURRENT);
-
- if (Notes.isDarkThemeActive(context, darkTheme)) {
- views = new RemoteViews(context.getPackageName(), R.layout.widget_note_list_dark);
- views.setTextViewText(R.id.widget_note_list_title_tv_dark, getWidgetTitle(context, displayMode, category));
- views.setOnClickPendingIntent(R.id.widget_note_header_icon_dark, openAppI);
- views.setOnClickPendingIntent(R.id.widget_note_list_title_tv_dark, openAppI);
- views.setOnClickPendingIntent(R.id.widget_note_list_create_icon_dark, newNoteI);
- views.setPendingIntentTemplate(R.id.note_list_widget_lv_dark, templatePI);
- views.setRemoteAdapter(appWidgetId, R.id.note_list_widget_lv_dark, serviceIntent);
- views.setEmptyView(R.id.note_list_widget_lv_dark, R.id.widget_note_list_placeholder_tv_dark);
- awm.notifyAppWidgetViewDataChanged(appWidgetId, R.id.note_list_widget_lv_dark);
- } else {
- views = new RemoteViews(context.getPackageName(), R.layout.widget_note_list);
- views.setTextViewText(R.id.widget_note_list_title_tv, getWidgetTitle(context, displayMode, category));
- views.setOnClickPendingIntent(R.id.widget_note_header_icon, openAppI);
- views.setOnClickPendingIntent(R.id.widget_note_list_title_tv, openAppI);
- views.setOnClickPendingIntent(R.id.widget_note_list_create_icon, newNoteI);
- views.setPendingIntentTemplate(R.id.note_list_widget_lv, templatePI);
- views.setRemoteAdapter(appWidgetId, R.id.note_list_widget_lv, serviceIntent);
- views.setEmptyView(R.id.note_list_widget_lv, R.id.widget_note_list_placeholder_tv);
- awm.notifyAppWidgetViewDataChanged(appWidgetId, R.id.note_list_widget_lv);
+ awm.updateAppWidget(appWidgetId, views);
+ } catch (NoSuchElementException e) {
+ Log.i(TAG, "onUpdate has been triggered before the user finished configuring the widget");
}
-
- awm.updateAppWidget(appWidgetId, views);
}
}
@@ -139,26 +161,20 @@ public class NoteListWidget extends AppWidgetProvider {
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
-
- SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
+ final NotesDatabase db = NotesDatabase.getInstance(context);
for (int appWidgetId : appWidgetIds) {
- editor.remove(WIDGET_MODE_KEY + appWidgetId);
- editor.remove(WIDGET_CATEGORY_KEY + appWidgetId);
- editor.remove(ACCOUNT_ID_KEY + appWidgetId);
- editor.remove(DARK_THEME_KEY + appWidgetId);
+ db.removeNoteListWidget(appWidgetId);
}
-
- editor.apply();
}
private static String getWidgetTitle(Context context, int displayMode, String category) {
switch (displayMode) {
- case NoteListWidget.NLW_DISPLAY_ALL:
+ case MODE_DISPLAY_ALL:
return context.getString(R.string.app_name);
- case NoteListWidget.NLW_DISPLAY_STARRED:
+ case MODE_DISPLAY_STARRED:
return context.getString(R.string.label_favorites);
- case NoteListWidget.NLW_DISPLAY_CATEGORY:
+ case MODE_DISPLAY_CATEGORY:
if ("".equals(category)) {
return context.getString(R.string.action_uncategorized);
} else {
@@ -168,4 +184,11 @@ public class NoteListWidget extends AppWidgetProvider {
return null;
}
}
+
+ /**
+ * Update note list widgets, if the note data was changed.
+ */
+ public static void updateNoteListWidgets(Context context) {
+ context.sendBroadcast(new Intent(context, NoteListWidget.class).setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE));
+ }
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidgetFactory.java b/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidgetFactory.java
index f6d0cce1..9956ff05 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidgetFactory.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/NoteListWidgetFactory.java
@@ -3,34 +3,32 @@ package it.niedermann.owncloud.notes.android.appwidget;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.RemoteViewsService;
-import androidx.preference.PreferenceManager;
-
import java.util.List;
import it.niedermann.owncloud.notes.R;
import it.niedermann.owncloud.notes.android.DarkModeSetting;
import it.niedermann.owncloud.notes.android.activity.EditNoteActivity;
import it.niedermann.owncloud.notes.model.DBNote;
+import it.niedermann.owncloud.notes.model.NoteListsWidgetData;
import it.niedermann.owncloud.notes.persistence.NotesDatabase;
import it.niedermann.owncloud.notes.util.Notes;
-import static it.niedermann.owncloud.notes.android.appwidget.NoteListWidget.DARK_THEME_KEY;
+import static it.niedermann.owncloud.notes.model.NoteListsWidgetData.MODE_DISPLAY_ALL;
+import static it.niedermann.owncloud.notes.model.NoteListsWidgetData.MODE_DISPLAY_CATEGORY;
+import static it.niedermann.owncloud.notes.model.NoteListsWidgetData.MODE_DISPLAY_STARRED;
public class NoteListWidgetFactory implements RemoteViewsService.RemoteViewsFactory {
private static final String TAG = NoteListWidgetFactory.class.getSimpleName();
private final Context context;
- private final int displayMode;
+ private final NoteListsWidgetData data;
private final boolean darkTheme;
- private final String category;
- private final long accountId;
private NotesDatabase db;
private List<DBNote> dbNotes;
@@ -38,28 +36,33 @@ public class NoteListWidgetFactory implements RemoteViewsService.RemoteViewsFact
this.context = context;
final int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
- final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this.context);
- displayMode = sp.getInt(NoteListWidget.WIDGET_MODE_KEY + appWidgetId, -1);
- DarkModeSetting theme = NoteWidgetHelper.getDarkThemeSetting(sp, DARK_THEME_KEY, appWidgetId);
- darkTheme = Notes.isDarkThemeActive(context, theme);
- category = sp.getString(NoteListWidget.WIDGET_CATEGORY_KEY + appWidgetId, "");
- accountId = sp.getLong(NoteListWidget.ACCOUNT_ID_KEY + appWidgetId, -1);
+
+ db = NotesDatabase.getInstance(context);
+ data = db.getNoteListWidgetData(appWidgetId);
+
+ darkTheme = Notes.isDarkThemeActive(context, DarkModeSetting.fromModeID(data.getThemeMode()));
}
@Override
public void onCreate() {
- db = NotesDatabase.getInstance(context);
}
@Override
public void onDataSetChanged() {
try {
- if (displayMode == NoteListWidget.NLW_DISPLAY_ALL) {
- dbNotes = db.getNotes(accountId);
- } else if (displayMode == NoteListWidget.NLW_DISPLAY_STARRED) {
- dbNotes = db.searchNotes(accountId, null, null, true);
- } else if (displayMode == NoteListWidget.NLW_DISPLAY_CATEGORY) {
- dbNotes = db.searchNotes(accountId, null, category, null);
+ Log.v(TAG, "--- data - " + data);
+ switch (data.getMode()) {
+ case MODE_DISPLAY_ALL:
+ dbNotes = db.getNotes(data.getAccountId());
+ break;
+ case MODE_DISPLAY_STARRED:
+ dbNotes = db.searchNotes(data.getAccountId(), null, null, true);
+ break;
+ case MODE_DISPLAY_CATEGORY:
+ if (data.getCategoryId() != null) {
+ dbNotes = db.searchNotes(data.getAccountId(), null, db.getCategoryTitleById(data.getAccountId(), data.getCategoryId()), null);
+ }
+ break;
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/SingleNoteWidget.java b/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/SingleNoteWidget.java
index 28408099..2237b9cb 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/SingleNoteWidget.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/appwidget/SingleNoteWidget.java
@@ -6,13 +6,10 @@ import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.net.Uri;
import android.util.Log;
import android.widget.RemoteViews;
-import androidx.preference.PreferenceManager;
-
import java.util.NoSuchElementException;
import it.niedermann.owncloud.notes.R;
@@ -83,16 +80,18 @@ public class SingleNoteWidget extends AppWidgetProvider {
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
- SharedPreferences.Editor editor = PreferenceManager
- .getDefaultSharedPreferences(context).edit();
-
final NotesDatabase db = NotesDatabase.getInstance(context);
for (int appWidgetId : appWidgetIds) {
db.removeSingleNoteWidget(appWidgetId);
}
-
- editor.apply();
super.onDeleted(context, appWidgetIds);
}
+
+ /**
+ * Update single note widget, if the note data was changed.
+ */
+ public static void updateSingleNoteWidgets(Context context) {
+ context.sendBroadcast(new Intent(context, SingleNoteWidget.class).setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE));
+ }
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/AccountChooserAdapter.java b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/AccountChooserAdapter.java
index cf20c7b6..135e1426 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/AccountChooserAdapter.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/AccountChooserAdapter.java
@@ -26,14 +26,14 @@ public class AccountChooserAdapter extends RecyclerView.Adapter<RecyclerView.Vie
@NonNull
private final List<LocalAccount> localAccounts;
@NonNull
- private final AccountChooserListener accountChooserListener;
+ private final MoveAccountListener moveAccountListener;
@NonNull
private final Context context;
- AccountChooserAdapter(@NonNull List<LocalAccount> localAccounts, @NonNull AccountChooserListener accountChooserListener, @NonNull Context context) {
+ AccountChooserAdapter(@NonNull List<LocalAccount> localAccounts, @NonNull MoveAccountListener moveAccountListener, @NonNull Context context) {
super();
this.localAccounts = localAccounts;
- this.accountChooserListener = accountChooserListener;
+ this.moveAccountListener = moveAccountListener;
this.context = context;
}
@@ -48,7 +48,7 @@ public class AccountChooserAdapter extends RecyclerView.Adapter<RecyclerView.Vie
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
LocalAccount localAccount = localAccounts.get(position);
AccountChooserViewHolder accountChooserViewHolder = (AccountChooserViewHolder) holder;
- accountChooserViewHolder.getAccountLayout().setOnClickListener((v) -> accountChooserListener.onAccountChosen(localAccount));
+ accountChooserViewHolder.getAccountLayout().setOnClickListener((v) -> moveAccountListener.moveToAccount(localAccount));
Glide
.with(context)
@@ -86,7 +86,7 @@ public class AccountChooserAdapter extends RecyclerView.Adapter<RecyclerView.Vie
}
}
- public interface AccountChooserListener {
- void onAccountChosen(LocalAccount account);
+ public interface MoveAccountListener {
+ void moveToAccount(LocalAccount account);
}
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/BaseNoteFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/BaseNoteFragment.java
index 8f5e3ec0..ccdfc6ab 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/BaseNoteFragment.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/BaseNoteFragment.java
@@ -3,9 +3,9 @@ package it.niedermann.owncloud.notes.android.fragment;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
+import android.graphics.Color;
import android.graphics.drawable.Icon;
import android.os.Build;
import android.os.Bundle;
@@ -13,11 +13,13 @@ import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+import android.view.View;
+import android.widget.ScrollView;
+import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.appcompat.widget.ShareActionProvider;
-import androidx.core.view.MenuItemCompat;
+import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
@@ -29,18 +31,24 @@ import com.nextcloud.android.sso.model.SingleSignOnAccount;
import it.niedermann.owncloud.notes.R;
import it.niedermann.owncloud.notes.android.activity.EditNoteActivity;
import it.niedermann.owncloud.notes.android.fragment.CategoryDialogFragment.CategoryDialogListener;
+import it.niedermann.owncloud.notes.branding.BrandedFragment;
import it.niedermann.owncloud.notes.model.CloudNote;
import it.niedermann.owncloud.notes.model.DBNote;
import it.niedermann.owncloud.notes.model.DBStatus;
import it.niedermann.owncloud.notes.model.ISyncCallback;
import it.niedermann.owncloud.notes.model.LocalAccount;
import it.niedermann.owncloud.notes.persistence.NotesDatabase;
+import it.niedermann.owncloud.notes.util.ColorUtil;
import it.niedermann.owncloud.notes.util.NoteUtil;
+import it.niedermann.owncloud.notes.util.ShareUtil;
import static androidx.core.content.pm.ShortcutManagerCompat.isRequestPinShortcutSupported;
import static it.niedermann.owncloud.notes.android.activity.EditNoteActivity.ACTION_SHORTCUT;
+import static it.niedermann.owncloud.notes.branding.BrandingUtil.tintMenuIcon;
+import static it.niedermann.owncloud.notes.util.ColorUtil.isColorDark;
+import static it.niedermann.owncloud.notes.util.Notes.isDarkThemeActive;
-public abstract class BaseNoteFragment extends Fragment implements CategoryDialogListener {
+public abstract class BaseNoteFragment extends BrandedFragment implements CategoryDialogListener {
private static final String TAG = BaseNoteFragment.class.getSimpleName();
@@ -56,8 +64,10 @@ public abstract class BaseNoteFragment extends Fragment implements CategoryDialo
private SingleSignOnAccount ssoAccount;
protected DBNote note;
+ // TODO do we really need this? The reference to note is currently the same
@Nullable
private DBNote originalNote;
+ private int originalScrollY;
protected NotesDatabase db;
private NoteFragmentListener listener;
@@ -88,7 +98,7 @@ public abstract class BaseNoteFragment extends Fragment implements CategoryDialo
if (content == null) {
throw new IllegalArgumentException(PARAM_NOTE_ID + " is not given, argument " + PARAM_NEWNOTE + " is missing and " + PARAM_CONTENT + " is missing.");
} else {
- note = new DBNote(-1, -1, null, NoteUtil.generateNoteTitle(content), content, false, getString(R.string.category_readonly), null, DBStatus.VOID, -1, "");
+ note = new DBNote(-1, -1, null, NoteUtil.generateNoteTitle(content), content, false, getString(R.string.category_readonly), null, DBStatus.VOID, -1, "", 0);
}
} else {
note = db.getNote(localAccount.getId(), db.addNoteAndSync(ssoAccount, localAccount.getId(), cloudNote));
@@ -105,6 +115,32 @@ public abstract class BaseNoteFragment extends Fragment implements CategoryDialo
}
}
+ @Nullable
+ protected abstract ScrollView getScrollView();
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ final ScrollView scrollView = getScrollView();
+ if (scrollView != null) {
+ scrollView.getViewTreeObserver().addOnScrollChangedListener(() -> {
+ if (scrollView.getScrollY() > 0) {
+ note.setScrollY(scrollView.getScrollY());
+ }
+ });
+ }
+ }
+
+ @Override
+ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ final ScrollView scrollView = getScrollView();
+ if (scrollView != null) {
+ this.originalScrollY = note.getScrollY();
+ scrollView.post(() -> scrollView.scrollTo(0, originalScrollY));
+ }
+ }
+
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
@@ -143,12 +179,14 @@ public abstract class BaseNoteFragment extends Fragment implements CategoryDialo
}
@Override
- public void onCreateOptionsMenu(@NonNull Menu menu, MenuInflater inflater) {
+ public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
inflater.inflate(R.menu.menu_note_fragment, menu);
if (isRequestPinShortcutSupported(requireActivity()) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
menu.add(Menu.NONE, MENU_ID_PIN, 110, R.string.pin_to_homescreen);
}
+
+ super.onCreateOptionsMenu(menu, inflater);
}
@Override
@@ -163,6 +201,7 @@ public abstract class BaseNoteFragment extends Fragment implements CategoryDialo
private void prepareFavoriteOption(MenuItem item) {
item.setIcon(note.isFavorite() ? R.drawable.ic_star_white_24dp : R.drawable.ic_star_border_white_24dp);
item.setChecked(note.isFavorite());
+ tintMenuIcon(item, colorAccent);
}
/**
@@ -192,23 +231,10 @@ public abstract class BaseNoteFragment extends Fragment implements CategoryDialo
showCategorySelector();
return true;
case R.id.menu_move:
- AccountChooserDialogFragment.newInstance().show(requireActivity().getSupportFragmentManager(), BaseNoteFragment.class.getSimpleName());
+ MoveAccountDialogFragment.newInstance().show(requireActivity().getSupportFragmentManager(), BaseNoteFragment.class.getSimpleName());
return true;
case R.id.menu_share:
- Intent shareIntent = new Intent();
- shareIntent.setAction(Intent.ACTION_SEND);
- shareIntent.setType("text/plain");
- shareIntent.putExtra(Intent.EXTRA_SUBJECT, note.getTitle());
- shareIntent.putExtra(Intent.EXTRA_TEXT, note.getContent());
-
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- startActivity(Intent.createChooser(shareIntent, note.getTitle()));
- } else {
- ShareActionProvider actionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(item);
- actionProvider.setShareIntent(shareIntent);
- }
-
+ ShareUtil.openShareDialog(requireContext(), note.getTitle(), note.getContent());
return false;
case MENU_ID_PIN:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -264,7 +290,12 @@ public abstract class BaseNoteFragment extends Fragment implements CategoryDialo
if (note != null) {
String newContent = getContent();
if (note.getContent().equals(newContent)) {
- Log.v(TAG, "... not saving, since nothing has changed");
+ if (note.getScrollY() != originalScrollY) {
+ Log.v(TAG, "... only saving new scroll state, since content did not change");
+ db.updateScrollY(note.getId(), note.getScrollY());
+ } else {
+ Log.v(TAG, "... not saving, since nothing has changed");
+ }
} else {
note = db.updateNoteAndSync(ssoAccount, localAccount.getId(), note, newContent, callback);
listener.onNoteUpdated(note);
@@ -274,22 +305,6 @@ public abstract class BaseNoteFragment extends Fragment implements CategoryDialo
}
}
- @SuppressWarnings("WeakerAccess") //PMD...
- protected float getFontSizeFromPreferences(SharedPreferences sp) {
- final String prefValueSmall = getString(R.string.pref_value_font_size_small);
- final String prefValueMedium = getString(R.string.pref_value_font_size_medium);
- // final String prefValueLarge = getString(R.string.pref_value_font_size_large);
- String fontSize = sp.getString(getString(R.string.pref_key_font_size), prefValueMedium);
-
- if (fontSize.equals(prefValueSmall)) {
- return getResources().getDimension(R.dimen.note_font_size_small);
- } else if (fontSize.equals(prefValueMedium)) {
- return getResources().getDimension(R.dimen.note_font_size_medium);
- } else {
- return getResources().getDimension(R.dimen.note_font_size_large);
- }
- }
-
protected abstract String getContent();
/**
@@ -322,6 +337,39 @@ public abstract class BaseNoteFragment extends Fragment implements CategoryDialo
listener.close();
}
+ @ColorInt
+ protected static int getTextHighlightBackgroundColor(@NonNull Context context, @ColorInt int mainColor, @ColorInt int colorPrimary, @ColorInt int colorAccent) {
+ if (isDarkThemeActive(context)) { // Dark background
+ if (isColorDark(mainColor)) { // Dark brand color
+ if (ColorUtil.contrastRatioIsSufficient(mainColor, colorPrimary)) { // But also dark text
+ return mainColor;
+ } else {
+ return ContextCompat.getColor(context, R.color.defaultTextHighlightBackground);
+ }
+ } else { // Light brand color
+ if (ColorUtil.contrastRatioIsSufficient(mainColor, colorAccent)) { // But also dark text
+ return Color.argb(77, Color.red(mainColor), Color.green(mainColor), Color.blue(mainColor));
+ } else {
+ return ContextCompat.getColor(context, R.color.defaultTextHighlightBackground);
+ }
+ }
+ } else { // Light background
+ if (isColorDark(mainColor)) { // Dark brand color
+ if (ColorUtil.contrastRatioIsSufficient(mainColor, colorAccent)) { // But also dark text
+ return Color.argb(77, Color.red(mainColor), Color.green(mainColor), Color.blue(mainColor));
+ } else {
+ return ContextCompat.getColor(context, R.color.defaultTextHighlightBackground);
+ }
+ } else { // Light brand color
+ if (ColorUtil.contrastRatioIsSufficient(mainColor, colorPrimary)) { // But also dark text
+ return mainColor;
+ } else {
+ return ContextCompat.getColor(context, R.color.defaultTextHighlightBackground);
+ }
+ }
+ }
+ }
+
public interface NoteFragmentListener {
void close();
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/CategoryAdapter.java b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/CategoryAdapter.java
index 94390106..5872172a 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/CategoryAdapter.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/CategoryAdapter.java
@@ -17,6 +17,7 @@ import java.util.List;
import it.niedermann.owncloud.notes.R;
import it.niedermann.owncloud.notes.databinding.ItemCategoryBinding;
+import it.niedermann.owncloud.notes.model.NavigationAdapter.CategoryNavigationItem;
import it.niedermann.owncloud.notes.model.NavigationAdapter.NavigationItem;
import it.niedermann.owncloud.notes.util.NoteUtil;
@@ -101,13 +102,14 @@ public class CategoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
}
- void setCategoryList(List<NavigationItem> categories, String currentSearchString) {
- this.categories = categories;
- NavigationItem clearItem = new NavigationItem(clearItemId, context.getString(R.string.no_category), 0, R.drawable.ic_clear_grey_24dp);
+ void setCategoryList(List<CategoryNavigationItem> categories, String currentSearchString) {
+ this.categories.clear();
+ this.categories.addAll(categories);
+ final NavigationItem clearItem = new NavigationItem(clearItemId, context.getString(R.string.no_category), 0, R.drawable.ic_clear_grey_24dp);
this.categories.add(0, clearItem);
if (currentSearchString != null && currentSearchString.trim().length() > 0) {
boolean currentSearchStringIsInCategories = false;
- for (NavigationItem category : categories.subList(1, categories.size())) {
+ for (NavigationItem category : categories) {
if (currentSearchString.equals(category.label)) {
currentSearchStringIsInCategories = true;
break;
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/CategoryDialogFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/CategoryDialogFragment.java
index 74f538ff..cd194cc0 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/CategoryDialogFragment.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/CategoryDialogFragment.java
@@ -1,6 +1,5 @@
package it.niedermann.owncloud.notes.android.fragment;
-import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
@@ -14,12 +13,14 @@ import android.view.WindowManager;
import android.widget.EditText;
import androidx.annotation.NonNull;
-import androidx.appcompat.app.AppCompatDialogFragment;
import androidx.fragment.app.Fragment;
import java.util.List;
import it.niedermann.owncloud.notes.R;
+import it.niedermann.owncloud.notes.branding.BrandedAlertDialogBuilder;
+import it.niedermann.owncloud.notes.branding.BrandedDialogFragment;
+import it.niedermann.owncloud.notes.branding.BrandingUtil;
import it.niedermann.owncloud.notes.databinding.DialogChangeCategoryBinding;
import it.niedermann.owncloud.notes.model.NavigationAdapter;
import it.niedermann.owncloud.notes.persistence.NotesDatabase;
@@ -29,16 +30,22 @@ import it.niedermann.owncloud.notes.persistence.NotesDatabase;
* It targetFragment is set it must implement the interface {@link CategoryDialogListener}.
* The calling Activity must implement the interface {@link CategoryDialogListener}.
*/
-public class CategoryDialogFragment extends AppCompatDialogFragment {
+public class CategoryDialogFragment extends BrandedDialogFragment {
private static final String TAG = CategoryDialogFragment.class.getSimpleName();
private static final String STATE_CATEGORY = "category";
+ private DialogChangeCategoryBinding binding;
private NotesDatabase db;
private CategoryDialogListener listener;
private EditText editCategory;
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ BrandingUtil.applyBrandToEditText(mainColor, textColor, binding.search);
+ }
+
/**
* Interface that must be implemented by the calling Activity.
*/
@@ -81,7 +88,7 @@ public class CategoryDialogFragment extends AppCompatDialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
View dialogView = View.inflate(getContext(), R.layout.dialog_change_category, null);
- DialogChangeCategoryBinding binding = DialogChangeCategoryBinding.bind(dialogView);
+ binding = DialogChangeCategoryBinding.bind(dialogView);
this.editCategory = binding.search;
if (savedInstanceState == null) {
@@ -131,7 +138,7 @@ public class CategoryDialogFragment extends AppCompatDialogFragment {
}
});
- return new AlertDialog.Builder(getActivity())
+ return new BrandedAlertDialogBuilder(getActivity())
.setTitle(R.string.change_category_title)
.setView(dialogView)
.setCancelable(true)
@@ -160,17 +167,17 @@ public class CategoryDialogFragment extends AppCompatDialogFragment {
}
- private class LoadCategoriesTask extends AsyncTask<String, Void, List<NavigationAdapter.NavigationItem>> {
+ private class LoadCategoriesTask extends AsyncTask<String, Void, List<NavigationAdapter.CategoryNavigationItem>> {
String currentSearchString;
@Override
- protected List<NavigationAdapter.NavigationItem> doInBackground(String... searchText) {
+ protected List<NavigationAdapter.CategoryNavigationItem> doInBackground(String... searchText) {
currentSearchString = searchText[0];
return db.searchCategories(accountId, currentSearchString);
}
@Override
- protected void onPostExecute(List<NavigationAdapter.NavigationItem> categories) {
+ protected void onPostExecute(List<NavigationAdapter.CategoryNavigationItem> categories) {
adapter.setCategoryList(categories, currentSearchString);
}
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/AccountChooserDialogFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/MoveAccountDialogFragment.java
index 880eafb6..ec0d2ff5 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/AccountChooserDialogFragment.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/MoveAccountDialogFragment.java
@@ -10,7 +10,6 @@ import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatDialogFragment;
import androidx.recyclerview.widget.RecyclerView;
@@ -18,27 +17,28 @@ import java.util.List;
import java.util.Objects;
import it.niedermann.owncloud.notes.R;
-import it.niedermann.owncloud.notes.android.fragment.AccountChooserAdapter.AccountChooserListener;
+import it.niedermann.owncloud.notes.android.fragment.AccountChooserAdapter.MoveAccountListener;
+import it.niedermann.owncloud.notes.branding.BrandedAlertDialogBuilder;
import it.niedermann.owncloud.notes.databinding.DialogChooseAccountBinding;
import it.niedermann.owncloud.notes.model.LocalAccount;
import it.niedermann.owncloud.notes.persistence.NotesDatabase;
-public class AccountChooserDialogFragment extends AppCompatDialogFragment implements AccountChooserListener {
- private AccountChooserListener accountChooserListener;
+public class MoveAccountDialogFragment extends AppCompatDialogFragment implements MoveAccountListener {
+ private MoveAccountListener moveAccountListener;
/**
* Use newInstance()-Method
*/
- public AccountChooserDialogFragment() {
+ public MoveAccountDialogFragment() {
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
- if (context instanceof AccountChooserListener) {
- this.accountChooserListener = (AccountChooserListener) context;
+ if (context instanceof MoveAccountListener) {
+ this.moveAccountListener = (MoveAccountListener) context;
} else {
- throw new ClassCastException("Caller must implement " + AccountChooserListener.class.getSimpleName());
+ throw new ClassCastException("Caller must implement " + MoveAccountListener.class.getSimpleName());
}
}
@@ -54,7 +54,7 @@ public class AccountChooserDialogFragment extends AppCompatDialogFragment implem
RecyclerView.Adapter adapter = new AccountChooserAdapter(accountsList, this, requireActivity());
binding.accountsList.setAdapter(adapter);
- return new AlertDialog.Builder(requireActivity())
+ return new BrandedAlertDialogBuilder(requireActivity())
.setView(binding.getRoot())
.setTitle(R.string.simple_move)
.setNegativeButton(android.R.string.cancel, null)
@@ -68,13 +68,13 @@ public class AccountChooserDialogFragment extends AppCompatDialogFragment implem
return super.onCreateView(inflater, container, savedInstanceState);
}
- public static AccountChooserDialogFragment newInstance() {
- return new AccountChooserDialogFragment();
+ public static MoveAccountDialogFragment newInstance() {
+ return new MoveAccountDialogFragment();
}
@Override
- public void onAccountChosen(LocalAccount account) {
- accountChooserListener.onAccountChosen(account);
+ public void moveToAccount(LocalAccount account) {
+ moveAccountListener.moveToAccount(account);
dismiss();
}
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/NoteEditFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/NoteEditFragment.java
index ff529277..1a1ab089 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/NoteEditFragment.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/NoteEditFragment.java
@@ -41,9 +41,12 @@ import it.niedermann.owncloud.notes.util.format.ContextBasedRangeFormattingCallb
import static androidx.core.view.ViewCompat.isAttachedToWindow;
import static it.niedermann.owncloud.notes.util.DisplayUtils.searchAndColor;
+import static it.niedermann.owncloud.notes.util.NoteUtil.getFontSizeFromPreferences;
public class NoteEditFragment extends SearchableBaseNoteFragment {
+ private static final String TAG = NoteEditFragment.class.getSimpleName();
+
private static final String LOG_TAG_AUTOSAVE = "AutoSave";
private static final long DELAY = 2000; // Wait for this time after typing before saving
@@ -147,10 +150,12 @@ public class NoteEditFragment extends SearchableBaseNoteFragment {
requireActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
- InputMethodManager imm = (InputMethodManager)
- requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.showSoftInput(getView(), InputMethodManager.SHOW_IMPLICIT);
-
+ final InputMethodManager imm = (InputMethodManager) requireContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ if (imm != null) {
+ imm.showSoftInput(getView(), InputMethodManager.SHOW_IMPLICIT);
+ } else {
+ Log.e(TAG, InputMethodManager.class.getSimpleName() + " is null.");
+ }
}
// workaround for issue yydcdut/RxMarkdown#41
@@ -159,7 +164,7 @@ public class NoteEditFragment extends SearchableBaseNoteFragment {
binding.editContent.setText(note.getContent());
binding.editContent.setEnabled(true);
- MarkdownProcessor markdownProcessor = new MarkdownProcessor(requireContext());
+ final MarkdownProcessor markdownProcessor = new MarkdownProcessor(requireContext());
markdownProcessor.config(MarkDownUtil.getMarkDownConfiguration(binding.editContent.getContext()).build());
markdownProcessor.factory(EditFactory.create());
markdownProcessor.live(binding.editContent);
@@ -168,8 +173,8 @@ public class NoteEditFragment extends SearchableBaseNoteFragment {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
binding.editContent.setCustomInsertionActionModeCallback(new ContextBasedFormattingCallback(binding.editContent));
}
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(requireContext().getApplicationContext());
- binding.editContent.setTextSize(TypedValue.COMPLEX_UNIT_PX, getFontSizeFromPreferences(sp));
+ final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(requireContext().getApplicationContext());
+ binding.editContent.setTextSize(TypedValue.COMPLEX_UNIT_PX, getFontSizeFromPreferences(requireContext(), sp));
if (sp.getBoolean(getString(R.string.pref_key_font), false)) {
binding.editContent.setTypeface(Typeface.MONOSPACE);
}
@@ -239,10 +244,16 @@ public class NoteEditFragment extends SearchableBaseNoteFragment {
}
@Override
- protected void colorWithText(@NonNull String newText, @Nullable Integer current) {
+ protected void colorWithText(@NonNull String newText, @Nullable Integer current, int mainColor, int textColor) {
if (binding != null && isAttachedToWindow(binding.editContent)) {
binding.editContent.clearFocus();
- binding.editContent.setText(searchAndColor(new SpannableString(getContent()), newText, requireContext(), current), TextView.BufferType.SPANNABLE);
+ binding.editContent.setText(searchAndColor(new SpannableString(getContent()), newText, requireContext(), current, mainColor, textColor), TextView.BufferType.SPANNABLE);
}
}
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ super.applyBrand(mainColor, textColor);
+ binding.editContent.setHighlightColor(getTextHighlightBackgroundColor(requireContext(), mainColor, colorPrimary, colorAccent));
+ }
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/NotePreviewFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/NotePreviewFragment.java
index 85fd5d7a..751cf474 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/NotePreviewFragment.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/NotePreviewFragment.java
@@ -48,6 +48,7 @@ import static it.niedermann.owncloud.notes.util.MarkDownUtil.CHECKBOX_UNCHECKED_
import static it.niedermann.owncloud.notes.util.MarkDownUtil.parseCompat;
import static it.niedermann.owncloud.notes.util.NoteLinksUtils.extractNoteRemoteId;
import static it.niedermann.owncloud.notes.util.NoteLinksUtils.replaceNoteLinksWithDummyUrls;
+import static it.niedermann.owncloud.notes.util.NoteUtil.getFontSizeFromPreferences;
public class NotePreviewFragment extends SearchableBaseNoteFragment implements OnRefreshListener {
@@ -117,8 +118,13 @@ public class NotePreviewFragment extends SearchableBaseNoteFragment implements O
* When (un)checking a checkbox in a note which contains code-blocks, the "`"-characters get stripped out in the TextView and therefore the given lineNumber is wrong
* Find number of lines starting with ``` before lineNumber
*/
+ boolean inCodefence = false;
for (int i = 0; i < lines.length; i++) {
if (lines[i].startsWith("```")) {
+ inCodefence = !inCodefence;
+ lineNumber++;
+ }
+ if (inCodefence && TextUtils.isEmpty(lines[i])) {
lineNumber++;
}
if (i == lineNumber) {
@@ -175,17 +181,17 @@ public class NotePreviewFragment extends SearchableBaseNoteFragment implements O
binding.swiperefreshlayout.setOnRefreshListener(this);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(requireActivity().getApplicationContext());
- binding.singleNoteContent.setTextSize(TypedValue.COMPLEX_UNIT_PX, getFontSizeFromPreferences(sp));
+ binding.singleNoteContent.setTextSize(TypedValue.COMPLEX_UNIT_PX, getFontSizeFromPreferences(requireContext(), sp));
if (sp.getBoolean(getString(R.string.pref_key_font), false)) {
binding.singleNoteContent.setTypeface(Typeface.MONOSPACE);
}
}
@Override
- protected void colorWithText(@NonNull String newText, @Nullable Integer current) {
+ protected void colorWithText(@NonNull String newText, @Nullable Integer current, int mainColor, int textColor) {
if (binding != null && ViewCompat.isAttachedToWindow(binding.singleNoteContent)) {
binding.singleNoteContent.setText(
- searchAndColor(new SpannableString(parseCompat(markdownProcessor, getContent())), newText, requireContext(), current),
+ searchAndColor(new SpannableString(parseCompat(markdownProcessor, getContent())), newText, requireContext(), current, mainColor, textColor),
TextView.BufferType.SPANNABLE);
}
}
@@ -216,4 +222,10 @@ public class NotePreviewFragment extends SearchableBaseNoteFragment implements O
Toast.makeText(requireContext(), getString(R.string.error_sync, getString(R.string.error_no_network)), Toast.LENGTH_LONG).show();
}
}
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ super.applyBrand(mainColor, textColor);
+ binding.singleNoteContent.setHighlightColor(getTextHighlightBackgroundColor(requireContext(), mainColor, colorPrimary, colorAccent));
+ }
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/NoteReadonlyFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/NoteReadonlyFragment.java
index c0c8e2fb..18607c90 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/NoteReadonlyFragment.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/NoteReadonlyFragment.java
@@ -36,6 +36,7 @@ import it.niedermann.owncloud.notes.util.NoteLinksUtils;
import static androidx.core.view.ViewCompat.isAttachedToWindow;
import static it.niedermann.owncloud.notes.util.DisplayUtils.searchAndColor;
import static it.niedermann.owncloud.notes.util.MarkDownUtil.parseCompat;
+import static it.niedermann.owncloud.notes.util.NoteUtil.getFontSizeFromPreferences;
public class NoteReadonlyFragment extends SearchableBaseNoteFragment {
@@ -130,7 +131,7 @@ public class NoteReadonlyFragment extends SearchableBaseNoteFragment {
binding.swiperefreshlayout.setEnabled(false);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(requireActivity().getApplicationContext());
- binding.singleNoteContent.setTextSize(TypedValue.COMPLEX_UNIT_PX, getFontSizeFromPreferences(sp));
+ binding.singleNoteContent.setTextSize(TypedValue.COMPLEX_UNIT_PX, getFontSizeFromPreferences(requireContext(), sp));
if (sp.getBoolean(getString(R.string.pref_key_font), false)) {
binding.singleNoteContent.setTypeface(Typeface.MONOSPACE);
}
@@ -147,9 +148,9 @@ public class NoteReadonlyFragment extends SearchableBaseNoteFragment {
}
@Override
- protected void colorWithText(@NonNull String newText, @Nullable Integer current) {
+ protected void colorWithText(@NonNull String newText, @Nullable Integer current, int mainColor, int textColor) {
if ((binding != null) && isAttachedToWindow(binding.singleNoteContent)) {
- binding.singleNoteContent.setText(searchAndColor(new SpannableString(parseCompat(markdownProcessor, getContent())), newText, requireContext(), current), TextView.BufferType.SPANNABLE);
+ binding.singleNoteContent.setText(searchAndColor(new SpannableString(parseCompat(markdownProcessor, getContent())), newText, requireContext(), current, mainColor, textColor), TextView.BufferType.SPANNABLE);
}
}
@@ -157,4 +158,10 @@ public class NoteReadonlyFragment extends SearchableBaseNoteFragment {
protected String getContent() {
return note.getContent();
}
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ super.applyBrand(mainColor, textColor);
+ binding.singleNoteContent.setHighlightColor(getTextHighlightBackgroundColor(requireContext(), mainColor, colorPrimary, colorAccent));
+ }
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/PreferencesFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/PreferencesFragment.java
index 27ce4fc7..76077f27 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/PreferencesFragment.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/PreferencesFragment.java
@@ -1,24 +1,39 @@
package it.niedermann.owncloud.notes.android.fragment;
import android.app.Activity;
+import android.content.Context;
import android.os.Bundle;
import android.util.Log;
+import androidx.annotation.ColorInt;
import androidx.annotation.Nullable;
import androidx.preference.ListPreference;
+import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
-import androidx.preference.SwitchPreference;
+import it.niedermann.owncloud.notes.BuildConfig;
import it.niedermann.owncloud.notes.R;
import it.niedermann.owncloud.notes.android.DarkModeSetting;
+import it.niedermann.owncloud.notes.branding.Branded;
+import it.niedermann.owncloud.notes.branding.BrandedSwitchPreference;
+import it.niedermann.owncloud.notes.branding.BrandingUtil;
+import it.niedermann.owncloud.notes.persistence.NotesDatabase;
import it.niedermann.owncloud.notes.persistence.SyncWorker;
import it.niedermann.owncloud.notes.util.DeviceCredentialUtil;
import it.niedermann.owncloud.notes.util.Notes;
-public class PreferencesFragment extends PreferenceFragmentCompat {
+import static it.niedermann.owncloud.notes.android.appwidget.NoteListWidget.updateNoteListWidgets;
+
+public class PreferencesFragment extends PreferenceFragmentCompat implements Branded {
private static final String TAG = PreferencesFragment.class.getSimpleName();
+ private BrandedSwitchPreference fontPref;
+ private BrandedSwitchPreference lockPref;
+ private BrandedSwitchPreference wifiOnlyPref;
+ private BrandedSwitchPreference brandingPref;
+ private BrandedSwitchPreference gridViewPref;
+
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -28,10 +43,45 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.preferences);
- final SwitchPreference lockPref = findPreference(getString(R.string.pref_key_lock));
+ fontPref = findPreference(getString(R.string.pref_key_font));
+
+ brandingPref = findPreference(getString(R.string.pref_key_branding));
+ if (brandingPref != null) {
+ brandingPref.setOnPreferenceChangeListener((Preference preference, Object newValue) -> {
+ updateNoteListWidgets(requireContext());
+ final Boolean branding = (Boolean) newValue;
+ Log.v(TAG, "branding: " + branding);
+ requireActivity().setResult(Activity.RESULT_OK);
+ requireActivity().recreate();
+ return true;
+ });
+ } else {
+ Log.e(TAG, "Could not find preference with key: \"" + getString(R.string.pref_key_branding) + "\"");
+ }
+
+ gridViewPref = findPreference(getString(R.string.pref_key_gridview));
+ if (gridViewPref != null) {
+ gridViewPref.setOnPreferenceChangeListener((Preference preference, Object newValue) -> {
+ final Boolean gridView = (Boolean) newValue;
+ Log.v(TAG, "gridView: " + gridView);
+ requireActivity().setResult(Activity.RESULT_OK);
+ Notes.updateGridViewEnabled(gridView);
+ return true;
+ });
+ } else {
+ Log.e(TAG, "Could not find preference with key: \"" + getString(R.string.pref_key_branding) + "\"");
+ }
+
+ lockPref = findPreference(getString(R.string.pref_key_lock));
if (lockPref != null) {
if (!DeviceCredentialUtil.areCredentialsAvailable(requireContext())) {
lockPref.setVisible(false);
+ Preference securityCategory = findPreference(getString(R.string.pref_category_security));
+ if (securityCategory != null) {
+ securityCategory.setVisible(false);
+ } else {
+ Log.e(TAG, "Could not find preference " + getString(R.string.pref_category_security));
+ }
} else {
lockPref.setOnPreferenceChangeListener((preference, newValue) -> {
Notes.setLockedPreference((Boolean) newValue);
@@ -51,7 +101,7 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
return true;
});
- final SwitchPreference wifiOnlyPref = findPreference(getString(R.string.pref_key_wifi_only));
+ wifiOnlyPref = findPreference(getString(R.string.pref_key_wifi_only));
assert wifiOnlyPref != null;
wifiOnlyPref.setOnPreferenceChangeListener((preference, newValue) -> {
Log.i(TAG, "syncOnWifiOnly: " + newValue);
@@ -66,4 +116,25 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
return true;
});
}
+
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ @Nullable Context context = getContext();
+ if (context != null) {
+ @ColorInt final int mainColor = BrandingUtil.readBrandMainColor(context);
+ @ColorInt final int textColor = BrandingUtil.readBrandTextColor(context);
+ applyBrand(mainColor, textColor);
+ }
+ }
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ fontPref.applyBrand(mainColor, textColor);
+ lockPref.applyBrand(mainColor, textColor);
+ wifiOnlyPref.applyBrand(mainColor, textColor);
+ brandingPref.applyBrand(mainColor, textColor);
+ gridViewPref.applyBrand(mainColor, textColor);
+ }
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/SearchableBaseNoteFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/SearchableBaseNoteFragment.java
index 10080457..be0cafd7 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/SearchableBaseNoteFragment.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/SearchableBaseNoteFragment.java
@@ -1,5 +1,6 @@
package it.niedermann.owncloud.notes.android.fragment;
+import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.text.Layout;
@@ -10,8 +11,9 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.LinearLayout;
-import android.widget.ScrollView;
+import androidx.annotation.CallSuper;
+import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.SearchView;
@@ -22,6 +24,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import it.niedermann.owncloud.notes.R;
+import it.niedermann.owncloud.notes.branding.BrandedActivity;
public abstract class SearchableBaseNoteFragment extends BaseNoteFragment {
@@ -35,6 +38,18 @@ public abstract class SearchableBaseNoteFragment extends BaseNoteFragment {
private String searchQuery = null;
private static final int delay = 50; // If the search string does not change after $delay ms, then the search task starts.
+ @ColorInt
+ private int mainColor;
+ @ColorInt
+ private int textColor;
+
+ @Override
+ public void onStart() {
+ this.mainColor = getResources().getColor(R.color.defaultBrand);
+ this.textColor = Color.WHITE;
+ super.onStart();
+ }
+
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@@ -73,12 +88,12 @@ public abstract class SearchableBaseNoteFragment extends BaseNoteFragment {
if (currentVisibility != oldVisibility) {
if (currentVisibility != View.VISIBLE) {
- colorWithText("", null);
+ colorWithText("", null, mainColor, textColor);
searchQuery = "";
hideSearchFabs();
} else {
jumpToOccurrence();
- colorWithText(searchQuery, null);
+ colorWithText(searchQuery, null, mainColor, textColor);
occurrenceCount = countOccurrences(getContent(), searchQuery);
showSearchFabs();
}
@@ -96,7 +111,7 @@ public abstract class SearchableBaseNoteFragment extends BaseNoteFragment {
next.setOnClickListener(v -> {
currentOccurrence++;
jumpToOccurrence();
- colorWithText(searchView.getQuery().toString(), currentOccurrence);
+ colorWithText(searchView.getQuery().toString(), currentOccurrence, mainColor, textColor);
});
}
@@ -105,7 +120,7 @@ public abstract class SearchableBaseNoteFragment extends BaseNoteFragment {
occurrenceCount = countOccurrences(getContent(), searchView.getQuery().toString());
currentOccurrence--;
jumpToOccurrence();
- colorWithText(searchView.getQuery().toString(), currentOccurrence);
+ colorWithText(searchView.getQuery().toString(), currentOccurrence, mainColor, textColor);
});
}
@@ -117,7 +132,7 @@ public abstract class SearchableBaseNoteFragment extends BaseNoteFragment {
public boolean onQueryTextSubmit(@NonNull String query) {
currentOccurrence++;
jumpToOccurrence();
- colorWithText(query, currentOccurrence);
+ colorWithText(query, currentOccurrence, mainColor, textColor);
return true;
}
@@ -137,7 +152,7 @@ public abstract class SearchableBaseNoteFragment extends BaseNoteFragment {
}
currentOccurrence = 1;
jumpToOccurrence();
- colorWithText(searchQuery, currentOccurrence);
+ colorWithText(searchQuery, currentOccurrence, mainColor, textColor);
}
private void queryWithHandler(@NonNull String newText) {
@@ -183,9 +198,7 @@ public abstract class SearchableBaseNoteFragment extends BaseNoteFragment {
}
}
- protected abstract void colorWithText(@NonNull String newText, @Nullable Integer current);
-
- protected abstract ScrollView getScrollView();
+ protected abstract void colorWithText(@NonNull String newText, @Nullable Integer current, int mainColor, int textColor);
protected abstract Layout getLayout();
@@ -273,4 +286,13 @@ public abstract class SearchableBaseNoteFragment extends BaseNoteFragment {
}
return count;
}
+
+ @CallSuper
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ this.mainColor = mainColor;
+ this.textColor = textColor;
+ BrandedActivity.applyBrandToFAB(mainColor, textColor, getSearchPrevButton());
+ BrandedActivity.applyBrandToFAB(mainColor, textColor, getSearchNextButton());
+ }
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/about/AboutFragmentLicenseTab.java b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/about/AboutFragmentLicenseTab.java
index 4ce5d5dc..b5b984cd 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/about/AboutFragmentLicenseTab.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/about/AboutFragmentLicenseTab.java
@@ -1,20 +1,27 @@
package it.niedermann.owncloud.notes.android.fragment.about;
import android.content.Intent;
+import android.content.res.ColorStateList;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
-import androidx.fragment.app.Fragment;
+import androidx.core.graphics.drawable.DrawableCompat;
import it.niedermann.owncloud.notes.R;
+import it.niedermann.owncloud.notes.branding.BrandedFragment;
+import it.niedermann.owncloud.notes.branding.BrandingUtil;
import it.niedermann.owncloud.notes.databinding.FragmentAboutLicenseTabBinding;
+import it.niedermann.owncloud.notes.util.ColorUtil;
import it.niedermann.owncloud.notes.util.SupportUtil;
-public class AboutFragmentLicenseTab extends Fragment {
+public class AboutFragmentLicenseTab extends BrandedFragment {
+
+ private FragmentAboutLicenseTabBinding binding;
private void openLicense() {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.url_license))));
@@ -22,9 +29,16 @@ public class AboutFragmentLicenseTab extends Fragment {
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- FragmentAboutLicenseTabBinding binding = FragmentAboutLicenseTabBinding.inflate(inflater, container, false);
+ binding = FragmentAboutLicenseTabBinding.inflate(inflater, container, false);
binding.aboutAppLicenseButton.setOnClickListener((v) -> openLicense());
SupportUtil.setHtml(binding.aboutIconsDisclaimer, R.string.about_icons_disclaimer, getString(R.string.about_app_icon_author));
return binding.getRoot();
}
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ @ColorInt final int finalMainColor = BrandingUtil.getSecondaryForegroundColorDependingOnTheme(requireContext(), mainColor);
+ DrawableCompat.setTintList(binding.aboutAppLicenseButton.getBackground(), ColorStateList.valueOf(finalMainColor));
+ binding.aboutAppLicenseButton.setTextColor(ColorUtil.getForegroundColorForBackgroundColor(finalMainColor));
+ }
} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/branding/Branded.java b/app/src/main/java/it/niedermann/owncloud/notes/branding/Branded.java
new file mode 100644
index 00000000..7ef9138d
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/branding/Branded.java
@@ -0,0 +1,9 @@
+package it.niedermann.owncloud.notes.branding;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.UiThread;
+
+public interface Branded {
+ @UiThread
+ void applyBrand(@ColorInt int mainColor, @ColorInt int textColor);
+} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedActivity.java
new file mode 100644
index 00000000..0eea5bff
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedActivity.java
@@ -0,0 +1,67 @@
+package it.niedermann.owncloud.notes.branding;
+
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.util.TypedValue;
+import android.view.Menu;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
+
+import it.niedermann.owncloud.notes.R;
+
+import static it.niedermann.owncloud.notes.branding.BrandingUtil.tintMenuIcon;
+
+public abstract class BrandedActivity extends AppCompatActivity implements Branded {
+
+ @ColorInt
+ protected int colorAccent;
+
+ public static void applyBrandToFAB(@ColorInt int mainColor, @ColorInt int textColor, @NonNull FloatingActionButton fab) {
+ fab.setSupportBackgroundTintList(ColorStateList.valueOf(mainColor));
+ fab.setColorFilter(textColor);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+
+ final TypedValue typedValue = new TypedValue();
+ getTheme().resolveAttribute(R.attr.colorAccent, typedValue, true);
+ colorAccent = typedValue.data;
+
+ if (BrandingUtil.isBrandingEnabled(this)) {
+ @ColorInt final int mainColor = BrandingUtil.readBrandMainColor(this);
+ @ColorInt final int textColor = BrandingUtil.readBrandTextColor(this);
+ applyBrand(mainColor, textColor);
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ for (int i = 0; i < menu.size(); i++) {
+ tintMenuIcon(menu.getItem(i), colorAccent);
+ }
+ return super.onCreateOptionsMenu(menu);
+ }
+
+ public void applyBrandToPrimaryToolbar(@NonNull Toolbar toolbar) {
+ final Drawable overflowDrawable = toolbar.getOverflowIcon();
+ if (overflowDrawable != null) {
+ overflowDrawable.setColorFilter(colorAccent, PorterDuff.Mode.SRC_ATOP);
+ toolbar.setOverflowIcon(overflowDrawable);
+ }
+
+ final Drawable navigationDrawable = toolbar.getNavigationIcon();
+ if (navigationDrawable != null) {
+ navigationDrawable.setColorFilter(colorAccent, PorterDuff.Mode.SRC_ATOP);
+ toolbar.setNavigationIcon(navigationDrawable);
+ }
+ }
+
+}
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
new file mode 100644
index 00000000..940d978d
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedAlertDialogBuilder.java
@@ -0,0 +1,48 @@
+package it.niedermann.owncloud.notes.branding;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.widget.Button;
+
+import androidx.annotation.CallSuper;
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+
+import static it.niedermann.owncloud.notes.branding.BrandingUtil.getSecondaryForegroundColorDependingOnTheme;
+
+public class BrandedAlertDialogBuilder extends AlertDialog.Builder implements Branded {
+
+ protected AlertDialog dialog;
+
+ public BrandedAlertDialogBuilder(Context context) {
+ super(context);
+ }
+
+ @NonNull
+ @Override
+ public AlertDialog create() {
+ this.dialog = super.create();
+
+ @NonNull Context context = getContext();
+ @ColorInt final int mainColor = BrandingUtil.readBrandMainColor(context);
+ @ColorInt final int textColor = BrandingUtil.readBrandTextColor(context);
+ applyBrand(mainColor, textColor);
+ dialog.setOnShowListener(dialog -> applyBrand(mainColor, textColor));
+ return dialog;
+ }
+
+ @CallSuper
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ final Button[] buttons = new Button[3];
+ buttons[0] = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ buttons[1] = dialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+ buttons[2] = dialog.getButton(DialogInterface.BUTTON_NEUTRAL);
+ for (Button button : buttons) {
+ if (button != null) {
+ button.setTextColor(getSecondaryForegroundColorDependingOnTheme(button.getContext(), mainColor));
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedDeleteAlertDialogBuilder.java b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedDeleteAlertDialogBuilder.java
new file mode 100644
index 00000000..113acf49
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedDeleteAlertDialogBuilder.java
@@ -0,0 +1,26 @@
+package it.niedermann.owncloud.notes.branding;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.widget.Button;
+
+import androidx.annotation.CallSuper;
+
+import it.niedermann.owncloud.notes.R;
+
+public class BrandedDeleteAlertDialogBuilder extends BrandedAlertDialogBuilder {
+
+ public BrandedDeleteAlertDialogBuilder(Context context) {
+ super(context);
+ }
+
+ @CallSuper
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ super.applyBrand(mainColor, textColor);
+ final Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ if (positiveButton != null) {
+ positiveButton.setTextColor(getContext().getResources().getColor(R.color.bg_attention));
+ }
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedDialogFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedDialogFragment.java
new file mode 100644
index 00000000..63eb2a69
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedDialogFragment.java
@@ -0,0 +1,24 @@
+package it.niedermann.owncloud.notes.branding;
+
+import android.content.Context;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.DialogFragment;
+
+public abstract class BrandedDialogFragment extends DialogFragment implements Branded {
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ @Nullable Context context = getContext();
+ if (context != null) {
+ if (BrandingUtil.isBrandingEnabled(context)) {
+ @ColorInt final int mainColor = BrandingUtil.readBrandMainColor(context);
+ @ColorInt final int textColor = BrandingUtil.readBrandTextColor(context);
+ applyBrand(mainColor, textColor);
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedFragment.java
new file mode 100644
index 00000000..5752bff8
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedFragment.java
@@ -0,0 +1,49 @@
+package it.niedermann.owncloud.notes.branding;
+
+import android.content.Context;
+import android.util.TypedValue;
+import android.view.Menu;
+import android.view.MenuInflater;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+import it.niedermann.owncloud.notes.R;
+
+import static it.niedermann.owncloud.notes.branding.BrandingUtil.tintMenuIcon;
+
+public abstract class BrandedFragment extends Fragment implements Branded {
+
+ @ColorInt
+ protected int colorAccent;
+ @ColorInt
+ protected int colorPrimary;
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ final TypedValue typedValue = new TypedValue();
+ requireActivity().getTheme().resolveAttribute(R.attr.colorAccent, typedValue, true);
+ colorAccent = typedValue.data;
+ requireActivity().getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true);
+ colorPrimary = typedValue.data;
+
+ @Nullable Context context = getContext();
+ if (context != null && BrandingUtil.isBrandingEnabled(context)) {
+ @ColorInt final int mainColor = BrandingUtil.readBrandMainColor(context);
+ @ColorInt final int textColor = BrandingUtil.readBrandTextColor(context);
+ applyBrand(mainColor, textColor);
+ }
+ }
+
+ @Override
+ public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ for (int i = 0; i < menu.size(); i++) {
+ tintMenuIcon(menu.getItem(i), colorAccent);
+ }
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedPreferenceCategory.java b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedPreferenceCategory.java
new file mode 100644
index 00000000..d2bcd274
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedPreferenceCategory.java
@@ -0,0 +1,46 @@
+package it.niedermann.owncloud.notes.branding;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.Nullable;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceViewHolder;
+
+import static it.niedermann.owncloud.notes.branding.BrandingUtil.getSecondaryForegroundColorDependingOnTheme;
+
+public class BrandedPreferenceCategory extends PreferenceCategory {
+
+ public BrandedPreferenceCategory(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ public BrandedPreferenceCategory(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public BrandedPreferenceCategory(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public BrandedPreferenceCategory(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+
+ if (BrandingUtil.isBrandingEnabled(getContext())) {
+ final View v = holder.itemView.findViewById(android.R.id.title);
+ @Nullable final Context context = getContext();
+ if (context != null && v instanceof TextView) {
+ @ColorInt final int mainColor = getSecondaryForegroundColorDependingOnTheme(context, BrandingUtil.readBrandMainColor(context));
+ ((TextView) v).setTextColor(mainColor);
+ }
+ }
+ }
+}
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
new file mode 100644
index 00000000..42b9c5cb
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedSnackbar.java
@@ -0,0 +1,31 @@
+package it.niedermann.owncloud.notes.branding;
+
+import android.graphics.Color;
+import android.view.View;
+
+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.owncloud.notes.util.ColorUtil;
+
+public class BrandedSnackbar {
+
+ @NonNull
+ public static Snackbar make(@NonNull View view, @NonNull CharSequence text, @BaseTransientBottomBar.Duration int duration) {
+ final Snackbar snackbar = Snackbar.make(view, text, duration);
+ if (BrandingUtil.isBrandingEnabled(view.getContext())) {
+ int color = BrandingUtil.readBrandMainColor(view.getContext());
+ snackbar.setActionTextColor(ColorUtil.isColorDark(color) ? Color.WHITE : color);
+ }
+ return snackbar;
+ }
+
+ @NonNull
+ 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/BrandedSwitchPreference.java b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedSwitchPreference.java
new file mode 100644
index 00000000..541d2f4a
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandedSwitchPreference.java
@@ -0,0 +1,116 @@
+package it.niedermann.owncloud.notes.branding;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Switch;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.Nullable;
+import androidx.core.graphics.drawable.DrawableCompat;
+import androidx.preference.PreferenceViewHolder;
+import androidx.preference.SwitchPreference;
+
+import it.niedermann.owncloud.notes.R;
+
+import static android.os.Build.VERSION.SDK_INT;
+import static android.os.Build.VERSION_CODES.JELLY_BEAN;
+import static it.niedermann.owncloud.notes.branding.BrandingUtil.getSecondaryForegroundColorDependingOnTheme;
+
+public class BrandedSwitchPreference extends SwitchPreference implements Branded {
+
+ @ColorInt
+ private Integer mainColor = null;
+
+ @ColorInt
+ private Integer textColor = null;
+
+ @Nullable
+ private Switch switchView;
+
+ public BrandedSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ public BrandedSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public BrandedSwitchPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public BrandedSwitchPreference(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+
+ if (holder.itemView instanceof ViewGroup) {
+ switchView = findSwitchWidget(holder.itemView);
+ if (mainColor != null && textColor != null) {
+ applyBrand();
+ }
+ }
+ }
+
+ @Override
+ public void applyBrand(@ColorInt int mainColor, @ColorInt int textColor) {
+ if (BrandingUtil.isBrandingEnabled(getContext())) {
+ this.mainColor = mainColor;
+ this.textColor = textColor;
+ } else {
+ this.mainColor = getContext().getResources().getColor(R.color.defaultBrand);
+ this.textColor = Color.WHITE;
+ }
+ // onBindViewHolder is called after applyBrand, therefore we have to store the given values and apply them later.
+ applyBrand();
+ }
+
+ private void applyBrand() {
+ if (switchView != null && SDK_INT >= JELLY_BEAN) {
+ final int finalMainColor = getSecondaryForegroundColorDependingOnTheme(getContext(), mainColor);
+ // int trackColor = Color.argb(77, Color.red(finalMainColor), Color.green(finalMainColor), Color.blue(finalMainColor));
+ DrawableCompat.setTintList(switchView.getThumbDrawable(), new ColorStateList(
+ new int[][]{new int[]{android.R.attr.state_checked}, new int[]{}},
+ new int[]{finalMainColor, getContext().getResources().getColor(R.color.fg_default_low)}
+ ));
+ DrawableCompat.setTintList(switchView.getTrackDrawable(), new ColorStateList(
+ new int[][]{new int[]{android.R.attr.state_checked}, new int[]{}},
+ new int[]{finalMainColor, getContext().getResources().getColor(R.color.fg_default_low)}
+ ));
+ }
+ }
+
+ /**
+ * Recursively go through view tree until we find an android.widget.Switch
+ *
+ * @param view Root view to start searching
+ * @return A Switch class or null
+ * @see <a href="https://gist.github.com/marchold/45e22839eb94aa14dfb5">Source</a>
+ */
+ private Switch findSwitchWidget(View view) {
+ if (view instanceof Switch) {
+ return (Switch) view;
+ }
+ if (view instanceof ViewGroup) {
+ ViewGroup viewGroup = (ViewGroup) view;
+ for (int i = 0; i < viewGroup.getChildCount(); i++) {
+ View child = viewGroup.getChildAt(i);
+ if (child instanceof ViewGroup) {
+ Switch result = findSwitchWidget(child);
+ if (result != null) return result;
+ }
+ if (child instanceof Switch) {
+ return (Switch) child;
+ }
+ }
+ }
+ return null;
+ }
+}
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
new file mode 100644
index 00000000..878917fa
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandingUtil.java
@@ -0,0 +1,133 @@
+package it.niedermann.owncloud.notes.branding;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.util.Log;
+import android.view.MenuItem;
+import android.widget.EditText;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.IdRes;
+import androidx.annotation.NonNull;
+import androidx.core.graphics.drawable.DrawableCompat;
+import androidx.preference.PreferenceManager;
+
+import it.niedermann.owncloud.notes.R;
+import it.niedermann.owncloud.notes.util.Notes;
+
+import static it.niedermann.owncloud.notes.util.ColorUtil.contrastRatioIsSufficient;
+
+public class BrandingUtil {
+
+ private static final String TAG = BrandingUtil.class.getSimpleName();
+ private static final String pref_key_branding_main = "branding_main";
+ private static final String pref_key_branding_text = "branding_text";
+
+ private BrandingUtil() {
+
+ }
+
+ public static boolean isBrandingEnabled(@NonNull Context context) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ return prefs.getBoolean(context.getString(R.string.pref_key_branding), true);
+ }
+
+ @ColorInt
+ public static int readBrandMainColor(@NonNull Context context) {
+ if (BrandingUtil.isBrandingEnabled(context)) {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
+ Log.v(TAG, "--- Read: shared_preference_theme_main");
+ return sharedPreferences.getInt(pref_key_branding_main, context.getApplicationContext().getResources().getColor(R.color.defaultBrand));
+ } else {
+ return context.getResources().getColor(R.color.defaultBrand);
+ }
+ }
+
+ @ColorInt
+ public static int readBrandTextColor(@NonNull Context context) {
+ if (isBrandingEnabled(context)) {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
+ Log.v(TAG, "--- Read: shared_preference_theme_text");
+ return sharedPreferences.getInt(pref_key_branding_text, Color.WHITE);
+ } else {
+ return Color.WHITE;
+ }
+ }
+
+ public static void saveBrandColors(@NonNull Context context, @ColorInt int mainColor, @ColorInt int textColor) {
+ final int previousMainColor = readBrandMainColor(context);
+ final int previousTextColor = readBrandTextColor(context);
+ SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
+ Log.v(TAG, "--- Write: shared_preference_theme_main" + " | " + mainColor);
+ Log.v(TAG, "--- Write: shared_preference_theme_text" + " | " + textColor);
+ editor.putInt(pref_key_branding_main, mainColor);
+ editor.putInt(pref_key_branding_text, textColor);
+ editor.apply();
+ if (isBrandingEnabled(context) && context instanceof BrandedActivity) {
+ if (mainColor != previousMainColor || textColor != previousTextColor) {
+ final BrandedActivity activity = (BrandedActivity) context;
+ activity.runOnUiThread(activity::recreate);
+ }
+ }
+ }
+
+ /**
+ * Since we may collide with dark theme in this area, we have to make sure that the color is visible depending on the background
+ */
+ @ColorInt
+ public static int getSecondaryForegroundColorDependingOnTheme(@NonNull Context context, @ColorInt int mainColor) {
+ final int primaryColor = context.getResources().getColor(R.color.primary);
+ final boolean isDarkTheme = Notes.isDarkThemeActive(context);
+ if (isDarkTheme && !contrastRatioIsSufficient(mainColor, primaryColor)) {
+ Log.v(TAG, "Contrast ratio between brand color " + String.format("#%06X", (0xFFFFFF & mainColor)) + " and dark theme is too low. Falling back to WHITE as brand color.");
+ return Color.WHITE;
+ } else if (!isDarkTheme && !contrastRatioIsSufficient(mainColor, primaryColor)) {
+ Log.v(TAG, "Contrast ratio between brand color " + String.format("#%06X", (0xFFFFFF & mainColor)) + " and light theme is too low. Falling back to BLACK as brand color.");
+ return Color.BLACK;
+ } else {
+ return mainColor;
+ }
+ }
+
+ public static void applyBrandToEditText(@ColorInt int mainColor, @ColorInt int textColor, @NonNull EditText editText) {
+ @ColorInt final int finalMainColor = getSecondaryForegroundColorDependingOnTheme(editText.getContext(), mainColor);
+ DrawableCompat.setTintList(editText.getBackground(), new ColorStateList(
+ new int[][]{
+ new int[]{android.R.attr.state_active},
+ new int[]{android.R.attr.state_activated},
+ new int[]{android.R.attr.state_focused},
+ new int[]{android.R.attr.state_pressed},
+ new int[]{}
+ },
+ new int[]{
+ finalMainColor,
+ finalMainColor,
+ finalMainColor,
+ finalMainColor,
+ editText.getContext().getResources().getColor(R.color.fg_default_low)
+ }
+ ));
+ }
+
+ public static void tintMenuIcon(@NonNull MenuItem menuItem, @ColorInt int color) {
+ Drawable drawable = menuItem.getIcon();
+ if (drawable != null) {
+ drawable = DrawableCompat.wrap(drawable);
+ DrawableCompat.setTint(drawable, color);
+ menuItem.setIcon(drawable);
+ }
+ }
+
+ public static void applyBrandToLayerDrawable(@NonNull LayerDrawable check, @IdRes int areaToColor, @ColorInt int mainColor) {
+ final Drawable drawable = check.findDrawableByLayerId(areaToColor);
+ if (drawable == null) {
+ Log.e(TAG, "Could not find areaToColor (" + areaToColor + "). Cannot apply brand.");
+ } else {
+ DrawableCompat.setTint(drawable, mainColor);
+ }
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/formattinghelp/FormattingHelpActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/formattinghelp/FormattingHelpActivity.java
new file mode 100644
index 00000000..299a9b18
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/formattinghelp/FormattingHelpActivity.java
@@ -0,0 +1,252 @@
+package it.niedermann.owncloud.notes.formattinghelp;
+
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.graphics.Typeface;
+import android.net.Uri;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.text.method.LinkMovementMethod;
+import android.util.TypedValue;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.preference.PreferenceManager;
+
+import com.yydcdut.markdown.MarkdownProcessor;
+import com.yydcdut.markdown.syntax.text.TextFactory;
+
+import it.niedermann.owncloud.notes.R;
+import it.niedermann.owncloud.notes.branding.BrandedActivity;
+import it.niedermann.owncloud.notes.databinding.ActivityFormattingHelpBinding;
+
+import static it.niedermann.owncloud.notes.util.MarkDownUtil.CHECKBOX_CHECKED_MINUS;
+import static it.niedermann.owncloud.notes.util.MarkDownUtil.CHECKBOX_CHECKED_STAR;
+import static it.niedermann.owncloud.notes.util.MarkDownUtil.CHECKBOX_UNCHECKED_MINUS;
+import static it.niedermann.owncloud.notes.util.MarkDownUtil.CHECKBOX_UNCHECKED_STAR;
+import static it.niedermann.owncloud.notes.util.MarkDownUtil.getMarkDownConfiguration;
+import static it.niedermann.owncloud.notes.util.MarkDownUtil.parseCompat;
+import static it.niedermann.owncloud.notes.util.NoteUtil.getFontSizeFromPreferences;
+
+public class FormattingHelpActivity extends BrandedActivity {
+
+ private ActivityFormattingHelpBinding binding;
+ private String content;
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ binding = ActivityFormattingHelpBinding.inflate(getLayoutInflater());
+ setContentView(binding.getRoot());
+
+ setSupportActionBar(binding.toolbar);
+
+ content = buildFormattingHelp();
+
+ final MarkdownProcessor markdownProcessor = new MarkdownProcessor(this);
+ markdownProcessor.factory(TextFactory.create());
+ markdownProcessor.config(getMarkDownConfiguration(binding.content.getContext())
+ .setOnTodoClickCallback((view, line, lineNumber) -> {
+ try {
+ String[] lines = TextUtils.split(content, "\\r?\\n");
+ /*
+ * Workaround for RxMarkdown-bug:
+ * When (un)checking a checkbox in a note which contains code-blocks, the "`"-characters get stripped out in the TextView and therefore the given lineNumber is wrong
+ * Find number of lines starting with ``` before lineNumber
+ */
+ boolean inCodefence = false;
+ for (int i = 0; i < lines.length; i++) {
+ if (lines[i].startsWith("```")) {
+ inCodefence = !inCodefence;
+ lineNumber++;
+ }
+ if (inCodefence && TextUtils.isEmpty(lines[i])) {
+ lineNumber++;
+ }
+ if (i == lineNumber) {
+ break;
+ }
+ }
+
+ /*
+ * Workaround for multiple RxMarkdown-bugs:
+ * When (un)checking a checkbox which is in the last line, every time it gets toggled, the last character of the line gets lost.
+ * When (un)checking a checkbox, every markdown gets stripped in the given line argument
+ */
+ if (lines[lineNumber].startsWith(CHECKBOX_UNCHECKED_MINUS) || lines[lineNumber].startsWith(CHECKBOX_UNCHECKED_STAR)) {
+ lines[lineNumber] = lines[lineNumber].replace(CHECKBOX_UNCHECKED_MINUS, CHECKBOX_CHECKED_MINUS);
+ lines[lineNumber] = lines[lineNumber].replace(CHECKBOX_UNCHECKED_STAR, CHECKBOX_CHECKED_STAR);
+ } else {
+ lines[lineNumber] = lines[lineNumber].replace(CHECKBOX_CHECKED_MINUS, CHECKBOX_UNCHECKED_MINUS);
+ lines[lineNumber] = lines[lineNumber].replace(CHECKBOX_CHECKED_STAR, CHECKBOX_UNCHECKED_STAR);
+ }
+
+ content = TextUtils.join("\n", lines);
+ binding.content.setText(parseCompat(markdownProcessor, content));
+ } catch (IndexOutOfBoundsException e) {
+ Toast.makeText(this, R.string.checkbox_could_not_be_toggled, Toast.LENGTH_SHORT).show();
+ e.printStackTrace();
+ }
+ return line;
+ }
+ )
+ .setOnLinkClickCallback((view, link) -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(link))))
+ .build());
+ binding.content.setMovementMethod(LinkMovementMethod.getInstance());
+ binding.content.setText(parseCompat(markdownProcessor, content));
+
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ binding.content.setTextSize(TypedValue.COMPLEX_UNIT_PX, getFontSizeFromPreferences(this, sp));
+ if (sp.getBoolean(getString(R.string.pref_key_font), false)) {
+ binding.content.setTypeface(Typeface.MONOSPACE);
+ }
+ }
+
+ @NonNull
+ private String buildFormattingHelp() {
+ final String lineBreak = "\n";
+ final String indention = " ";
+ final String divider = getString(R.string.formatting_help_divider);
+ final String codefence = getString(R.string.formatting_help_codefence);
+
+ int numberedListItem = 1;
+ final String lists = getString(R.string.formatting_help_lists_body_1) + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_ol, numberedListItem++, getString(R.string.formatting_help_lists_body_2)) + lineBreak +
+ getString(R.string.formatting_help_ol, numberedListItem++, getString(R.string.formatting_help_lists_body_3)) + lineBreak +
+ getString(R.string.formatting_help_ol, numberedListItem, getString(R.string.formatting_help_lists_body_4)) + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_lists_body_5) + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_ul, getString(R.string.formatting_help_lists_body_6)) + lineBreak +
+ getString(R.string.formatting_help_ul, getString(R.string.formatting_help_lists_body_7)) + lineBreak +
+ indention + getString(R.string.formatting_help_ul, getString(R.string.formatting_help_lists_body_8)) + lineBreak +
+ indention + getString(R.string.formatting_help_ul, getString(R.string.formatting_help_lists_body_9)) + lineBreak;
+
+ final String checkboxes = getString(R.string.formatting_help_checkboxes_body_1) + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_checkbox_checked, getString(R.string.formatting_help_checkboxes_body_2)) + lineBreak +
+ getString(R.string.formatting_help_checkbox_unchecked, getString(R.string.formatting_help_checkboxes_body_3)) + lineBreak;
+
+ final String structuredDocuments = getString(R.string.formatting_help_structured_documents_body_1, "`#`", "`##`") + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_title_level_3, getString(R.string.formatting_help_structured_documents_body_2)) + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_structured_documents_body_3, "`#`", "`######`") + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_structured_documents_body_4, getString(R.string.formatting_help_quote_keyword)) + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_quote, getString(R.string.formatting_help_structured_documents_body_5)) + lineBreak +
+ getString(R.string.formatting_help_quote, getString(R.string.formatting_help_structured_documents_body_6)) + lineBreak;
+
+ final String javascript = getString(R.string.formatting_help_javascript_1) + lineBreak +
+ indention + indention + getString(R.string.formatting_help_javascript_2) + lineBreak +
+ getString(R.string.formatting_help_javascript_3) + lineBreak;
+
+ return getString(R.string.formatting_help_title, getString(R.string.formatting_help_cbf_title)) + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_cbf_body_1) + lineBreak +
+ getString(R.string.formatting_help_cbf_body_2,
+ getString(R.string.formatting_help_codefence_inline, getString(android.R.string.cut)),
+ getString(R.string.formatting_help_codefence_inline, getString(android.R.string.copy)),
+ getString(R.string.formatting_help_codefence_inline, getString(android.R.string.selectAll)),
+ getString(R.string.formatting_help_codefence_inline, getString(R.string.simple_link)),
+ getString(R.string.formatting_help_codefence_inline, getString(R.string.simple_checkbox))
+ ) + lineBreak +
+ lineBreak +
+ divider + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_title, getString(R.string.formatting_help_text_title)) + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_text_body,
+ getString(R.string.formatting_help_bold),
+ getString(R.string.formatting_help_italic),
+ getString(R.string.formatting_help_strike_through)
+ ) + lineBreak +
+ lineBreak +
+ codefence + lineBreak +
+ getString(R.string.formatting_help_text_body,
+ getString(R.string.formatting_help_bold),
+ getString(R.string.formatting_help_italic),
+ getString(R.string.formatting_help_strike_through)
+ ) + lineBreak +
+ codefence + lineBreak +
+ lineBreak +
+ divider + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_title, getString(R.string.formatting_help_lists_title)) + lineBreak +
+ lineBreak +
+ lists +
+ lineBreak +
+ codefence + lineBreak +
+ lists +
+ codefence + lineBreak +
+ lineBreak +
+ divider + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_title, getString(R.string.formatting_help_checkboxes_title)) + lineBreak +
+ lineBreak +
+ checkboxes +
+ lineBreak +
+ codefence + lineBreak +
+ checkboxes +
+ codefence + lineBreak +
+ lineBreak +
+ divider + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_title, getString(R.string.formatting_help_structured_documents_title)) + lineBreak +
+ lineBreak +
+ structuredDocuments +
+ lineBreak +
+ codefence + lineBreak +
+ structuredDocuments +
+ codefence + lineBreak +
+ lineBreak +
+ divider + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_title, getString(R.string.formatting_help_code_title)) + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_code_body_1) + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_codefence_inline_escaped, getString(R.string.formatting_help_code_javascript_inline)) + lineBreak +
+ getString(R.string.formatting_help_codefence_inline, getString(R.string.formatting_help_code_javascript_inline)) + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_code_body_2) + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_codefence_escaped) + lineBreak +
+ javascript +
+ getString(R.string.formatting_help_codefence_escaped) + lineBreak +
+ lineBreak +
+ codefence + lineBreak +
+ javascript +
+ codefence + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_code_body_3) + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_codefence_javascript_escaped) + lineBreak +
+ javascript +
+ getString(R.string.formatting_help_codefence_escaped) + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_codefence_javascript) + lineBreak +
+ javascript +
+ codefence + lineBreak +
+ lineBreak +
+ divider + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_title, getString(R.string.formatting_help_unsupported_title)) + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_unsupported_body_1) + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_ul, getString(R.string.formatting_help_unsupported_body_2)) + lineBreak +
+ getString(R.string.formatting_help_ul, getString(R.string.formatting_help_unsupported_body_3)) + lineBreak +
+ lineBreak +
+ getString(R.string.formatting_help_unsupported_body_4) + lineBreak;
+ }
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/glide/SingleSignOnStreamFetcher.java b/app/src/main/java/it/niedermann/owncloud/notes/glide/SingleSignOnStreamFetcher.java
index a70c816c..c519e9af 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/glide/SingleSignOnStreamFetcher.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/glide/SingleSignOnStreamFetcher.java
@@ -1,5 +1,6 @@
package it.niedermann.owncloud.notes.glide;
+import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -8,9 +9,15 @@ import com.bumptech.glide.Priority;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.model.GlideUrl;
+import com.google.gson.GsonBuilder;
import com.nextcloud.android.sso.aidl.NextcloudRequest;
import com.nextcloud.android.sso.api.NextcloudAPI;
import com.nextcloud.android.sso.api.Response;
+import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException;
+import com.nextcloud.android.sso.exceptions.NoCurrentAccountSelectedException;
+import com.nextcloud.android.sso.exceptions.TokenMismatchException;
+import com.nextcloud.android.sso.helper.SingleAccountHelper;
+import com.nextcloud.android.sso.model.SingleSignOnAccount;
import java.io.InputStream;
import java.net.MalformedURLException;
@@ -25,36 +32,79 @@ import java.util.Map;
*/
public class SingleSignOnStreamFetcher implements DataFetcher<InputStream> {
- private final NextcloudAPI client;
+ private static final String TAG = SingleSignOnStreamFetcher.class.getSimpleName();
+ private static final String METHOD_GET = "GET";
+
+ private static final Map<String, NextcloudAPI> INITIALIZED_APIs = new HashMap<>();
+
+ private final Context context;
private final GlideUrl url;
// Public API.
@SuppressWarnings("WeakerAccess")
- public SingleSignOnStreamFetcher(NextcloudAPI client, GlideUrl url) {
- this.client = client;
+ public SingleSignOnStreamFetcher(Context context, GlideUrl url) {
+ this.context = context;
this.url = url;
}
@Override
- public void loadData(@NonNull Priority priority, @NonNull final DataCallback<? super InputStream> callback) {Log.v("yey", "yey fetcher");
+ public void loadData(@NonNull Priority priority, @NonNull final DataCallback<? super InputStream> callback) {
+ NextcloudAPI client = null;
try {
- NextcloudRequest.Builder requestBuilder = new NextcloudRequest.Builder()
- .setMethod("GET")
- .setUrl(url.toURL().getPath());
- Map<String, List<String>> header = new HashMap<>();
- for (Map.Entry<String, String> headerEntry : url.getHeaders().entrySet()) {
- header.put(headerEntry.getKey(), Collections.singletonList(headerEntry.getValue()));
+ SingleSignOnAccount ssoAccount = SingleAccountHelper.getCurrentSingleSignOnAccount(context);
+ client = INITIALIZED_APIs.get(ssoAccount.name);
+ boolean didInitialize = false;
+ if (client == null) {
+ client = new NextcloudAPI(context, SingleAccountHelper.getCurrentSingleSignOnAccount(context), new GsonBuilder().create(), new NextcloudAPI.ApiConnectedListener() {
+ @Override
+ public void onConnected() {
+ Log.v(TAG, "SSO API successfully initialized");
+ }
+
+ @Override
+ public void onError(Exception ex) {
+ Log.e(TAG, ex.getMessage(), ex);
+ }
+ });
+ INITIALIZED_APIs.put(ssoAccount.name, client);
+ didInitialize = true;
}
- requestBuilder.setHeader(header);
- NextcloudRequest nextcloudRequest = requestBuilder.build();
- Response response = client.performNetworkRequestV2(nextcloudRequest);
- callback.onDataReady(response.getBody());
- } catch (MalformedURLException e) {
- callback.onLoadFailed(e);
- } catch (Exception e) {
- callback.onLoadFailed(e);
- }
+ NextcloudRequest.Builder requestBuilder = null;
+ try {
+ requestBuilder = new NextcloudRequest.Builder()
+ .setMethod(METHOD_GET)
+ .setUrl(url.toURL().getPath());
+ Map<String, List<String>> header = new HashMap<>();
+ for (Map.Entry<String, String> headerEntry : url.getHeaders().entrySet()) {
+ header.put(headerEntry.getKey(), Collections.singletonList(headerEntry.getValue()));
+ }
+ requestBuilder.setHeader(header);
+ NextcloudRequest nextcloudRequest = requestBuilder.build();
+ Log.v(TAG, nextcloudRequest.toString());
+ Response response = client.performNetworkRequestV2(nextcloudRequest);
+ callback.onDataReady(response.getBody());
+ } catch (MalformedURLException e) {
+ callback.onLoadFailed(e);
+ } catch (TokenMismatchException e) {
+ if (!didInitialize) {
+ Log.w(TAG, "SSO Glide loader failed with TokenMismatchException, trying to re-initialize...");
+ client.stop();
+ INITIALIZED_APIs.remove(ssoAccount.name);
+ loadData(priority, callback);
+ } else {
+ e.printStackTrace();
+ callback.onLoadFailed(e);
+ }
+ } catch (Exception e) {
+ callback.onLoadFailed(e);
+ }
+
+ } catch (NextcloudFilesAppAccountNotFoundException e) {
+ e.printStackTrace();
+ } catch (NoCurrentAccountSelectedException e) {
+ e.printStackTrace();
+ }
}
@Override
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/glide/SingleSignOnUrlLoader.java b/app/src/main/java/it/niedermann/owncloud/notes/glide/SingleSignOnUrlLoader.java
index 890d96b7..864918a9 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/glide/SingleSignOnUrlLoader.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/glide/SingleSignOnUrlLoader.java
@@ -1,7 +1,6 @@
package it.niedermann.owncloud.notes.glide;
import android.content.Context;
-import android.util.Log;
import androidx.annotation.NonNull;
@@ -10,11 +9,6 @@ import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.ModelLoader;
import com.bumptech.glide.load.model.ModelLoaderFactory;
import com.bumptech.glide.load.model.MultiModelLoaderFactory;
-import com.google.gson.GsonBuilder;
-import com.nextcloud.android.sso.api.NextcloudAPI;
-import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException;
-import com.nextcloud.android.sso.exceptions.NoCurrentAccountSelectedException;
-import com.nextcloud.android.sso.helper.SingleAccountHelper;
import java.io.InputStream;
@@ -24,12 +18,12 @@ import java.io.InputStream;
public class SingleSignOnUrlLoader implements ModelLoader<GlideUrl, InputStream> {
private static final String TAG = SingleSignOnUrlLoader.class.getSimpleName();
- private final NextcloudAPI client;
+ private final Context context;
// Public API.
@SuppressWarnings("WeakerAccess")
- public SingleSignOnUrlLoader(@NonNull NextcloudAPI client) {
- this.client = client;
+ public SingleSignOnUrlLoader(@NonNull Context context) {
+ this.context = context;
}
@Override
@@ -40,7 +34,7 @@ public class SingleSignOnUrlLoader implements ModelLoader<GlideUrl, InputStream>
@Override
public LoadData<InputStream> buildLoadData(
@NonNull GlideUrl model, int width, int height, @NonNull Options options) {
- return new LoadData<>(model, new SingleSignOnStreamFetcher(client, model));
+ return new LoadData<>(model, new SingleSignOnStreamFetcher(context, model));
}
/**
@@ -55,28 +49,12 @@ public class SingleSignOnUrlLoader implements ModelLoader<GlideUrl, InputStream>
* Constructor for a new Factory that runs requests using given client.
*/
public Factory(@NonNull Context context) {
- try {
- loader = new SingleSignOnUrlLoader(new NextcloudAPI(context, SingleAccountHelper.getCurrentSingleSignOnAccount(context), new GsonBuilder().create(), new NextcloudAPI.ApiConnectedListener() {
- @Override
- public void onConnected() {
- Log.v(TAG, "SSO API successfully initialized");
- }
-
- @Override
- public void onError(Exception ex) {
- Log.e(TAG, ex.getMessage(), ex);
- }
- }));
- } catch (NextcloudFilesAppAccountNotFoundException e) {
- e.printStackTrace();
- } catch (NoCurrentAccountSelectedException e) {
- e.printStackTrace();
- }
+ loader = new SingleSignOnUrlLoader(context);
}
@NonNull
@Override
- public ModelLoader<GlideUrl, InputStream> build(MultiModelLoaderFactory multiFactory) {
+ public ModelLoader<GlideUrl, InputStream> build(@NonNull MultiModelLoaderFactory multiFactory) {
return loader;
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountAdapter.java b/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountAdapter.java
new file mode 100644
index 00000000..50ab925b
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountAdapter.java
@@ -0,0 +1,80 @@
+package it.niedermann.owncloud.notes.manageaccounts;
+
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.util.Consumer;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import it.niedermann.owncloud.notes.R;
+import it.niedermann.owncloud.notes.model.LocalAccount;
+
+public class ManageAccountAdapter extends RecyclerView.Adapter<ManageAccountViewHolder> {
+
+ @Nullable
+ private LocalAccount currentLocalAccount = null;
+ @NonNull
+ private final List<LocalAccount> localAccounts = new ArrayList<>();
+ @NonNull
+ private final Consumer<LocalAccount> onAccountClick;
+ @Nullable
+ private final Consumer<LocalAccount> onAccountDelete;
+
+ public ManageAccountAdapter(@NonNull Consumer<LocalAccount> onAccountClick, @Nullable Consumer<LocalAccount> onAccountDelete) {
+ this.onAccountClick = onAccountClick;
+ this.onAccountDelete = onAccountDelete;
+ setHasStableIds(true);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return localAccounts.get(position).getId();
+ }
+
+ @NonNull
+ @Override
+ public ManageAccountViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ return new ManageAccountViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_account_choose, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ManageAccountViewHolder holder, int position) {
+ final LocalAccount localAccount = localAccounts.get(position);
+ holder.bind(localAccount, (localAccountClicked) -> {
+ setCurrentLocalAccount(localAccountClicked);
+ onAccountClick.accept(localAccountClicked);
+ }, (localAccountToDelete -> {
+ if (onAccountDelete != null) {
+ for (int i = 0; i < localAccounts.size(); i++) {
+ if (localAccounts.get(i).getId() == localAccountToDelete.getId()) {
+ localAccounts.remove(i);
+ notifyItemRemoved(i);
+ break;
+ }
+ }
+ onAccountDelete.accept(localAccountToDelete);
+ }
+ }), currentLocalAccount != null && currentLocalAccount.getId() == localAccount.getId());
+ }
+
+ @Override
+ public int getItemCount() {
+ return localAccounts.size();
+ }
+
+ public void setLocalAccounts(@NonNull List<LocalAccount> localAccounts) {
+ this.localAccounts.clear();
+ this.localAccounts.addAll(localAccounts);
+ notifyDataSetChanged();
+ }
+
+ public void setCurrentLocalAccount(@Nullable LocalAccount currentLocalAccount) {
+ this.currentLocalAccount = currentLocalAccount;
+ notifyDataSetChanged();
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountViewHolder.java b/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountViewHolder.java
new file mode 100644
index 00000000..df56fba5
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountViewHolder.java
@@ -0,0 +1,53 @@
+package it.niedermann.owncloud.notes.manageaccounts;
+
+import android.graphics.drawable.LayerDrawable;
+import android.net.Uri;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.util.Consumer;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.RequestOptions;
+
+import it.niedermann.owncloud.notes.R;
+import it.niedermann.owncloud.notes.databinding.ItemAccountChooseBinding;
+import it.niedermann.owncloud.notes.model.LocalAccount;
+
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+import static it.niedermann.owncloud.notes.branding.BrandingUtil.applyBrandToLayerDrawable;
+
+public class ManageAccountViewHolder extends RecyclerView.ViewHolder {
+
+ private ItemAccountChooseBinding binding;
+
+ public ManageAccountViewHolder(@NonNull View itemView) {
+ super(itemView);
+ binding = ItemAccountChooseBinding.bind(itemView);
+ }
+
+ public void bind(@NonNull LocalAccount localAccount, @NonNull Consumer<LocalAccount> onAccountClick, @Nullable Consumer<LocalAccount> onAccountDelete, boolean isCurrentAccount) {
+ binding.accountItemLabel.setText(localAccount.getAccountName());
+ Glide.with(itemView.getContext())
+ .load(localAccount.getUrl() + "/index.php/avatar/" + Uri.encode(localAccount.getUserName()) + "/64")
+ .error(R.drawable.ic_account_circle_grey_24dp)
+ .apply(RequestOptions.circleCropTransform())
+ .into(binding.accountItemAvatar);
+ itemView.setOnClickListener((v) -> onAccountClick.accept(localAccount));
+ if (onAccountDelete == null) {
+ binding.delete.setVisibility(GONE);
+ } else {
+ binding.delete.setVisibility(VISIBLE);
+ binding.delete.setOnClickListener((v) -> onAccountDelete.accept(localAccount));
+ }
+ if (isCurrentAccount) {
+ binding.currentAccountIndicator.setVisibility(VISIBLE);
+ applyBrandToLayerDrawable((LayerDrawable) binding.currentAccountIndicator.getDrawable(), R.id.area, localAccount.getColor());
+ } else {
+ binding.currentAccountIndicator.setVisibility(GONE);
+ }
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountsActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountsActivity.java
new file mode 100644
index 00000000..123f345e
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/manageaccounts/ManageAccountsActivity.java
@@ -0,0 +1,74 @@
+package it.niedermann.owncloud.notes.manageaccounts;
+
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+
+import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException;
+import com.nextcloud.android.sso.exceptions.NoCurrentAccountSelectedException;
+import com.nextcloud.android.sso.helper.SingleAccountHelper;
+import com.nextcloud.android.sso.model.SingleSignOnAccount;
+
+import java.util.List;
+
+import it.niedermann.owncloud.notes.android.activity.LockedActivity;
+import it.niedermann.owncloud.notes.databinding.ActivityManageAccountsBinding;
+import it.niedermann.owncloud.notes.model.LocalAccount;
+import it.niedermann.owncloud.notes.persistence.NotesDatabase;
+
+public class ManageAccountsActivity extends LockedActivity {
+
+ private ActivityManageAccountsBinding binding;
+ private ManageAccountAdapter adapter;
+ private NotesDatabase db = null;
+
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ binding = ActivityManageAccountsBinding.inflate(getLayoutInflater());
+ setContentView(binding.getRoot());
+
+ setSupportActionBar(binding.toolbar);
+
+ db = NotesDatabase.getInstance(this);
+
+ List<LocalAccount> localAccounts = db.getAccounts();
+
+ adapter = new ManageAccountAdapter((localAccount) -> {
+ SingleAccountHelper.setCurrentAccount(getApplicationContext(), localAccount.getAccountName());
+ }, (localAccount) -> {
+ db.deleteAccount(localAccount);
+ for (LocalAccount temp : localAccounts) {
+ if (temp.getId() == localAccount.getId()) {
+ localAccounts.remove(temp);
+ break;
+ }
+ }
+ if (localAccounts.size() > 0) {
+ SingleAccountHelper.setCurrentAccount(getApplicationContext(), localAccounts.get(0).getAccountName());
+ adapter.setCurrentLocalAccount(localAccounts.get(0));
+ } else {
+ setResult(AppCompatActivity.RESULT_FIRST_USER);
+ finish();
+ }
+ });
+ adapter.setLocalAccounts(localAccounts);
+ try {
+ SingleSignOnAccount ssoAccount = SingleAccountHelper.getCurrentSingleSignOnAccount(this);
+ if (ssoAccount != null) {
+ adapter.setCurrentLocalAccount(db.getLocalAccountByAccountName(ssoAccount.name));
+ }
+ } catch (NextcloudFilesAppAccountNotFoundException | NoCurrentAccountSelectedException e) {
+ e.printStackTrace();
+ }
+ binding.accounts.setAdapter(adapter);
+ }
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ applyBrandToPrimaryToolbar(binding.toolbar);
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/AbstractWidgetData.java b/app/src/main/java/it/niedermann/owncloud/notes/model/AbstractWidgetData.java
new file mode 100644
index 00000000..672ba170
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/model/AbstractWidgetData.java
@@ -0,0 +1,42 @@
+package it.niedermann.owncloud.notes.model;
+
+public abstract class AbstractWidgetData {
+
+ private int appWidgetId;
+ private long accountId;
+ private int themeMode;
+
+ protected AbstractWidgetData() {
+
+ }
+
+ protected AbstractWidgetData(int appWidgetId, long accountId, int themeMode) {
+ this.appWidgetId = appWidgetId;
+ this.accountId = accountId;
+ this.themeMode = themeMode;
+ }
+
+ public int getAppWidgetId() {
+ return appWidgetId;
+ }
+
+ public void setAppWidgetId(int appWidgetId) {
+ this.appWidgetId = appWidgetId;
+ }
+
+ public long getAccountId() {
+ return accountId;
+ }
+
+ public void setAccountId(long accountId) {
+ this.accountId = accountId;
+ }
+
+ public int getThemeMode() {
+ return themeMode;
+ }
+
+ public void setThemeMode(int themeMode) {
+ this.themeMode = themeMode;
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/DBNote.java b/app/src/main/java/it/niedermann/owncloud/notes/model/DBNote.java
index aeb67031..d2be6aa2 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/model/DBNote.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/model/DBNote.java
@@ -15,13 +15,15 @@ public class DBNote extends CloudNote implements Item, Serializable {
private final long accountId;
private DBStatus status;
private String excerpt;
+ private int scrollY;
- public DBNote(long id, long remoteId, Calendar modified, String title, String content, boolean favorite, String category, String etag, DBStatus status, long accountId, String excerpt) {
+ public DBNote(long id, long remoteId, Calendar modified, String title, String content, boolean favorite, String category, String etag, DBStatus status, long accountId, String excerpt, int scrollY) {
super(remoteId, modified, title, content, favorite, category, etag);
this.id = id;
this.excerpt = excerpt;
this.status = status;
this.accountId = accountId;
+ this.scrollY = scrollY;
}
public long getId() {
@@ -67,4 +69,12 @@ public class DBNote extends CloudNote implements Item, Serializable {
", excerpt='" + excerpt + '\'' +
'}';
}
+
+ public int getScrollY() {
+ return scrollY;
+ }
+
+ public void setScrollY(int scrollY) {
+ this.scrollY = scrollY;
+ }
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/GridItemDecoration.java b/app/src/main/java/it/niedermann/owncloud/notes/model/GridItemDecoration.java
new file mode 100644
index 00000000..68b349e0
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/model/GridItemDecoration.java
@@ -0,0 +1,53 @@
+package it.niedermann.owncloud.notes.model;
+
+import android.graphics.Rect;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Px;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.StaggeredGridLayoutManager;
+
+public class GridItemDecoration extends SectionItemDecoration {
+
+ @NonNull
+ private final ItemAdapter adapter;
+ private final int spanCount;
+ private final int gutter;
+
+ public GridItemDecoration(@NonNull ItemAdapter adapter, int spanCount, @Px int sectionLeft, @Px int sectionTop, @Px int sectionRight, @Px int sectionBottom, @Px int gutter) {
+ super(adapter, sectionLeft, sectionTop, sectionRight, sectionBottom);
+ this.spanCount = spanCount;
+ this.adapter = adapter;
+ this.gutter = gutter;
+ }
+
+ @Override
+ public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
+ super.getItemOffsets(outRect, view, parent, state);
+ final int position = parent.getChildAdapterPosition(view);
+ final StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
+
+ if (adapter.getItemViewType(position) == ItemAdapter.TYPE_SECTION) {
+ lp.setFullSpan(true);
+ } else {
+ final int spanIndex = lp.getSpanIndex();
+
+ if (position >= 0) {
+ // First row gets some spacing at the top
+ if (position < spanCount && position < adapter.getFirstPositionOfViewType(ItemAdapter.TYPE_SECTION)) {
+ outRect.top = gutter;
+ }
+
+ // First column gets some spacing at the left and the right side
+ if (spanIndex == 0) {
+ outRect.left = gutter;
+ }
+
+ // All columns get some spacing at the bottom and at the right side
+ outRect.right = gutter;
+ outRect.bottom = gutter;
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/ItemAdapter.java b/app/src/main/java/it/niedermann/owncloud/notes/model/ItemAdapter.java
index c2f2cc4b..f6efada4 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/model/ItemAdapter.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/model/ItemAdapter.java
@@ -1,41 +1,78 @@
package it.niedermann.owncloud.notes.model;
-import android.text.Html;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.graphics.Color;
+import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
-import android.view.View;
import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
+import androidx.annotation.ColorInt;
+import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
+import androidx.annotation.Px;
+import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import it.niedermann.owncloud.notes.R;
-import it.niedermann.owncloud.notes.databinding.ItemNotesListNoteItemBinding;
+import it.niedermann.owncloud.notes.branding.Branded;
+import it.niedermann.owncloud.notes.databinding.ItemNotesListNoteItemGridBinding;
+import it.niedermann.owncloud.notes.databinding.ItemNotesListNoteItemGridOnlyTitleBinding;
+import it.niedermann.owncloud.notes.databinding.ItemNotesListNoteItemWithExcerptBinding;
+import it.niedermann.owncloud.notes.databinding.ItemNotesListNoteItemWithoutExcerptBinding;
import it.niedermann.owncloud.notes.databinding.ItemNotesListSectionItemBinding;
-import static androidx.recyclerview.widget.RecyclerView.NO_POSITION;
+import static it.niedermann.owncloud.notes.util.NoteUtil.getFontSizeFromPreferences;
-public class ItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+public class ItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements Branded {
private static final String TAG = ItemAdapter.class.getSimpleName();
- private static final int section_type = 0;
- private static final int note_type = 1;
+ public static final int TYPE_SECTION = 0;
+ public static final int TYPE_NOTE_WITH_EXCERPT = 1;
+ public static final int TYPE_NOTE_WITHOUT_EXCERPT = 2;
+ public static final int TYPE_NOTE_ONLY_TITLE = 3;
+
private final NoteClickListener noteClickListener;
- private List<Item> itemList;
+ private final boolean gridView;
+ private List<Item> itemList = new ArrayList<>();
private boolean showCategory = true;
- private final List<Integer> selected;
-
- public ItemAdapter(@NonNull NoteClickListener noteClickListener) {
- this.itemList = new ArrayList<>();
- this.selected = new ArrayList<>();
- this.noteClickListener = noteClickListener;
- }
+ private CharSequence searchQuery;
+ private final List<Integer> selected = new ArrayList<>();
+ @Px
+ private final float fontSize;
+ private final boolean monospace;
+ @ColorInt
+ private int mainColor;
+ @ColorInt
+ private int textColor;
+
+ public <T extends Context & NoteClickListener> ItemAdapter(@NonNull T context, boolean gridView) {
+ this.noteClickListener = context;
+ this.gridView = gridView;
+ this.mainColor = context.getResources().getColor(R.color.defaultBrand);
+ this.textColor = Color.WHITE;
+ final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
+ this.fontSize = getFontSizeFromPreferences(context, sp);
+ this.monospace = sp.getBoolean(context.getString(R.string.pref_key_font), false);
+ // FIXME see getItemId()
+ // setHasStableIds(true);
+ }
+
+
+ /*
+ FIXME this causes {@link it.niedermann.owncloud.notes.android.NotesListViewItemTouchHelper} to not call clearView anymore → After marking a note as favorite, it stays yellow.
+ @Override
+ public long getItemId(int position) {
+ return getItemViewType(position) == TYPE_SECTION
+ ? ((SectionItem) getItem(position)).getTitle().hashCode() * -1
+ : ((DBNote) getItem(position)).getId();
+ }
+ */
/**
* Updates the item list and notifies respective view to update.
@@ -66,41 +103,57 @@ public class ItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
notifyDataSetChanged();
}
- // Create new views (invoked by the layout manager)
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
- View v;
- if (viewType == section_type) {
- v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_notes_list_section_item, parent, false);
- return new SectionViewHolder(v);
+ if (gridView) {
+ switch (viewType) {
+ case TYPE_SECTION: {
+ return new SectionViewHolder(ItemNotesListSectionItemBinding.inflate(LayoutInflater.from(parent.getContext())));
+ }
+ case TYPE_NOTE_ONLY_TITLE: {
+ return new NoteViewGridHolderOnlyTitle(ItemNotesListNoteItemGridOnlyTitleBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false), noteClickListener, monospace, fontSize);
+ }
+ case TYPE_NOTE_WITH_EXCERPT:
+ case TYPE_NOTE_WITHOUT_EXCERPT: {
+ return new NoteViewGridHolder(ItemNotesListNoteItemGridBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false), noteClickListener, monospace, fontSize);
+ }
+ default: {
+ throw new IllegalArgumentException("Not supported viewType: " + viewType);
+ }
+ }
} else {
- v = LayoutInflater.from(parent.getContext())
- .inflate(R.layout.item_notes_list_note_item, parent, false);
- return new NoteViewHolder(v);
+ switch (viewType) {
+ case TYPE_SECTION: {
+ return new SectionViewHolder(ItemNotesListSectionItemBinding.inflate(LayoutInflater.from(parent.getContext())));
+ }
+ case TYPE_NOTE_WITH_EXCERPT: {
+ return new NoteViewHolderWithExcerpt(ItemNotesListNoteItemWithExcerptBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false), noteClickListener);
+ }
+ case TYPE_NOTE_ONLY_TITLE:
+ case TYPE_NOTE_WITHOUT_EXCERPT: {
+ return new NoteViewHolderWithoutExcerpt(ItemNotesListNoteItemWithoutExcerptBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false), noteClickListener);
+ }
+ default: {
+ throw new IllegalArgumentException("Not supported viewType: " + viewType);
+ }
+ }
}
}
- // Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int position) {
- // - get element from your dataset at this position
- // - replace the contents of the view with that element
- Item item = itemList.get(position);
- if (item.isSection()) {
- SectionItem section = (SectionItem) item;
- ((SectionViewHolder) holder).sectionTitle.setText(section.geTitle());
- } else {
- final DBNote note = (DBNote) item;
- final NoteViewHolder nvHolder = ((NoteViewHolder) holder);
- nvHolder.noteSwipeable.setAlpha(DBStatus.LOCAL_DELETED.equals(note.getStatus()) ? 0.5f : 1.0f);
- nvHolder.noteTitle.setText(Html.fromHtml(note.getTitle()));
- nvHolder.noteCategory.setVisibility(showCategory && !note.getCategory().isEmpty() ? View.VISIBLE : View.GONE);
- nvHolder.noteCategory.setText(Html.fromHtml(note.getCategory()));
- nvHolder.noteExcerpt.setText(Html.fromHtml(note.getExcerpt()));
- nvHolder.noteStatus.setVisibility(DBStatus.VOID.equals(note.getStatus()) ? View.INVISIBLE : View.VISIBLE);
- nvHolder.noteFavorite.setImageResource(note.isFavorite() ? R.drawable.ic_star_yellow_24dp : R.drawable.ic_star_grey_ccc_24dp);
- nvHolder.noteFavorite.setOnClickListener(view -> noteClickListener.onNoteFavoriteClick(holder.getAdapterPosition(), view));
+ switch (getItemViewType(position)) {
+ case TYPE_SECTION: {
+ ((SectionViewHolder) holder).bind((SectionItem) itemList.get(position));
+ break;
+ }
+ case TYPE_NOTE_WITH_EXCERPT:
+ case TYPE_NOTE_WITHOUT_EXCERPT:
+ case TYPE_NOTE_ONLY_TITLE: {
+ ((NoteViewHolder) holder).bind((DBNote) itemList.get(position), showCategory, mainColor, textColor, searchQuery);
+ break;
+ }
}
}
@@ -108,7 +161,7 @@ public class ItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
return !selected.contains(position) && selected.add(position);
}
- public void clearSelection(RecyclerView recyclerView) {
+ public void clearSelection(@NonNull RecyclerView recyclerView) {
for (Integer i : getSelected()) {
RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(i);
if (viewHolder != null) {
@@ -154,68 +207,45 @@ public class ItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
return itemList.size();
}
+ @IntRange(from = 0, to = 3)
@Override
public int getItemViewType(int position) {
- return getItem(position).isSection() ? section_type : note_type;
- }
-
- public interface NoteClickListener {
- void onNoteClick(int position, View v);
-
- void onNoteFavoriteClick(int position, View v);
-
- boolean onNoteLongClick(int position, View v);
- }
-
- public class NoteViewHolder extends RecyclerView.ViewHolder implements View.OnLongClickListener, View.OnClickListener {
- public View noteSwipeable;
- private final ItemNotesListNoteItemBinding b;
- private final TextView noteTitle;
- private final TextView noteCategory;
- private final TextView noteExcerpt;
- private final ImageView noteStatus;
- private final ImageView noteFavorite;
-
- private NoteViewHolder(View v) {
- super(v);
- b = ItemNotesListNoteItemBinding.bind(v);
- this.noteSwipeable = b.noteSwipeable;
- this.noteTitle = b.noteTitle;
- this.noteCategory = b.noteCategory;
- this.noteExcerpt = b.noteExcerpt;
- this.noteStatus = b.noteStatus;
- this.noteFavorite = b.noteFavorite;
- v.setOnClickListener(this);
- v.setOnLongClickListener(this);
+ Item item = getItem(position);
+ if (item == null) {
+ throw new IllegalArgumentException("Item at position " + position + " must not be null");
}
-
- @Override
- public void onClick(View v) {
- final int adapterPosition = getAdapterPosition();
- if (adapterPosition != NO_POSITION) {
- noteClickListener.onNoteClick(adapterPosition, v);
+ if (getItem(position).isSection()) return TYPE_SECTION;
+ DBNote note = (DBNote) getItem(position);
+ if (TextUtils.isEmpty(note.getExcerpt())) {
+ if (TextUtils.isEmpty(note.getCategory())) {
+ return TYPE_NOTE_ONLY_TITLE;
+ } else {
+ return TYPE_NOTE_WITHOUT_EXCERPT;
}
}
+ return TYPE_NOTE_WITH_EXCERPT;
+ }
- @Override
- public boolean onLongClick(View v) {
- return noteClickListener.onNoteLongClick(getAdapterPosition(), v);
- }
-
- public void showSwipe(boolean left) {
- b.noteFavoriteLeft.setVisibility(left ? View.VISIBLE : View.INVISIBLE);
- b.noteDeleteRight.setVisibility(left ? View.INVISIBLE : View.VISIBLE);
- b.noteSwipeFrame.setBackgroundResource(left ? R.color.bg_warning : R.color.bg_attention);
- }
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ this.mainColor = mainColor;
+ this.textColor = textColor;
+ notifyDataSetChanged();
}
- public static class SectionViewHolder extends RecyclerView.ViewHolder {
- private TextView sectionTitle;
+ public void setHighlightSearchQuery(CharSequence searchQuery) {
+ this.searchQuery = searchQuery;
+ }
- private SectionViewHolder(View view) {
- super(view);
- ItemNotesListSectionItemBinding binding = ItemNotesListSectionItemBinding.bind(view);
- this.sectionTitle = binding.sectionTitle;
+ /**
+ * @return the position of the first item which matches the given viewtype, -1 if not available
+ */
+ public int getFirstPositionOfViewType(@IntRange(from = 0, to = 3) int viewType) {
+ for (int i = 0; i < itemList.size(); i++) {
+ if (getItemViewType(i) == viewType) {
+ return i;
+ }
}
+ return -1;
}
} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/NavigationAdapter.java b/app/src/main/java/it/niedermann/owncloud/notes/model/NavigationAdapter.java
index 6b061109..751fc581 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/model/NavigationAdapter.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/model/NavigationAdapter.java
@@ -1,5 +1,6 @@
package it.niedermann.owncloud.notes.model;
+import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
@@ -7,6 +8,7 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
+import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -17,11 +19,16 @@ import java.util.ArrayList;
import java.util.List;
import it.niedermann.owncloud.notes.R;
+import it.niedermann.owncloud.notes.branding.BrandingUtil;
import it.niedermann.owncloud.notes.databinding.ItemNavigationBinding;
import it.niedermann.owncloud.notes.util.NoteUtil;
public class NavigationAdapter extends RecyclerView.Adapter<NavigationAdapter.ViewHolder> {
+ @NonNull
+ private final Context context;
+ @ColorInt
+ private int mainColor;
@DrawableRes
public static final int ICON_FOLDER = R.drawable.ic_folder_grey600_24dp;
@DrawableRes
@@ -35,6 +42,11 @@ public class NavigationAdapter extends RecyclerView.Adapter<NavigationAdapter.Vi
@DrawableRes
public static final int ICON_SUB_MULTIPLE = R.drawable.ic_create_new_folder_grey600_18dp;
+ public void applyBrand(int mainColor, int textColor) {
+ this.mainColor = BrandingUtil.getSecondaryForegroundColorDependingOnTheme(context, mainColor);
+ notifyDataSetChanged();
+ }
+
public static class NavigationItem {
@NonNull
public String id;
@@ -53,6 +65,16 @@ public class NavigationAdapter extends RecyclerView.Adapter<NavigationAdapter.Vi
}
}
+ public static class CategoryNavigationItem extends NavigationItem {
+ @NonNull
+ public Long categoryId;
+
+ public CategoryNavigationItem(@NonNull String id, @NonNull String label, @Nullable Integer count, @DrawableRes int icon, @NonNull Long categoryId) {
+ super(id, label, count, icon);
+ this.categoryId = categoryId;
+ }
+ }
+
class ViewHolder extends RecyclerView.ViewHolder {
@NonNull
private final View view;
@@ -77,7 +99,7 @@ public class NavigationAdapter extends RecyclerView.Adapter<NavigationAdapter.Vi
itemView.setOnClickListener(view -> clickListener.onItemClick(currentItem));
}
- private void assignItem(@NonNull NavigationItem item) {
+ private void bind(@NonNull NavigationItem item) {
currentItem = item;
boolean isSelected = item.id.equals(selectedItem);
name.setText(NoteUtil.extendCategory(item.label));
@@ -90,7 +112,7 @@ public class NavigationAdapter extends RecyclerView.Adapter<NavigationAdapter.Vi
icon.setVisibility(View.GONE);
}
view.setBackgroundColor(isSelected ? view.getResources().getColor(R.color.bg_highlighted) : Color.TRANSPARENT);
- int textColor = view.getResources().getColor(isSelected ? R.color.primary_dark : R.color.fg_default);
+ int textColor = isSelected ? mainColor : view.getResources().getColor(R.color.fg_default);
name.setTextColor(textColor);
count.setTextColor(textColor);
@@ -110,7 +132,9 @@ public class NavigationAdapter extends RecyclerView.Adapter<NavigationAdapter.Vi
@NonNull
private final ClickListener clickListener;
- public NavigationAdapter(@NonNull ClickListener clickListener) {
+ public NavigationAdapter(@NonNull Context context, @NonNull ClickListener clickListener) {
+ this.context = context;
+ this.mainColor = BrandingUtil.getSecondaryForegroundColorDependingOnTheme(context, BrandingUtil.readBrandMainColor(context));
this.clickListener = clickListener;
}
@@ -123,7 +147,7 @@ public class NavigationAdapter extends RecyclerView.Adapter<NavigationAdapter.Vi
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
- holder.assignItem(items.get(position));
+ holder.bind(items.get(position));
}
@Override
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/NoteClickListener.java b/app/src/main/java/it/niedermann/owncloud/notes/model/NoteClickListener.java
new file mode 100644
index 00000000..8dd1748d
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/model/NoteClickListener.java
@@ -0,0 +1,11 @@
+package it.niedermann.owncloud.notes.model;
+
+import android.view.View;
+
+public interface NoteClickListener {
+ void onNoteClick(int position, View v);
+
+ void onNoteFavoriteClick(int position, View v);
+
+ boolean onNoteLongClick(int position, View v);
+} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/NoteListsWidgetData.java b/app/src/main/java/it/niedermann/owncloud/notes/model/NoteListsWidgetData.java
new file mode 100644
index 00000000..f0b95dcf
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/model/NoteListsWidgetData.java
@@ -0,0 +1,40 @@
+package it.niedermann.owncloud.notes.model;
+
+import androidx.annotation.IntRange;
+import androidx.annotation.Nullable;
+
+public class NoteListsWidgetData extends AbstractWidgetData {
+ public static final int MODE_DISPLAY_ALL = 0;
+ public static final int MODE_DISPLAY_STARRED = 1;
+ public static final int MODE_DISPLAY_CATEGORY = 2;
+
+ @IntRange(from = 0, to = 2)
+ private int mode;
+ @Nullable
+ private Long categoryId;
+
+ public int getMode() {
+ return mode;
+ }
+
+ public void setMode(@IntRange(from = 0, to = 2) int mode) {
+ this.mode = mode;
+ }
+
+ @Nullable
+ public Long getCategoryId() {
+ return categoryId;
+ }
+
+ public void setCategoryId(@Nullable Long categoryId) {
+ this.categoryId = categoryId;
+ }
+
+ @Override
+ public String toString() {
+ return "NoteListsWidgetData{" +
+ "mode=" + mode +
+ ", categoryId=" + categoryId +
+ '}';
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/NoteViewGridHolder.java b/app/src/main/java/it/niedermann/owncloud/notes/model/NoteViewGridHolder.java
new file mode 100644
index 00000000..6f840fb1
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/model/NoteViewGridHolder.java
@@ -0,0 +1,55 @@
+package it.niedermann.owncloud.notes.model;
+
+import android.content.Context;
+import android.graphics.Typeface;
+import android.text.TextUtils;
+import android.util.TypedValue;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.Px;
+
+import it.niedermann.owncloud.notes.databinding.ItemNotesListNoteItemGridBinding;
+
+import static android.view.View.GONE;
+import static android.view.View.INVISIBLE;
+import static android.view.View.VISIBLE;
+import static it.niedermann.owncloud.notes.util.NoteUtil.EXCERPT_LINE_SEPARATOR;
+
+public class NoteViewGridHolder extends NoteViewHolder {
+ @NonNull
+ private final ItemNotesListNoteItemGridBinding binding;
+
+ public NoteViewGridHolder(@NonNull ItemNotesListNoteItemGridBinding binding, @NonNull NoteClickListener noteClickListener, boolean monospace, @Px float fontSize) {
+ super(binding.getRoot(), noteClickListener);
+ this.binding = binding;
+
+ binding.noteTitle.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize * 1.1f);
+ binding.noteExcerpt.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize * .8f);
+ if (monospace) {
+ binding.noteTitle.setTypeface(Typeface.MONOSPACE);
+ binding.noteExcerpt.setTypeface(Typeface.MONOSPACE);
+ }
+ }
+
+ public void showSwipe(boolean left) {
+ throw new UnsupportedOperationException(NoteViewGridHolder.class.getSimpleName() + " does not support swiping");
+ }
+
+ public void bind(@NonNull DBNote note, boolean showCategory, int mainColor, int textColor, @Nullable CharSequence searchQuery) {
+ super.bind(note, showCategory, mainColor, textColor, searchQuery);
+ @NonNull final Context context = itemView.getContext();
+ bindCategory(context, binding.noteCategory, showCategory, note.getCategory(), mainColor);
+ binding.noteStatus.setVisibility(DBStatus.VOID.equals(note.getStatus()) ? INVISIBLE : VISIBLE);
+ bindFavorite(binding.noteFavorite, note.isFavorite());
+ bindSearchableContent(context, binding.noteTitle, searchQuery, note.getTitle(), mainColor);
+ bindSearchableContent(context, binding.noteExcerpt, searchQuery, note.getExcerpt().replace(EXCERPT_LINE_SEPARATOR, "\n"), mainColor);
+ binding.noteExcerpt.setVisibility(TextUtils.isEmpty(note.getExcerpt()) ? GONE : VISIBLE);
+ }
+
+ @Nullable
+ public View getNoteSwipeable() {
+ return null;
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/NoteViewGridHolderOnlyTitle.java b/app/src/main/java/it/niedermann/owncloud/notes/model/NoteViewGridHolderOnlyTitle.java
new file mode 100644
index 00000000..59e14eff
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/model/NoteViewGridHolderOnlyTitle.java
@@ -0,0 +1,47 @@
+package it.niedermann.owncloud.notes.model;
+
+import android.content.Context;
+import android.graphics.Typeface;
+import android.util.TypedValue;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.Px;
+
+import it.niedermann.owncloud.notes.databinding.ItemNotesListNoteItemGridOnlyTitleBinding;
+
+import static android.view.View.INVISIBLE;
+import static android.view.View.VISIBLE;
+
+public class NoteViewGridHolderOnlyTitle extends NoteViewHolder {
+ @NonNull
+ private final ItemNotesListNoteItemGridOnlyTitleBinding binding;
+
+ public NoteViewGridHolderOnlyTitle(@NonNull ItemNotesListNoteItemGridOnlyTitleBinding binding, @NonNull NoteClickListener noteClickListener, boolean monospace, @Px float fontSize) {
+ super(binding.getRoot(), noteClickListener);
+ this.binding = binding;
+
+ binding.noteTitle.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize * 1.1f);
+ if (monospace) {
+ binding.noteTitle.setTypeface(Typeface.MONOSPACE);
+ }
+ }
+
+ public void showSwipe(boolean left) {
+ throw new UnsupportedOperationException(NoteViewGridHolderOnlyTitle.class.getSimpleName() + " does not support swiping");
+ }
+
+ public void bind(@NonNull DBNote note, boolean showCategory, int mainColor, int textColor, @Nullable CharSequence searchQuery) {
+ super.bind(note, showCategory, mainColor, textColor, searchQuery);
+ @NonNull final Context context = itemView.getContext();
+ binding.noteStatus.setVisibility(DBStatus.VOID.equals(note.getStatus()) ? INVISIBLE : VISIBLE);
+ bindFavorite(binding.noteFavorite, note.isFavorite());
+ bindSearchableContent(context, binding.noteTitle, searchQuery, note.getTitle(), mainColor);
+ }
+
+ @Nullable
+ public View getNoteSwipeable() {
+ return null;
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/NoteViewHolder.java b/app/src/main/java/it/niedermann/owncloud/notes/model/NoteViewHolder.java
new file mode 100644
index 00000000..c4e222e3
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/model/NoteViewHolder.java
@@ -0,0 +1,127 @@
+package it.niedermann.owncloud.notes.model;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.graphics.drawable.GradientDrawable;
+import android.os.Build;
+import android.text.SpannableString;
+import android.text.TextUtils;
+import android.text.style.BackgroundColorSpan;
+import android.text.style.ForegroundColorSpan;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.CallSuper;
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.graphics.drawable.DrawableCompat;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.android.material.chip.Chip;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import it.niedermann.owncloud.notes.R;
+import it.niedermann.owncloud.notes.branding.BrandingUtil;
+import it.niedermann.owncloud.notes.util.Notes;
+
+import static it.niedermann.owncloud.notes.util.ColorUtil.contrastRatioIsSufficient;
+import static it.niedermann.owncloud.notes.util.ColorUtil.isColorDark;
+
+public abstract class NoteViewHolder extends RecyclerView.ViewHolder {
+ @NonNull
+ private final NoteClickListener noteClickListener;
+
+ public NoteViewHolder(@NonNull View v, @NonNull NoteClickListener noteClickListener) {
+ super(v);
+ this.noteClickListener = noteClickListener;
+ }
+
+ @CallSuper
+ public void bind(@NonNull DBNote note, boolean showCategory, int mainColor, int textColor, @Nullable CharSequence searchQuery) {
+ itemView.setOnClickListener((view) -> noteClickListener.onNoteClick(getAdapterPosition(), view));
+ itemView.setOnLongClickListener((view) -> noteClickListener.onNoteLongClick(getAdapterPosition(), view));
+ }
+
+ protected void bindCategory(@NonNull Context context, @NonNull TextView noteCategory, boolean showCategory, @NonNull String category, int mainColor) {
+ final boolean isDarkThemeActive = Notes.isDarkThemeActive(context);
+ noteCategory.setVisibility(showCategory && !category.isEmpty() ? View.VISIBLE : View.GONE);
+ noteCategory.setText(category);
+
+ @ColorInt int categoryForeground;
+ @ColorInt int categoryBackground;
+
+ if (isDarkThemeActive) {
+ if (isColorDark(mainColor)) {
+ if (contrastRatioIsSufficient(mainColor, Color.BLACK)) {
+ categoryBackground = mainColor;
+ categoryForeground = Color.WHITE;
+ } else {
+ categoryBackground = Color.WHITE;
+ categoryForeground = mainColor;
+ }
+ } else {
+ categoryBackground = mainColor;
+ categoryForeground = Color.BLACK;
+ }
+ } else {
+ categoryForeground = Color.BLACK;
+ if (isColorDark(mainColor) || contrastRatioIsSufficient(mainColor, Color.WHITE)) {
+ categoryBackground = mainColor;
+ } else {
+ categoryBackground = Color.BLACK;
+ }
+ }
+
+ noteCategory.setTextColor(categoryForeground);
+ if (noteCategory instanceof Chip) {
+ ((Chip) noteCategory).setChipStrokeColor(ColorStateList.valueOf(categoryBackground));
+ ((Chip) noteCategory).setChipBackgroundColor(ColorStateList.valueOf(isDarkThemeActive ? categoryBackground : Color.TRANSPARENT));
+ } else {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ DrawableCompat.setTint(noteCategory.getBackground(), categoryBackground);
+ } else {
+ final GradientDrawable drawable = (GradientDrawable) noteCategory.getBackground();
+ drawable.setStroke(1, categoryBackground);
+ drawable.setColor(isDarkThemeActive ? categoryBackground : Color.TRANSPARENT);
+ }
+ }
+ }
+
+ protected void bindFavorite(@NonNull ImageView noteFavorite, boolean isFavorite) {
+ noteFavorite.setImageResource(isFavorite ? R.drawable.ic_star_yellow_24dp : R.drawable.ic_star_grey_ccc_24dp);
+ noteFavorite.setOnClickListener(view -> noteClickListener.onNoteFavoriteClick(getAdapterPosition(), view));
+ }
+
+ protected void bindSearchableContent(@NonNull Context context, @NonNull TextView textView, @Nullable CharSequence searchQuery, @NonNull String content, int mainColor) {
+ CharSequence processedContent = content;
+ if (!TextUtils.isEmpty(searchQuery)) {
+ @ColorInt final int searchBackground = context.getResources().getColor(R.color.bg_highlighted);
+ @ColorInt final int searchForeground = BrandingUtil.getSecondaryForegroundColorDependingOnTheme(context, mainColor);
+
+ // The Pattern.quote method will add \Q to the very beginning of the string and \E to the end of the string
+ // It implies that the string between \Q and \E is a literal string and thus the reserved keyword in such string will be ignored.
+ // See https://stackoverflow.com/questions/15409296/what-is-the-use-of-pattern-quote-method
+ final Pattern pattern = Pattern.compile("(" + Pattern.quote(searchQuery.toString()) + ")", Pattern.CASE_INSENSITIVE);
+ SpannableString spannableString = new SpannableString(content);
+ Matcher matcher = pattern.matcher(spannableString);
+
+ while (matcher.find()) {
+ spannableString.setSpan(new ForegroundColorSpan(searchForeground), matcher.start(), matcher.end(), 0);
+ spannableString.setSpan(new BackgroundColorSpan(searchBackground), matcher.start(), matcher.end(), 0);
+ }
+
+ processedContent = spannableString;
+ }
+ textView.setText(processedContent);
+ }
+
+ public abstract void showSwipe(boolean left);
+
+ @Nullable
+ public abstract View getNoteSwipeable();
+} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/NoteViewHolderWithExcerpt.java b/app/src/main/java/it/niedermann/owncloud/notes/model/NoteViewHolderWithExcerpt.java
new file mode 100644
index 00000000..032e868f
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/model/NoteViewHolderWithExcerpt.java
@@ -0,0 +1,44 @@
+package it.niedermann.owncloud.notes.model;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import it.niedermann.owncloud.notes.R;
+import it.niedermann.owncloud.notes.databinding.ItemNotesListNoteItemWithExcerptBinding;
+
+public class NoteViewHolderWithExcerpt extends NoteViewHolder {
+ @NonNull
+ private final ItemNotesListNoteItemWithExcerptBinding binding;
+
+ public NoteViewHolderWithExcerpt(@NonNull ItemNotesListNoteItemWithExcerptBinding binding, @NonNull NoteClickListener noteClickListener) {
+ super(binding.getRoot(), noteClickListener);
+ this.binding = binding;
+ }
+
+ public void showSwipe(boolean left) {
+ binding.noteFavoriteLeft.setVisibility(left ? View.VISIBLE : View.INVISIBLE);
+ binding.noteDeleteRight.setVisibility(left ? View.INVISIBLE : View.VISIBLE);
+ binding.noteSwipeFrame.setBackgroundResource(left ? R.color.bg_warning : R.color.bg_attention);
+ }
+
+ public void bind(@NonNull DBNote note, boolean showCategory, int mainColor, int textColor, @Nullable CharSequence searchQuery) {
+ super.bind(note, showCategory, mainColor, textColor, searchQuery);
+ @NonNull final Context context = itemView.getContext();
+ binding.noteSwipeable.setAlpha(DBStatus.LOCAL_DELETED.equals(note.getStatus()) ? 0.5f : 1.0f);
+ bindCategory(context, binding.noteCategory, showCategory, note.getCategory(), mainColor);
+ binding.noteStatus.setVisibility(DBStatus.VOID.equals(note.getStatus()) ? View.INVISIBLE : View.VISIBLE);
+ bindFavorite(binding.noteFavorite, note.isFavorite());
+
+ bindSearchableContent(context, binding.noteTitle, searchQuery, note.getTitle(), mainColor);
+ bindSearchableContent(context, binding.noteExcerpt, searchQuery, note.getExcerpt(), mainColor);
+ }
+
+ @NonNull
+ public View getNoteSwipeable() {
+ return binding.noteSwipeable;
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/NoteViewHolderWithoutExcerpt.java b/app/src/main/java/it/niedermann/owncloud/notes/model/NoteViewHolderWithoutExcerpt.java
new file mode 100644
index 00000000..acdb4fb6
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/model/NoteViewHolderWithoutExcerpt.java
@@ -0,0 +1,41 @@
+package it.niedermann.owncloud.notes.model;
+
+import android.content.Context;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import it.niedermann.owncloud.notes.R;
+import it.niedermann.owncloud.notes.databinding.ItemNotesListNoteItemWithoutExcerptBinding;
+
+public class NoteViewHolderWithoutExcerpt extends NoteViewHolder {
+ @NonNull
+ private final ItemNotesListNoteItemWithoutExcerptBinding binding;
+
+ public NoteViewHolderWithoutExcerpt(@NonNull ItemNotesListNoteItemWithoutExcerptBinding binding, @NonNull NoteClickListener noteClickListener) {
+ super(binding.getRoot(), noteClickListener);
+ this.binding = binding;
+ }
+
+ public void showSwipe(boolean left) {
+ binding.noteFavoriteLeft.setVisibility(left ? View.VISIBLE : View.INVISIBLE);
+ binding.noteDeleteRight.setVisibility(left ? View.INVISIBLE : View.VISIBLE);
+ binding.noteSwipeFrame.setBackgroundResource(left ? R.color.bg_warning : R.color.bg_attention);
+ }
+
+ public void bind(@NonNull DBNote note, boolean showCategory, int mainColor, int textColor, @Nullable CharSequence searchQuery) {
+ super.bind(note, showCategory, mainColor, textColor, searchQuery);
+ @NonNull final Context context = itemView.getContext();
+ binding.noteSwipeable.setAlpha(DBStatus.LOCAL_DELETED.equals(note.getStatus()) ? 0.5f : 1.0f);
+ bindCategory(context, binding.noteCategory, showCategory, note.getCategory(), mainColor);
+ binding.noteStatus.setVisibility(DBStatus.VOID.equals(note.getStatus()) ? View.INVISIBLE : View.VISIBLE);
+ bindFavorite(binding.noteFavorite, note.isFavorite());
+ bindSearchableContent(context, binding.noteTitle, searchQuery, note.getTitle(), mainColor);
+ }
+
+ @NonNull
+ public View getNoteSwipeable() {
+ return binding.noteSwipeable;
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/SectionItem.java b/app/src/main/java/it/niedermann/owncloud/notes/model/SectionItem.java
index c144211b..27e4758a 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/model/SectionItem.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/model/SectionItem.java
@@ -8,7 +8,7 @@ public class SectionItem implements Item {
this.title = title;
}
- public String geTitle() {
+ public String getTitle() {
return title;
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/SectionItemDecoration.java b/app/src/main/java/it/niedermann/owncloud/notes/model/SectionItemDecoration.java
new file mode 100644
index 00000000..baf95926
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/model/SectionItemDecoration.java
@@ -0,0 +1,39 @@
+package it.niedermann.owncloud.notes.model;
+
+import android.graphics.Rect;
+import android.view.View;
+
+import androidx.annotation.CallSuper;
+import androidx.annotation.NonNull;
+import androidx.annotation.Px;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.StaggeredGridLayoutManager;
+
+public class SectionItemDecoration extends RecyclerView.ItemDecoration {
+
+ @NonNull
+ private final ItemAdapter adapter;
+ private final int sectionLeft;
+ private final int sectionTop;
+ private final int sectionRight;
+ private final int sectionBottom;
+
+ public SectionItemDecoration(@NonNull ItemAdapter adapter, @Px int sectionLeft, @Px int sectionTop, @Px int sectionRight, @Px int sectionBottom) {
+ this.adapter = adapter;
+ this.sectionLeft = sectionLeft;
+ this.sectionTop = sectionTop;
+ this.sectionRight = sectionRight;
+ this.sectionBottom = sectionBottom;
+ }
+
+ @CallSuper
+ public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
+ final int position = parent.getChildAdapterPosition(view);
+ if (adapter.getItemViewType(position) == ItemAdapter.TYPE_SECTION) {
+ outRect.left = sectionLeft;
+ outRect.top = sectionTop;
+ outRect.right = sectionRight;
+ outRect.bottom = sectionBottom;
+ }
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/SectionViewHolder.java b/app/src/main/java/it/niedermann/owncloud/notes/model/SectionViewHolder.java
new file mode 100644
index 00000000..eccdd7d9
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/model/SectionViewHolder.java
@@ -0,0 +1,19 @@
+package it.niedermann.owncloud.notes.model;
+
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.StaggeredGridLayoutManager;
+
+import it.niedermann.owncloud.notes.databinding.ItemNotesListSectionItemBinding;
+
+public class SectionViewHolder extends RecyclerView.ViewHolder {
+ private final ItemNotesListSectionItemBinding binding;
+
+ public SectionViewHolder(ItemNotesListSectionItemBinding binding) {
+ super(binding.getRoot());
+ this.binding = binding;
+ }
+
+ public void bind(SectionItem item) {
+ binding.sectionTitle.setText(item.getTitle());
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/SingleNoteWidgetData.java b/app/src/main/java/it/niedermann/owncloud/notes/model/SingleNoteWidgetData.java
index 8cb4bace..556c1041 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/model/SingleNoteWidgetData.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/model/SingleNoteWidgetData.java
@@ -1,36 +1,15 @@
package it.niedermann.owncloud.notes.model;
-public class SingleNoteWidgetData {
- private int appWidgetId;
- private long accountId;
+public class SingleNoteWidgetData extends AbstractWidgetData {
private long noteId;
- private int themeMode;
public SingleNoteWidgetData() {
}
public SingleNoteWidgetData(int appWidgetId, long accountId, long noteId, int themeMode) {
- this.appWidgetId = appWidgetId;
- this.accountId = accountId;
+ super(appWidgetId, accountId, themeMode);
this.noteId = noteId;
- this.themeMode = themeMode;
- }
-
- public int getAppWidgetId() {
- return appWidgetId;
- }
-
- public void setAppWidgetId(int appWidgetId) {
- this.appWidgetId = appWidgetId;
- }
-
- public long getAccountId() {
- return accountId;
- }
-
- public void setAccountId(long accountId) {
- this.accountId = accountId;
}
public long getNoteId() {
@@ -41,11 +20,4 @@ public class SingleNoteWidgetData {
this.noteId = noteId;
}
- public int getThemeMode() {
- return themeMode;
- }
-
- public void setThemeMode(int themeMode) {
- this.themeMode = themeMode;
- }
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/AbstractNotesDatabase.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/AbstractNotesDatabase.java
index da689211..66635dd6 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/AbstractNotesDatabase.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/AbstractNotesDatabase.java
@@ -1,49 +1,41 @@
package it.niedermann.owncloud.notes.persistence;
-import android.appwidget.AppWidgetManager;
-import android.content.ComponentName;
-import android.content.ContentValues;
import android.content.Context;
-import android.content.SharedPreferences;
-import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
-import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.preference.PreferenceManager;
-import androidx.work.WorkManager;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Hashtable;
-import java.util.Map;
-
-import it.niedermann.owncloud.notes.android.DarkModeSetting;
-import it.niedermann.owncloud.notes.android.appwidget.NoteListWidget;
-import it.niedermann.owncloud.notes.android.appwidget.SingleNoteWidget;
-import it.niedermann.owncloud.notes.model.DBStatus;
+import it.niedermann.owncloud.notes.persistence.migration.Migration_10_11;
+import it.niedermann.owncloud.notes.persistence.migration.Migration_11_12;
+import it.niedermann.owncloud.notes.persistence.migration.Migration_12_13;
+import it.niedermann.owncloud.notes.persistence.migration.Migration_13_14;
+import it.niedermann.owncloud.notes.persistence.migration.Migration_14_15;
+import it.niedermann.owncloud.notes.persistence.migration.Migration_15_16;
+import it.niedermann.owncloud.notes.persistence.migration.Migration_16_17;
+import it.niedermann.owncloud.notes.persistence.migration.Migration_4_5;
+import it.niedermann.owncloud.notes.persistence.migration.Migration_5_6;
+import it.niedermann.owncloud.notes.persistence.migration.Migration_6_7;
+import it.niedermann.owncloud.notes.persistence.migration.Migration_7_8;
+import it.niedermann.owncloud.notes.persistence.migration.Migration_8_9;
+import it.niedermann.owncloud.notes.persistence.migration.Migration_9_10;
import it.niedermann.owncloud.notes.util.DatabaseIndexUtil;
-import it.niedermann.owncloud.notes.util.NoteUtil;
-// Protected APIs
-@SuppressWarnings("WeakerAccess")
abstract class AbstractNotesDatabase extends SQLiteOpenHelper {
- private static final String TAG = AbstractNotesDatabase.class.getSimpleName();
- private static final int database_version = 16;
+ private static final int database_version = 18;
@NonNull
- private final Context context;
+ protected final Context context;
protected static final String database_name = "OWNCLOUD_NOTES";
protected static final String table_notes = "NOTES";
protected static final String table_accounts = "ACCOUNTS";
protected static final String table_category = "CATEGORIES";
protected static final String table_widget_single_notes = "WIDGET_SINGLE_NOTES";
+ protected static final String table_widget_note_list = "WIDGET_NOTE_LISTS";
protected static final String key_id = "ID";
-
protected static final String key_url = "URL";
protected static final String key_account_name = "ACCOUNT_NAME";
protected static final String key_username = "USERNAME";
@@ -66,6 +58,8 @@ abstract class AbstractNotesDatabase extends SQLiteOpenHelper {
protected static final String key_category_title = "CATEGORY_TITLE";
protected static final String key_category_account_id = "CATEGORY_ACCOUNT_ID";
protected static final String key_theme_mode = "THEME_MODE";
+ protected static final String key_mode = "MODE";
+ protected static final String key_scroll_y = "SCROLL_Y";
protected static final String key_category_sorting_method = "CATEGORY_SORTING_METHOD";
@@ -91,6 +85,7 @@ abstract class AbstractNotesDatabase extends SQLiteOpenHelper {
createNotesTable(db);
createCategoryTable(db);
createWidgetSingleNoteTable(db);
+ createWidgetNoteListTable(db);
}
private void createNotesTable(@NonNull SQLiteDatabase db) {
@@ -106,6 +101,7 @@ abstract class AbstractNotesDatabase extends SQLiteOpenHelper {
key_category + " INTEGER, " +
key_etag + " TEXT," +
key_excerpt + " TEXT NOT NULL DEFAULT '', " +
+ key_scroll_y + " INTEGER DEFAULT 0, " +
"FOREIGN KEY(" + key_category + ") REFERENCES " + table_category + "(" + key_category_id + "), " +
"FOREIGN KEY(" + key_account_id + ") REFERENCES " + table_accounts + "(" + key_id + "))");
DatabaseIndexUtil.createIndex(db, table_notes, key_remote_id, key_account_id, key_status, key_favorite, key_category, key_modified);
@@ -137,7 +133,6 @@ abstract class AbstractNotesDatabase extends SQLiteOpenHelper {
DatabaseIndexUtil.createIndex(db, table_category, key_category_id, key_category_account_id, key_category_title, key_category_sorting_method);
}
-
private void createWidgetSingleNoteTable(@NonNull SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + table_widget_single_notes + " ( " +
key_id + " INTEGER PRIMARY KEY, " +
@@ -148,301 +143,57 @@ abstract class AbstractNotesDatabase extends SQLiteOpenHelper {
"FOREIGN KEY(" + key_note_id + ") REFERENCES " + table_notes + "(" + key_id + "))");
}
+ private void createWidgetNoteListTable(@NonNull SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + table_widget_note_list + " ( " +
+ key_id + " INTEGER PRIMARY KEY, " +
+ key_account_id + " INTEGER, " +
+ key_category_id + " INTEGER, " +
+ key_mode + " INTEGER NOT NULL, " +
+ key_theme_mode + " INTEGER NOT NULL, " +
+ "FOREIGN KEY(" + key_account_id + ") REFERENCES " + table_accounts + "(" + key_id + "), " +
+ "FOREIGN KEY(" + key_category_id + ") REFERENCES " + table_category + "(" + key_category_id + "))");
+ }
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- if (oldVersion < 4) {
- recreateDatabase(db);
- return;
- }
- if (oldVersion < 5) {
- db.execSQL("ALTER TABLE NOTES ADD COLUMN REMOTEID INTEGER");
- db.execSQL("UPDATE NOTES SET REMOTEID=ID WHERE (REMOTEID IS NULL OR REMOTEID=0) AND STATUS!=?", new String[]{"LOCAL_CREATED"});
- db.execSQL("UPDATE NOTES SET REMOTEID=0, STATUS=? WHERE STATUS=?", new String[]{DBStatus.LOCAL_EDITED.getTitle(), "LOCAL_CREATED"});
- }
- if (oldVersion < 6) {
- db.execSQL("ALTER TABLE NOTES ADD COLUMN FAVORITE INTEGER DEFAULT 0");
- }
- if (oldVersion < 7) {
- DatabaseIndexUtil.dropIndexes(db);
- db.execSQL("ALTER TABLE NOTES ADD COLUMN CATEGORY TEXT NOT NULL DEFAULT ''");
- db.execSQL("ALTER TABLE NOTES ADD COLUMN ETAG TEXT");
- DatabaseIndexUtil.createIndex(db, "NOTES", "REMOTEID", "STATUS", "FAVORITE", "CATEGORY", "MODIFIED");
- }
- if (oldVersion < 8) {
- final String table_temp = "NOTES_TEMP";
- db.execSQL("CREATE TABLE " + table_temp + " ( " +
- "ID INTEGER PRIMARY KEY AUTOINCREMENT, " +
- "REMOTEID INTEGER, " +
- "STATUS VARCHAR(50), " +
- "TITLE TEXT, " +
- "MODIFIED INTEGER DEFAULT 0, " +
- "CONTENT TEXT, " +
- "FAVORITE INTEGER DEFAULT 0, " +
- "CATEGORY TEXT NOT NULL DEFAULT '', " +
- "ETAG TEXT)");
- DatabaseIndexUtil.createIndex(db, table_temp, "REMOTEID", "STATUS", "FAVORITE", "CATEGORY", "MODIFIED");
- db.execSQL(String.format("INSERT INTO %s(%s,%s,%s,%s,%s,%s,%s,%s,%s) ", table_temp, "ID", "REMOTEID", "STATUS", "TITLE", "MODIFIED", "CONTENT", "FAVORITE", "CATEGORY", "ETAG")
- + String.format("SELECT %s,%s,%s,%s,strftime('%%s',%s),%s,%s,%s,%s FROM %s", "ID", "REMOTEID", "STATUS", "TITLE", "MODIFIED", "CONTENT", "FAVORITE", "CATEGORY", "ETAG", "NOTES"));
- db.execSQL("DROP TABLE NOTES");
- db.execSQL(String.format("ALTER TABLE %s RENAME TO %s", table_temp, "NOTES"));
- }
- if (oldVersion < 9) {
- // Create accounts table
- db.execSQL("CREATE TABLE ACCOUNTS ( " +
- "ID INTEGER PRIMARY KEY AUTOINCREMENT, " +
- "URL TEXT, " +
- "USERNAME TEXT, " +
- "ACCOUNT_NAME TEXT UNIQUE, " +
- "ETAG TEXT, " +
- "MODIFIED INTEGER)");
- DatabaseIndexUtil.createIndex(db, "ACCOUNTS", "URL", "USERNAME", "ACCOUNT_NAME", "ETAG", "MODIFIED");
-
- // Add accountId to notes table
- db.execSQL("ALTER TABLE NOTES ADD COLUMN ACCOUNT_ID INTEGER NOT NULL DEFAULT 0");
- DatabaseIndexUtil.createIndex(db, "NOTES", "ACCOUNT_ID");
-
- // Migrate existing account from SharedPreferences
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
- String username = sharedPreferences.getString("settingsUsername", "");
- String url = sharedPreferences.getString("settingsUrl", "");
- if (!url.isEmpty() && url.endsWith("/")) {
- url = url.substring(0, url.length() - 1);
- try {
- String accountName = username + "@" + new URL(url).getHost();
-
- ContentValues migratedAccountValues = new ContentValues();
- migratedAccountValues.put("URL", url);
- migratedAccountValues.put("USERNAME", username);
- migratedAccountValues.put("ACCOUNT_NAME", accountName);
- db.insert("ACCOUNTS", null, migratedAccountValues);
-
- // After successful insertion of migrated account, set accountId to 1 in each note
- ContentValues values = new ContentValues();
- values.put("ACCOUNT_ID", 1);
- db.update("NOTES", values, "ACCOUNT_ID = ?", new String[]{"NULL"});
-
- // Add FOREIGN_KEY constraint
- final String table_temp = "NOTES_TEMP";
- db.execSQL(String.format("ALTER TABLE %s RENAME TO %s", "NOTES", table_temp));
-
- db.execSQL("CREATE TABLE NOTES ( " +
- "ID INTEGER PRIMARY KEY AUTOINCREMENT, " +
- "REMOTEID INTEGER, " +
- "ACCOUNT_ID INTEGER, " +
- "STATUS VARCHAR(50), " +
- "TITLE TEXT, " +
- "MODIFIED INTEGER DEFAULT 0, " +
- "CONTENT TEXT, " +
- "FAVORITE INTEGER DEFAULT 0, " +
- "CATEGORY TEXT NOT NULL DEFAULT '', " +
- "ETAG TEXT," +
- "FOREIGN KEY(ACCOUNT_ID) REFERENCES ACCOUNTS(ID))");
- DatabaseIndexUtil.createIndex(db, "NOTES", "REMOTEID", "ACCOUNT_ID", "STATUS", "FAVORITE", "CATEGORY", "MODIFIED");
-
- db.execSQL(String.format("INSERT INTO %s(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) ", "NOTES", "ID", "ACCOUNT_ID", "REMOTEID", "STATUS", "TITLE", "MODIFIED", "CONTENT", "FAVORITE", "CATEGORY", "ETAG")
- + String.format("SELECT %s,%s,%s,%s,%s,%s,%s,%s,%s,%s FROM %s", "ID", values.get("ACCOUNT_ID"), "REMOTEID", "STATUS", "TITLE", "MODIFIED", "CONTENT", "FAVORITE", "CATEGORY", "ETAG", table_temp));
- db.execSQL(String.format("DROP TABLE %s;", table_temp));
-
- AppWidgetManager awm = AppWidgetManager.getInstance(context);
- SharedPreferences.Editor editor = sharedPreferences.edit();
-
- // Add accountId '1' to any existing (and configured) appwidgets
- int[] appWidgetIdsNLW = awm.getAppWidgetIds(new ComponentName(context, NoteListWidget.class));
- int[] appWidgetIdsSNW = awm.getAppWidgetIds(new ComponentName(context, SingleNoteWidget.class));
-
- for (int appWidgetId : appWidgetIdsNLW) {
- if (sharedPreferences.getInt(NoteListWidget.WIDGET_MODE_KEY + appWidgetId, -1) >= 0) {
- editor.putLong(NoteListWidget.ACCOUNT_ID_KEY + appWidgetId, 1);
- }
- }
-
- for (int appWidgetId : appWidgetIdsSNW) {
- if (sharedPreferences.getLong("single_note_widget" + appWidgetId, -1) >= 0) {
- editor.putLong("SNW_accountId" + appWidgetId, 1);
- }
- }
-
- notifyNotesChanged();
-
- // Clean up no longer needed SharedPreferences
- editor.remove("notes_last_etag");
- editor.remove("notes_last_modified");
- editor.remove("settingsUrl");
- editor.remove("settingsUsername");
- editor.remove("settingsPassword");
- editor.apply();
- } catch (MalformedURLException e) {
- Log.e(TAG, "Previous URL could not be parsed. Recreating database...");
- e.printStackTrace();
- recreateDatabase(db);
- return;
- }
- } else {
- Log.e(TAG, "Previous URL is empty or does not end with a '/' character. Recreating database...");
+ switch (oldVersion) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
recreateDatabase(db);
return;
+ case 4:
+ new Migration_4_5(db);
+ case 5:
+ new Migration_5_6(db);
+ case 6:
+ new Migration_6_7(db);
+ case 7:
+ new Migration_7_8(db);
+ case 8:
+ new Migration_8_9(db, context, this::recreateDatabase, this::notifyWidgets);
+ case 9:
+ new Migration_9_10(db);
+ case 10:
+ new Migration_10_11(context);
+ case 11:
+ new Migration_11_12(db, context);
+ case 12:
+ new Migration_12_13(db, context);
+ case 13:
+ new Migration_13_14(db, context, this::notifyWidgets);
+ case 14:
+ new Migration_14_15(db);
+ case 15:
+ new Migration_15_16(db, context, this::notifyWidgets);
+ case 16:
+ new Migration_16_17(db);
+ case 17: {
+ // add a new column to store the sorting method for a category note list
+ db.execSQL("ALTER TABLE " + table_category + " ADD COLUMN " + key_category_sorting_method + " INTEGER DEFAULT 0");
}
}
- if (oldVersion < 10) {
- db.execSQL("ALTER TABLE NOTES ADD COLUMN EXCERPT INTEGER NOT NULL DEFAULT ''");
- Cursor cursor = db.query("NOTES", new String[]{"ID", "CONTENT"}, null, null, null, null, null, null);
- while (cursor.moveToNext()) {
- ContentValues values = new ContentValues();
- values.put("EXCERPT", NoteUtil.generateNoteExcerpt(cursor.getString(1)));
- db.update("NOTES", values, "ID" + " = ? ", new String[]{cursor.getString(0)});
- }
- cursor.close();
- }
- if (oldVersion < 11) {
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
- SharedPreferences.Editor editor = sharedPreferences.edit();
- Map<String, ?> prefs = sharedPreferences.getAll();
- for (Map.Entry<String, ?> pref : prefs.entrySet()) {
- String key = pref.getKey();
- if ("darkTheme".equals(key) || key.startsWith(NoteListWidget.DARK_THEME_KEY) || key.startsWith("SNW_darkTheme")) {
- Boolean darkTheme = (Boolean) pref.getValue();
- editor.putString(pref.getKey(), darkTheme ? DarkModeSetting.DARK.name() : DarkModeSetting.LIGHT.name());
- }
- }
- editor.apply();
- }
- if (oldVersion < 12) {
- db.execSQL("ALTER TABLE ACCOUNTS ADD COLUMN API_VERSION TEXT");
- db.execSQL("ALTER TABLE ACCOUNTS ADD COLUMN COLOR VARCHAR(6) NOT NULL DEFAULT '000000'");
- db.execSQL("ALTER TABLE ACCOUNTS ADD COLUMN TEXT_COLOR VARCHAR(6) NOT NULL DEFAULT '0082C9'");
- CapabilitiesWorker.update(context);
- }
- if (oldVersion < 13) {
- db.execSQL("ALTER TABLE ACCOUNTS ADD COLUMN CAPABILITIES_ETAG TEXT");
- WorkManager.getInstance(context.getApplicationContext()).cancelUniqueWork("it.niedermann.owncloud.notes.persistence.SyncWorker");
- WorkManager.getInstance(context.getApplicationContext()).cancelUniqueWork("SyncWorker");
- }
- if (oldVersion < 14) {
- // #754 Move single note widget preferences to database
- db.execSQL("CREATE TABLE WIDGET_SINGLE_NOTES ( " +
- "ID INTEGER PRIMARY KEY, " +
- "ACCOUNT_ID INTEGER, " +
- "NOTE_ID INTEGER, " +
- "THEME_MODE INTEGER NOT NULL, " +
- "FOREIGN KEY(ACCOUNT_ID) REFERENCES ACCOUNTS(ID), " +
- "FOREIGN KEY(NOTE_ID) REFERENCES NOTES(ID))");
-
- final String SP_WIDGET_KEY = "single_note_widget";
- final String SP_ACCOUNT_ID_KEY = "SNW_accountId";
- final String SP_DARK_THEME_KEY = "SNW_darkTheme";
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
- SharedPreferences.Editor editor = sharedPreferences.edit();
- Map<String, ?> prefs = sharedPreferences.getAll();
- for (Map.Entry<String, ?> pref : prefs.entrySet()) {
- final String key = pref.getKey();
- Integer widgetId = null;
- Long noteId = null;
- Long accountId = null;
- Integer themeMode = null;
- if (key != null && key.startsWith(SP_WIDGET_KEY)) {
- try {
- widgetId = Integer.parseInt(key.substring(SP_WIDGET_KEY.length()));
- noteId = (Long) pref.getValue();
- accountId = sharedPreferences.getLong(SP_ACCOUNT_ID_KEY + widgetId, -1);
-
- try {
- themeMode = DarkModeSetting.valueOf(sharedPreferences.getString(SP_DARK_THEME_KEY + widgetId, DarkModeSetting.SYSTEM_DEFAULT.name())).getModeId();
- } catch (ClassCastException e) {
- //DARK_THEME was a boolean in older versions of the app. We thereofre have to still support the old setting.
- themeMode = sharedPreferences.getBoolean(SP_DARK_THEME_KEY + widgetId, false) ? DarkModeSetting.DARK.getModeId() : DarkModeSetting.LIGHT.getModeId();
- }
-
- ContentValues migratedWidgetValues = new ContentValues();
- migratedWidgetValues.put("ID", widgetId);
- migratedWidgetValues.put("ACCOUNT_ID", accountId);
- migratedWidgetValues.put("NOTE_ID", noteId);
- migratedWidgetValues.put("THEME_MODE", themeMode);
- db.insert("WIDGET_SINGLE_NOTES", null, migratedWidgetValues);
- } catch (Throwable t) {
- Log.e(TAG, "Could not migrate widget {widgetId: " + widgetId + ", accountId: " + accountId + ", noteId: " + noteId + ", themeMode: " + themeMode + "}");
- t.printStackTrace();
- } finally {
- // Clean up old shared preferences
- editor.remove(SP_WIDGET_KEY + widgetId);
- editor.remove(SP_DARK_THEME_KEY + widgetId);
- editor.remove(SP_ACCOUNT_ID_KEY + widgetId);
- }
- }
- }
- editor.apply();
- notifyNotesChanged();
- }
- if (oldVersion < 15) {
- // Rename a tmp_NOTES table.
- String tmpTableNotes = String.format("tmp_%s", "NOTES");
- db.execSQL("ALTER TABLE NOTES RENAME TO " + tmpTableNotes);
- db.execSQL("CREATE TABLE NOTES ( " +
- "ID INTEGER PRIMARY KEY AUTOINCREMENT, " +
- "REMOTEID INTEGER, " +
- "ACCOUNT_ID INTEGER, " +
- "STATUS VARCHAR(50), " +
- "TITLE TEXT, " +
- "MODIFIED INTEGER DEFAULT 0, " +
- "CONTENT TEXT, " +
- "FAVORITE INTEGER DEFAULT 0, " +
- "CATEGORY INTEGER, " +
- "ETAG TEXT," +
- "EXCERPT TEXT NOT NULL DEFAULT '', " +
- "FOREIGN KEY(CATEGORY) REFERENCES CATEGORIES(CATEGORY_ID), " +
- "FOREIGN KEY(ACCOUNT_ID) REFERENCES ACCOUNTS(ID))");
- DatabaseIndexUtil.createIndex(db, "NOTES", "REMOTEID", "ACCOUNT_ID", "STATUS", "FAVORITE", "CATEGORY", "MODIFIED");
- db.execSQL("CREATE TABLE CATEGORIES(" +
- "CATEGORY_ID INTEGER PRIMARY KEY AUTOINCREMENT, " +
- "CATEGORY_ACCOUNT_ID INTEGER NOT NULL, " +
- "CATEGORY_TITLE TEXT NOT NULL, " +
- "UNIQUE( CATEGORY_ACCOUNT_ID , CATEGORY_TITLE), " +
- "FOREIGN KEY(CATEGORY_ACCOUNT_ID) REFERENCES ACCOUNTS(ID))");
- DatabaseIndexUtil.createIndex(db, "CATEGORIES", "CATEGORY_ID", "CATEGORY_ACCOUNT_ID", "CATEGORY_TITLE");
- // A hashtable storing categoryTitle - categoryId Mapping
- // This is used to prevent too many searches in database
- Hashtable<String, Integer> categoryTitleIdMap = new Hashtable<>();
- int id = 1;
- Cursor tmpNotesCursor = db.rawQuery("SELECT * FROM " + tmpTableNotes, null);
- while (tmpNotesCursor.moveToNext()) {
- String categoryTitle = tmpNotesCursor.getString(8);
- int accountId = tmpNotesCursor.getInt(2);
- Log.e("###", accountId + "");
- Integer categoryId;
- if (categoryTitleIdMap.containsKey(categoryTitle) && categoryTitleIdMap.get(categoryTitle) != null) {
- categoryId = categoryTitleIdMap.get(categoryTitle);
- } else {
- // The category does not exists in the database, create it.
- categoryId = id++;
- ContentValues values = new ContentValues();
- values.put("CATEGORY_ID", categoryId);
- values.put("CATEGORY_ACCOUNT_ID", accountId);
- values.put("CATEGORY_TITLE", categoryTitle);
- db.insert("CATEGORIES", null, values);
- categoryTitleIdMap.put(categoryTitle, categoryId);
- }
- // Move the data in tmp_NOTES to NOTES
- ContentValues values = new ContentValues();
- values.put("ID", tmpNotesCursor.getInt(0));
- values.put("REMOTEID", tmpNotesCursor.getInt(1));
- values.put("ACCOUNT_ID", tmpNotesCursor.getInt(2));
- values.put("STATUS", tmpNotesCursor.getString(3));
- values.put("TITLE", tmpNotesCursor.getString(4));
- values.put("MODIFIED", tmpNotesCursor.getLong(5));
- values.put("CONTENT", tmpNotesCursor.getString(6));
- values.put("FAVORITE", tmpNotesCursor.getInt(7));
- values.put("CATEGORY", categoryId);
- values.put("ETAG", tmpNotesCursor.getString(9));
- values.put("EXCERPT", tmpNotesCursor.getString(10));
- db.insert("NOTES", null, values);
- }
- tmpNotesCursor.close();
- db.execSQL("DROP TABLE IF EXISTS " + tmpTableNotes);
- }
- if (oldVersion < 16) {
- // add a new column to store the sorting method for a category note list
- db.execSQL("ALTER TABLE " + table_category + " ADD COLUMN " + key_category_sorting_method + " INTEGER DEFAULT 0");
- }
}
@Override
@@ -458,6 +209,5 @@ abstract class AbstractNotesDatabase extends SQLiteOpenHelper {
onCreate(db);
}
-
- protected abstract void notifyNotesChanged();
+ protected abstract void notifyWidgets();
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/LoadNotesListTask.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/LoadNotesListTask.java
index e370f52e..bb60fd63 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/LoadNotesListTask.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/LoadNotesListTask.java
@@ -1,14 +1,8 @@
package it.niedermann.owncloud.notes.persistence;
import android.content.Context;
-import android.graphics.Color;
import android.os.AsyncTask;
-import android.text.Html;
-import android.text.SpannableString;
-import android.text.TextUtils;
import android.text.format.DateUtils;
-import android.text.style.BackgroundColorSpan;
-import android.text.style.ForegroundColorSpan;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -17,8 +11,6 @@ import androidx.annotation.WorkerThread;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
import it.niedermann.owncloud.notes.R;
import it.niedermann.owncloud.notes.model.Category;
@@ -36,8 +28,6 @@ public class LoadNotesListTask extends AsyncTask<Void, Void, List<Item>> {
private final Category category;
private final CharSequence searchQuery;
private final long accountId;
- private final int searchForeground;
- private final int searchBackground;
public LoadNotesListTask(long accountId, @NonNull Context context, @NonNull NotesLoadedListener callback, @NonNull Category category, @Nullable CharSequence searchQuery) {
this.context = context;
@@ -45,8 +35,6 @@ public class LoadNotesListTask extends AsyncTask<Void, Void, List<Item>> {
this.category = category;
this.searchQuery = searchQuery;
this.accountId = accountId;
- this.searchBackground = context.getResources().getColor(R.color.bg_highlighted);
- this.searchForeground = DisplayUtils.getForeground(Integer.toHexString(this.searchBackground)) ? Color.WHITE : context.getResources().getColor(R.color.primary);
}
@Override
@@ -67,30 +55,6 @@ public class LoadNotesListTask extends AsyncTask<Void, Void, List<Item>> {
}
}
- private DBNote colorTheNote(DBNote dbNote) {
- if (!TextUtils.isEmpty(searchQuery)) {
- SpannableString spannableString = new SpannableString(dbNote.getTitle());
- Matcher matcher = Pattern.compile("(" + searchQuery + ")", Pattern.CASE_INSENSITIVE).matcher(spannableString);
- while (matcher.find()) {
- spannableString.setSpan(new ForegroundColorSpan(searchForeground), matcher.start(), matcher.end(), 0);
- spannableString.setSpan(new BackgroundColorSpan(searchBackground), matcher.start(), matcher.end(), 0);
- }
-
- dbNote.setTitle(Html.toHtml(spannableString));
-
- spannableString = new SpannableString(dbNote.getExcerpt());
- matcher = Pattern.compile("(" + searchQuery + ")", Pattern.CASE_INSENSITIVE).matcher(spannableString);
- while (matcher.find()) {
- spannableString.setSpan(new ForegroundColorSpan(searchForeground), matcher.start(), matcher.end(), 0);
- spannableString.setSpan(new BackgroundColorSpan(searchBackground), matcher.start(), matcher.end(), 0);
- }
-
- dbNote.setExcerpt(Html.toHtml(spannableString));
- }
-
- return dbNote;
- }
-
@NonNull
@WorkerThread
private List<Item> fillListByCategory(@NonNull List<DBNote> noteList) {
@@ -101,7 +65,7 @@ public class LoadNotesListTask extends AsyncTask<Void, Void, List<Item>> {
itemList.add(new SectionItem(NoteUtil.extendCategory(note.getCategory())));
}
- itemList.add(colorTheNote(note));
+ itemList.add(note);
currentCategory = note.getCategory();
}
return itemList;
@@ -119,7 +83,7 @@ public class LoadNotesListTask extends AsyncTask<Void, Void, List<Item>> {
if (i > 0 && !timeslot.equals(lastTimeslot)) {
itemList.add(new SectionItem(timeslot));
}
- itemList.add(colorTheNote(currentNote));
+ itemList.add(currentNote);
lastTimeslot = timeslot;
}
@@ -146,11 +110,11 @@ public class LoadNotesListTask extends AsyncTask<Void, Void, List<Item>> {
@Override
protected void onPostExecute(List<Item> items) {
- callback.onNotesLoaded(items, category.category == null);
+ callback.onNotesLoaded(items, category.category == null, searchQuery);
}
public interface NotesLoadedListener {
- void onNotesLoaded(List<Item> notes, boolean showCategory);
+ void onNotesLoaded(List<Item> notes, boolean showCategory, CharSequence searchQuery);
}
private class Timeslotter {
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NoteServerSyncHelper.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NoteServerSyncHelper.java
index d48b7529..7158c9d2 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NoteServerSyncHelper.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NoteServerSyncHelper.java
@@ -34,6 +34,7 @@ import java.util.Set;
import it.niedermann.owncloud.notes.R;
import it.niedermann.owncloud.notes.android.fragment.ExceptionDialogFragment;
+import it.niedermann.owncloud.notes.branding.BrandedSnackbar;
import it.niedermann.owncloud.notes.model.CloudNote;
import it.niedermann.owncloud.notes.model.DBNote;
import it.niedermann.owncloud.notes.model.DBStatus;
@@ -499,7 +500,7 @@ public class NoteServerSyncHelper {
}
if (!status.pullSuccessful || !status.pushSuccessful) {
if (context instanceof ViewProvider && context instanceof AppCompatActivity) {
- Snackbar.make(((ViewProvider) context).getView(), R.string.error_synchronization, Snackbar.LENGTH_LONG)
+ BrandedSnackbar.make(((ViewProvider) context).getView(), R.string.error_synchronization, Snackbar.LENGTH_LONG)
.setAction(R.string.simple_more, v -> ExceptionDialogFragment.newInstance(exceptions)
.show(((AppCompatActivity) context).getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()))
.show();
@@ -512,7 +513,7 @@ public class NoteServerSyncHelper {
callback.onFinish();
}
}
- db.notifyNotesChanged();
+ db.notifyWidgets();
db.updateDynamicShortcuts(localAccount.getId());
// start next sync if scheduled meanwhile
if (syncScheduled.containsKey(ssoAccount.name) && syncScheduled.get(ssoAccount.name) != null && Boolean.TRUE.equals(syncScheduled.get(ssoAccount.name))) {
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesDatabase.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesDatabase.java
index 5b0226da..eb608ebe 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesDatabase.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesDatabase.java
@@ -22,6 +22,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import androidx.preference.PreferenceManager;
+import androidx.core.content.ContextCompat;
import com.nextcloud.android.sso.AccountImporter;
import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException;
@@ -31,7 +32,6 @@ import org.json.JSONArray;
import org.json.JSONException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
@@ -43,8 +43,6 @@ import java.util.Set;
import it.niedermann.owncloud.notes.R;
import it.niedermann.owncloud.notes.android.activity.EditNoteActivity;
-import it.niedermann.owncloud.notes.android.appwidget.NoteListWidget;
-import it.niedermann.owncloud.notes.android.appwidget.SingleNoteWidget;
import it.niedermann.owncloud.notes.model.ApiVersion;
import it.niedermann.owncloud.notes.model.Capabilities;
import it.niedermann.owncloud.notes.model.Category;
@@ -55,10 +53,15 @@ import it.niedermann.owncloud.notes.model.ISyncCallback;
import it.niedermann.owncloud.notes.model.LocalAccount;
import it.niedermann.owncloud.notes.model.NavigationAdapter;
import it.niedermann.owncloud.notes.util.CategorySortingMethod;
+import it.niedermann.owncloud.notes.model.NoteListsWidgetData;
import it.niedermann.owncloud.notes.model.SingleNoteWidgetData;
+import it.niedermann.owncloud.notes.util.ColorUtil;
import it.niedermann.owncloud.notes.util.NoteUtil;
import static it.niedermann.owncloud.notes.android.activity.EditNoteActivity.ACTION_SHORTCUT;
+import static it.niedermann.owncloud.notes.android.appwidget.NoteListWidget.updateNoteListWidgets;
+import static it.niedermann.owncloud.notes.android.appwidget.SingleNoteWidget.updateSingleNoteWidgets;
+import static it.niedermann.owncloud.notes.model.NoteListsWidgetData.MODE_DISPLAY_CATEGORY;
/**
* Helps to add, get, update and delete Notes with the option to trigger a Resync with the Server.
@@ -95,9 +98,9 @@ public class NotesDatabase extends AbstractNotesDatabase {
* @param note Note
*/
public long addNoteAndSync(SingleSignOnAccount ssoAccount, long accountId, CloudNote note) {
- DBNote dbNote = new DBNote(0, 0, note.getModified(), note.getTitle(), note.getContent(), note.isFavorite(), note.getCategory(), note.getEtag(), DBStatus.LOCAL_EDITED, accountId, NoteUtil.generateNoteExcerpt(note.getContent()));
+ DBNote dbNote = new DBNote(0, 0, note.getModified(), note.getTitle(), note.getContent(), note.isFavorite(), note.getCategory(), note.getEtag(), DBStatus.LOCAL_EDITED, accountId, NoteUtil.generateNoteExcerpt(note.getContent()), 0);
long id = addNote(accountId, dbNote);
- notifyNotesChanged();
+ notifyWidgets();
getNoteServerSyncHelper().scheduleSync(ssoAccount, true);
return id;
}
@@ -110,7 +113,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
*/
long addNote(long accountId, CloudNote note) {
SQLiteDatabase db = this.getWritableDatabase();
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(11);
if (note instanceof DBNote) {
DBNote dbNote = (DBNote) note;
if (dbNote.getId() > 0) {
@@ -141,7 +144,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
addNoteAndSync(ssoAccount, newAccountId, new CloudNote(0, note.getModified(), note.getTitle(), note.getContent(), note.isFavorite(), note.getCategory(), null));
deleteNoteAndSync(ssoAccount, note.getId());
- notifyNotesChanged();
+ notifyWidgets();
getNoteServerSyncHelper().scheduleSync(ssoAccount, true);
}
@@ -215,8 +218,8 @@ public class NotesDatabase extends AbstractNotesDatabase {
if (selectionArgs.length > 2) {
Log.v(TAG, selection + " ---- " + selectionArgs[0] + " " + selectionArgs[1] + " " + selectionArgs[2]);
}
- String cols = String.format("%s, %s, %s, %s, %s, %s, %s, %s, %s",
- key_id, key_remote_id, key_status, key_title, key_modified, key_favorite, key_category_title, key_etag, key_excerpt);
+ String cols = String.format("%s, %s, %s, %s, %s, %s, %s, %s, %s, %s",
+ key_id, key_remote_id, key_status, key_title, key_modified, key_favorite, key_category_title, key_etag, key_excerpt, key_scroll_y);
if (!pruneContent) {
cols = String.format("%s, %s", cols, key_content);
}
@@ -249,13 +252,14 @@ public class NotesDatabase extends AbstractNotesDatabase {
cursor.getLong(1),
modified,
cursor.getString(3),
- pruneContent ? "" : cursor.getString(9),
+ pruneContent ? "" : cursor.getString(10),
cursor.getInt(5) > 0,
cursor.getString(6),
cursor.getString(7),
DBStatus.parse(cursor.getString(2)),
accountId,
- cursor.getString(8)
+ cursor.getString(8),
+ cursor.getInt(9)
);
}
@@ -399,7 +403,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
*/
@NonNull
@WorkerThread
- public List<NavigationAdapter.NavigationItem> getCategories(long accountId) {
+ public List<NavigationAdapter.CategoryNavigationItem> getCategories(long accountId) {
return searchCategories(accountId, null);
}
@@ -415,9 +419,9 @@ public class NotesDatabase extends AbstractNotesDatabase {
*/
@NonNull
@WorkerThread
- public List<NavigationAdapter.NavigationItem> searchCategories(long accountId, String search) {
+ public List<NavigationAdapter.CategoryNavigationItem> searchCategories(long accountId, String search) {
validateAccountId(accountId);
- String columns = key_category_title + ", COUNT(*)";
+ String columns = key_category_id + ", " + key_category_title + ", COUNT(*)";
String selection = key_status + " != ? AND " +
key_category_account_id + " = ? AND " +
key_category_title + " LIKE ? " +
@@ -432,10 +436,11 @@ public class NotesDatabase extends AbstractNotesDatabase {
Cursor cursor = getReadableDatabase().rawQuery(rawQuery,
new String[]{DBStatus.LOCAL_DELETED.getTitle(), String.valueOf(accountId),
search == null ? "%" : "%" + search.trim() + "%"});
- List<NavigationAdapter.NavigationItem> categories = new ArrayList<>(cursor.getCount());
+
+ List<NavigationAdapter.CategoryNavigationItem> categories = new ArrayList<>(cursor.getCount());
while (cursor.moveToNext()) {
Resources res = getContext().getResources();
- String category = cursor.getString(0).toLowerCase();
+ String category = cursor.getString(1).toLowerCase();
int icon = NavigationAdapter.ICON_FOLDER;
if (category.equals(res.getString(R.string.category_music).toLowerCase())) {
icon = R.drawable.ic_library_music_grey600_24dp;
@@ -444,18 +449,31 @@ public class NotesDatabase extends AbstractNotesDatabase {
} else if (category.equals(res.getString(R.string.category_work).toLowerCase())) {
icon = R.drawable.ic_work_grey600_24dp;
}
- categories.add(new NavigationAdapter.NavigationItem("category:" + cursor.getString(0), cursor.getString(0), cursor.getInt(1), icon));
+ categories.add(new NavigationAdapter.CategoryNavigationItem("category:" + cursor.getString(1), cursor.getString(1), cursor.getInt(2), icon, cursor.getLong(0)));
}
cursor.close();
return categories;
}
+ public String getCategoryTitleById(long accountId, long categoryId) {
+ validateAccountId(accountId);
+ final String categoryTitle;
+ final Cursor cursor = getReadableDatabase().query(table_category, new String[]{key_category_title}, key_category_id + " = ?", new String[]{String.valueOf(categoryId)}, null, null, null);
+ if (cursor.moveToFirst()) {
+ categoryTitle = cursor.getString(0);
+ } else {
+ categoryTitle = null;
+ }
+ cursor.close();
+ return categoryTitle;
+ }
+
public void toggleFavorite(SingleSignOnAccount ssoAccount, @NonNull DBNote note, @Nullable ISyncCallback callback) {
note.setFavorite(!note.isFavorite());
note.setStatus(DBStatus.LOCAL_EDITED);
SQLiteDatabase db = this.getWritableDatabase();
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(2);
values.put(key_status, note.getStatus().getTitle());
values.put(key_favorite, note.isFavorite() ? "1" : "0");
db.update(table_notes, values, key_id + " = ?", new String[]{String.valueOf(note.getId())});
@@ -479,7 +497,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
note.setCategory(category);
note.setStatus(DBStatus.LOCAL_EDITED);
SQLiteDatabase db = this.getWritableDatabase();
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(2);
values.put(key_status, note.getStatus().getTitle());
int id = getCategoryIdByTitle(note.getAccountId(), note.getCategory());
values.put(key_category, id);
@@ -494,7 +512,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
private long addCategory(long accountId, @NonNull String title) {
validateAccountId(accountId);
SQLiteDatabase db = getWritableDatabase();
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(2);
values.put(key_category_account_id, accountId);
values.put(key_category_title, title);
return db.insert(table_category, null, values);
@@ -513,23 +531,24 @@ public class NotesDatabase extends AbstractNotesDatabase {
//debugPrintFullDB();
DBNote newNote;
if (newContent == null) {
- newNote = new DBNote(oldNote.getId(), oldNote.getRemoteId(), oldNote.getModified(), oldNote.getTitle(), oldNote.getContent(), oldNote.isFavorite(), oldNote.getCategory(), oldNote.getEtag(), DBStatus.LOCAL_EDITED, accountId, oldNote.getExcerpt());
+ newNote = new DBNote(oldNote.getId(), oldNote.getRemoteId(), oldNote.getModified(), oldNote.getTitle(), oldNote.getContent(), oldNote.isFavorite(), oldNote.getCategory(), oldNote.getEtag(), DBStatus.LOCAL_EDITED, accountId, oldNote.getExcerpt(), oldNote.getScrollY());
} else {
- newNote = new DBNote(oldNote.getId(), oldNote.getRemoteId(), Calendar.getInstance(), NoteUtil.generateNonEmptyNoteTitle(newContent, getContext()), newContent, oldNote.isFavorite(), oldNote.getCategory(), oldNote.getEtag(), DBStatus.LOCAL_EDITED, accountId, NoteUtil.generateNoteExcerpt(newContent));
+ newNote = new DBNote(oldNote.getId(), oldNote.getRemoteId(), Calendar.getInstance(), NoteUtil.generateNonEmptyNoteTitle(newContent, getContext()), newContent, oldNote.isFavorite(), oldNote.getCategory(), oldNote.getEtag(), DBStatus.LOCAL_EDITED, accountId, NoteUtil.generateNoteExcerpt(newContent), oldNote.getScrollY());
}
SQLiteDatabase db = this.getWritableDatabase();
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(7);
values.put(key_status, newNote.getStatus().getTitle());
values.put(key_title, newNote.getTitle());
values.put(key_category, getCategoryIdByTitle(newNote.getAccountId(), newNote.getCategory()));
values.put(key_modified, newNote.getModified().getTimeInMillis() / 1000);
values.put(key_content, newNote.getContent());
values.put(key_excerpt, newNote.getExcerpt());
+ values.put(key_scroll_y, newNote.getScrollY());
int rows = db.update(table_notes, values, key_id + " = ? AND (" + key_content + " != ? OR " + key_category + " != ?)", new String[]{String.valueOf(newNote.getId()), newNote.getContent(), newNote.getCategory()});
removeEmptyCategory(accountId);
// if data was changed, set new status and schedule sync (with callback); otherwise invoke callback directly.
if (rows > 0) {
- notifyNotesChanged();
+ notifyWidgets();
if (callback != null) {
serverSyncHelper.addCallbackPush(ssoAccount, callback);
}
@@ -543,6 +562,14 @@ public class NotesDatabase extends AbstractNotesDatabase {
}
}
+ public void updateScrollY(long noteId, int scrollY) {
+ Log.e(TAG, "Updated scrollY: " + scrollY);
+ SQLiteDatabase db = this.getWritableDatabase();
+ ContentValues values = new ContentValues(1);
+ values.put(key_scroll_y, scrollY);
+ db.update(table_notes, values, key_id + " = ? ", new String[]{String.valueOf(noteId)});
+ }
+
/**
* Updates a single Note with data from the server, (if it was not modified locally).
* Thereby, an optimistic concurrency control is realized in order to prevent conflicts arising due to parallel changes from the UI and synchronization.
@@ -556,7 +583,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
SQLiteDatabase db = this.getWritableDatabase();
// First, update the remote ID, since this field cannot be changed in parallel, but have to be updated always.
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(8);
values.put(key_remote_id, remoteNote.getRemoteId());
db.update(table_notes, values, key_id + " = ?", new String[]{String.valueOf(id)});
@@ -599,24 +626,28 @@ public class NotesDatabase extends AbstractNotesDatabase {
*/
public void deleteNoteAndSync(SingleSignOnAccount ssoAccount, long id) {
SQLiteDatabase db = this.getWritableDatabase();
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(1);
values.put(key_status, DBStatus.LOCAL_DELETED.getTitle());
db.update(table_notes,
values,
key_id + " = ?",
new String[]{String.valueOf(id)});
- notifyNotesChanged();
+ notifyWidgets();
getNoteServerSyncHelper().scheduleSync(ssoAccount, true);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ShortcutManager shortcutManager = getContext().getSystemService(ShortcutManager.class);
- shortcutManager.getPinnedShortcuts().forEach((shortcut) -> {
- String shortcutId = id + "";
- if (shortcut.getId().equals(shortcutId)) {
- Log.v(TAG, "Removing shortcut for " + shortcutId);
- shortcutManager.disableShortcuts(Collections.singletonList(shortcutId), getContext().getResources().getString(R.string.note_has_been_deleted));
- }
- });
+ if (shortcutManager != null) {
+ shortcutManager.getPinnedShortcuts().forEach((shortcut) -> {
+ String shortcutId = id + "";
+ if (shortcut.getId().equals(shortcutId)) {
+ Log.v(TAG, "Removing shortcut for " + shortcutId);
+ shortcutManager.disableShortcuts(Collections.singletonList(shortcutId), getContext().getResources().getString(R.string.note_has_been_deleted));
+ }
+ });
+ } else {
+ Log.e(TAG, ShortcutManager.class.getSimpleName() + "is null.");
+ }
}
}
@@ -638,7 +669,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
/**
* Notify about changed notes.
*/
- protected void notifyNotesChanged() {
+ protected void notifyWidgets() {
updateSingleNoteWidgets(getContext());
updateNoteListWidgets(getContext());
}
@@ -674,24 +705,6 @@ public class NotesDatabase extends AbstractNotesDatabase {
}).start();
}
- /**
- * Update single note widget, if the note data was changed.
- */
- private static void updateSingleNoteWidgets(Context context) {
- Intent intent = new Intent(context, SingleNoteWidget.class);
- intent.setAction("android.appwidget.action.APPWIDGET_UPDATE");
- context.sendBroadcast(intent);
- }
-
- /**
- * Update note list widgets, if the note data was changed.
- */
- private static void updateNoteListWidgets(Context context) {
- Intent intent = new Intent(context, NoteListWidget.class);
- intent.setAction("android.appwidget.action.APPWIDGET_UPDATE");
- context.sendBroadcast(intent);
- }
-
public boolean hasAccounts() {
return DatabaseUtils.queryNumEntries(getReadableDatabase(), table_accounts) > 0;
}
@@ -705,14 +718,13 @@ public class NotesDatabase extends AbstractNotesDatabase {
*/
public void addAccount(@NonNull String url, @NonNull String username, @NonNull String accountName, @NonNull Capabilities capabilities) throws SQLiteConstraintException {
SQLiteDatabase db = this.getWritableDatabase();
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(4);
values.put(key_url, url);
values.put(key_username, username);
values.put(key_account_name, accountName);
- values.put(key_color, capabilities.getColor().substring(1));
- values.put(key_text_color, capabilities.getTextColor().substring(1));
values.put(key_capabilities_etag, capabilities.getETag());
- db.insertOrThrow(table_accounts, null, values);
+ long accountId = db.insertOrThrow(table_accounts, null, values);
+ updateBrand(accountId, capabilities);
}
/**
@@ -800,15 +812,26 @@ public class NotesDatabase extends AbstractNotesDatabase {
public void updateBrand(long accountId, @NonNull Capabilities capabilities) throws IllegalArgumentException {
validateAccountId(accountId);
- // Validate color format
- Color.parseColor(capabilities.getColor());
- Color.parseColor(capabilities.getTextColor());
+
+ String color;
+ try {
+ color = ColorUtil.formatColorToParsableHexString(capabilities.getColor()).substring(1);
+ } catch (Exception e) {
+ color = String.format("%06X", (0xFFFFFF & ContextCompat.getColor(context, R.color.defaultBrand)));
+ }
+
+ String textColor;
+ try {
+ textColor = ColorUtil.formatColorToParsableHexString(capabilities.getTextColor()).substring(1);
+ } catch (Exception e) {
+ textColor = String.format("%06X", (0xFFFFFF & ContextCompat.getColor(context, android.R.color.white)));
+ }
final SQLiteDatabase db = this.getWritableDatabase();
- final ContentValues values = new ContentValues();
+ final ContentValues values = new ContentValues(2);
- values.put(key_color, capabilities.getColor().substring(1));
- values.put(key_text_color, capabilities.getTextColor().substring(1));
+ values.put(key_color, color);
+ values.put(key_text_color, textColor);
final int updatedRows = db.update(table_accounts, values, key_id + " = ?", new String[]{String.valueOf(accountId)});
if (updatedRows == 1) {
@@ -833,7 +856,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
}
if (apiVersions.length() > 0) {
final SQLiteDatabase db = this.getWritableDatabase();
- final ContentValues values = new ContentValues();
+ final ContentValues values = new ContentValues(1);
values.put(key_api_version, apiVersion);
final int updatedRows = db.update(table_accounts, values, key_id + " = ?", new String[]{String.valueOf(accountId)});
if (updatedRows == 1) {
@@ -885,7 +908,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
void updateETag(long accountId, String etag) {
validateAccountId(accountId);
SQLiteDatabase db = this.getWritableDatabase();
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(1);
values.put(key_etag, etag);
final int updatedRows = db.update(table_accounts, values, key_id + " = ?", new String[]{String.valueOf(accountId)});
if (updatedRows == 1) {
@@ -898,7 +921,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
public void updateCapabilitiesETag(long accountId, String capabilitiesETag) {
validateAccountId(accountId);
SQLiteDatabase db = this.getWritableDatabase();
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(1);
values.put(key_capabilities_etag, capabilitiesETag);
final int updatedRows = db.update(table_accounts, values, key_id + " = ?", new String[]{String.valueOf(accountId)});
if (updatedRows == 1) {
@@ -914,7 +937,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
throw new IllegalArgumentException("modified must be greater or equal 0");
}
SQLiteDatabase db = this.getWritableDatabase();
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(1);
values.put(key_modified, modified);
final int updatedRows = db.update(table_accounts, values, key_id + " = ?", new String[]{String.valueOf(accountId)});
if (updatedRows == 1) {
@@ -954,7 +977,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
public void createOrUpdateSingleNoteWidgetData(@NonNull SingleNoteWidgetData data) throws SQLException {
validateAccountId(data.getAccountId());
final SQLiteDatabase db = getWritableDatabase();
- final ContentValues values = new ContentValues();
+ final ContentValues values = new ContentValues(4);
values.put(key_id, data.getAppWidgetId());
values.put(key_account_id, data.getAccountId());
values.put(key_note_id, data.getNoteId());
@@ -962,6 +985,44 @@ public class NotesDatabase extends AbstractNotesDatabase {
db.replaceOrThrow(table_widget_single_notes, null, values);
}
+ @NonNull
+ public NoteListsWidgetData getNoteListWidgetData(int appWidgetId) throws NoSuchElementException {
+ NoteListsWidgetData data = new NoteListsWidgetData();
+ final SQLiteDatabase db = getReadableDatabase();
+ final Cursor cursor = db.query(table_widget_note_list, new String[]{key_account_id, key_category_id, key_theme_mode, key_mode}, key_id + " = ?", new String[]{String.valueOf(appWidgetId)}, null, null, null, null);
+ if (cursor.moveToNext()) {
+ data.setAppWidgetId(appWidgetId);
+ data.setAccountId(cursor.getLong(0));
+ data.setCategoryId(cursor.getLong(1));
+ data.setThemeMode(cursor.getInt(2));
+ data.setMode(cursor.getInt(3));
+ } else {
+ throw new NoSuchElementException();
+ }
+ cursor.close();
+ return data;
+ }
+
+ public void removeNoteListWidget(int appWidgetId) {
+ final SQLiteDatabase db = getWritableDatabase();
+ db.delete(table_widget_note_list, key_id + " = ?", new String[]{String.valueOf(appWidgetId)});
+ }
+
+ public void createOrUpdateNoteListWidgetData(@NonNull NoteListsWidgetData data) throws SQLException {
+ validateAccountId(data.getAccountId());
+ final SQLiteDatabase db = getWritableDatabase();
+ final ContentValues values = new ContentValues(5);
+ if (data.getMode() != MODE_DISPLAY_CATEGORY && data.getCategoryId() != null) {
+ throw new UnsupportedOperationException("Cannot create a widget with a categoryId when mode is not " + MODE_DISPLAY_CATEGORY);
+ }
+ values.put(key_id, data.getAppWidgetId());
+ values.put(key_account_id, data.getAccountId());
+ values.put(key_category_id, data.getCategoryId());
+ values.put(key_theme_mode, data.getThemeMode());
+ values.put(key_mode, data.getMode());
+ db.replaceOrThrow(table_widget_note_list, null, values);
+ }
+
private static void validateAccountId(long accountId) {
if (accountId < 1) {
throw new IllegalArgumentException("accountId must be greater than 0");
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_10_11.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_10_11.java
new file mode 100644
index 00000000..82a627aa
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_10_11.java
@@ -0,0 +1,31 @@
+package it.niedermann.owncloud.notes.persistence.migration;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import androidx.annotation.NonNull;
+import androidx.preference.PreferenceManager;
+
+import java.util.Map;
+
+import it.niedermann.owncloud.notes.android.DarkModeSetting;
+
+public class Migration_10_11 {
+ /**
+ * Changes the boolean for light / dark mode to {@link DarkModeSetting} to also be able to represent system default value
+ */
+ public Migration_10_11(@NonNull Context context) {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+ SharedPreferences.Editor editor = sharedPreferences.edit();
+ Map<String, ?> prefs = sharedPreferences.getAll();
+ for (Map.Entry<String, ?> pref : prefs.entrySet()) {
+ String key = pref.getKey();
+ final String DARK_THEME_KEY = "NLW_darkTheme";
+ if ("darkTheme".equals(key) || key.startsWith(DARK_THEME_KEY) || key.startsWith("SNW_darkTheme")) {
+ Boolean darkTheme = (Boolean) pref.getValue();
+ editor.putString(pref.getKey(), darkTheme ? DarkModeSetting.DARK.name() : DarkModeSetting.LIGHT.name());
+ }
+ }
+ editor.apply();
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_11_12.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_11_12.java
new file mode 100644
index 00000000..82a9984e
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_11_12.java
@@ -0,0 +1,21 @@
+package it.niedermann.owncloud.notes.persistence.migration;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+
+import androidx.annotation.NonNull;
+
+import it.niedermann.owncloud.notes.model.ApiVersion;
+import it.niedermann.owncloud.notes.persistence.CapabilitiesWorker;
+
+public class Migration_11_12 {
+ /**
+ * Adds columns to store the {@link ApiVersion} and the theme colors
+ */
+ public Migration_11_12(@NonNull SQLiteDatabase db, @NonNull Context context) {
+ db.execSQL("ALTER TABLE ACCOUNTS ADD COLUMN API_VERSION TEXT");
+ db.execSQL("ALTER TABLE ACCOUNTS ADD COLUMN COLOR VARCHAR(6) NOT NULL DEFAULT '000000'");
+ db.execSQL("ALTER TABLE ACCOUNTS ADD COLUMN TEXT_COLOR VARCHAR(6) NOT NULL DEFAULT '0082C9'");
+ CapabilitiesWorker.update(context);
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_12_13.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_12_13.java
new file mode 100644
index 00000000..895a59a1
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_12_13.java
@@ -0,0 +1,20 @@
+package it.niedermann.owncloud.notes.persistence.migration;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+
+import androidx.annotation.NonNull;
+import androidx.work.WorkManager;
+
+import it.niedermann.owncloud.notes.model.Capabilities;
+
+public class Migration_12_13 {
+ /**
+ * Adds a column to store the ETag of the server {@link Capabilities}
+ */
+ public Migration_12_13(@NonNull SQLiteDatabase db, @NonNull Context context) {
+ db.execSQL("ALTER TABLE ACCOUNTS ADD COLUMN CAPABILITIES_ETAG TEXT");
+ WorkManager.getInstance(context.getApplicationContext()).cancelUniqueWork("it.niedermann.owncloud.notes.persistence.SyncWorker");
+ WorkManager.getInstance(context.getApplicationContext()).cancelUniqueWork("SyncWorker");
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_13_14.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_13_14.java
new file mode 100644
index 00000000..d69396d3
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_13_14.java
@@ -0,0 +1,78 @@
+package it.niedermann.owncloud.notes.persistence.migration;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.database.sqlite.SQLiteDatabase;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.preference.PreferenceManager;
+
+import java.util.Map;
+
+import it.niedermann.owncloud.notes.android.DarkModeSetting;
+
+public class Migration_13_14 {
+
+ private static final String TAG = Migration_13_14.class.getSimpleName();
+
+ /**
+ * Move single note widget preferences to database
+ * https://github.com/stefan-niedermann/nextcloud-notes/issues/754
+ */
+ public Migration_13_14(@NonNull SQLiteDatabase db, @NonNull Context context, @NonNull Runnable notifyWidgets) {
+ db.execSQL("CREATE TABLE WIDGET_SINGLE_NOTES ( " +
+ "ID INTEGER PRIMARY KEY, " +
+ "ACCOUNT_ID INTEGER, " +
+ "NOTE_ID INTEGER, " +
+ "THEME_MODE INTEGER NOT NULL, " +
+ "FOREIGN KEY(ACCOUNT_ID) REFERENCES ACCOUNTS(ID), " +
+ "FOREIGN KEY(NOTE_ID) REFERENCES NOTES(ID))");
+
+ final String SP_WIDGET_KEY = "single_note_widget";
+ final String SP_ACCOUNT_ID_KEY = "SNW_accountId";
+ final String SP_DARK_THEME_KEY = "SNW_darkTheme";
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+ SharedPreferences.Editor editor = sharedPreferences.edit();
+ Map<String, ?> prefs = sharedPreferences.getAll();
+ for (Map.Entry<String, ?> pref : prefs.entrySet()) {
+ final String key = pref.getKey();
+ Integer widgetId = null;
+ Long noteId = null;
+ Long accountId = null;
+ Integer themeMode = null;
+ if (key != null && key.startsWith(SP_WIDGET_KEY)) {
+ try {
+ widgetId = Integer.parseInt(key.substring(SP_WIDGET_KEY.length()));
+ noteId = (Long) pref.getValue();
+ accountId = sharedPreferences.getLong(SP_ACCOUNT_ID_KEY + widgetId, -1);
+
+ try {
+ themeMode = DarkModeSetting.valueOf(sharedPreferences.getString(SP_DARK_THEME_KEY + widgetId, DarkModeSetting.SYSTEM_DEFAULT.name())).getModeId();
+ } catch (ClassCastException e) {
+ //DARK_THEME was a boolean in older versions of the app. We thereofre have to still support the old setting.
+ themeMode = sharedPreferences.getBoolean(SP_DARK_THEME_KEY + widgetId, false) ? DarkModeSetting.DARK.getModeId() : DarkModeSetting.LIGHT.getModeId();
+ }
+
+ ContentValues migratedWidgetValues = new ContentValues();
+ migratedWidgetValues.put("ID", widgetId);
+ migratedWidgetValues.put("ACCOUNT_ID", accountId);
+ migratedWidgetValues.put("NOTE_ID", noteId);
+ migratedWidgetValues.put("THEME_MODE", themeMode);
+ db.insert("WIDGET_SINGLE_NOTES", null, migratedWidgetValues);
+ } catch (Throwable t) {
+ Log.e(TAG, "Could not migrate widget {widgetId: " + widgetId + ", accountId: " + accountId + ", noteId: " + noteId + ", themeMode: " + themeMode + "}");
+ t.printStackTrace();
+ } finally {
+ // Clean up old shared preferences
+ editor.remove(SP_WIDGET_KEY + widgetId);
+ editor.remove(SP_DARK_THEME_KEY + widgetId);
+ editor.remove(SP_ACCOUNT_ID_KEY + widgetId);
+ }
+ }
+ }
+ editor.apply();
+ notifyWidgets.run();
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_14_15.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_14_15.java
new file mode 100644
index 00000000..b025bbaa
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_14_15.java
@@ -0,0 +1,83 @@
+package it.niedermann.owncloud.notes.persistence.migration;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.util.Log;
+
+import java.util.Hashtable;
+
+import it.niedermann.owncloud.notes.util.DatabaseIndexUtil;
+
+public class Migration_14_15 {
+ /**
+ * Normalize database (move category from string field to own table)
+ * https://github.com/stefan-niedermann/nextcloud-notes/issues/814
+ */
+ public Migration_14_15(SQLiteDatabase db) {
+ // Rename a tmp_NOTES table.
+ String tmpTableNotes = String.format("tmp_%s", "NOTES");
+ db.execSQL("ALTER TABLE NOTES RENAME TO " + tmpTableNotes);
+ db.execSQL("CREATE TABLE NOTES ( " +
+ "ID INTEGER PRIMARY KEY AUTOINCREMENT, " +
+ "REMOTEID INTEGER, " +
+ "ACCOUNT_ID INTEGER, " +
+ "STATUS VARCHAR(50), " +
+ "TITLE TEXT, " +
+ "MODIFIED INTEGER DEFAULT 0, " +
+ "CONTENT TEXT, " +
+ "FAVORITE INTEGER DEFAULT 0, " +
+ "CATEGORY INTEGER, " +
+ "ETAG TEXT," +
+ "EXCERPT TEXT NOT NULL DEFAULT '', " +
+ "FOREIGN KEY(CATEGORY) REFERENCES CATEGORIES(CATEGORY_ID), " +
+ "FOREIGN KEY(ACCOUNT_ID) REFERENCES ACCOUNTS(ID))");
+ DatabaseIndexUtil.createIndex(db, "NOTES", "REMOTEID", "ACCOUNT_ID", "STATUS", "FAVORITE", "CATEGORY", "MODIFIED");
+ db.execSQL("CREATE TABLE CATEGORIES(" +
+ "CATEGORY_ID INTEGER PRIMARY KEY AUTOINCREMENT, " +
+ "CATEGORY_ACCOUNT_ID INTEGER NOT NULL, " +
+ "CATEGORY_TITLE TEXT NOT NULL, " +
+ "UNIQUE( CATEGORY_ACCOUNT_ID , CATEGORY_TITLE), " +
+ "FOREIGN KEY(CATEGORY_ACCOUNT_ID) REFERENCES ACCOUNTS(ID))");
+ DatabaseIndexUtil.createIndex(db, "CATEGORIES", "CATEGORY_ID", "CATEGORY_ACCOUNT_ID", "CATEGORY_TITLE");
+ // A hashtable storing categoryTitle - categoryId Mapping
+ // This is used to prevent too many searches in database
+ Hashtable<String, Integer> categoryTitleIdMap = new Hashtable<>();
+ int id = 1;
+ Cursor tmpNotesCursor = db.rawQuery("SELECT * FROM " + tmpTableNotes, null);
+ while (tmpNotesCursor.moveToNext()) {
+ String categoryTitle = tmpNotesCursor.getString(8);
+ int accountId = tmpNotesCursor.getInt(2);
+ Log.e("###", accountId + "");
+ Integer categoryId;
+ if (categoryTitleIdMap.containsKey(categoryTitle) && categoryTitleIdMap.get(categoryTitle) != null) {
+ categoryId = categoryTitleIdMap.get(categoryTitle);
+ } else {
+ // The category does not exists in the database, create it.
+ categoryId = id++;
+ ContentValues values = new ContentValues();
+ values.put("CATEGORY_ID", categoryId);
+ values.put("CATEGORY_ACCOUNT_ID", accountId);
+ values.put("CATEGORY_TITLE", categoryTitle);
+ db.insert("CATEGORIES", null, values);
+ categoryTitleIdMap.put(categoryTitle, categoryId);
+ }
+ // Move the data in tmp_NOTES to NOTES
+ ContentValues values = new ContentValues();
+ values.put("ID", tmpNotesCursor.getInt(0));
+ values.put("REMOTEID", tmpNotesCursor.getInt(1));
+ values.put("ACCOUNT_ID", tmpNotesCursor.getInt(2));
+ values.put("STATUS", tmpNotesCursor.getString(3));
+ values.put("TITLE", tmpNotesCursor.getString(4));
+ values.put("MODIFIED", tmpNotesCursor.getLong(5));
+ values.put("CONTENT", tmpNotesCursor.getString(6));
+ values.put("FAVORITE", tmpNotesCursor.getInt(7));
+ values.put("CATEGORY", categoryId);
+ values.put("ETAG", tmpNotesCursor.getString(9));
+ values.put("EXCERPT", tmpNotesCursor.getString(10));
+ db.insert("NOTES", null, values);
+ }
+ tmpNotesCursor.close();
+ db.execSQL("DROP TABLE IF EXISTS " + tmpTableNotes);
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_15_16.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_15_16.java
new file mode 100644
index 00000000..396f29e1
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_15_16.java
@@ -0,0 +1,103 @@
+package it.niedermann.owncloud.notes.persistence.migration;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.preference.PreferenceManager;
+
+import java.util.Map;
+
+import it.niedermann.owncloud.notes.android.DarkModeSetting;
+
+public class Migration_15_16 {
+
+ private static final String TAG = Migration_15_16.class.getSimpleName();
+
+ /**
+ * Moves note list widget preferences from {@link SharedPreferences} to database
+ * https://github.com/stefan-niedermann/nextcloud-notes/issues/832
+ */
+ public Migration_15_16(SQLiteDatabase db, @NonNull Context context, @NonNull Runnable notifyWidgets) {
+ db.execSQL("CREATE TABLE WIDGET_NOTE_LISTS ( " +
+ "ID INTEGER PRIMARY KEY, " +
+ "ACCOUNT_ID INTEGER, " +
+ "CATEGORY_ID INTEGER, " +
+ "MODE INTEGER NOT NULL, " +
+ "THEME_MODE INTEGER NOT NULL, " +
+ "FOREIGN KEY(ACCOUNT_ID) REFERENCES ACCOUNTS(ID), " +
+ "FOREIGN KEY(CATEGORY_ID) REFERENCES CATEGORIES(CATEGORY_ID))");
+
+ final String SP_WIDGET_KEY = "NLW_mode";
+ final String SP_ACCOUNT_ID_KEY = "NLW_account";
+ final String SP_DARK_THEME_KEY = "NLW_darkTheme";
+ final String SP_CATEGORY_KEY = "NLW_cat";
+
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+ SharedPreferences.Editor editor = sharedPreferences.edit();
+ Map<String, ?> prefs = sharedPreferences.getAll();
+ for (Map.Entry<String, ?> pref : prefs.entrySet()) {
+ final String key = pref.getKey();
+ Integer widgetId = null;
+ Integer mode = null;
+ Long accountId = null;
+ Integer themeMode = null;
+ Integer categoryId = null;
+ if (key != null && key.startsWith(SP_WIDGET_KEY)) {
+ try {
+ widgetId = Integer.parseInt(key.substring(SP_WIDGET_KEY.length()));
+ mode = (Integer) pref.getValue();
+ accountId = sharedPreferences.getLong(SP_ACCOUNT_ID_KEY + widgetId, -1);
+
+ try {
+ themeMode = DarkModeSetting.valueOf(sharedPreferences.getString(SP_DARK_THEME_KEY + widgetId, DarkModeSetting.SYSTEM_DEFAULT.name())).getModeId();
+ } catch (ClassCastException e) {
+ //DARK_THEME was a boolean in older versions of the app. We thereofre have to still support the old setting.
+ themeMode = sharedPreferences.getBoolean(SP_DARK_THEME_KEY + widgetId, false) ? DarkModeSetting.DARK.getModeId() : DarkModeSetting.LIGHT.getModeId();
+ }
+
+ if (mode == 2) {
+ final String categoryTitle = sharedPreferences.getString(SP_CATEGORY_KEY + widgetId, null);
+ Cursor cursor = db.query(
+ "CATEGORIES",
+ new String[]{"CATEGORY_ID"},
+ "CATEGORY_TITLE = ? AND CATEGORY_ACCOUNT_ID = ? ",
+ new String[]{categoryTitle, String.valueOf(accountId)},
+ null,
+ null,
+ null);
+ if (cursor.moveToNext()) {
+ categoryId = cursor.getInt(0);
+ } else {
+ throw new IllegalStateException("No category id found for title \"" + categoryTitle + "\"");
+ }
+ cursor.close();
+ }
+
+ ContentValues migratedWidgetValues = new ContentValues();
+ migratedWidgetValues.put("ID", widgetId);
+ migratedWidgetValues.put("ACCOUNT_ID", accountId);
+ migratedWidgetValues.put("CATEGORY_ID", categoryId);
+ migratedWidgetValues.put("MODE", mode);
+ migratedWidgetValues.put("THEME_MODE", themeMode);
+ db.insert("WIDGET_NOTE_LISTS", null, migratedWidgetValues);
+ } catch (Throwable t) {
+ Log.e(TAG, "Could not migrate widget {widgetId: " + widgetId + ", accountId: " + accountId + ", mode: " + mode + ", categoryId: " + categoryId + ", themeMode: " + themeMode + "}");
+ t.printStackTrace();
+ } finally {
+ // Clean up old shared preferences
+ editor.remove(SP_WIDGET_KEY + widgetId);
+ editor.remove(SP_CATEGORY_KEY + widgetId);
+ editor.remove(SP_DARK_THEME_KEY + widgetId);
+ editor.remove(SP_ACCOUNT_ID_KEY + widgetId);
+ }
+ }
+ }
+ editor.apply();
+ notifyWidgets.run();
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_16_17.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_16_17.java
new file mode 100644
index 00000000..547cb6c7
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_16_17.java
@@ -0,0 +1,15 @@
+package it.niedermann.owncloud.notes.persistence.migration;
+
+import android.database.sqlite.SQLiteDatabase;
+
+import androidx.annotation.NonNull;
+
+public class Migration_16_17 {
+ /**
+ * Adds a column to store the current scroll position per note
+ * https://github.com/stefan-niedermann/nextcloud-notes/issues/227
+ */
+ public Migration_16_17(@NonNull SQLiteDatabase db) {
+ db.execSQL("ALTER TABLE NOTES ADD COLUMN SCROLL_Y INTEGER DEFAULT 0");
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_4_5.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_4_5.java
new file mode 100644
index 00000000..612ed1cb
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_4_5.java
@@ -0,0 +1,18 @@
+package it.niedermann.owncloud.notes.persistence.migration;
+
+import android.database.sqlite.SQLiteDatabase;
+
+import androidx.annotation.NonNull;
+
+import it.niedermann.owncloud.notes.model.DBStatus;
+
+public class Migration_4_5 {
+ /**
+ * Differentiate between local id and remote id
+ */
+ public Migration_4_5(@NonNull SQLiteDatabase db) {
+ db.execSQL("ALTER TABLE NOTES ADD COLUMN REMOTEID INTEGER");
+ db.execSQL("UPDATE NOTES SET REMOTEID=ID WHERE (REMOTEID IS NULL OR REMOTEID=0) AND STATUS!=?", new String[]{"LOCAL_CREATED"});
+ db.execSQL("UPDATE NOTES SET REMOTEID=0, STATUS=? WHERE STATUS=?", new String[]{DBStatus.LOCAL_EDITED.getTitle(), "LOCAL_CREATED"});
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_5_6.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_5_6.java
new file mode 100644
index 00000000..184a6033
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_5_6.java
@@ -0,0 +1,14 @@
+package it.niedermann.owncloud.notes.persistence.migration;
+
+import android.database.sqlite.SQLiteDatabase;
+
+import androidx.annotation.NonNull;
+
+public class Migration_5_6 {
+ /**
+ * Adds a column to support marking notes as favorite
+ */
+ public Migration_5_6(@NonNull SQLiteDatabase db) {
+ db.execSQL("ALTER TABLE NOTES ADD COLUMN FAVORITE INTEGER DEFAULT 0");
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_6_7.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_6_7.java
new file mode 100644
index 00000000..399d6f40
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_6_7.java
@@ -0,0 +1,19 @@
+package it.niedermann.owncloud.notes.persistence.migration;
+
+import android.database.sqlite.SQLiteDatabase;
+
+import androidx.annotation.NonNull;
+
+import it.niedermann.owncloud.notes.util.DatabaseIndexUtil;
+
+public class Migration_6_7 {
+ /**
+ * Adds columns for category support and ETags
+ */
+ public Migration_6_7(@NonNull SQLiteDatabase db) {
+ DatabaseIndexUtil.dropIndexes(db);
+ db.execSQL("ALTER TABLE NOTES ADD COLUMN CATEGORY TEXT NOT NULL DEFAULT ''");
+ db.execSQL("ALTER TABLE NOTES ADD COLUMN ETAG TEXT");
+ DatabaseIndexUtil.createIndex(db, "NOTES", "REMOTEID", "STATUS", "FAVORITE", "CATEGORY", "MODIFIED");
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_7_8.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_7_8.java
new file mode 100644
index 00000000..9a968fe1
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_7_8.java
@@ -0,0 +1,28 @@
+package it.niedermann.owncloud.notes.persistence.migration;
+
+import android.database.sqlite.SQLiteDatabase;
+
+import androidx.annotation.NonNull;
+
+import it.niedermann.owncloud.notes.util.DatabaseIndexUtil;
+
+public class Migration_7_8 {
+ public Migration_7_8(@NonNull SQLiteDatabase db) {
+ final String table_temp = "NOTES_TEMP";
+ db.execSQL("CREATE TABLE " + table_temp + " ( " +
+ "ID INTEGER PRIMARY KEY AUTOINCREMENT, " +
+ "REMOTEID INTEGER, " +
+ "STATUS VARCHAR(50), " +
+ "TITLE TEXT, " +
+ "MODIFIED INTEGER DEFAULT 0, " +
+ "CONTENT TEXT, " +
+ "FAVORITE INTEGER DEFAULT 0, " +
+ "CATEGORY TEXT NOT NULL DEFAULT '', " +
+ "ETAG TEXT)");
+ DatabaseIndexUtil.createIndex(db, table_temp, "REMOTEID", "STATUS", "FAVORITE", "CATEGORY", "MODIFIED");
+ db.execSQL(String.format("INSERT INTO %s(%s,%s,%s,%s,%s,%s,%s,%s,%s) ", table_temp, "ID", "REMOTEID", "STATUS", "TITLE", "MODIFIED", "CONTENT", "FAVORITE", "CATEGORY", "ETAG")
+ + String.format("SELECT %s,%s,%s,%s,strftime('%%s',%s),%s,%s,%s,%s FROM %s", "ID", "REMOTEID", "STATUS", "TITLE", "MODIFIED", "CONTENT", "FAVORITE", "CATEGORY", "ETAG", "NOTES"));
+ db.execSQL("DROP TABLE NOTES");
+ db.execSQL(String.format("ALTER TABLE %s RENAME TO %s", table_temp, "NOTES"));
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_8_9.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_8_9.java
new file mode 100644
index 00000000..31957fc0
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_8_9.java
@@ -0,0 +1,127 @@
+package it.niedermann.owncloud.notes.persistence.migration;
+
+import android.appwidget.AppWidgetManager;
+import android.content.ComponentName;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.database.sqlite.SQLiteDatabase;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.core.util.Consumer;
+import androidx.preference.PreferenceManager;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import it.niedermann.owncloud.notes.android.appwidget.NoteListWidget;
+import it.niedermann.owncloud.notes.android.appwidget.SingleNoteWidget;
+import it.niedermann.owncloud.notes.util.DatabaseIndexUtil;
+
+public class Migration_8_9 {
+
+ private static final String TAG = Migration_8_9.class.getSimpleName();
+
+ /**
+ * Adds an account table for multi account usage in combination with SingleSignOn
+ */
+ public Migration_8_9(@NonNull SQLiteDatabase db, @NonNull Context context, @NonNull Consumer<SQLiteDatabase> recreateDatabase, @NonNull Runnable notifyWidgets) {
+ // Create accounts table
+ db.execSQL("CREATE TABLE ACCOUNTS ( " +
+ "ID INTEGER PRIMARY KEY AUTOINCREMENT, " +
+ "URL TEXT, " +
+ "USERNAME TEXT, " +
+ "ACCOUNT_NAME TEXT UNIQUE, " +
+ "ETAG TEXT, " +
+ "MODIFIED INTEGER)");
+ DatabaseIndexUtil.createIndex(db, "ACCOUNTS", "URL", "USERNAME", "ACCOUNT_NAME", "ETAG", "MODIFIED");
+
+ // Add accountId to notes table
+ db.execSQL("ALTER TABLE NOTES ADD COLUMN ACCOUNT_ID INTEGER NOT NULL DEFAULT 0");
+ DatabaseIndexUtil.createIndex(db, "NOTES", "ACCOUNT_ID");
+
+ // Migrate existing account from SharedPreferences
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+ String username = sharedPreferences.getString("settingsUsername", "");
+ String url = sharedPreferences.getString("settingsUrl", "");
+ if (!url.isEmpty() && url.endsWith("/")) {
+ url = url.substring(0, url.length() - 1);
+ try {
+ String accountName = username + "@" + new URL(url).getHost();
+
+ ContentValues migratedAccountValues = new ContentValues();
+ migratedAccountValues.put("URL", url);
+ migratedAccountValues.put("USERNAME", username);
+ migratedAccountValues.put("ACCOUNT_NAME", accountName);
+ db.insert("ACCOUNTS", null, migratedAccountValues);
+
+ // After successful insertion of migrated account, set accountId to 1 in each note
+ ContentValues values = new ContentValues();
+ values.put("ACCOUNT_ID", 1);
+ db.update("NOTES", values, "ACCOUNT_ID = ?", new String[]{"NULL"});
+
+ // Add FOREIGN_KEY constraint
+ final String table_temp = "NOTES_TEMP";
+ db.execSQL(String.format("ALTER TABLE %s RENAME TO %s", "NOTES", table_temp));
+
+ db.execSQL("CREATE TABLE NOTES ( " +
+ "ID INTEGER PRIMARY KEY AUTOINCREMENT, " +
+ "REMOTEID INTEGER, " +
+ "ACCOUNT_ID INTEGER, " +
+ "STATUS VARCHAR(50), " +
+ "TITLE TEXT, " +
+ "MODIFIED INTEGER DEFAULT 0, " +
+ "CONTENT TEXT, " +
+ "FAVORITE INTEGER DEFAULT 0, " +
+ "CATEGORY TEXT NOT NULL DEFAULT '', " +
+ "ETAG TEXT," +
+ "FOREIGN KEY(ACCOUNT_ID) REFERENCES ACCOUNTS(ID))");
+ DatabaseIndexUtil.createIndex(db, "NOTES", "REMOTEID", "ACCOUNT_ID", "STATUS", "FAVORITE", "CATEGORY", "MODIFIED");
+
+ db.execSQL(String.format("INSERT INTO %s(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) ", "NOTES", "ID", "ACCOUNT_ID", "REMOTEID", "STATUS", "TITLE", "MODIFIED", "CONTENT", "FAVORITE", "CATEGORY", "ETAG")
+ + String.format("SELECT %s,%s,%s,%s,%s,%s,%s,%s,%s,%s FROM %s", "ID", values.get("ACCOUNT_ID"), "REMOTEID", "STATUS", "TITLE", "MODIFIED", "CONTENT", "FAVORITE", "CATEGORY", "ETAG", table_temp));
+ db.execSQL(String.format("DROP TABLE %s;", table_temp));
+
+ AppWidgetManager awm = AppWidgetManager.getInstance(context);
+ SharedPreferences.Editor editor = sharedPreferences.edit();
+
+ // Add accountId '1' to any existing (and configured) appwidgets
+ int[] appWidgetIdsNLW = awm.getAppWidgetIds(new ComponentName(context, NoteListWidget.class));
+ int[] appWidgetIdsSNW = awm.getAppWidgetIds(new ComponentName(context, SingleNoteWidget.class));
+
+ final String WIDGET_MODE_KEY = "NLW_mode";
+ final String ACCOUNT_ID_KEY = "NLW_account";
+
+ for (int appWidgetId : appWidgetIdsNLW) {
+ if (sharedPreferences.getInt(WIDGET_MODE_KEY + appWidgetId, -1) >= 0) {
+ editor.putLong(ACCOUNT_ID_KEY + appWidgetId, 1);
+ }
+ }
+
+ for (int appWidgetId : appWidgetIdsSNW) {
+ if (sharedPreferences.getLong("single_note_widget" + appWidgetId, -1) >= 0) {
+ editor.putLong("SNW_accountId" + appWidgetId, 1);
+ }
+ }
+
+ notifyWidgets.run();
+
+ // Clean up no longer needed SharedPreferences
+ editor.remove("notes_last_etag");
+ editor.remove("notes_last_modified");
+ editor.remove("settingsUrl");
+ editor.remove("settingsUsername");
+ editor.remove("settingsPassword");
+ editor.apply();
+ } catch (MalformedURLException e) {
+ Log.e(TAG, "Previous URL could not be parsed. Recreating database...");
+ e.printStackTrace();
+ recreateDatabase.accept(db);
+ }
+ } else {
+ Log.e(TAG, "Previous URL is empty or does not end with a '/' character. Recreating database...");
+ recreateDatabase.accept(db);
+ }
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_9_10.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_9_10.java
new file mode 100644
index 00000000..98ddc601
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/migration/Migration_9_10.java
@@ -0,0 +1,26 @@
+package it.niedermann.owncloud.notes.persistence.migration;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+
+import androidx.annotation.NonNull;
+
+import it.niedermann.owncloud.notes.util.NoteUtil;
+
+public class Migration_9_10 {
+ /**
+ * Adds a column to store excerpt instead of regenerating it each time
+ * https://github.com/stefan-niedermann/nextcloud-notes/issues/528
+ */
+ public Migration_9_10(@NonNull SQLiteDatabase db) {
+ db.execSQL("ALTER TABLE NOTES ADD COLUMN EXCERPT INTEGER NOT NULL DEFAULT ''");
+ Cursor cursor = db.query("NOTES", new String[]{"ID", "CONTENT"}, null, null, null, null, null, null);
+ while (cursor.moveToNext()) {
+ ContentValues values = new ContentValues();
+ values.put("EXCERPT", NoteUtil.generateNoteExcerpt(cursor.getString(1)));
+ db.update("NOTES", values, "ID" + " = ? ", new String[]{cursor.getString(0)});
+ }
+ cursor.close();
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/util/ColorUtil.java b/app/src/main/java/it/niedermann/owncloud/notes/util/ColorUtil.java
index 8649d7a0..3b44c0f2 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/util/ColorUtil.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/util/ColorUtil.java
@@ -3,6 +3,7 @@ package it.niedermann.owncloud.notes.util;
import android.graphics.Color;
import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Pair;
@@ -107,4 +108,47 @@ public final class ColorUtil {
return result;
}
}
+
+ /**
+ * @return well formatted string starting with a hash followed by 6 hex numbers that is parsable by {@link Color#parseColor(String)}.
+ */
+ public static String formatColorToParsableHexString(String input) {
+ if (input == null) {
+ throw new IllegalArgumentException("input color string is null");
+ }
+ if (isParsableValidHexColorString(input)) {
+ return input;
+ }
+ final char[] chars = input.replaceAll("#", "").toCharArray();
+ final StringBuilder sb = new StringBuilder(7).append("#");
+ if (chars.length == 6) {
+ sb.append(chars);
+ } else if (chars.length == 3) {
+ for (char c : chars) {
+ sb.append(c).append(c);
+ }
+ } else {
+ throw new IllegalArgumentException("unparsable color string: \"" + input + "\"");
+ }
+ final String formattedHexColor = sb.toString();
+ if (isParsableValidHexColorString(formattedHexColor)) {
+ return formattedHexColor;
+ } else {
+ throw new IllegalArgumentException("\"" + input + "\" is not a valid color string. Result of tried normalizing: " + formattedHexColor);
+ }
+ }
+
+ /**
+ * Checking for {@link Color#parseColor(String)} being able to parse the input is the important part because we don't know the implementation and rely on it to be able to parse the color.
+ *
+ * @return true, if the input starts with a hash followed by 6 characters of hex numbers and is parsable by {@link Color#parseColor(String)}.
+ */
+ private static boolean isParsableValidHexColorString(@NonNull String input) {
+ try {
+ Color.parseColor(input);
+ return input.matches("#[a-fA-F0-9]{6}");
+ } catch (Exception e) {
+ return false;
+ }
+ }
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/util/DisplayUtils.java b/app/src/main/java/it/niedermann/owncloud/notes/util/DisplayUtils.java
index a4fd4c41..50931618 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/util/DisplayUtils.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/util/DisplayUtils.java
@@ -26,6 +26,7 @@ import android.text.TextPaint;
import android.text.TextUtils;
import android.text.style.MetricAffectingSpan;
+import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -33,6 +34,9 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import it.niedermann.owncloud.notes.R;
+import it.niedermann.owncloud.notes.branding.BrandingUtil;
+
+import static it.niedermann.owncloud.notes.util.ColorUtil.isColorDark;
public class DisplayUtils {
@@ -40,7 +44,7 @@ public class DisplayUtils {
}
- public static Spannable searchAndColor(Spannable spannable, CharSequence searchText, Context context, @Nullable Integer current) {
+ public static Spannable searchAndColor(Spannable spannable, CharSequence searchText, @NonNull Context context, @Nullable Integer current, @ColorInt int mainColor, @ColorInt int textColor) {
CharSequence text = spannable.toString();
Object[] spansToRemove = spannable.getSpans(0, text.length(), Object.class);
@@ -60,7 +64,7 @@ public class DisplayUtils {
while (m.find()) {
int start = m.start();
int end = m.end();
- spannable.setSpan(new SearchSpan(context, (current != null && i == current)), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ spannable.setSpan(new SearchSpan(context, mainColor, textColor, (current != null && i == current)), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
i++;
}
@@ -71,19 +75,51 @@ public class DisplayUtils {
static class SearchSpan extends MetricAffectingSpan {
private final boolean current;
- private final int bgColorPrimary;
- private final int bgColorSecondary;
-
- SearchSpan(Context context, boolean current) {
+ @NonNull
+ Context context;
+ @ColorInt
+ private final int mainColor;
+ @ColorInt
+ private final int textColor;
+ @ColorInt
+ private final int highlightColor;
+
+ SearchSpan(@NonNull Context context, @ColorInt int mainColor, @ColorInt int textColor, boolean current) {
+ this.context = context;
+ this.mainColor = mainColor;
+ this.textColor = textColor;
this.current = current;
- this.bgColorPrimary = context.getResources().getColor(R.color.bg_search_primary);
- this.bgColorSecondary = context.getResources().getColor(R.color.bg_search_secondary);
+ this.highlightColor = context.getResources().getColor(R.color.bg_highlighted);
}
@Override
public void updateDrawState(TextPaint tp) {
- tp.bgColor = current ? bgColorPrimary : bgColorSecondary;
- tp.setColor(current ? (getForeground(Integer.toHexString(tp.bgColor)) ? Color.WHITE : Color.BLACK) : bgColorPrimary);
+ if (current) {
+ if (Notes.isDarkThemeActive(context)) {
+ if (isColorDark(mainColor)) {
+ tp.bgColor = Color.WHITE;
+ tp.setColor(mainColor);
+ } else {
+ tp.bgColor = mainColor;
+ tp.setColor(Color.BLACK);
+ }
+ } else {
+ if (isColorDark(mainColor)) {
+ tp.bgColor = mainColor;
+ tp.setColor(Color.WHITE);
+ } else {
+ if (ColorUtil.contrastRatioIsSufficient(mainColor, highlightColor)) {
+ tp.bgColor = highlightColor;
+ } else {
+ tp.bgColor = Color.BLACK;
+ }
+ tp.setColor(mainColor);
+ }
+ }
+ } else {
+ tp.bgColor = highlightColor;
+ tp.setColor(BrandingUtil.getSecondaryForegroundColorDependingOnTheme(context, mainColor));
+ }
tp.setFakeBoldText(true);
}
@@ -92,12 +128,4 @@ public class DisplayUtils {
tp.setFakeBoldText(true);
}
}
-
- public static boolean getForeground(String backgroundColorHex) {
- return ((float) (
- 0.2126 * Integer.valueOf(backgroundColorHex.substring(1, 3), 16)
- + 0.7152 * Integer.valueOf(backgroundColorHex.substring(3, 5), 16)
- + 0.0722 * Integer.valueOf(backgroundColorHex.substring(5, 7), 16)
- ) < 140);
- }
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/util/MarkDownUtil.java b/app/src/main/java/it/niedermann/owncloud/notes/util/MarkDownUtil.java
index 9d9abe95..1a8c4b15 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/util/MarkDownUtil.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/util/MarkDownUtil.java
@@ -65,7 +65,7 @@ public class MarkDownUtil {
darkTheme ? R.color.widget_fg_dark_theme : R.color.widget_fg_default, null))
.setTodoDoneColor(ResourcesCompat.getColor(context.getResources(),
darkTheme ? R.color.widget_fg_dark_theme : R.color.widget_fg_default, null))
- .setLinkFontColor(ResourcesCompat.getColor(context.getResources(), R.color.primary, null))
+ .setLinkFontColor(ResourcesCompat.getColor(context.getResources(), R.color.defaultBrand, null))
.setRxMDImageLoader(new NotesImageLoader(context))
.setDefaultImageSize(400, 300);
}
@@ -85,14 +85,10 @@ public class MarkDownUtil {
return "";
}
- Log.v(TAG, "parseCompat - Original: \"" + text + "\"");
-
while (TextUtils.indexOf(text, MD_IMAGE_WITH_EMPTY_DESCRIPTION) >= 0) {
text = TextUtils.replace(text, MD_IMAGE_WITH_EMPTY_DESCRIPTION_ARRAY, MD_IMAGE_WITH_SPACE_DESCRIPTION_ARRAY);
}
- Log.v(TAG, "parseCompat - Replaced empty image descriptions: \"" + text + "\"");
-
return markdownProcessor.parse(text);
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/util/NoteUtil.java b/app/src/main/java/it/niedermann/owncloud/notes/util/NoteUtil.java
index 0db9b3ea..26127b44 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/util/NoteUtil.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/util/NoteUtil.java
@@ -1,6 +1,7 @@
package it.niedermann.owncloud.notes.util;
import android.content.Context;
+import android.content.SharedPreferences;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -23,6 +24,8 @@ public class NoteUtil {
private static final Pattern pSpace1 = Pattern.compile("^\\s+", Pattern.MULTILINE);
private static final Pattern pSpace2 = Pattern.compile("\\s+$", Pattern.MULTILINE);
+ public static final String EXCERPT_LINE_SEPARATOR = " ";
+
private NoteUtil() {
}
@@ -86,7 +89,7 @@ public class NoteUtil {
@NonNull
public static String generateNoteExcerpt(@NonNull String content) {
if (content.contains("\n"))
- return truncateString(removeMarkDown(content.replaceFirst("^.*\n", "")), 200).replace("\n", " ");
+ return truncateString(removeMarkDown(content.replaceFirst("^.*\n", "")), 200).replace("\n", EXCERPT_LINE_SEPARATOR);
else
return "";
}
@@ -140,4 +143,20 @@ public class NoteUtil {
public static String extendCategory(@NonNull String category) {
return category.replace("/", " / ");
}
+
+ @SuppressWarnings("WeakerAccess") //PMD...
+ public static float getFontSizeFromPreferences(@NonNull Context context, @NonNull SharedPreferences sp) {
+ final String prefValueSmall = context.getString(R.string.pref_value_font_size_small);
+ final String prefValueMedium = context.getString(R.string.pref_value_font_size_medium);
+ // final String prefValueLarge = getString(R.string.pref_value_font_size_large);
+ String fontSize = sp.getString(context.getString(R.string.pref_key_font_size), prefValueMedium);
+
+ if (fontSize.equals(prefValueSmall)) {
+ return context.getResources().getDimension(R.dimen.note_font_size_small);
+ } else if (fontSize.equals(prefValueMedium)) {
+ return context.getResources().getDimension(R.dimen.note_font_size_medium);
+ } else {
+ return context.getResources().getDimension(R.dimen.note_font_size_large);
+ }
+ }
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/util/Notes.java b/app/src/main/java/it/niedermann/owncloud/notes/util/Notes.java
index 9a4de905..5a5e74c5 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/util/Notes.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/util/Notes.java
@@ -6,12 +6,15 @@ import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.util.Log;
+import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.preference.PreferenceManager;
import it.niedermann.owncloud.notes.R;
import it.niedermann.owncloud.notes.android.DarkModeSetting;
+import static androidx.preference.PreferenceManager.getDefaultSharedPreferences;
+
public class Notes extends Application {
private static final String TAG = Notes.class.getSimpleName();
@@ -20,6 +23,7 @@ public class Notes extends Application {
private static boolean isLocked = true;
private static long lastInteraction = 0;
private static String PREF_KEY_THEME;
+ private static boolean isGridViewEnabled = false;
@Override
public void onCreate() {
@@ -27,6 +31,7 @@ public class Notes extends Application {
setAppTheme(getAppTheme(getApplicationContext()));
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
lockedPreference = prefs.getBoolean(getString(R.string.pref_key_lock), false);
+ isGridViewEnabled = getDefaultSharedPreferences(this).getBoolean(getString(R.string.pref_key_gridview), false);
super.onCreate();
}
@@ -34,6 +39,14 @@ public class Notes extends Application {
AppCompatDelegate.setDefaultNightMode(setting.getModeId());
}
+ public static boolean isGridViewEnabled() {
+ return isGridViewEnabled;
+ }
+
+ public static void updateGridViewEnabled(boolean gridView) {
+ isGridViewEnabled = gridView;
+ }
+
public static DarkModeSetting getAppTheme(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String mode;
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/util/SSOUtil.java b/app/src/main/java/it/niedermann/owncloud/notes/util/SSOUtil.java
index 5089f14d..77fa0d2c 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/util/SSOUtil.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/util/SSOUtil.java
@@ -45,9 +45,7 @@ public class SSOUtil {
try {
SingleAccountHelper.getCurrentSingleSignOnAccount(context);
return true;
- } catch (NextcloudFilesAppAccountNotFoundException e) {
- return false;
- } catch (NoCurrentAccountSelectedException e) {
+ } catch (NextcloudFilesAppAccountNotFoundException | NoCurrentAccountSelectedException e) {
return false;
}
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/util/ShareUtil.java b/app/src/main/java/it/niedermann/owncloud/notes/util/ShareUtil.java
new file mode 100644
index 00000000..1a1f6f37
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/util/ShareUtil.java
@@ -0,0 +1,20 @@
+package it.niedermann.owncloud.notes.util;
+
+import android.content.Context;
+import android.content.Intent;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import static android.content.ClipDescription.MIMETYPE_TEXT_PLAIN;
+
+public class ShareUtil {
+ public static void openShareDialog(@NonNull Context context, @Nullable String subject, @Nullable String text) {
+ context.startActivity(Intent.createChooser(new Intent()
+ .setAction(Intent.ACTION_SEND)
+ .setType(MIMETYPE_TEXT_PLAIN)
+ .putExtra(Intent.EXTRA_SUBJECT, subject)
+ .putExtra(Intent.EXTRA_TITLE, subject)
+ .putExtra(Intent.EXTRA_TEXT, text), subject));
+ }
+}
diff --git a/app/src/main/res/animator/appbar_elevation_off.xml b/app/src/main/res/animator/appbar_elevation_off.xml
new file mode 100644
index 00000000..d24dcb34
--- /dev/null
+++ b/app/src/main/res/animator/appbar_elevation_off.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item>
+ <objectAnimator
+ android:propertyName="elevation"
+ android:valueTo="0dp"
+ android:valueType="floatType" />
+ </item>
+</selector>
diff --git a/app/src/main/res/animator/appbar_elevation_on.xml b/app/src/main/res/animator/appbar_elevation_on.xml
new file mode 100644
index 00000000..6bd52cf3
--- /dev/null
+++ b/app/src/main/res/animator/appbar_elevation_on.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:ignore="PrivateResource">
+ <item>
+ <objectAnimator
+ android:propertyName="elevation"
+ android:valueTo="@dimen/design_appbar_elevation"
+ android:valueType="floatType" />
+ </item>
+</selector>
diff --git a/app/src/main/res/drawable-night/border.xml b/app/src/main/res/drawable-night/border.xml
index 48ec3e9b..ab9d52ea 100644
--- a/app/src/main/res/drawable-night/border.xml
+++ b/app/src/main/res/drawable-night/border.xml
@@ -1,6 +1,8 @@
-<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
<solid android:color="@color/category_background" />
- <stroke android:width="1dip" android:color="@color/category_border"/>
- <corners
- android:radius="4dp" />
+ <stroke
+ android:width="1dip"
+ android:color="@color/category_border" />
+ <corners android:radius="4dp" />
</shape> \ No newline at end of file
diff --git a/app/src/main/res/drawable-v21/grid_item_background_selector.xml b/app/src/main/res/drawable-v21/grid_item_background_selector.xml
new file mode 100644
index 00000000..37de2a6f
--- /dev/null
+++ b/app/src/main/res/drawable-v21/grid_item_background_selector.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Selector is used for Background Colors in List Items -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="@color/bg_highlighted">
+ <!-- :selected -->
+ <item>
+ <selector>
+ <item android:state_selected="true">
+ <color android:color="@color/bg_highlighted" />
+ </item>
+
+ <item android:state_activated="true">
+ <color android:color="@color/bg_highlighted" />
+ </item>
+
+ <item>
+ <color android:color="@android:color/transparent" />
+ </item>
+ </selector>
+ </item>
+</ripple> \ No newline at end of file
diff --git a/app/src/main/res/drawable-v21/list_item_background_selector.xml b/app/src/main/res/drawable-v21/list_item_background_selector.xml
index ea3fa361..8c562151 100644
--- a/app/src/main/res/drawable-v21/list_item_background_selector.xml
+++ b/app/src/main/res/drawable-v21/list_item_background_selector.xml
@@ -1,8 +1,6 @@
<?xml version="1.0" encoding="utf-8"?><!-- Selector is used for Background Colors in List Items -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="@color/bg_highlighted">
<!-- :selected -->
-
-
<item>
<selector>
<item android:state_selected="true">
diff --git a/app/src/main/res/drawable/border.xml b/app/src/main/res/drawable/border.xml
index 48ec3e9b..319814a6 100644
--- a/app/src/main/res/drawable/border.xml
+++ b/app/src/main/res/drawable/border.xml
@@ -1,6 +1,8 @@
-<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
- <solid android:color="@color/category_background" />
- <stroke android:width="1dip" android:color="@color/category_border"/>
- <corners
- android:radius="4dp" />
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@android:color/transparent" />
+ <stroke
+ android:width="1dip"
+ android:color="@color/category_border" />
+ <corners android:radius="4dp" />
</shape> \ No newline at end of file
diff --git a/app/src/main/res/drawable/check.xml b/app/src/main/res/drawable/check.xml
new file mode 100644
index 00000000..4c6c6b76
--- /dev/null
+++ b/app/src/main/res/drawable/check.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/area">
+ <shape android:shape="oval">
+ <solid android:color="@color/defaultBrand" />
+ <stroke
+ android:width="1dp"
+ android:color="@android:color/white" />
+ </shape>
+ </item>
+ <item android:drawable="@drawable/ic_check_white_24dp" />
+</layer-list> \ No newline at end of file
diff --git a/app/src/main/res/drawable/grid_item_background_selector.xml b/app/src/main/res/drawable/grid_item_background_selector.xml
new file mode 100644
index 00000000..24ab9be7
--- /dev/null
+++ b/app/src/main/res/drawable/grid_item_background_selector.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Selector is used for Background Colors in List Items -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- :selected -->
+ <item android:drawable="@color/bg_highlighted" android:state_selected="true" />
+ <item android:drawable="@android:color/transparent" />
+</selector>
diff --git a/app/src/main/res/drawable/ic_arrow_back_white_24dp.xml b/app/src/main/res/drawable/ic_arrow_back_grey600_24dp.xml
index cc2b6f53..99f77385 100644
--- a/app/src/main/res/drawable/ic_arrow_back_white_24dp.xml
+++ b/app/src/main/res/drawable/ic_arrow_back_grey600_24dp.xml
@@ -1,5 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
- android:tint="#FFFFFF" android:viewportHeight="24.0"
+ android:tint="#757575" android:viewportHeight="24.0"
android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
</vector>
diff --git a/app/src/main/res/drawable/ic_baseline_dashboard_24.xml b/app/src/main/res/drawable/ic_baseline_dashboard_24.xml
new file mode 100644
index 00000000..6c526e9c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_dashboard_24.xml
@@ -0,0 +1,5 @@
+<vector android:autoMirrored="true" android:height="24dp"
+ android:tint="#757575" android:viewportHeight="24"
+ android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="@android:color/white" android:pathData="M3,13h8L11,3L3,3v10zM3,21h8v-6L3,15v6zM13,21h8L21,11h-8v10zM13,3v6h8L21,3h-8z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_baseline_help_outline_24.xml b/app/src/main/res/drawable/ic_baseline_help_outline_24.xml
new file mode 100644
index 00000000..7897850e
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_help_outline_24.xml
@@ -0,0 +1,5 @@
+<vector android:height="24dp" android:tint="#757575"
+ android:viewportHeight="24" android:viewportWidth="24"
+ android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#757575" android:pathData="M11,18h2v-2h-2v2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM12,6c-2.21,0 -4,1.79 -4,4h2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2c0,2 -3,1.75 -3,5h2c0,-2.25 3,-2.5 3,-5 0,-2.21 -1.79,-4 -4,-4z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_baseline_menu_24.xml b/app/src/main/res/drawable/ic_baseline_menu_24.xml
new file mode 100644
index 00000000..be2baed8
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_menu_24.xml
@@ -0,0 +1,5 @@
+<vector android:autoMirrored="true" android:height="24dp"
+ android:tint="#757575" android:viewportHeight="24"
+ android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="@android:color/white" android:pathData="M3,18h18v-2L3,16v2zM3,13h18v-2L3,11v2zM3,6v2h18L21,6L3,6z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_check_white_24dp.xml b/app/src/main/res/drawable/ic_check_white_24dp.xml
new file mode 100644
index 00000000..65eff3fd
--- /dev/null
+++ b/app/src/main/res/drawable/ic_check_white_24dp.xml
@@ -0,0 +1,5 @@
+<vector android:height="24dp"
+ android:tint="#FFFFFF" android:viewportHeight="24.0"
+ android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#FF000000" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_color_lens_grey600_24dp.xml b/app/src/main/res/drawable/ic_color_lens_grey600_24dp.xml
new file mode 100644
index 00000000..33db0157
--- /dev/null
+++ b/app/src/main/res/drawable/ic_color_lens_grey600_24dp.xml
@@ -0,0 +1,5 @@
+<vector android:autoMirrored="true" android:height="24dp"
+ android:tint="#757575" android:viewportHeight="24.0"
+ android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#FF000000" android:pathData="M12,3c-4.97,0 -9,4.03 -9,9s4.03,9 9,9c0.83,0 1.5,-0.67 1.5,-1.5 0,-0.39 -0.15,-0.74 -0.39,-1.01 -0.23,-0.26 -0.38,-0.61 -0.38,-0.99 0,-0.83 0.67,-1.5 1.5,-1.5L16,16c2.76,0 5,-2.24 5,-5 0,-4.42 -4.03,-8 -9,-8zM6.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S5.67,9 6.5,9 8,9.67 8,10.5 7.33,12 6.5,12zM9.5,8C8.67,8 8,7.33 8,6.5S8.67,5 9.5,5s1.5,0.67 1.5,1.5S10.33,8 9.5,8zM14.5,8c-0.83,0 -1.5,-0.67 -1.5,-1.5S13.67,5 14.5,5s1.5,0.67 1.5,1.5S15.33,8 14.5,8zM17.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S16.67,9 17.5,9s1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_delete_white_24dp.xml b/app/src/main/res/drawable/ic_delete_white_24dp.xml
deleted file mode 100644
index 4d020aff..00000000
--- a/app/src/main/res/drawable/ic_delete_white_24dp.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector android:autoMirrored="true" android:height="24dp"
- android:tint="#FFFFFF" android:viewportHeight="24.0"
- android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
- <path android:fillColor="#FFFFFFFF" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
-</vector>
diff --git a/app/src/main/res/drawable/ic_edit_white_24dp.xml b/app/src/main/res/drawable/ic_edit_grey600_24dp.xml
index 5af858dd..1c520a99 100644
--- a/app/src/main/res/drawable/ic_edit_white_24dp.xml
+++ b/app/src/main/res/drawable/ic_edit_grey600_24dp.xml
@@ -1,5 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
- android:tint="#FFFFFF" android:viewportHeight="24.0"
+ android:tint="#757575" android:viewportHeight="24.0"
android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FFFFFFFF" android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
</vector>
diff --git a/app/src/main/res/drawable/ic_eye_white_24dp.xml b/app/src/main/res/drawable/ic_eye_grey600_24dp.xml
index 2386233f..64cf84b1 100644
--- a/app/src/main/res/drawable/ic_eye_white_24dp.xml
+++ b/app/src/main/res/drawable/ic_eye_grey600_24dp.xml
@@ -1,5 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
- android:tint="#FFFFFF" android:viewportHeight="24.0"
+ android:tint="#757575" android:viewportHeight="24.0"
android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FFFFFFFF" android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
</vector>
diff --git a/app/src/main/res/drawable/ic_launcher_foreground_full.xml b/app/src/main/res/drawable/ic_launcher_foreground_full.xml
new file mode 100644
index 00000000..e3e1f1ac
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_foreground_full.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="32"
+ android:viewportHeight="32">
+ <group android:translateX="0"
+ android:translateY="0">
+ <path
+ android:fillColor="#fff"
+ android:pathData="m24.484 3.5156c-1.0237 0-2.0471 0.38887-2.8281 1.1699l5.6582 5.6582c1.5621-1.5621 1.5621-4.0961 0-5.6582-0.78105-0.78105-1.8064-1.1699-2.8301-1.1699zm-4.2422 2.584-12.02 12.021 5.6562 5.6562 12.021-12.02-5.6582-5.6582zm-13.436 13.436-2.1211 7.7793 7.7793-2.1211-5.6582-5.6582z" />
+ </group>
+</vector> \ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_remove_red_eye_grey_24dp.xml b/app/src/main/res/drawable/ic_remove_red_eye_grey_24dp.xml
index dc85cfe3..d9b1702d 100644
--- a/app/src/main/res/drawable/ic_remove_red_eye_grey_24dp.xml
+++ b/app/src/main/res/drawable/ic_remove_red_eye_grey_24dp.xml
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
<path
android:fillColor="#FF757575"
- android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
+ android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z" />
</vector>
diff --git a/app/src/main/res/drawable/ic_search_grey600_24dp.xml b/app/src/main/res/drawable/ic_search_grey600_24dp.xml
new file mode 100644
index 00000000..d46f2cb3
--- /dev/null
+++ b/app/src/main/res/drawable/ic_search_grey600_24dp.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FF757575"
+ android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z" />
+</vector>
diff --git a/app/src/main/res/drawable/ic_search_white_24dp.xml b/app/src/main/res/drawable/ic_search_white_24dp.xml
deleted file mode 100644
index 3e71206e..00000000
--- a/app/src/main/res/drawable/ic_search_white_24dp.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector android:height="24dp" android:tint="#FFFFFF"
- android:viewportHeight="24.0" android:viewportWidth="24.0"
- android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
- <path android:fillColor="#FFFFFFFF" android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
-</vector>
diff --git a/app/src/main/res/drawable/ic_send_white_24dp.xml b/app/src/main/res/drawable/ic_send_grey600_24dp.xml
index 97dd32a4..08fdc123 100644
--- a/app/src/main/res/drawable/ic_send_white_24dp.xml
+++ b/app/src/main/res/drawable/ic_send_grey600_24dp.xml
@@ -1,5 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
- android:tint="#FFFFFF" android:viewportHeight="24.0"
+ android:tint="#757575" android:viewportHeight="24.0"
android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z"/>
</vector>
diff --git a/app/src/main/res/drawable/splashscreen.xml b/app/src/main/res/drawable/splashscreen.xml
index e61ed69b..e6856ad7 100644
--- a/app/src/main/res/drawable/splashscreen.xml
+++ b/app/src/main/res/drawable/splashscreen.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/ic_launcher_background" />
+ <item android:drawable="@color/defaultBrand" />
<item>
<bitmap
diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml
index 3aac5851..8e6c0a2f 100644
--- a/app/src/main/res/layout/activity_about.xml
+++ b/app/src/main/res/layout/activity_about.xml
@@ -1,31 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:orientation="vertical">
- <androidx.appcompat.widget.Toolbar
- android:id="@+id/toolbar"
+ <com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="?attr/colorPrimary"
- android:theme="@style/toolbarStyle"
- app:contentInsetStartWithNavigation="0dp"
- app:elevation="4dp"
- app:navigationIcon="@drawable/ic_arrow_back_white_24dp"
- app:titleMarginStart="0dp"
- tools:title="@string/simple_about" />
+ android:layout_height="wrap_content">
- <com.google.android.material.tabs.TabLayout
- android:id="@+id/tabs"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ <androidx.appcompat.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:background="?attr/colorPrimary"
+ app:contentInsetStartWithNavigation="0dp"
+ app:navigationIcon="@drawable/ic_arrow_back_grey600_24dp"
+ app:titleMarginStart="0dp"
+ tools:title="@string/simple_about" />
+
+ <com.google.android.material.tabs.TabLayout
+ android:id="@+id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:tabIndicatorColor="@color/defaultBrand"
+ android:background="?attr/colorPrimary" />
+ </com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager.widget.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:background="?attr/colorPrimary" />
</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/activity_edit.xml b/app/src/main/res/layout/activity_edit.xml
index c01930b7..e7da04b0 100644
--- a/app/src/main/res/layout/activity_edit.xml
+++ b/app/src/main/res/layout/activity_edit.xml
@@ -1,26 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
- xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical">
- <androidx.appcompat.widget.Toolbar
- android:id="@+id/toolbar"
+ <com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="?attr/colorPrimary"
- android:theme="@style/toolbarStyle"
- app:contentInsetStartWithNavigation="0dp"
- app:elevation="4dp"
- app:navigationIcon="@drawable/ic_arrow_back_white_24dp"
- app:titleMarginStart="0dp"
- tools:title="Edit Sample note" />
+ android:layout_height="wrap_content">
+
+ <androidx.appcompat.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:background="?attr/colorPrimary"
+ app:contentInsetStartWithNavigation="0dp"
+ app:navigationIcon="@drawable/ic_arrow_back_grey600_24dp"
+ app:titleMarginStart="0dp"
+ tools:title="Edit Sample note" />
+ </com.google.android.material.appbar.AppBarLayout>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_container_view"
android:layout_width="match_parent"
+ android:background="?attr/colorPrimary"
android:layout_height="match_parent" />
</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/activity_exception.xml b/app/src/main/res/layout/activity_exception.xml
index 37dc4bcb..e1e25491 100644
--- a/app/src/main/res/layout/activity_exception.xml
+++ b/app/src/main/res/layout/activity_exception.xml
@@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:background="?attr/colorPrimary"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
@@ -11,7 +12,6 @@
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
- android:theme="@style/toolbarStyle"
app:contentInsetStartWithNavigation="0dp"
app:elevation="4dp"
app:titleMarginStart="0dp"
@@ -30,12 +30,12 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="@dimen/spacer_2x"
- android:layout_marginLeft="16dp"
- android:layout_marginEnd="16dp"
- android:layout_marginRight="16dp"
+ android:layout_marginLeft="@dimen/spacer_2x"
+ android:layout_marginEnd="@dimen/spacer_2x"
+ android:layout_marginRight="@dimen/spacer_2x"
android:layout_weight="1"
android:background="@color/bg_highlighted"
- android:padding="8dp"
+ android:padding="@dimen/spacer_1x"
android:scrollbars="horizontal|vertical"
android:textIsSelectable="true"
android:typeface="monospace"
@@ -45,7 +45,7 @@
style="?android:buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_margin="16dp"
+ android:layout_margin="@dimen/spacer_2x"
android:gravity="end"
android:orientation="horizontal"
android:weightSum="1.0">
@@ -56,7 +56,8 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight=".5"
- android:text="@string/simple_close" />
+ android:text="@string/simple_close"
+ android:textColor="@color/defaultBrand" />
<Button
android:id="@+id/copy"
@@ -66,7 +67,7 @@
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:layout_weight=".5"
- android:background="@color/primary"
+ android:background="@color/defaultBrand"
android:foreground="?attr/selectableItemBackground"
android:text="@string/simple_copy"
android:textColor="@color/fg_contrast"
diff --git a/app/src/main/res/layout/activity_formatting_help.xml b/app/src/main/res/layout/activity_formatting_help.xml
new file mode 100644
index 00000000..69c6838d
--- /dev/null
+++ b/app/src/main/res/layout/activity_formatting_help.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout 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"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/primary"
+ android:orientation="vertical">
+
+ <com.google.android.material.appbar.AppBarLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <androidx.appcompat.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:background="?attr/colorPrimary"
+ app:contentInsetStartWithNavigation="0dp"
+ app:navigationIcon="@drawable/ic_arrow_back_grey600_24dp"
+ app:title="@string/action_formatting_help"
+ app:titleMarginStart="0dp" />
+ </com.google.android.material.appbar.AppBarLayout>
+
+ <ScrollView
+ android:id="@+id/scrollView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ tools:context="it.niedermann.owncloud.notes.android.activity.EditNoteActivity">
+
+ <com.yydcdut.markdown.MarkdownTextView
+ android:id="@+id/content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/spacer_2x"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/fg_default"
+ android:textIsSelectable="true"
+ android:theme="@style/textViewStyle"
+ tools:text="@tools:sample/lorem/random" />
+ </ScrollView>
+</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/activity_manage_accounts.xml b/app/src/main/res/layout/activity_manage_accounts.xml
new file mode 100644
index 00000000..60e684cf
--- /dev/null
+++ b/app/src/main/res/layout/activity_manage_accounts.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout 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"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="?attr/colorPrimary"
+ android:orientation="vertical">
+
+ <com.google.android.material.appbar.AppBarLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <androidx.appcompat.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:background="?attr/colorPrimary"
+ app:contentInsetStartWithNavigation="0dp"
+ app:navigationIcon="@drawable/ic_arrow_back_grey600_24dp"
+ app:title="@string/manage_accounts"
+ app:titleMarginStart="0dp" />
+ </com.google.android.material.appbar.AppBarLayout>
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/accounts"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
+ tools:listitem="@layout/item_account_choose" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/activity_note_list_configuration.xml b/app/src/main/res/layout/activity_note_list_configuration.xml
index bf14a9fe..061784e3 100644
--- a/app/src/main/res/layout/activity_note_list_configuration.xml
+++ b/app/src/main/res/layout/activity_note_list_configuration.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView 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"
diff --git a/app/src/main/res/layout/activity_notes_list_view.xml b/app/src/main/res/layout/activity_notes_list_view.xml
index 4df0e857..47aa0186 100644
--- a/app/src/main/res/layout/activity_notes_list_view.xml
+++ b/app/src/main/res/layout/activity_notes_list_view.xml
@@ -11,23 +11,94 @@
android:layout_height="match_parent"
android:orientation="vertical">
- <androidx.appcompat.widget.Toolbar
- android:id="@+id/toolbar"
+ <com.google.android.material.appbar.AppBarLayout
+ android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
- android:background="?attr/colorPrimary"
- android:theme="@style/toolbarStyle"
- app:contentInsetStartWithNavigation="0dp"
- app:elevation="4dp"
- app:titleMarginStart="0dp"
- tools:navigationIcon="@drawable/ic_arrow_back_white_24dp"
- tools:title="@string/app_name"/>
+ app:elevation="0dp">
+
+ <androidx.appcompat.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone"
+ app:contentInsetStartWithNavigation="0dp"
+ app:navigationIcon="@drawable/ic_arrow_back_grey600_24dp"
+ app:titleMarginStart="0dp"
+ tools:title="@string/app_name">
+
+ <androidx.appcompat.widget.SearchView
+ android:id="@+id/search_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </androidx.appcompat.widget.Toolbar>
+
+ <com.google.android.material.card.MaterialCardView
+ android:id="@+id/home_toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/spacer_1x"
+ android:layout_marginLeft="@dimen/spacer_1x"
+ android:layout_marginTop="@dimen/design_appbar_elevation"
+ android:layout_marginEnd="@dimen/spacer_1x"
+ android:layout_marginRight="@dimen/spacer_1x"
+ android:layout_marginBottom="@dimen/design_appbar_elevation"
+ app:cardCornerRadius="@dimen/spacer_1x"
+ app:cardElevation="6dp"
+ app:strokeWidth="0dp">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <androidx.appcompat.widget.AppCompatImageButton
+ android:id="@+id/menu_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="?attr/selectableItemBackgroundBorderless"
+ android:paddingStart="@dimen/spacer_1x"
+ android:paddingLeft="@dimen/spacer_1x"
+ android:paddingTop="@dimen/spacer_2x"
+ android:paddingEnd="@dimen/spacer_1x"
+ android:paddingRight="@dimen/spacer_1x"
+ android:paddingBottom="@dimen/spacer_2x"
+ android:tint="?attr/colorAccent"
+ app:srcCompat="@drawable/ic_baseline_menu_24" />
+
+ <com.google.android.material.textview.MaterialTextView
+ android:id="@+id/search_text"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="@dimen/spacer_1x"
+ android:layout_marginLeft="@dimen/spacer_1x"
+ android:layout_marginEnd="@dimen/spacer_1x"
+ android:layout_marginRight="@dimen/spacer_1x"
+ android:layout_weight="1"
+ android:ellipsize="end"
+ android:gravity="start"
+ android:lines="1"
+ android:textSize="16sp"
+ tools:text="@string/search_in_all" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/launchAccountSwitcher"
+ android:layout_width="?attr/actionBarSize"
+ android:layout_height="?attr/actionBarSize"
+ android:layout_gravity="center_vertical|end"
+ android:background="?attr/selectableItemBackgroundBorderless"
+ android:padding="12dp"
+ app:srcCompat="@drawable/ic_account_circle_grey_24dp" />
+ </LinearLayout>
+
+ </com.google.android.material.card.MaterialCardView>
+ </com.google.android.material.appbar.AppBarLayout>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swiperefreshlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/bg_normal"
tools:context="it.niedermann.owncloud.notes.android.activity.NotesListViewActivity">
<FrameLayout
@@ -43,15 +114,16 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
+ android:indeterminateTint="@color/defaultBrand"
+ tools:targetApi="lollipop"
tools:visibility="gone" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@color/bg_highlighted"
android:scrollbars="vertical"
- tools:listitem="@layout/item_notes_list_note_item" />
+ tools:listitem="@layout/item_notes_list_note_item_with_excerpt" />
</FrameLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
@@ -61,7 +133,6 @@
android:id="@+id/fab_create"
style="@style/fab"
android:title="@string/action_create"
- app:backgroundTint="@color/primary"
- app:rippleColor="@color/primary_dark"
+ app:backgroundTint="@color/defaultBrand"
app:srcCompat="@drawable/ic_add_white_24dp" />
</androidx.coordinatorlayout.widget.CoordinatorLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/activity_preferences.xml b/app/src/main/res/layout/activity_preferences.xml
index a8e43cc1..10b8089e 100644
--- a/app/src/main/res/layout/activity_preferences.xml
+++ b/app/src/main/res/layout/activity_preferences.xml
@@ -5,21 +5,25 @@
android:layout_height="match_parent"
android:orientation="vertical">
- <androidx.appcompat.widget.Toolbar
- android:id="@+id/toolbar"
+ <com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="?attr/colorPrimary"
- android:theme="@style/toolbarStyle"
- app:contentInsetStartWithNavigation="0dp"
- app:elevation="4dp"
- app:navigationIcon="@drawable/ic_arrow_back_white_24dp"
- app:title="@string/action_settings"
- app:titleMarginStart="0dp" />
+ android:layout_height="wrap_content">
+
+ <androidx.appcompat.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:background="?attr/colorPrimary"
+ app:contentInsetStartWithNavigation="0dp"
+ app:navigationIcon="@drawable/ic_arrow_back_grey600_24dp"
+ app:title="@string/action_settings"
+ app:titleMarginStart="0dp" />
+ </com.google.android.material.appbar.AppBarLayout>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_container_view"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"
+ android:background="?attr/colorPrimary" />
</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_account_switcher.xml b/app/src/main/res/layout/dialog_account_switcher.xml
new file mode 100644
index 00000000..f5260947
--- /dev/null
+++ b/app/src/main/res/layout/dialog_account_switcher.xml
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout 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"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:id="@+id/accountLayout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?attr/selectableItemBackground"
+ android:orientation="horizontal"
+ android:padding="@dimen/spacer_3x">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/currentAccountItemAvatar"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:contentDescription="@null"
+ android:focusable="false"
+ android:scaleType="center"
+ app:srcCompat="@drawable/ic_account_circle_grey_24dp" />
+
+ <TextView
+ android:id="@+id/accountItemLabel"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_marginStart="@dimen/spacer_2x"
+ android:layout_marginLeft="@dimen/spacer_2x"
+ android:layout_marginEnd="@dimen/spacer_2x"
+ android:layout_marginRight="@dimen/spacer_2x"
+ android:layout_weight="1"
+ android:ellipsize="middle"
+ android:singleLine="true"
+ android:textAppearance="@style/TextAppearance.AppCompat.Widget.TextView.SpinnerItem"
+ android:textColor="?android:textColorPrimary"
+ tools:text="@tools:sample/full_names" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/check"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:contentDescription="@null"
+ android:focusable="false"
+ android:scaleType="center"
+ app:srcCompat="@drawable/check" />
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@color/fg_default_high" />
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/accounts_list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="0dp"
+ android:scrollbarStyle="outsideOverlay"
+ android:scrollbars="vertical"
+ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
+ tools:itemCount="3"
+ tools:listitem="@layout/item_account_choose" />
+
+ <LinearLayout
+ android:id="@+id/add_account"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?attr/selectableItemBackground"
+ android:orientation="horizontal"
+ android:paddingStart="@dimen/spacer_3x"
+ android:paddingLeft="@dimen/spacer_3x"
+ android:paddingTop="@dimen/spacer_1x"
+ android:paddingEnd="@dimen/spacer_3x"
+ android:paddingRight="@dimen/spacer_3x"
+ android:paddingBottom="@dimen/spacer_1x">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:contentDescription="@null"
+ android:focusable="false"
+ android:scaleType="center"
+ app:srcCompat="@drawable/ic_person_add_grey600_24dp" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_marginStart="@dimen/spacer_2x"
+ android:layout_marginLeft="@dimen/spacer_2x"
+ android:ellipsize="middle"
+ android:singleLine="true"
+ android:text="@string/add_account"
+ android:textAppearance="@style/TextAppearance.AppCompat.Widget.TextView.SpinnerItem"
+ android:textColor="?android:textColorPrimary" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/manage_accounts"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/spacer_2x"
+ android:background="?attr/selectableItemBackground"
+ android:orientation="horizontal"
+ android:paddingStart="@dimen/spacer_3x"
+ android:paddingLeft="@dimen/spacer_3x"
+ android:paddingTop="@dimen/spacer_1x"
+ android:paddingEnd="@dimen/spacer_3x"
+ android:paddingRight="@dimen/spacer_3x"
+ android:paddingBottom="@dimen/spacer_1x">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:contentDescription="@null"
+ android:focusable="false"
+ android:scaleType="center"
+ app:srcCompat="@drawable/ic_settings_grey600_24dp" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_marginStart="@dimen/spacer_2x"
+ android:layout_marginLeft="@dimen/spacer_2x"
+ android:ellipsize="middle"
+ android:singleLine="true"
+ android:text="@string/manage_accounts"
+ android:textAppearance="@style/TextAppearance.AppCompat.Widget.TextView.SpinnerItem"
+ android:textColor="?android:textColorPrimary" />
+
+ </LinearLayout>
+</LinearLayout>
+
diff --git a/app/src/main/res/layout/dialog_change_category.xml b/app/src/main/res/layout/dialog_change_category.xml
index a73a32e9..86243c23 100644
--- a/app/src/main/res/layout/dialog_change_category.xml
+++ b/app/src/main/res/layout/dialog_change_category.xml
@@ -5,21 +5,16 @@
android:id="@+id/editCategoryLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical">
+ android:orientation="vertical"
+ android:padding="?attr/dialogPreferredPadding">
- <com.google.android.material.textfield.TextInputLayout
+ <EditText
+ android:id="@+id/search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="16dp">
-
- <EditText
- android:id="@+id/search"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="@string/change_category_title"
- android:importantForAutofill="no"
- android:inputType="text" />
- </com.google.android.material.textfield.TextInputLayout>
+ android:hint="@string/change_category_title"
+ android:importantForAutofill="no"
+ android:inputType="text" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
diff --git a/app/src/main/res/layout/dialog_exception.xml b/app/src/main/res/layout/dialog_exception.xml
index c5327464..875605ac 100644
--- a/app/src/main/res/layout/dialog_exception.xml
+++ b/app/src/main/res/layout/dialog_exception.xml
@@ -47,7 +47,7 @@
android:layout_marginBottom="@dimen/spacer_2x"
android:layout_weight="1"
android:background="@color/bg_highlighted"
- android:padding="8dp"
+ android:padding="@dimen/spacer_1x"
android:scrollbars="horizontal|vertical"
android:textIsSelectable="true"
android:typeface="monospace"
diff --git a/app/src/main/res/layout/drawer_layout.xml b/app/src/main/res/layout/drawer_layout.xml
index 74419fd9..ec445d1c 100644
--- a/app/src/main/res/layout/drawer_layout.xml
+++ b/app/src/main/res/layout/drawer_layout.xml
@@ -5,7 +5,6 @@
android:id="@+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:fitsSystemWindows="true"
tools:openDrawer="left">
<include
@@ -23,7 +22,8 @@
<androidx.core.widget.NestedScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:background="?attr/colorPrimary">
<LinearLayout
android:layout_width="match_parent"
@@ -33,120 +33,53 @@
<RelativeLayout
android:id="@+id/header_view"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="?attr/colorPrimary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark">
-
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="match_parent"
- android:layout_height="164dp"
- android:contentDescription="@null"
- android:scaleType="centerCrop"
- app:srcCompat="@drawable/background" />
+ android:layout_height="@dimen/drawer_header_height"
+ android:background="@color/defaultBrand">
<androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/current_account_image"
- android:layout_width="@dimen/avatar_size"
- android:layout_height="@dimen/avatar_size"
- android:layout_gravity="center_vertical"
- android:layout_marginStart="@dimen/header_padding"
- android:layout_marginLeft="@dimen/header_padding"
- android:layout_marginTop="46dp"
- android:contentDescription="@string/app_name"
- app:srcCompat="@mipmap/ic_launcher" />
+ android:id="@+id/logo"
+ android:layout_width="@dimen/drawer_header_logo_size"
+ android:layout_height="@dimen/drawer_header_logo_size"
+ android:layout_centerVertical="true"
+ android:layout_margin="@dimen/spacer_2x"
+ android:gravity="center"
+ app:srcCompat="@drawable/ic_launcher_foreground_full" />
<TextView
android:id="@+id/app_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@id/current_account_image"
- android:layout_marginTop="6dp"
- android:layout_marginStart="@dimen/header_padding"
- android:layout_marginLeft="@dimen/header_padding"
- android:layout_marginEnd="@dimen/header_padding"
- android:layout_marginRight="@dimen/header_padding"
- android:ellipsize="end"
- android:shadowColor="@android:color/black"
- android:shadowDx="0.5"
- android:shadowDy="0"
- android:shadowRadius="2"
- android:text="@string/app_name_long"
- android:textColor="@android:color/white"
- android:textSize="14sp"
- android:textStyle="bold" />
-
- <TextView
- android:id="@+id/account"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@+id/app_name"
- android:layout_marginStart="@dimen/header_padding"
- android:layout_marginLeft="@dimen/header_padding"
- android:layout_marginEnd="@dimen/widget_margin"
- android:layout_marginRight="@dimen/widget_margin"
+ android:layout_centerVertical="true"
+ android:layout_toEndOf="@id/logo"
+ android:layout_toRightOf="@id/logo"
android:ellipsize="end"
- android:maxLines="1"
- android:shadowColor="@android:color/black"
- android:layout_alignParentStart="true"
- android:layout_toStartOf="@id/account_arrow"
- android:shadowDx="0.5"
- android:shadowDy="0"
- android:shadowRadius="2"
+ android:fontFamily="sans-serif-light"
+ android:gravity="center_vertical"
+ android:text="@string/app_name"
android:textColor="@android:color/white"
- android:textSize="12sp"
- tools:text="user@nextcloud.example.comuser@nextcloud.example.comuser@nextcloud.example.com"
- android:layout_alignParentLeft="true"
- android:layout_toLeftOf="@id/account_arrow" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/account_arrow"
- app:srcCompat="@drawable/ic_arrow_drop_down_white_24dp"
- android:layout_alignParentEnd="true"
- android:layout_alignBottom="@+id/account"
- android:layout_marginEnd="@dimen/header_padding"
- android:layout_alignParentRight="true"
- android:layout_marginRight="@dimen/header_padding" />
+ android:textSize="24sp" />
</RelativeLayout>
- <LinearLayout
- android:id="@+id/accountNavigation"
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/navigationList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <androidx.recyclerview.widget.RecyclerView
- android:id="@+id/navigationList"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- app:layoutManager="LinearLayoutManager"
- tools:listitem="@layout/item_navigation" />
-
- <androidx.recyclerview.widget.RecyclerView
- android:id="@+id/navigationMenu"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- app:layoutManager="LinearLayoutManager"
- tools:listitem="@layout/item_navigation" />
- </LinearLayout>
-
- <LinearLayout
- android:id="@+id/accountChooser"
+ android:paddingTop="@dimen/spacer_1x"
+ android:paddingBottom="@dimen/spacer_1x"
+ app:layoutManager="LinearLayoutManager"
+ tools:itemCount="6"
+ tools:listitem="@layout/item_navigation" />
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/navigationMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:orientation="vertical"
- android:visibility="gone"/>
+ android:paddingTop="@dimen/spacer_1x"
+ android:paddingBottom="@dimen/spacer_1x"
+ app:layoutManager="LinearLayoutManager"
+ tools:itemCount="3"
+ tools:listitem="@layout/item_navigation" />
</LinearLayout>
-
</androidx.core.widget.NestedScrollView>
-
</com.google.android.material.navigation.NavigationView>
-
</androidx.drawerlayout.widget.DrawerLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_about_license_tab.xml b/app/src/main/res/layout/fragment_about_license_tab.xml
index c57c88ed..6afaa763 100644
--- a/app/src/main/res/layout/fragment_about_license_tab.xml
+++ b/app/src/main/res/layout/fragment_about_license_tab.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -22,17 +23,19 @@
android:padding="10dp"
android:text="@string/about_app_license" />
- <Button
+ <com.google.android.material.button.MaterialButton
android:id="@+id/about_app_license_button"
+ style="@style/Widget.MaterialComponents.Button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/about_app_license_button" />
+ android:text="@string/about_app_license_button"
+ app:backgroundTint="@color/defaultBrand" />
<TextView
style="?android:attr/listSeparatorTextViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
+ android:layout_marginTop="@dimen/spacer_2x"
android:text="@string/about_icons_disclaimer_title" />
<TextView
diff --git a/app/src/main/res/layout/fragment_note_edit.xml b/app/src/main/res/layout/fragment_note_edit.xml
index 954351b0..a6ea2fde 100644
--- a/app/src/main/res/layout/fragment_note_edit.xml
+++ b/app/src/main/res/layout/fragment_note_edit.xml
@@ -3,7 +3,17 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ tools:background="?attr/colorPrimary">
+
+ <!-- Dummy item to prevent editContent from receiving focus -->
+ <LinearLayout
+ android:id="@+id/focus_workaround"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:orientation="horizontal" />
<ScrollView
android:id="@+id/scrollView"
@@ -17,12 +27,13 @@
android:id="@+id/editContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@null"
+ android:background="?attr/colorPrimary"
android:ems="10"
android:gravity="top"
android:inputType="textMultiLine|textCapSentences"
- android:padding="16dp"
+ android:padding="@dimen/spacer_2x"
android:textColor="@color/fg_default"
+ android:theme="@style/textViewStyle"
tools:text="@tools:sample/lorem/random" />
</ScrollView>
@@ -32,6 +43,7 @@
android:layout_gravity="bottom|end"
android:translationY="-56dp"
android:visibility="gone"
+ app:backgroundTint="@color/defaultBrand"
app:fabSize="mini"
app:srcCompat="@drawable/ic_keyboard_arrow_up_white_24dp"
tools:visibility="visible" />
@@ -41,6 +53,7 @@
style="@style/fab"
android:layout_gravity="bottom|end"
android:visibility="gone"
+ app:backgroundTint="@color/defaultBrand"
app:fabSize="mini"
app:srcCompat="@drawable/ic_keyboard_arrow_down_white_24dp"
tools:visibility="visible" />
diff --git a/app/src/main/res/layout/fragment_note_preview.xml b/app/src/main/res/layout/fragment_note_preview.xml
index 0e81b33e..d841f3c2 100644
--- a/app/src/main/res/layout/fragment_note_preview.xml
+++ b/app/src/main/res/layout/fragment_note_preview.xml
@@ -3,13 +3,13 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ tools:background="?attr/colorPrimary">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swiperefreshlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/bg_normal"
tools:context="it.niedermann.owncloud.notes.android.activity.NotesListViewActivity"
tools:ignore="MergeRootFrame">
@@ -24,11 +24,11 @@
android:id="@+id/single_note_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@color/bg_normal"
- android:padding="16dp"
+ android:padding="@dimen/spacer_2x"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="@color/fg_default"
android:textIsSelectable="true"
+ android:theme="@style/textViewStyle"
tools:text="@tools:sample/lorem/random" />
</ScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
@@ -39,6 +39,7 @@
android:layout_gravity="bottom|end"
android:translationY="-56dp"
android:visibility="gone"
+ app:backgroundTint="@color/defaultBrand"
app:fabSize="mini"
app:srcCompat="@drawable/ic_keyboard_arrow_up_white_24dp"
tools:visibility="visible" />
@@ -48,6 +49,7 @@
style="@style/fab"
android:layout_gravity="bottom|end"
android:visibility="gone"
+ app:backgroundTint="@color/defaultBrand"
app:fabSize="mini"
app:srcCompat="@drawable/ic_keyboard_arrow_down_white_24dp"
tools:visibility="visible" />
diff --git a/app/src/main/res/layout/item_account.xml b/app/src/main/res/layout/item_account.xml
index ac14985b..18c6f52e 100644
--- a/app/src/main/res/layout/item_account.xml
+++ b/app/src/main/res/layout/item_account.xml
@@ -6,8 +6,8 @@
android:background="?attr/selectableItemBackground"
android:paddingLeft="6dp"
android:paddingStart="6dp"
- android:paddingRight="8dp"
- android:paddingEnd="8dp">
+ android:paddingRight="@dimen/spacer_1x"
+ android:paddingEnd="@dimen/spacer_1x">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/accountItemAvatar"
diff --git a/app/src/main/res/layout/item_account_choose.xml b/app/src/main/res/layout/item_account_choose.xml
index fc4899aa..33abe594 100644
--- a/app/src/main/res/layout/item_account_choose.xml
+++ b/app/src/main/res/layout/item_account_choose.xml
@@ -5,28 +5,60 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
- android:padding="24dp"
- android:orientation="horizontal">
+ android:orientation="horizontal"
+ android:padding="@dimen/spacer_3x">
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/accountItemAvatar"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:scaleType="center"
- android:focusable="false"
- app:srcCompat="@drawable/ic_account_circle_grey_24dp"
- android:contentDescription="@null" />
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/spacer_1hx"
+ android:layout_marginRight="@dimen/spacer_1hx">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/accountItemAvatar"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:contentDescription="@null"
+ android:focusable="false"
+ android:scaleType="center"
+ app:srcCompat="@drawable/ic_account_circle_grey_24dp" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/currentAccountIndicator"
+ android:layout_width="12dp"
+ android:layout_height="12dp"
+ android:layout_gravity="end|bottom"
+ android:visibility="gone"
+ app:srcCompat="@drawable/check"
+ tools:visibility="visible" />
+ </FrameLayout>
<TextView
android:id="@+id/accountItemLabel"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_width="wrap_content"
android:layout_gravity="center"
+ android:layout_marginStart="@dimen/spacer_2x"
+ android:layout_marginLeft="@dimen/spacer_2x"
+ android:layout_marginEnd="@dimen/spacer_2x"
+ android:layout_marginRight="@dimen/spacer_2x"
+ android:layout_weight="1"
android:ellipsize="middle"
android:singleLine="true"
- android:layout_marginLeft="16dp"
- android:layout_marginStart="16dp"
+ android:textAppearance="@style/TextAppearance.AppCompat.Widget.TextView.SpinnerItem"
android:textColor="?android:textColorPrimary"
- tools:hint="Username"/>
+ tools:text="@tools:sample/full_names" />
+
-</LinearLayout> \ No newline at end of file
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/delete"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:background="?attr/selectableItemBackgroundBorderless"
+ android:contentDescription="@null"
+ android:focusable="false"
+ android:scaleType="center"
+ android:visibility="gone"
+ app:srcCompat="@drawable/ic_delete_grey600_24dp"
+ tools:visibility="visible" />
+</LinearLayout>
diff --git a/app/src/main/res/layout/item_category.xml b/app/src/main/res/layout/item_category.xml
index 95c76732..b23a6e3f 100644
--- a/app/src/main/res/layout/item_category.xml
+++ b/app/src/main/res/layout/item_category.xml
@@ -7,14 +7,14 @@
android:background="?android:selectableItemBackground"
android:clickable="true"
android:focusable="true"
- android:padding="16dp">
+ android:padding="@dimen/spacer_2x">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginEnd="16dp"
- android:layout_marginRight="16dp"
+ android:layout_marginEnd="@dimen/spacer_2x"
+ android:layout_marginRight="@dimen/spacer_2x"
android:contentDescription="@null"
android:focusable="false"
android:scaleType="center"
@@ -36,8 +36,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|end"
- android:layout_marginStart="16dp"
- android:layout_marginLeft="16dp"
+ android:layout_marginStart="@dimen/spacer_2x"
+ android:layout_marginLeft="@dimen/spacer_2x"
android:textColor="@color/fg_default"
tools:text="23" />
</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/item_navigation.xml b/app/src/main/res/layout/item_navigation.xml
index 65fb4438..e1dc16e8 100644
--- a/app/src/main/res/layout/item_navigation.xml
+++ b/app/src/main/res/layout/item_navigation.xml
@@ -1,12 +1,13 @@
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout 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"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingStart="6dp"
- android:paddingLeft="6dp"
- android:paddingEnd="8dp"
- android:paddingRight="8dp">
+ android:gravity="center_vertical"
+ android:paddingStart="@dimen/spacer_1x"
+ android:paddingLeft="@dimen/spacer_1x"
+ android:paddingEnd="@dimen/spacer_1x"
+ android:paddingRight="@dimen/spacer_1x">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/navigationItemIcon"
@@ -14,33 +15,26 @@
android:layout_height="44dp"
android:contentDescription="@null"
android:focusable="false"
- android:padding="10dp"
android:scaleType="center"
app:srcCompat="@drawable/ic_folder_grey600_24dp" />
<TextView
- android:id="@+id/navigationItemCount"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentEnd="true"
- android:layout_alignParentRight="true"
- android:layout_centerVertical="true"
- android:padding="8dp"
- android:textColor="?android:textColorPrimary"
- tools:text="37" />
-
- <TextView
android:id="@+id/navigationItemLabel"
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_marginStart="64dp"
- android:layout_marginLeft="64dp"
- android:layout_toStartOf="@id/navigationItemCount"
- android:layout_toLeftOf="@id/navigationItemCount"
+ android:layout_marginStart="@dimen/spacer_1x"
+ android:layout_marginLeft="@dimen/spacer_1x"
+ android:layout_weight="1"
android:ellipsize="end"
android:lines="1"
android:textColor="?android:textColorSecondary"
- tools:text="Category 1" />
+ tools:text="@tools:sample/lorem/random" />
-</RelativeLayout> \ No newline at end of file
+ <TextView
+ android:id="@+id/navigationItemCount"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/spacer_1x"
+ android:textColor="?android:textColorPrimary"
+ tools:text="37" />
+</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/item_notes_list_note_item_grid.xml b/app/src/main/res/layout/item_notes_list_note_item_grid.xml
new file mode 100644
index 00000000..9f66f71e
--- /dev/null
+++ b/app/src/main/res/layout/item_notes_list_note_item_grid.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.google.android.material.card.MaterialCardView 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"
+ android:id="@+id/card"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:focusable="true">
+
+ <LinearLayout
+ android:id="@+id/wrapper"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/grid_item_background_selector"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/spacer_1x">
+
+ <TextView
+ android:id="@+id/noteTitle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/spacer_2x"
+ android:layout_marginLeft="@dimen/spacer_2x"
+ android:layout_marginTop="@dimen/spacer_2x"
+ android:layout_marginEnd="@dimen/spacer_2x"
+ android:layout_marginRight="@dimen/spacer_2x"
+ android:layout_marginBottom="@dimen/spacer_1x"
+ android:hyphenationFrequency="full"
+ android:textAppearance="?attr/textAppearanceHeadline5"
+ android:textColor="@color/fg_default"
+ tools:maxLength="50"
+ tools:targetApi="m"
+ tools:text="@tools:sample/lorem/random" />
+
+
+ <TextView
+ android:id="@+id/noteExcerpt"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/spacer_2x"
+ android:layout_marginLeft="@dimen/spacer_2x"
+ android:layout_marginEnd="@dimen/spacer_2x"
+ android:layout_marginRight="@dimen/spacer_2x"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/fg_default"
+ tools:maxLength="200"
+ tools:text="@tools:sample/lorem/random" />
+
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:baselineAligned="false"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <FrameLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1">
+
+ <com.google.android.material.chip.Chip
+ android:id="@+id/noteCategory"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/spacer_2x"
+ android:layout_marginLeft="@dimen/spacer_2x"
+ android:layout_marginEnd="0dp"
+ android:layout_marginRight="0dp"
+ android:ellipsize="middle"
+ android:textColor="?android:textColorPrimary"
+ android:textSize="@dimen/secondary_font_size"
+ app:chipBackgroundColor="@color/primary"
+ app:chipStrokeColor="@color/defaultBrand"
+ app:chipStrokeWidth="1dp"
+ tools:maxLength="50"
+ tools:text="@tools:sample/lorem/random" />
+ </FrameLayout>
+
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <ImageView
+ android:id="@+id/noteFavorite"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="?attr/selectableItemBackgroundBorderless"
+ android:contentDescription="@string/menu_favorite"
+ android:padding="@dimen/spacer_2x"
+ tools:src="@drawable/ic_star_yellow_24dp" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/noteStatus"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|end"
+ android:layout_marginTop="12dp"
+ android:layout_marginEnd="4dp"
+ android:layout_marginRight="4dp"
+ android:baseline="14dp"
+ app:srcCompat="@drawable/ic_sync_blue_18dp" />
+ </FrameLayout>
+ </LinearLayout>
+ </LinearLayout>
+</com.google.android.material.card.MaterialCardView> \ No newline at end of file
diff --git a/app/src/main/res/layout/item_notes_list_note_item_grid_only_title.xml b/app/src/main/res/layout/item_notes_list_note_item_grid_only_title.xml
new file mode 100644
index 00000000..869a4f70
--- /dev/null
+++ b/app/src/main/res/layout/item_notes_list_note_item_grid_only_title.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.google.android.material.card.MaterialCardView 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"
+ android:id="@+id/card"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:focusable="true">
+
+ <LinearLayout
+ android:id="@+id/wrapper"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/grid_item_background_selector"
+ android:orientation="horizontal"
+ android:paddingBottom="@dimen/spacer_1x">
+
+ <TextView
+ android:id="@+id/noteTitle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/spacer_2x"
+ android:layout_marginLeft="@dimen/spacer_2x"
+ android:layout_marginTop="@dimen/spacer_2x"
+ android:layout_marginEnd="@dimen/spacer_2x"
+ android:layout_marginRight="@dimen/spacer_2x"
+ android:layout_marginBottom="@dimen/spacer_1x"
+ android:layout_weight="1"
+ android:hyphenationFrequency="full"
+ android:textAppearance="?attr/textAppearanceHeadline5"
+ android:textColor="@color/fg_default"
+ tools:maxLength="50"
+ tools:targetApi="m"
+ tools:text="@tools:sample/lorem/random" />
+
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <ImageView
+ android:id="@+id/noteFavorite"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="?attr/selectableItemBackgroundBorderless"
+ android:contentDescription="@string/menu_favorite"
+ android:padding="@dimen/spacer_2x"
+ tools:src="@drawable/ic_star_yellow_24dp" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/noteStatus"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|end"
+ android:layout_marginTop="12dp"
+ android:layout_marginEnd="4dp"
+ android:layout_marginRight="4dp"
+ android:baseline="14dp"
+ app:srcCompat="@drawable/ic_sync_blue_18dp" />
+ </FrameLayout>
+ </LinearLayout>
+</com.google.android.material.card.MaterialCardView> \ No newline at end of file
diff --git a/app/src/main/res/layout/item_notes_list_note_item.xml b/app/src/main/res/layout/item_notes_list_note_item_with_excerpt.xml
index 61ad02fc..fe4d8b0b 100644
--- a/app/src/main/res/layout/item_notes_list_note_item.xml
+++ b/app/src/main/res/layout/item_notes_list_note_item_with_excerpt.xml
@@ -12,8 +12,8 @@
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center_vertical"
- android:layout_marginLeft="@dimen/button_padding"
android:layout_marginStart="@dimen/button_padding"
+ android:layout_marginLeft="@dimen/button_padding"
android:contentDescription="@string/menu_favorite"
app:srcCompat="@drawable/ic_star_white_24dp" />
@@ -27,105 +27,103 @@
android:contentDescription="@string/menu_delete"
app:srcCompat="@drawable/ic_delete_white_32dp" />
- <androidx.appcompat.widget.LinearLayoutCompat
+ <LinearLayout
android:id="@+id/noteSwipeable"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@drawable/list_item_background_selector">
+ android:background="@drawable/list_item_background_selector"
+ android:baselineAligned="false">
<FrameLayout
- android:layout_centerVertical="true"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<ImageView
android:id="@+id/noteFavorite"
- android:contentDescription="@string/menu_favorite"
- android:padding="16dp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- tools:src="@drawable/ic_star_yellow_24dp"/>
+ android:background="?attr/selectableItemBackgroundBorderless"
+ android:contentDescription="@string/menu_favorite"
+ android:padding="@dimen/spacer_2x"
+ tools:src="@drawable/ic_star_yellow_24dp" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/noteStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|end"
+ android:layout_marginTop="12dp"
android:layout_marginEnd="4dp"
android:layout_marginRight="4dp"
- android:layout_marginTop="12dp"
- android:layout_gravity="center_vertical|end"
android:baseline="14dp"
app:srcCompat="@drawable/ic_sync_blue_18dp" />
</FrameLayout>
- <androidx.appcompat.widget.LinearLayoutCompat
- android:layout_weight="1"
- android:layout_width="wrap_content"
+ <LinearLayout
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:paddingTop="16dp"
- android:paddingRight="16dp"
- android:paddingEnd="16dp"
- android:paddingLeft="0dp"
+ android:layout_weight="1"
+ android:orientation="vertical"
android:paddingStart="0dp"
- android:paddingBottom="16dp"
- android:orientation="vertical">
+ android:paddingLeft="0dp"
+ android:paddingTop="@dimen/spacer_2x"
+ android:paddingEnd="@dimen/spacer_2x"
+ android:paddingRight="@dimen/spacer_2x"
+ android:paddingBottom="@dimen/spacer_2x">
- <androidx.appcompat.widget.LinearLayoutCompat
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/noteTitle"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:layout_weight="1"
android:ellipsize="end"
android:maxLines="1"
- android:layout_weight="1"
- android:textSize="@dimen/primary_font_size"
android:textColor="?android:textColorPrimary"
- tools:text="@tools:sample/lorem/random"/>
- </androidx.appcompat.widget.LinearLayoutCompat>
+ android:textSize="@dimen/primary_font_size"
+ tools:text="@tools:sample/lorem/random" />
+ </LinearLayout>
- <androidx.appcompat.widget.LinearLayoutCompat
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/noteExcerpt"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
+ android:layout_weight="1"
android:ellipsize="end"
android:maxLines="1"
- android:paddingBottom="1dp"
android:paddingTop="1dp"
- android:layout_weight="1"
+ android:paddingBottom="1dp"
android:textSize="@dimen/secondary_font_size"
- tools:text="@tools:sample/lorem/random"/>
+ tools:text="@tools:sample/lorem/random" />
<TextView
android:id="@+id/noteCategory"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_alignParentEnd="true"
+ android:layout_marginStart="@dimen/spacer_1x"
+ android:layout_marginLeft="@dimen/spacer_1x"
android:background="@drawable/border"
android:maxLines="1"
- android:paddingBottom="1dp"
- android:paddingLeft="8dp"
- android:paddingRight="8dp"
+ android:paddingLeft="@dimen/spacer_1x"
android:paddingTop="1dp"
- android:layout_marginStart="8dp"
- android:layout_marginLeft="8dp"
+ android:paddingRight="@dimen/spacer_1x"
+ android:paddingBottom="1dp"
android:singleLine="true"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/secondary_font_size"
- tools:text="@string/category_work"/>
- </androidx.appcompat.widget.LinearLayoutCompat>
- </androidx.appcompat.widget.LinearLayoutCompat>
- </androidx.appcompat.widget.LinearLayoutCompat>
+ tools:maxLength="15"
+ tools:text="@tools:sample/lorem/random" />
+ </LinearLayout>
+ </LinearLayout>
+ </LinearLayout>
</FrameLayout>
diff --git a/app/src/main/res/layout/item_notes_list_note_item_without_excerpt.xml b/app/src/main/res/layout/item_notes_list_note_item_without_excerpt.xml
new file mode 100644
index 00000000..cf61752d
--- /dev/null
+++ b/app/src/main/res/layout/item_notes_list_note_item_without_excerpt.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout 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"
+ android:id="@+id/noteSwipeFrame"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/bg_attention">
+
+ <ImageView
+ android:id="@+id/noteFavoriteLeft"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="@dimen/button_padding"
+ android:layout_marginLeft="@dimen/button_padding"
+ android:contentDescription="@string/menu_favorite"
+ app:srcCompat="@drawable/ic_star_white_24dp" />
+
+ <ImageView
+ android:id="@+id/noteDeleteRight"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_gravity="end|center_vertical"
+ android:layout_marginEnd="@dimen/button_padding"
+ android:layout_marginRight="@dimen/button_padding"
+ android:contentDescription="@string/menu_delete"
+ app:srcCompat="@drawable/ic_delete_white_32dp" />
+
+ <LinearLayout
+ android:id="@+id/noteSwipeable"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/list_item_background_selector"
+ android:baselineAligned="false"
+ android:gravity="center_vertical">
+
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent">
+
+ <ImageView
+ android:id="@+id/noteFavorite"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:background="?attr/selectableItemBackgroundBorderless"
+ android:contentDescription="@string/menu_favorite"
+ android:padding="@dimen/spacer_2x"
+ tools:src="@drawable/ic_star_yellow_24dp" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/noteStatus"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|end"
+ android:layout_marginTop="12dp"
+ android:layout_marginEnd="4dp"
+ android:layout_marginRight="4dp"
+ android:baseline="14dp"
+ app:srcCompat="@drawable/ic_sync_blue_18dp" />
+ </FrameLayout>
+
+ <TextView
+ android:id="@+id/noteTitle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10sp"
+ android:layout_marginBottom="10sp"
+ android:layout_weight="1"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:paddingTop="@dimen/spacer_2x"
+ android:paddingBottom="@dimen/spacer_2x"
+ android:textColor="?android:textColorPrimary"
+ android:textSize="@dimen/primary_font_size"
+ tools:text="@tools:sample/lorem/random" />
+
+ <TextView
+ android:id="@+id/noteCategory"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/spacer_1x"
+ android:layout_marginLeft="@dimen/spacer_1x"
+ android:layout_marginTop="1dp"
+ android:layout_marginEnd="@dimen/spacer_2x"
+ android:layout_marginRight="@dimen/spacer_2x"
+ android:background="@drawable/border"
+ android:maxLines="1"
+ android:paddingLeft="@dimen/spacer_1x"
+ android:paddingRight="@dimen/spacer_1x"
+ android:paddingBottom="1dp"
+ android:singleLine="true"
+ android:textColor="?android:textColorPrimary"
+ android:textSize="@dimen/secondary_font_size"
+ tools:maxLength="15"
+ tools:text="@tools:sample/lorem/random" />
+ </LinearLayout>
+
+</FrameLayout>
diff --git a/app/src/main/res/layout/item_notes_list_section_item.xml b/app/src/main/res/layout/item_notes_list_section_item.xml
index 68af3740..3f29866a 100644
--- a/app/src/main/res/layout/item_notes_list_section_item.xml
+++ b/app/src/main/res/layout/item_notes_list_section_item.xml
@@ -1,28 +1,17 @@
<?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">
-
- <TextView
- android:id="@+id/sectionTitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentEnd="false"
- android:layout_alignParentRight="true"
- android:layout_alignParentStart="true"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
- android:layout_alignWithParentIfMissing="true"
- android:background="@color/bg_normal"
- android:ellipsize="end"
- android:gravity="center_vertical"
- android:paddingBottom="8dp"
- android:paddingLeft="56dp"
- android:paddingStart="56dp"
- android:paddingRight="16dp"
- android:paddingEnd="16dp"
- android:paddingTop="48dp"
- android:textColor="@color/fg_default_selection"
- android:textSize="@dimen/secondary_font_size"
- android:hint="@string/listview_updated_yesterday"/>
-</RelativeLayout> \ No newline at end of file
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/sectionTitle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignWithParentIfMissing="true"
+ android:layout_alignParentStart="true"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentEnd="false"
+ android:layout_alignParentRight="true"
+ android:ellipsize="end"
+ android:gravity="center_vertical"
+ android:hint="@string/listview_updated_yesterday"
+ android:padding="@dimen/spacer_1x"
+ android:textColor="@color/fg_default_selection"
+ android:textSize="@dimen/secondary_font_size" /> \ No newline at end of file
diff --git a/app/src/main/res/layout/item_pref.xml b/app/src/main/res/layout/item_pref.xml
index 8237bdad..48d035ef 100644
--- a/app/src/main/res/layout/item_pref.xml
+++ b/app/src/main/res/layout/item_pref.xml
@@ -11,7 +11,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:contentDescription="@null"
- android:padding="16dp"
+ android:padding="@dimen/spacer_2x"
tools:src="@drawable/ic_settings_grey600_24dp" />
<LinearLayout
@@ -22,7 +22,6 @@
android:orientation="vertical"
tools:ignore="RtlSymmetry">
-
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
@@ -49,6 +48,6 @@
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="vertical"
- android:padding="16dp" />
+ android:padding="@dimen/spacer_2x" />
</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/item_preference_category.xml b/app/src/main/res/layout/item_preference_category.xml
new file mode 100644
index 00000000..4580a438
--- /dev/null
+++ b/app/src/main/res/layout/item_preference_category.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@android:id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="56dp"
+ android:paddingLeft="56dp"
+ android:paddingTop="@dimen/spacer_3x"
+ android:paddingEnd="0dp"
+ android:paddingRight="0dp"
+ tools:text="@tools:sample/lorem" />
diff --git a/app/src/main/res/layout/widget_create_note.xml b/app/src/main/res/layout/widget_create_note.xml
index 7ef09873..b101f38d 100644
--- a/app/src/main/res/layout/widget_create_note.xml
+++ b/app/src/main/res/layout/widget_create_note.xml
@@ -1,17 +1,9 @@
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/widget_create_note"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
+ android:layout_margin="@dimen/widget_margin"
android:clickable="true"
- android:orientation="vertical"
- android:padding="@dimen/widget_margin"
- android:focusable="true">
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical|center_horizontal"
- android:background="@drawable/ic_widget_create"
- android:contentDescription="@string/widget_create_note" />
-</LinearLayout> \ No newline at end of file
+ android:contentDescription="@string/widget_create_note"
+ android:focusable="true"
+ android:src="@drawable/ic_widget_create" /> \ No newline at end of file
diff --git a/app/src/main/res/layout/widget_entry.xml b/app/src/main/res/layout/widget_entry.xml
index 5a36fd8f..029e2f39 100644
--- a/app/src/main/res/layout/widget_entry.xml
+++ b/app/src/main/res/layout/widget_entry.xml
@@ -39,6 +39,6 @@
android:paddingEnd="@dimen/widget_note_list_outer_padding"
android:paddingRight="@dimen/widget_note_list_outer_padding"
android:textColor="@color/widget_fg_default"
- tools:text="@string/app_name_long" />
+ tools:text="@tools:sample/lorem/random" />
</LinearLayout>
diff --git a/app/src/main/res/layout/widget_entry_dark.xml b/app/src/main/res/layout/widget_entry_dark.xml
index 86159782..84079185 100644
--- a/app/src/main/res/layout/widget_entry_dark.xml
+++ b/app/src/main/res/layout/widget_entry_dark.xml
@@ -40,6 +40,6 @@
android:paddingEnd="@dimen/widget_note_list_outer_padding"
android:paddingRight="@dimen/widget_note_list_outer_padding"
android:textColor="@color/fg_default_dark_theme"
- tools:text="@string/app_name_long" />
+ tools:text="@tools:sample/lorem/random" />
</LinearLayout>
diff --git a/app/src/main/res/layout/widget_note_list.xml b/app/src/main/res/layout/widget_note_list.xml
index 0e4ec607..6f13212f 100644
--- a/app/src/main/res/layout/widget_note_list.xml
+++ b/app/src/main/res/layout/widget_note_list.xml
@@ -8,9 +8,10 @@
<!-- Widget header -->
<RelativeLayout
+ android:id="@+id/widget_note_header"
android:layout_width="match_parent"
android:layout_height="@dimen/widget_note_list_header_height"
- android:background="@drawable/ic_launcher_background"
+ android:background="@color/defaultBrand"
android:padding="@dimen/widget_note_list_hdr_padding">
<ImageView
@@ -37,14 +38,16 @@
android:layout_toLeftOf="@id/widget_note_list_create_icon"
android:layout_toEndOf="@id/widget_note_header_icon"
android:layout_toRightOf="@id/widget_note_header_icon"
+ android:ellipsize="middle"
android:gravity="center_vertical"
- android:paddingStart="@dimen/widget_note_list_outer_padding"
- android:paddingLeft="@dimen/widget_note_list_outer_padding"
- android:paddingEnd="@dimen/widget_note_list_inner_padding"
- android:paddingRight="@dimen/widget_note_list_inner_padding"
+ android:paddingStart="@dimen/widget_note_list_hdr_padding"
+ android:paddingLeft="@dimen/widget_note_list_hdr_padding"
+ android:paddingEnd="@dimen/widget_note_list_hdr_padding"
+ android:paddingRight="@dimen/widget_note_list_hdr_padding"
+ android:singleLine="true"
android:textColor="@color/widget_fg_contrast"
android:textSize="18sp"
- tools:text="@string/app_name" />
+ tools:text="@tools:sample/lorem/random" />
<ImageView
android:id="@+id/widget_note_list_create_icon"
diff --git a/app/src/main/res/layout/widget_note_list_dark.xml b/app/src/main/res/layout/widget_note_list_dark.xml
index 1a94f1d1..048a1f70 100644
--- a/app/src/main/res/layout/widget_note_list_dark.xml
+++ b/app/src/main/res/layout/widget_note_list_dark.xml
@@ -9,6 +9,7 @@
<!-- Widget header -->
<RelativeLayout
+ android:id="@+id/widget_note_header_dark"
android:layout_width="match_parent"
android:layout_height="@dimen/widget_note_list_header_height"
android:background="@drawable/ic_launcher_background"
@@ -38,14 +39,16 @@
android:layout_toLeftOf="@id/widget_note_list_create_icon_dark"
android:layout_toEndOf="@id/widget_note_header_icon_dark"
android:layout_toRightOf="@id/widget_note_header_icon_dark"
+ android:ellipsize="middle"
android:gravity="center_vertical"
android:paddingStart="@dimen/widget_note_list_outer_padding"
android:paddingLeft="@dimen/widget_note_list_outer_padding"
android:paddingEnd="@dimen/widget_note_list_inner_padding"
android:paddingRight="@dimen/widget_note_list_inner_padding"
+ android:singleLine="true"
android:textColor="@color/widget_fg_contrast"
android:textSize="18sp"
- tools:text="@string/app_name" />
+ tools:text="@tools:sample/lorem/random" />
<ImageView
android:id="@+id/widget_note_list_create_icon_dark"
diff --git a/app/src/main/res/menu/menu_list_context_multiple.xml b/app/src/main/res/menu/menu_list_context_multiple.xml
index e6054140..9e44a799 100644
--- a/app/src/main/res/menu/menu_list_context_multiple.xml
+++ b/app/src/main/res/menu/menu_list_context_multiple.xml
@@ -3,15 +3,22 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
+ android:id="@+id/menu_share"
+ android:icon="@drawable/ic_share_white_24dp"
+ android:orderInCategory="90"
+ android:title="@string/menu_share"
+ app:showAsAction="ifRoom" />
+
+ <item
android:id="@+id/menu_delete"
- android:icon="@drawable/ic_delete_white_24dp"
+ android:icon="@drawable/ic_delete_grey600_24dp"
android:orderInCategory="100"
android:title="@string/menu_delete"
app:showAsAction="ifRoom" />
<item
android:id="@+id/menu_move"
- android:icon="@drawable/ic_send_white_24dp"
+ android:icon="@drawable/ic_send_grey600_24dp"
android:orderInCategory="110"
android:title="@string/simple_move"
app:showAsAction="ifRoom" />
diff --git a/app/src/main/res/menu/menu_list_view.xml b/app/src/main/res/menu/menu_list_view.xml
index 6da62936..e69de29b 100644
--- a/app/src/main/res/menu/menu_list_view.xml
+++ b/app/src/main/res/menu/menu_list_view.xml
@@ -1,17 +0,0 @@
-<?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:tools="http://schemas.android.com/tools"
- tools:context="com.example.owncloudnotes.NotesListViewActivity">
- <item
- android:id="@+id/sorting_method"
- android:title="@string/action_sorting_method"
- android:icon="@drawable/alphabetical_asc"
- app:showAsAction="collapseActionView|always" />
- <item
- android:id="@+id/search"
- android:title="@string/action_search"
- android:icon="@drawable/ic_search_white_24dp"
- app:actionViewClass="androidx.appcompat.widget.SearchView"
- app:showAsAction="collapseActionView|always" />
-</menu> \ No newline at end of file
diff --git a/app/src/main/res/menu/menu_note_activity.xml b/app/src/main/res/menu/menu_note_activity.xml
index 311c5108..967bb4f0 100644
--- a/app/src/main/res/menu/menu_note_activity.xml
+++ b/app/src/main/res/menu/menu_note_activity.xml
@@ -3,13 +3,13 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_preview"
- android:icon="@drawable/ic_eye_white_24dp"
+ android:icon="@drawable/ic_eye_grey600_24dp"
android:orderInCategory="60"
android:title="@string/menu_preview"
app:showAsAction="ifRoom" />
<item
android:id="@+id/menu_edit"
- android:icon="@drawable/ic_edit_white_24dp"
+ android:icon="@drawable/ic_edit_grey600_24dp"
android:orderInCategory="60"
android:title="@string/simple_edit"
app:showAsAction="ifRoom" />
diff --git a/app/src/main/res/menu/menu_note_fragment.xml b/app/src/main/res/menu/menu_note_fragment.xml
index 82a9ba2d..83d82772 100644
--- a/app/src/main/res/menu/menu_note_fragment.xml
+++ b/app/src/main/res/menu/menu_note_fragment.xml
@@ -5,7 +5,7 @@
<item
android:id="@+id/search"
android:title="@string/action_search"
- android:icon="@drawable/ic_search_white_24dp"
+ android:icon="@drawable/ic_search_grey600_24dp"
android:orderInCategory="50"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="ifRoom|collapseActionView" />
@@ -27,11 +27,10 @@
android:icon="@drawable/ic_share_white_24dp"
android:orderInCategory="100"
android:title="@string/menu_share"
- app:showAsAction="never"
- app:actionProviderClass="androidx.appcompat.widget.ShareActionProvider" />
+ app:showAsAction="never" />
<item
android:id="@+id/menu_move"
- android:icon="@drawable/ic_send_white_24dp"
+ android:icon="@drawable/ic_send_grey600_24dp"
android:orderInCategory="120"
android:title="@string/simple_move"
app:showAsAction="never" />
@@ -43,7 +42,7 @@
app:showAsAction="never" />
<item
android:id="@+id/menu_delete"
- android:icon="@drawable/ic_delete_white_24dp"
+ android:icon="@drawable/ic_delete_grey600_24dp"
android:orderInCategory="140"
android:title="@string/menu_delete"
app:showAsAction="never" />
diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml
index 0ea34264..d33644b9 100644
--- a/app/src/main/res/values-ca/strings.xml
+++ b/app/src/main/res/values-ca/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Edita</string>
<string name="action_edit_save">Desa</string>
<string name="simple_about">Quant a</string>
+ <string name="simple_accounts">Comptes</string>
<string name="simple_bold">Negreta</string>
<string name="simple_link">Enllaç</string>
<string name="simple_italic">Cursiva</string>
@@ -121,6 +122,10 @@
<string name="add_category">Afegeix %1$s</string>
<string name="simple_checkbox">Casella de selecció</string>
<string name="simple_beta">Beta</string>
+ <string name="simple_security">Seguretat</string>
+ <string name="simple_appearance">Aparença</string>
+ <string name="simple_synchronization">Sincronització</string>
+ <string name="manage_accounts">Gestiona els comptes</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
<item>Obre en mode d\'edició</item>
diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml
index d3f01d24..f9a32f5c 100644
--- a/app/src/main/res/values-cs-rCZ/strings.xml
+++ b/app/src/main/res/values-cs-rCZ/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Upravit</string>
<string name="action_edit_save">Uložit</string>
<string name="simple_about">O aplikaci</string>
+ <string name="simple_accounts">Účty</string>
<string name="simple_bold">Tučné</string>
<string name="simple_link">Odkaz</string>
<string name="simple_italic">Skloněné</string>
@@ -28,6 +29,9 @@
<string name="menu_preview">Náhled</string>
<string name="menu_share">Sdílet</string>
+ <string name="search_in_category">Hledat v %1$s</string>
+ <string name="search_in_all">Prohledat všechny poznámky</string>
+
<string name="change_category_title">Zvolte kategorii</string>
<string name="listview_updated_today">Dnes</string>
@@ -150,6 +154,14 @@
<string name="added_content">Přidáno „%1$s“</string>
<string name="shared_text_empty">Sdílený text je prázdný</string>
<string name="append_to_note">Připojit k poznámce</string>
+ <string name="settings_branding">Opatření vlastním logem</string>
+ <string name="simple_security">Zabezpečení</string>
+ <string name="simple_appearance">Vzhled</string>
+ <string name="simple_synchronization">Synchronizace</string>
+ <string name="simple_behavior">Chování</string>
+ <string name="share_multiple">Sdílet obsah %1$d poznámek</string>
+ <string name="manage_accounts">Spravovat účty</string>
+ <string name="action_formatting_help">Formátování</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
@@ -186,4 +198,48 @@
<item quantity="many">vybráno %d</item>
<item quantity="other">vybrány %d</item>
</plurals>
+
+ <string name="formatting_help_divider" translateable="false">---</string>
+ <string name="formatting_help_codefence_inline" translateable="false">`%1$s`</string>
+ <string name="formatting_help_codefence_inline_escaped" translateable="false">\\`%1$s\\`</string>
+ <string name="formatting_help_codefence" translateable="false">```</string>
+ <string name="formatting_help_codefence_javascript" translateable="false">```javascript</string>
+ <string name="formatting_help_cbf_title">Formátování založené na kontextu</string>
+ <string name="formatting_help_cbf_body_1">Hlavním cílem návrhu aplikace Poznámky je poskytovat nástroj, kterého používání nerozptyluje. Ačkoli můžete texty formátovat pomocí Markdown značek. Pro různé z níže uvedených příkladů můžete použít zkratky, takže své poznámky můžete formátovat bez zadávání níže uvedených kódů.</string>
+ <string name="formatting_help_cbf_body_2">Stačí jen vybrat část textu nebo klepnout na kurzor v libovolné pozici a obdržíte vyskakovací nabídky, která obsahuje kromě výchozích položek %1$s, %2$s, %3$s položky jako %4$s nebo %5$s.</string>
+
+ <string name="formatting_help_text_title">Text</string>
+ <string name="formatting_help_text_body">Pomocí značkovacího jazyka Markdown je velice jednoduché vypsat některé slova %1$stučně%1$s a jiná %2$sskloněná (kurzíva)%2$s. Je také možné některá slova %3$spřeškrtnout%3$s a dokonce [odkaz na Nextcloud](https://nextcloud.com).</string>
+
+ <string name="formatting_help_lists_title">Seznamy</string>
+ <string name="formatting_help_lists_body_1">Pokud budete chtít číslované seznamy:</string>
+ <string name="formatting_help_lists_body_2">Jedna</string>
+ <string name="formatting_help_lists_body_3">Dva</string>
+ <string name="formatting_help_lists_body_4">Tři</string>
+ <string name="formatting_help_lists_body_5">Pokud budete chtít odrážky:</string>
+ <string name="formatting_help_lists_body_6">Řádek začněte znakem mínus</string>
+ <string name="formatting_help_lists_body_7">A pokud máte dílčí body, pak před mínus či hvězdičku dejte dvě mezery:</string>
+ <string name="formatting_help_lists_body_8">Dát lajk</string>
+ <string name="formatting_help_lists_body_9">A toto</string>
+
+ <string name="formatting_help_checkboxes_title">Zatržítka</string>
+ <string name="formatting_help_checkboxes_body_1">Pro vytvoření zaškrtávací kolonky použijte seznam následovaný závorkami</string>
+ <string name="formatting_help_checkboxes_body_2">Položka 1</string>
+ <string name="formatting_help_checkboxes_body_3">Položka 2</string>
+
+ <string name="formatting_help_structured_documents_title">Strukturované dokumenty</string>
+ <string name="formatting_help_structured_documents_body_1">Někdy je užitečné mít různé úrovně nadpisů a strukturovat tak dokumenty. Začněte s řádky s %1$s pro vytvoření nadpisů. Vícero %2$s za sebou značí nižší úrovně nadpisů.</string>
+ <string name="formatting_help_structured_documents_body_2">Toto je nadpis třetí úrovně</string>
+ <string name="formatting_help_structured_documents_body_3">Je také možné použít jedno %1$s až po %2$s šest pro různé velikosti nadpisů.</string>
+ <string name="formatting_help_structured_documents_body_4">Pokud chcete někoho citovat, použijte před řádkem znak %1$s:</string>
+ <string name="formatting_help_code_title">Kód</string>
+ <string name="formatting_help_code_body_1">Ve značkovacím jazyce Markdown existuje mnoho různých způsobů jak opatřovat stylem zápis kódu. Pokud máte bloky kódu přímo v rámci řádku, obklopte je zpětnými jednoduchými uvozovkami (backticks):</string>
+ <string name="formatting_help_code_body_2">Značkovací jazyk Markdown také podporuje něco co se nazývá „oplocení“ kódu, což umožňuje vícero řádek bez odsazení:</string>
+ <string name="formatting_help_code_body_3">A pokud chcete použít zvýrazňování syntaxe, včetně jazyka:</string>
+
+ <string name="formatting_help_unsupported_title">Nepodporováno</string>
+ <string name="formatting_help_unsupported_body_1">Byť se neustále snažíme vylepšovat podporu pro Markdown, je zde několik funkcí, které Poznámky ještě nepodporují:</string>
+ <string name="formatting_help_unsupported_body_2">Tabulky</string>
+ <string name="formatting_help_unsupported_body_3">Obrázky</string>
+ <string name="formatting_help_unsupported_body_4">Pokud chcete se chtěli zapojit a přidat podporu pro tyto funkce, obraťte se na nás prostřednictvím portálu GitHub nebo e-mailu.</string>
</resources>
diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml
index 9502a7e5..6eea7792 100644
--- a/app/src/main/res/values-da/strings.xml
+++ b/app/src/main/res/values-da/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Rediger</string>
<string name="action_edit_save">Gem</string>
<string name="simple_about">Om</string>
+ <string name="simple_accounts">Konti</string>
<string name="simple_bold">Fed</string>
<string name="simple_link">Link</string>
<string name="simple_italic">Kursiv</string>
@@ -145,6 +146,11 @@
<string name="error_dialog_insufficient_storage">Din Nextcloud-instans har ikke mere ledig lagerplads. Slet venligst nogle filer for at synkronisere dine lokale ændringer ind i skyen.</string>
<string name="error_dialog_contact_us">Du er altid velkommen til at kontakte os, hvis problemet varer ved. Du kan finde vores kontaktoplysninger i sektionen Om i sidebjælken.</string>
<string name="error_dialog_we_need_info">Vi har brug for følgende tekniske information for at hjælpe dig:</string>
+ <string name="settings_branding">Branding</string>
+ <string name="simple_security">Sikkerhed</string>
+ <string name="simple_appearance">Udseende</string>
+ <string name="simple_synchronization">Synchronization</string>
+ <string name="manage_accounts">Administrer konti</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
<item>Åbn i redigeringstilstand</item>
@@ -178,4 +184,8 @@
<item quantity="one">%d valgt</item>
<item quantity="other">%d valgt</item>
</plurals>
-</resources>
+
+ <string name="formatting_help_text_title">Tekst</string>
+ <string name="formatting_help_code_title">Kode</string>
+ <string name="formatting_help_unsupported_body_3">Billeder</string>
+ </resources>
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 1c595ab3..d06acda6 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Bearbeiten</string>
<string name="action_edit_save">Speichern</string>
<string name="simple_about">Über</string>
+ <string name="simple_accounts">Konten</string>
<string name="simple_bold">Fett</string>
<string name="simple_link">Link</string>
<string name="simple_italic">Kursiv</string>
@@ -28,6 +29,9 @@
<string name="menu_preview">Vorschau</string>
<string name="menu_share">Teilen</string>
+ <string name="search_in_category">Suche in %1$s</string>
+ <string name="search_in_all">In allen Notizen suchen</string>
+
<string name="change_category_title">Kategorie auswählen</string>
<string name="listview_updated_today">Heute</string>
@@ -150,6 +154,14 @@
<string name="added_content">„%1$s“ hinzugefügt</string>
<string name="shared_text_empty">Der geteilte Text war ohne Inhalt</string>
<string name="append_to_note">An Notiz anhängen</string>
+ <string name="settings_branding">Branding</string>
+ <string name="simple_security">Sicherheit</string>
+ <string name="simple_appearance">Aussehen</string>
+ <string name="simple_synchronization">Synchronisierung</string>
+ <string name="simple_behavior">Verhalten</string>
+ <string name="share_multiple">Inhalt von %1$d Notizen teilen</string>
+ <string name="manage_accounts">Konten verwalten</string>
+ <string name="action_formatting_help">Formatierung</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
@@ -184,4 +196,48 @@
<item quantity="one">%d ausgewählt</item>
<item quantity="other">%d ausgewählt</item>
</plurals>
+
+ <string name="formatting_help_divider" translateable="false">---</string>
+ <string name="formatting_help_codefence_inline" translateable="false">`%1$s`</string>
+ <string name="formatting_help_codefence_inline_escaped" translateable="false">\\`%1$s\\`</string>
+ <string name="formatting_help_codefence" translateable="false">```</string>
+ <string name="formatting_help_codefence_javascript" translateable="false">```javascript</string>
+ <string name="formatting_help_cbf_title">Kontextbasierte Formatierung</string>
+ <string name="formatting_help_cbf_body_1">Ein wichtiges Designziel der Notes-App ist die Bereitstellung eines ablenkungsfreien Tools. Sie können Ihre Texte jedoch mit Markdown formatieren. Für verschiedene der unten genannten Beispiele können Sie Verknüpfungen verwenden, um Ihre Notizen zu formatieren, ohne die folgenden Codes eingeben zu müssen.</string>
+ <string name="formatting_help_cbf_body_2">Wählen Sie einfach einen Textbereich aus oder tippen Sie an einer beliebigen Stelle auf den Cursor und Sie erhalten ein Popup-Menü, das neben den Standardeinträgen %1$s, %2$s, %3$s auch Einträge wie %4$s oder %5$s enthält.</string>
+
+ <string name="formatting_help_text_title">Text</string>
+ <string name="formatting_help_text_body">Es ist sehr einfach, einige Wörter %1$sfett%1$s und andere Wörter %2$skursiv%2$s mit Markdown zu versehen. Sie können einige Wörter %3$sdurchstreichen%3$s und sogar zu Nextcloud [verlinken](https://nextcloud.com).</string>
+
+ <string name="formatting_help_lists_title">Listen</string>
+ <string name="formatting_help_lists_body_1">Manchmal werden nummerierte Listen benötigt:</string>
+ <string name="formatting_help_lists_body_2">Eins</string>
+ <string name="formatting_help_lists_body_3">Zwei</string>
+ <string name="formatting_help_lists_body_4">Drei</string>
+ <string name="formatting_help_lists_body_5">Manchmal werden Aufzählungszeichen benötigt:</string>
+ <string name="formatting_help_lists_body_6">Beginnen Sie eine Zeile mit einem Stern</string>
+ <string name="formatting_help_lists_body_7">Und wenn Sie Unterpunkte haben, setzen Sie zwei Leerzeichen vor den Bindestrich oder Stern:</string>
+ <string name="formatting_help_lists_body_8">Wie dieses</string>
+ <string name="formatting_help_lists_body_9">Und dies</string>
+
+ <string name="formatting_help_checkboxes_title">Kontrollkästchen</string>
+ <string name="formatting_help_checkboxes_body_1">Verwenden Sie zum Erstellen eines Kontrollkästchens eine Liste gefolgt von Klammern</string>
+ <string name="formatting_help_checkboxes_body_2">Punkt 1</string>
+ <string name="formatting_help_checkboxes_body_3">Punkt 2</string>
+
+ <string name="formatting_help_structured_documents_title">Strukturierte Dokumente</string>
+ <string name="formatting_help_structured_documents_body_1">Manchmal ist es nützlich, verschiedene Ebenen von Überschriften zu haben, um Ihre Dokumente zu strukturieren. Beginnen Sie Zeilen mit %1$s, um Überschriften zu erstellen. Mehrere %2$s in einer Reihe kennzeichnen kleinere Überschriftengrößen.</string>
+ <string name="formatting_help_structured_documents_body_2">Dies ist eine Überschrift der dritten Stufe</string>
+ <string name="formatting_help_structured_documents_body_3">Sie können ein %1$s bis zu sechs %2$s für verschiedene Kopfgrößen verwenden.</string>
+ <string name="formatting_help_structured_documents_body_4">Wenn Sie jemanden zitieren möchten, verwenden Sie das %1$s-Zeichen vor der Zeile:</string>
+ <string name="formatting_help_code_title">Quelltext</string>
+ <string name="formatting_help_code_body_1">Es gibt viele verschiedene Möglichkeiten, Text mit Markdown zu formatieren. Wenn Sie Inline-Codeblöcke haben, betten Sie diese in Backticks ein:</string>
+ <string name="formatting_help_code_body_2">Markdown unterstützt auch das sogenannte Code-Fencing, das mehrere Zeilen ohne Einrückung zulässt:</string>
+ <string name="formatting_help_code_body_3">Wenn Sie die Syntaxhervorhebung verwenden möchten, geben Sie folgendes ein:</string>
+
+ <string name="formatting_help_unsupported_title">Nicht unterstützt</string>
+ <string name="formatting_help_unsupported_body_1">Obwohl wir versuchen, die Unterstützung für Markdown ständig zu verbessern, gibt es einige Funktionen, die von Notes noch nicht unterstützt werden:</string>
+ <string name="formatting_help_unsupported_body_2">Tabellen</string>
+ <string name="formatting_help_unsupported_body_3">Bilder</string>
+ <string name="formatting_help_unsupported_body_4">Wenn Sie uns bei der Entwicklung einer dieser Funktionen unterstützen möchten, setzen Sie sich bitte über GitHub oder E-Mail mit uns in Verbindung.</string>
</resources>
diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml
index 8206d88e..cf53b0ec 100644
--- a/app/src/main/res/values-el/strings.xml
+++ b/app/src/main/res/values-el/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Επεξεργασία</string>
<string name="action_edit_save">Αποθήκευση</string>
<string name="simple_about">Περί</string>
+ <string name="simple_accounts">Λογαριασμοί</string>
<string name="simple_bold">Έντονα</string>
<string name="simple_link">Σύνδεσμος</string>
<string name="simple_italic">Πλάγια</string>
@@ -28,6 +29,9 @@
<string name="menu_preview">Προεπισκόπηση</string>
<string name="menu_share">Διαμοιρασμός</string>
+ <string name="search_in_category">Αναζήτηση σε %1$s</string>
+ <string name="search_in_all">Αναζήτηση όλων των σημειώσεων</string>
+
<string name="change_category_title">Επιλογή κατηγορίας</string>
<string name="listview_updated_today">Σήμερα</string>
@@ -150,6 +154,14 @@
<string name="added_content">Προστέθηκε \"%1$s\"</string>
<string name="shared_text_empty">Το κοινόχρηστο κείμενο είναι κενό</string>
<string name="append_to_note">Προσάρτηση στη σημείωση</string>
+ <string name="settings_branding">Επωνυμία</string>
+ <string name="simple_security">Ασφάλεια</string>
+ <string name="simple_appearance">Εμφάνιση</string>
+ <string name="simple_synchronization">Συγχρονισμός</string>
+ <string name="simple_behavior">Συμπεριφορά</string>
+ <string name="share_multiple">Κοινόχρηστο περιεχόμενο από %1$d σημειώσεις</string>
+ <string name="manage_accounts">Διαχείριση λογαριασμών</string>
+ <string name="action_formatting_help">Διαμόρφωση σε εξέλιξη</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
@@ -184,4 +196,48 @@
<item quantity="one">%d επιλέχτηκε</item>
<item quantity="other">%d επιλέχτηκαν</item>
</plurals>
+
+ <string name="formatting_help_divider" translateable="false">---</string>
+ <string name="formatting_help_codefence_inline" translateable="false">`%1$s`</string>
+ <string name="formatting_help_codefence_inline_escaped" translateable="false">\\`%1$s\\`</string>
+ <string name="formatting_help_codefence" translateable="false">```</string>
+ <string name="formatting_help_codefence_javascript" translateable="false">```javascript</string>
+ <string name="formatting_help_cbf_title">Μορφοποίηση βάσει κατάστασης</string>
+ <string name="formatting_help_cbf_body_1">Ένας κύριος σχεδιαστικός στόχος της εφαρμογής Σημειώσεις, είναι να παρέχει ένα ανεξάρτητο εργαλείο. Θα μπορείτε να μορφοποιήσετε τα κείμενά σας με το Markdown. Για διάφορα από τα παρακάτω παραδείγματα, μπορείτε να χρησιμοποιήσετε συντομεύσεις για να μορφοποιήσετε τις σημειώσεις σας χωρίς να πληκτρολογήσετε τους παρακάτω κωδικούς.</string>
+ <string name="formatting_help_cbf_body_2">Απλώς επιλέξτε ένα εύρος κειμένου ή πατήστε τον κέρσορα σε οποιαδήποτε θέση και θα λάβετε ένα αναδυόμενο μενού που περιέχει δίπλα στις προεπιλεγμένες καταχωρήσεις %1$s, %2$s, %3$s καταχωρίσεις όπως %4$s ή %5$s.</string>
+
+ <string name="formatting_help_text_title">Κείμενο</string>
+ <string name="formatting_help_text_body">Είναι πολύ εύκολο να γράψετε μερικές λέξεις με %1$sέντονη%1$s και άλλες με %2$sπλάγια%2$s μορφή με το Markdown. Μπορείτε %3$sχτυπήσετε%3$s μερικές λέξεις μέσω του [συνδέσμου για Nextcloud] (https://nextcloud.com).</string>
+
+ <string name="formatting_help_lists_title">Λίστες</string>
+ <string name="formatting_help_lists_body_1">Μερικές φορές θέλετε αριθμημένες λίστες:</string>
+ <string name="formatting_help_lists_body_2">Ένα</string>
+ <string name="formatting_help_lists_body_3">Δύο</string>
+ <string name="formatting_help_lists_body_4">Τρία</string>
+ <string name="formatting_help_lists_body_5">Μερικές φορές θέλετε κουκκίδες:</string>
+ <string name="formatting_help_lists_body_6">Ξεκινήστε μια γραμμή με παύλα</string>
+ <string name="formatting_help_lists_body_7">Και αν έχετε δευτερεύοντα σημεία, βάλτε δύο κενά πριν από την παύλα ή το αστέρι:</string>
+ <string name="formatting_help_lists_body_8">Όπως αυτό</string>
+ <string name="formatting_help_lists_body_9">Και αυτό</string>
+
+ <string name="formatting_help_checkboxes_title">Πλαίσια ελέγχου</string>
+ <string name="formatting_help_checkboxes_body_1">Για να δημιουργήσετε ένα πλαίσιο ελέγχου, χρησιμοποιήστε μια λίστα ακολουθούμενη από αγκύλες</string>
+ <string name="formatting_help_checkboxes_body_2">Αντικείμενο 1</string>
+ <string name="formatting_help_checkboxes_body_3">Αντικείμενο 2</string>
+
+ <string name="formatting_help_structured_documents_title">Δομημένα έγγραφα</string>
+ <string name="formatting_help_structured_documents_body_1">Μερικές φορές είναι χρήσιμο να έχετε διαφορετικά επίπεδα επικεφαλίδων για τη δομή των εγγράφων σας. Ξεκινήστε τις γραμμές με ένα %1$s για να δημιουργήσετε επικεφαλίδες. Πολλαπλά %2$s στη σειρά δηλώνουν μικρότερα μεγέθη επικεφαλίδας.</string>
+ <string name="formatting_help_structured_documents_body_2">Αυτή είναι μια επικεφαλίδα τρίτου επιπέδου</string>
+ <string name="formatting_help_structured_documents_body_3">Μπορείτε να χρησιμοποιήσετε ένα %1$s μέχρι έξι %2$s διαφορετικά μεγέθη επικεφαλίδας.</string>
+ <string name="formatting_help_structured_documents_body_4">Αν θέλετε να αναφέρετε κάποιο όνομα, χρησιμοποιήστε τον χαρακτήρα %1$s πριν από τη γραμμή:</string>
+ <string name="formatting_help_code_title">Κώδικας</string>
+ <string name="formatting_help_code_body_1">Υπάρχουν πολλοί διαφορετικοί τρόποι δημιουργίας κώδικα με το Markdown. Εάν έχετε ενσωματωμένα μπλοκ κώδικα, περικλείεται με πλάγια κάθετο:</string>
+ <string name="formatting_help_code_body_2">Το Markdown υποστηρίζει επίσης κάτι που ονομάζεται code fencing, το οποίο επιτρέπει πολλαπλές γραμμές χωρίς εσοχή:</string>
+ <string name="formatting_help_code_body_3">Και αν θέλετε να χρησιμοποιήσετε την επισήμανση σύνταξης, συμπεριλάβετε τη γλώσσα:</string>
+
+ <string name="formatting_help_unsupported_title">Μη υποστηριζόμενο</string>
+ <string name="formatting_help_unsupported_body_1">Ενώ προσπαθούμε να βελτιώνουμε συνεχώς την υποστήριξη για το Markdown, υπάρχουν μερικές δυνατότητες που δεν υποστηρίζονται ακόμη από τις Σημειώσεις:</string>
+ <string name="formatting_help_unsupported_body_2">Πίνακες</string>
+ <string name="formatting_help_unsupported_body_3">Εικόνες</string>
+ <string name="formatting_help_unsupported_body_4">Εάν ενδιαφέρεστε να συνεισφέρετε σε μία από αυτές τις λειτουργίες, επικοινωνήστε μαζί μας μέσω GitHub ή E-Mail.</string>
</resources>
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 3c55f9d5..12279f9e 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Editar</string>
<string name="action_edit_save">Guardar</string>
<string name="simple_about">Acerca de</string>
+ <string name="simple_accounts">Cuentas</string>
<string name="simple_bold">Negrita</string>
<string name="simple_link">Enlace</string>
<string name="simple_italic">Cursiva</string>
@@ -150,7 +151,12 @@
<string name="added_content">Se ha añadido «%1$s»</string>
<string name="shared_text_empty">El texto compartido estaba vacío</string>
<string name="append_to_note">Añadir a la nota</string>
-
+ <string name="settings_branding">Branding</string>
+ <string name="simple_security">Seguridad</string>
+ <string name="simple_appearance">Apariencia</string>
+ <string name="simple_synchronization">Sincronización</string>
+ <string name="share_multiple">Compartido contenido de %1$d notas</string>
+ <string name="manage_accounts">Gestionar cuentas</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
<item>Abrir en modo edición</item>
@@ -184,4 +190,10 @@
<item quantity="one">%d selecionado</item>
<item quantity="other">%d seleccionados</item>
</plurals>
-</resources>
+
+ <string name="formatting_help_text_title">Text</string>
+ <string name="formatting_help_checkboxes_title">Casillas de verificación</string>
+ <string name="formatting_help_code_title">Código</string>
+ <string name="formatting_help_unsupported_title">No soportado</string>
+ <string name="formatting_help_unsupported_body_3">Imágenes</string>
+ </resources>
diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml
index ba7d89f6..217f2449 100644
--- a/app/src/main/res/values-eu/strings.xml
+++ b/app/src/main/res/values-eu/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Editatu</string>
<string name="action_edit_save">Gorde</string>
<string name="simple_about">Honi buruz</string>
+ <string name="simple_accounts">Kontuak</string>
<string name="simple_bold">Lodia</string>
<string name="simple_link">Esteka</string>
<string name="simple_italic">Etzana</string>
@@ -150,7 +151,11 @@
<string name="added_content">\"%1$s\" gehituta</string>
<string name="shared_text_empty">Partekatutako testua hutsik zegoen</string>
<string name="append_to_note">Gehitu notara</string>
-
+ <string name="settings_branding">Marka</string>
+ <string name="simple_security">Segurtasuna</string>
+ <string name="simple_appearance">Itxura</string>
+ <string name="simple_synchronization">Sinkronizazioa</string>
+ <string name="manage_accounts">Kudeatu kontuak</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
<item>Ireki edizio moduan</item>
@@ -184,4 +189,9 @@
<item quantity="one">%d hautatuta</item>
<item quantity="other">%d hautatuta</item>
</plurals>
-</resources>
+
+ <string name="formatting_help_text_title">Testu</string>
+ <string name="formatting_help_checkboxes_title">Kontrol-laukiak</string>
+ <string name="formatting_help_unsupported_title">Ez da onartzen</string>
+ <string name="formatting_help_unsupported_body_3">Irudiak</string>
+ </resources>
diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml
index b55d5790..8b6db628 100644
--- a/app/src/main/res/values-fa/strings.xml
+++ b/app/src/main/res/values-fa/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">ویرایش</string>
<string name="action_edit_save">ذخیره</string>
<string name="simple_about">درباره</string>
+ <string name="simple_accounts">حساب‌ها</string>
<string name="simple_bold">درشت</string>
<string name="simple_link">Link</string>
<string name="simple_italic">Italic</string>
@@ -126,6 +127,10 @@
<string name="add_category">افزودن%1$s</string>
<string name="simple_checkbox">جعبه علامت</string>
<string name="could_not_copy_to_clipboard">به کلیپ بورد کپی نشد</string>
+ <string name="simple_security">امنیت</string>
+ <string name="simple_appearance">ظاهر</string>
+ <string name="simple_synchronization">هم‌گام‌سازی</string>
+ <string name="manage_accounts">مدیریت حساب‌ها</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
<item>در حالت ویرایش باز کنید</item>
diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml
index 8777be1e..3e89af97 100644
--- a/app/src/main/res/values-fi-rFI/strings.xml
+++ b/app/src/main/res/values-fi-rFI/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Muokkaa</string>
<string name="action_edit_save">Tallenna</string>
<string name="simple_about">Tietoja</string>
+ <string name="simple_accounts">Tilit</string>
<string name="simple_bold">Lihavoitu</string>
<string name="simple_link">Linkki</string>
<string name="simple_italic">Kursivoitu</string>
@@ -118,6 +119,10 @@
<string name="simple_checkbox">Valintaruutu</string>
<string name="simple_beta">Beta</string>
<string name="could_not_copy_to_clipboard">Ei voitu kopioida leikepöydälle</string>
+ <string name="simple_security">Tietoturva</string>
+ <string name="simple_appearance">Ulkoasu</string>
+ <string name="simple_synchronization">Synkronointi</string>
+ <string name="manage_accounts">Tilien hallinta</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
<item>Avaa muokkaustilassa</item>
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index e12c0c5d..9397aaef 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Modifier</string>
<string name="action_edit_save">Enregistrer</string>
<string name="simple_about">À propos</string>
+ <string name="simple_accounts">Comptes</string>
<string name="simple_bold">Gras</string>
<string name="simple_link">Lien</string>
<string name="simple_italic">Italique</string>
@@ -28,6 +29,9 @@
<string name="menu_preview">Aperçu</string>
<string name="menu_share">Partager</string>
+ <string name="search_in_category">Rechercher dans %1$s</string>
+ <string name="search_in_all">Rechercher dans toutes les notes</string>
+
<string name="change_category_title">Choisir une catégorie</string>
<string name="listview_updated_today">Aujourd\'hui</string>
@@ -150,7 +154,13 @@
<string name="added_content">\"%1$s\" ajouté</string>
<string name="shared_text_empty">Le texte partagé est vide</string>
<string name="append_to_note">Ajouter à la note</string>
-
+ <string name="settings_branding">marque</string>
+ <string name="simple_security">Sécurité</string>
+ <string name="simple_appearance">Apparence</string>
+ <string name="simple_synchronization">Synchronisation</string>
+ <string name="simple_behavior">Comportement</string>
+ <string name="share_multiple">Partager le contenu de %1$d notes</string>
+ <string name="manage_accounts">Gérer les comptes</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
<item>Ouvrir en mode édition</item>
@@ -184,4 +194,19 @@
<item quantity="one">%d sélectionné</item>
<item quantity="other">%d sélectionné(s)</item>
</plurals>
-</resources>
+
+ <string name="formatting_help_codefence_javascript" translateable="false">```javascript</string>
+ <string name="formatting_help_text_title">Texte</string>
+ <string name="formatting_help_lists_title">Listes</string>
+ <string name="formatting_help_lists_body_1">Parfois, vous voulez des listes numérotées :</string>
+ <string name="formatting_help_lists_body_2">Un</string>
+ <string name="formatting_help_lists_body_3">Deux</string>
+ <string name="formatting_help_lists_body_4">Trois</string>
+ <string name="formatting_help_lists_body_5">Parfois, vous voulez des puces :</string>
+ <string name="formatting_help_checkboxes_title">Case à cocher</string>
+ <string name="formatting_help_checkboxes_body_1">Pour créer une case à cocher, utilisez une liste suivie de crochets.</string>
+ <string name="formatting_help_structured_documents_title">Documents structurés</string>
+ <string name="formatting_help_code_title">Code</string>
+ <string name="formatting_help_unsupported_title">Non pris en charge</string>
+ <string name="formatting_help_unsupported_body_3">Images</string>
+ </resources>
diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml
index 35d40362..21785e10 100644
--- a/app/src/main/res/values-gl/strings.xml
+++ b/app/src/main/res/values-gl/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Editar</string>
<string name="action_edit_save">Gardar</string>
<string name="simple_about">Sobre</string>
+ <string name="simple_accounts">Contas</string>
<string name="simple_bold">Negra</string>
<string name="simple_link">Ligazón</string>
<string name="simple_italic">Itálica</string>
@@ -28,6 +29,9 @@
<string name="menu_preview">Vista previa</string>
<string name="menu_share">Compartir</string>
+ <string name="search_in_category">Buscar en %1$s</string>
+ <string name="search_in_all">Buscar todas as notas</string>
+
<string name="change_category_title">Escolla unha categoría</string>
<string name="listview_updated_today">Hoxe</string>
@@ -42,7 +46,7 @@
<string name="settings_theme_title">Tema escuro</string>
<string name="settings_font_title">Letra monoespazada</string>
<string name="settings_font_size">Tamaño da letra</string>
- <string name="settings_wifi_only">Sincronizar só con WiFi</string>
+ <string name="settings_wifi_only">Sincronizar só con wifi</string>
<string name="settings_lock">Protección por contrasinal</string>
<string name="settings_background_sync">Sincronización do traballo en segundo plano</string>
@@ -98,7 +102,7 @@
<!-- These values should not be translatable. They should be migrated at some point. -->
<string name="pref_value_font_normal">Normal</string>
- <string name="pref_value_wifi_and_mobile">Sincronización con WiFi e con datos móbiles</string>
+ <string name="pref_value_wifi_and_mobile">Sincronización con wifi e con datos móbiles</string>
<string name="pref_value_lock">Protección por contrasinal</string>
<string name="simple_error">Erro</string>
@@ -138,7 +142,7 @@
<string name="error_dialog_tip_files_force_stop">Semella que algo está mal na súa apli Nextcloud. Tente forzar a parar ambas, a apli Nextcloud e a apli Nextcloud Notes.</string>
<string name="error_dialog_tip_files_delete_storage">Se detelos pola forza non axuda, pode tentar limpar o almacenamento de ambas as aplicacións.</string>
<string name="error_dialog_timeout_instance">Non houbo resposta do seu servidor no tempo dado. Asegúrese de que a súa instancia funciona correctamente.</string>
- <string name="error_dialog_timeout_toggle">Comprobe a súa conexión de rede. Ás veces apagar e volver acender os datos móbiles ou a Wi-Fi pode axudar.</string>
+ <string name="error_dialog_timeout_toggle">Comprobe a súa conexión de rede. Ás veces apagar e volver acender os datos móbiles ou a wifi pode axudar.</string>
<string name="error_dialog_check_server">A resposta do servidor non foi correcta. Comprobe se pode acceder a Notas a través de interface web.</string>
<string name="error_dialog_check_server_logs">Hai un problema coa configuración do Nextcloud. Bótelle un ollo aos ficheiros de rexistro do servidor.</string>
<string name="error_dialog_check_maintenance">Comprobe que a súa instancia Nextcloud non se atope en modo de mantemento.</string>
@@ -150,6 +154,14 @@
<string name="added_content">Engadido «%1$s»</string>
<string name="shared_text_empty">O texto compartido estaba baleiro</string>
<string name="append_to_note">Anexo á nota</string>
+ <string name="settings_branding">Xestión da marca</string>
+ <string name="simple_security">Seguridade</string>
+ <string name="simple_appearance">Aparencia</string>
+ <string name="simple_synchronization">Sincronización</string>
+ <string name="simple_behavior">Comportamento</string>
+ <string name="share_multiple">Compartir o contido de %1$dnotas</string>
+ <string name="manage_accounts">Administrar contas</string>
+ <string name="action_formatting_help">Formatado</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
@@ -184,4 +196,9 @@
<item quantity="one">%d seleccionado</item>
<item quantity="other">%d seleccionados</item>
</plurals>
-</resources>
+
+ <string name="formatting_help_text_title">Texto</string>
+ <string name="formatting_help_checkboxes_title">Caixas de verificación</string>
+ <string name="formatting_help_unsupported_title">Non admitido</string>
+ <string name="formatting_help_unsupported_body_3">Imaxes</string>
+ </resources>
diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml
index 59127584..d07fcb17 100644
--- a/app/src/main/res/values-he/strings.xml
+++ b/app/src/main/res/values-he/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">עריכה</string>
<string name="action_edit_save">שמירה</string>
<string name="simple_about">על אודות</string>
+ <string name="simple_accounts">חשבונות</string>
<string name="simple_bold">מודגש</string>
<string name="simple_link">קישור</string>
<string name="simple_italic">נטוי</string>
@@ -135,7 +136,11 @@
<string name="error_dialog_we_need_info">אנו זקוקים לפירוט הטכני הבא כדי לסייע לך:</string>
<string name="shared_text_empty">הטקסט ששותף היה ריק</string>
<string name="append_to_note">הוספה לסוף הפתק</string>
-
+ <string name="settings_branding">מיתוג</string>
+ <string name="simple_security">אבטחה</string>
+ <string name="simple_appearance">מראה</string>
+ <string name="simple_synchronization">סנכרון</string>
+ <string name="manage_accounts">ניהול חשבונות</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
<item>פתיחה במצב עריכה</item>
diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml
index df30bb74..1c11e65b 100644
--- a/app/src/main/res/values-hr/strings.xml
+++ b/app/src/main/res/values-hr/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Uredi</string>
<string name="action_edit_save">Spremi</string>
<string name="simple_about">Informacije</string>
+ <string name="simple_accounts">Računi</string>
<string name="simple_bold">Podebljano</string>
<string name="simple_link">Poveznica</string>
<string name="simple_italic">U kurzivu</string>
@@ -146,6 +147,11 @@
<string name="error_dialog_contact_us">Obratite nam se bez odlaganja ako problemi i dalje postoje. Naše podatke za kontakt možete pronaći u odjeljku s informacijama na bočnoj traci.</string>
<string name="error_dialog_we_need_info">Potrebne su nam sljedeće tehničke informacije kako bismo vam pomogli:</string>
<string name="error_dialog_redirect">Vaš je poslužitelj vratio šifru statusa HTTP 302, što znači da aplikacija Notes nije instalirana na poslužitelju ili postoji pogreška u konfiguraciji. To mogu uzrokovati prilagođena prepisivanja u datoteci .htaccess ili određene aplikacije u Nextcloudu, kao što je OID Client.</string>
+ <string name="settings_branding">Brendiranje</string>
+ <string name="simple_security">Sigurnost</string>
+ <string name="simple_appearance">Izgled</string>
+ <string name="simple_synchronization">Sinkronizacija</string>
+ <string name="manage_accounts">Upravljaj računima</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
<item>Otvori u načinu uređivanja</item>
@@ -180,4 +186,9 @@
<item quantity="few">Odabrano je %d</item>
<item quantity="other">Odabrano je %d</item>
</plurals>
-</resources>
+
+ <string name="formatting_help_text_title">Tekst</string>
+ <string name="formatting_help_checkboxes_title">Potvrdni okviri</string>
+ <string name="formatting_help_unsupported_title">Bez podrške</string>
+ <string name="formatting_help_unsupported_body_3">Slike</string>
+ </resources>
diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml
index efb1b359..b4847faa 100644
--- a/app/src/main/res/values-hu-rHU/strings.xml
+++ b/app/src/main/res/values-hu-rHU/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Szerkesztés</string>
<string name="action_edit_save">Mentés</string>
<string name="simple_about">Névjegy</string>
+ <string name="simple_accounts">Fiókok</string>
<string name="simple_bold">Vastag</string>
<string name="simple_link">Hivatkozás</string>
<string name="simple_italic">Dőlt</string>
@@ -139,6 +140,11 @@
<string name="error_dialog_insufficient_storage">A Nextcloud példányán elfogyott a szabad hely. Töröljön pár fájlt, hogy szinkronizálhassa a helyi változtatásait a felhővel.</string>
<string name="error_dialog_contact_us">Nyugodtan lépjen velünk kapcsolatba, ha a probléma továbbra is fennáll. A kapcsolati információkat az oldalsáv névjegy részében találja.</string>
<string name="error_dialog_we_need_info">A következő műszaki információkra van szükségünk, hogy segíthessünk:</string>
+ <string name="settings_branding">Márkázas</string>
+ <string name="simple_security">Biztonság</string>
+ <string name="simple_appearance">Megjelenés</string>
+ <string name="simple_synchronization">Szinkronizálás</string>
+ <string name="manage_accounts">Fiókok kezelése</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
<item>Megnyitás szerkesztésre</item>
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index c12ee149..fe5ba82b 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Modifica</string>
<string name="action_edit_save">Salva</string>
<string name="simple_about">Informazioni</string>
+ <string name="simple_accounts">Account</string>
<string name="simple_bold">Grassetto</string>
<string name="simple_link">Collegamento</string>
<string name="simple_italic">Corsivo</string>
@@ -28,6 +29,9 @@
<string name="menu_preview">Anteprima</string>
<string name="menu_share">Condividi</string>
+ <string name="search_in_category">Cerca in %1$s</string>
+ <string name="search_in_all">Cerca tutte le note</string>
+
<string name="change_category_title">Scegli una categoria</string>
<string name="listview_updated_today">Oggi</string>
@@ -150,6 +154,14 @@
<string name="added_content">Aggiunto \"%1$s\"</string>
<string name="shared_text_empty">Il testo condiviso era vuoto</string>
<string name="append_to_note">Aggiungi a nota</string>
+ <string name="settings_branding">Marchio</string>
+ <string name="simple_security">Sicurezza</string>
+ <string name="simple_appearance">Aspetto</string>
+ <string name="simple_synchronization">Sincronizzazione</string>
+ <string name="simple_behavior">Comportamento</string>
+ <string name="share_multiple">Condividi il contenuto di %1$d note</string>
+ <string name="manage_accounts">Gestisci account</string>
+ <string name="action_formatting_help">Formattazione</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
@@ -184,4 +196,48 @@
<item quantity="one">%d selezionato</item>
<item quantity="other">%d selezionati</item>
</plurals>
+
+ <string name="formatting_help_divider" translateable="false">---</string>
+ <string name="formatting_help_codefence_inline" translateable="false">`%1$s`</string>
+ <string name="formatting_help_codefence_inline_escaped" translateable="false">\\`%1$s\\`</string>
+ <string name="formatting_help_codefence" translateable="false">```</string>
+ <string name="formatting_help_codefence_javascript" translateable="false">```javascript</string>
+ <string name="formatting_help_cbf_title">Formattazione basata sul contesto</string>
+ <string name="formatting_help_cbf_body_1">Un obiettivo fondamentale dell\'applicazione Note è di fornire uno strumento senza distrazioni. Potrai comunque formattare i tuoi testi con Markdown. Per i vari esempi sotto indicati, puoi usare le scorciatoie in modo da formattare le note senza digitare i codici sottostanti.</string>
+ <string name="formatting_help_cbf_body_2">Ti basta selezionare un intervallo di testo o toccare il cursore in qualsiasi posizione e apparirà un menu contenente accanto alle voci predefinite %1$s, %2$s, %3$s elementi come %4$s o %5$s.</string>
+
+ <string name="formatting_help_text_title">Testo</string>
+ <string name="formatting_help_text_body">È molto semplice rendere alcune parole in %1$sgrassetto%1$s e altre in %2$scorsivo%2$s con Markdown. Puoi %3$sbarrare%3$s alcune parole e anche [collegarle a Nextcloud](https://nextcloud.com).</string>
+
+ <string name="formatting_help_lists_title">Elenchi</string>
+ <string name="formatting_help_lists_body_1">A volte hai bisogno di elenchi numerati:</string>
+ <string name="formatting_help_lists_body_2">Uno</string>
+ <string name="formatting_help_lists_body_3">Due</string>
+ <string name="formatting_help_lists_body_4">Tre</string>
+ <string name="formatting_help_lists_body_5">A volte hai bisogno dei punti elenco:</string>
+ <string name="formatting_help_lists_body_6">Inizia un riga con un trattino</string>
+ <string name="formatting_help_lists_body_7">E se hai sotto-punti, metti due spazi prima del trattino o dell\'asterisco:</string>
+ <string name="formatting_help_lists_body_8">Come questo</string>
+ <string name="formatting_help_lists_body_9">E questo</string>
+
+ <string name="formatting_help_checkboxes_title">Caselle di selezione</string>
+ <string name="formatting_help_checkboxes_body_1">Per creare una casella di selezione, usa un elenco seguito da parentesi</string>
+ <string name="formatting_help_checkboxes_body_2">Elemento 1</string>
+ <string name="formatting_help_checkboxes_body_3">Elemento 2</string>
+
+ <string name="formatting_help_structured_documents_title">Documenti strutturati</string>
+ <string name="formatting_help_structured_documents_body_1">Talvolta è utile avere diversi livelli di intestazione per strutturare i tuoi documenti. Inizia le righe con un %1$s per creare intestazioni. Più %2$s in una riga indicano dimensioni minori di intestazione.</string>
+ <string name="formatting_help_structured_documents_body_2">Questa è un\'intestazione di terzo livello</string>
+ <string name="formatting_help_structured_documents_body_3">Puoi utilizzare da un %1$s fino a sei %2$s per diverse dimensioni di intestazione.</string>
+ <string name="formatting_help_structured_documents_body_4">Se vuoi citare qualcuno, utilizza il carattere %1$s prima della riga:</string>
+ <string name="formatting_help_code_title">Codice</string>
+ <string name="formatting_help_code_body_1">Esistono molti modi diversi per definire lo stile del codice con Markdown. Se hai blocchi di codice in linea, racchiudili tra apici inversi:</string>
+ <string name="formatting_help_code_body_2">Markdown supporta anche raggruppamenti di codice, che consente a righe multiple senza indentazione:</string>
+ <string name="formatting_help_code_body_3">E se desideri utilizzare l\'evidenziazione della sintassi, includi il linguaggio:</string>
+
+ <string name="formatting_help_unsupported_title">Non supportato</string>
+ <string name="formatting_help_unsupported_body_1">Mentre proviamo a migliorare continuamente il supporto per Markdown, ci sono alcune funzionalità che non sono ancora supportate da Note:</string>
+ <string name="formatting_help_unsupported_body_2">Tabelle</string>
+ <string name="formatting_help_unsupported_body_3">Immagini</string>
+ <string name="formatting_help_unsupported_body_4">Se sei interessato a fornire supporto per una di queste funzionalità, contattaci tramite GitHub o email.</string>
</resources>
diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml
index 557b5b10..d59d9c0c 100644
--- a/app/src/main/res/values-ja-rJP/strings.xml
+++ b/app/src/main/res/values-ja-rJP/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">編集</string>
<string name="action_edit_save">保存</string>
<string name="simple_about">バージョン情報</string>
+ <string name="simple_accounts">アカウント</string>
<string name="simple_bold">太字</string>
<string name="simple_link">リンク</string>
<string name="simple_italic">斜体</string>
@@ -146,6 +147,11 @@
<string name="error_dialog_contact_us">問題が継続する場合はお問い合わせください。我々の連絡先はサイドバーのaboutセクションにかかれています。</string>
<string name="error_dialog_we_need_info">サポートには下記技術情報が必要です:</string>
<string name="error_dialog_redirect">サーバがHTTPステータスコード 302を返しました。これはNotesアプリがインストールされていないか、構成が誤っていることを意味します。.htaccessファイルのカスタムオーバーライドやOIDクライアントのようなNextcloudアプリが原因の可能性があります。</string>
+ <string name="settings_branding">ブランディング</string>
+ <string name="simple_security">セキュリティ</string>
+ <string name="simple_appearance">表示</string>
+ <string name="simple_synchronization">同期</string>
+ <string name="manage_accounts">アカウント管理</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
<item>編集モードで開く</item>
@@ -178,4 +184,8 @@
<plurals name="ab_selected">
<item quantity="other">%d 選択済</item>
</plurals>
-</resources>
+
+ <string name="formatting_help_text_title">テキスト</string>
+ <string name="formatting_help_unsupported_title">サポートされていません。</string>
+ <string name="formatting_help_unsupported_body_3">画像</string>
+ </resources>
diff --git a/app/src/main/res/values-lt-rLT/strings.xml b/app/src/main/res/values-lt-rLT/strings.xml
index 1b5e55c2..f2759c78 100644
--- a/app/src/main/res/values-lt-rLT/strings.xml
+++ b/app/src/main/res/values-lt-rLT/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Taisyti</string>
<string name="action_edit_save">Įrašyti</string>
<string name="simple_about">Apie</string>
+ <string name="simple_accounts">Paskyros</string>
<string name="simple_bold">Pusjuodis</string>
<string name="simple_link">Nuoroda</string>
<string name="simple_italic">Kursyvas</string>
@@ -130,6 +131,10 @@
<string name="could_not_copy_to_clipboard">Nepavyko nukopijuoti į iškarpinę</string>
<string name="error_dialog_title">O, ne - Kas dabar? 🙁</string>
<string name="error_dialog_we_need_info">Norint jums padėti, mums reikia techninės informacijos:</string>
+ <string name="simple_security">Saugumas</string>
+ <string name="simple_appearance">Išvaizda</string>
+ <string name="simple_synchronization">Sinchronizacija</string>
+ <string name="manage_accounts">Tvarkyti paskyras</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
<item>Atverti redagavimo veiksenoje</item>
diff --git a/app/src/main/res/values-night/booleans.xml b/app/src/main/res/values-night/booleans.xml
new file mode 100644
index 00000000..41cc6feb
--- /dev/null
+++ b/app/src/main/res/values-night/booleans.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <bool name="isDayMode">false</bool>
+</resources>
diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml
index c01010ad..3c3e134c 100644
--- a/app/src/main/res/values-night/colors.xml
+++ b/app/src/main/res/values-night/colors.xml
@@ -2,10 +2,14 @@
<resources>
<!-- Colors -->
- <color name="primary_dark">#286090</color>
+ <color name="primary">#121212</color>
+ <color name="accent">#f5f5f5</color>
+
+ <color name="cursorHandles">#eee5e5ee</color>
+ <color name="defaultTextHighlightBackground">#55eeeeff</color>
<color name="bg_highlighted">#2a2a2a</color>
- <color name="bg_normal">#121212</color>
+ <color name="bg_normal">@color/primary</color>
<color name="bg_attention">#ff3333</color>
<color name="fg_default">#eeeeee</color>
<color name="fg_default_selection">#cccccc</color>
@@ -13,5 +17,5 @@
<color name="fg_default_high">#757575</color>
<color name="fg_contrast">#000000</color>
- <color name="category_background">@color/primary</color>
+ <color name="category_background">@color/defaultBrand</color>
</resources> \ No newline at end of file
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index 1a0f2cc8..6dd6798e 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Bewerken</string>
<string name="action_edit_save">Opslaan</string>
<string name="simple_about">Over</string>
+ <string name="simple_accounts">Accounts</string>
<string name="simple_bold">Vet</string>
<string name="simple_link">Link</string>
<string name="simple_italic">Scheef</string>
@@ -151,7 +152,12 @@
<string name="added_content">\"%1$s\" toegevoegd</string>
<string name="shared_text_empty">Gedeelde tekst was leeg</string>
<string name="append_to_note">Achteraan toevoegen aan notitie</string>
-
+ <string name="settings_branding">Brandmerken</string>
+ <string name="simple_security">Beveiliging</string>
+ <string name="simple_appearance">Uiterlijk</string>
+ <string name="simple_synchronization">Synchronisatie</string>
+ <string name="share_multiple">Deel de inhoud van %1$d notities</string>
+ <string name="manage_accounts">Accounts beheren </string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
<item>Open in wbewerkmodus</item>
@@ -185,4 +191,10 @@
<item quantity="one">%d geselecteerd</item>
<item quantity="other">%d geselecteerd</item>
</plurals>
-</resources>
+
+ <string name="formatting_help_text_title">Tekst</string>
+ <string name="formatting_help_checkboxes_title">Aanvinkvakjes</string>
+ <string name="formatting_help_code_title">Code</string>
+ <string name="formatting_help_unsupported_title">Niet ondersteund</string>
+ <string name="formatting_help_unsupported_body_3">Afbeeldingen</string>
+ </resources>
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index f278d403..a025786e 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Edytuj</string>
<string name="action_edit_save">Zapisz</string>
<string name="simple_about">O aplikacji</string>
+ <string name="simple_accounts">Konta</string>
<string name="simple_bold">Pogrubienie</string>
<string name="simple_link">Odnośnik</string>
<string name="simple_italic">Kursywa</string>
@@ -28,6 +29,9 @@
<string name="menu_preview">Podgląd</string>
<string name="menu_share">Udostępnij</string>
+ <string name="search_in_category">Szukaj w %1$s</string>
+ <string name="search_in_all">Szukaj w notatkach</string>
+
<string name="change_category_title">Wybierz kategorię</string>
<string name="listview_updated_today">Dzisiaj</string>
@@ -67,7 +71,7 @@
<string name="about_translators_transifex">Społeczność Nextcloud na &lt;a href=\"%1$s\">Transifex&lt;/a></string>
<string name="about_testers_title">Testerzy</string>
<string name="about_source_title">Kod źródłowy</string>
- <string name="about_source">Ten projekt jest hostowany na GitHub: &lt;a href=\"%1$s\">%1$s&lt;/a></string>
+ <string name="about_source">Projekt jest hostowany na GitHub: &lt;a href=\"%1$s\">%1$s&lt;/a></string>
<string name="about_issues_title">Problemy</string>
<string name="about_issues">Możesz zgłaszać błędy, propozycje ulepszeń i prośby o funkcje w liście problemów na GitHub: &lt;a href=\"%1$s\">%1$s&lt;/a></string>
<string name="about_translate_title">Tłumaczyć</string>
@@ -150,6 +154,14 @@
<string name="added_content">Dodano \"%1$s\"</string>
<string name="shared_text_empty">Udostępniony tekst był pusty</string>
<string name="append_to_note">Dołącz do notatki</string>
+ <string name="settings_branding">Motyw serwera</string>
+ <string name="simple_security">Bezpieczeństwo</string>
+ <string name="simple_appearance">Wygląd</string>
+ <string name="simple_synchronization">Synchronizacja</string>
+ <string name="simple_behavior">Zachowanie</string>
+ <string name="share_multiple">Udostępnij treść notatki %1$d</string>
+ <string name="manage_accounts">Zarządzaj kontami</string>
+ <string name="action_formatting_help">Formatowanie</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
@@ -186,4 +198,39 @@
<item quantity="many">%d wybranych</item>
<item quantity="other">%d wybranych</item>
</plurals>
+
+ <string name="formatting_help_divider" translateable="false">---</string>
+ <string name="formatting_help_codefence" translateable="false">```</string>
+ <string name="formatting_help_codefence_javascript" translateable="false">```javascript</string>
+ <string name="formatting_help_cbf_title">Formatowanie kontekstowe</string>
+ <string name="formatting_help_cbf_body_1">Głównym celem projektowym aplikacji Notes jest zapewnienie narzędzia bez rozpraszania uwagi. Chociaż będziesz mógł sformatować swoje teksty za pomocą Markdown. W przypadku różnych wymienionych poniżej przykładów możesz użyć skrótów, dzięki czemu możesz sformatować swoje notatki bez wpisywania poniższych kodów.</string>
+ <string name="formatting_help_text_title">Tekst</string>
+ <string name="formatting_help_lists_title">Listy</string>
+ <string name="formatting_help_lists_body_1">Czasami chcesz mieć listy ponumerowane:</string>
+ <string name="formatting_help_lists_body_2">1 Jeden</string>
+ <string name="formatting_help_lists_body_3">2. Dwa</string>
+ <string name="formatting_help_lists_body_4">3. Trzy</string>
+ <string name="formatting_help_lists_body_5">Czasami chcesz wypunktować:</string>
+ <string name="formatting_help_lists_body_6">Rozpocznij linię gwiazdką</string>
+ <string name="formatting_help_lists_body_7">A jeśli masz podpunkty, umieść dwie spacje przed kreską lub gwiazdką:</string>
+ <string name="formatting_help_lists_body_8">Lubię to</string>
+ <string name="formatting_help_lists_body_9">I to też</string>
+
+ <string name="formatting_help_checkboxes_title">Pola wyboru</string>
+ <string name="formatting_help_checkboxes_body_1">Aby utworzyć pole wyboru, użyj listy i nawiasów</string>
+ <string name="formatting_help_checkboxes_body_2">Pozycja 1</string>
+ <string name="formatting_help_checkboxes_body_3">Pozycja 2</string>
+
+ <string name="formatting_help_structured_documents_title">Dokumenty strukturalne</string>
+ <string name="formatting_help_structured_documents_body_2">To nagłówek trzeciego poziomu</string>
+ <string name="formatting_help_code_title">Kod</string>
+ <string name="formatting_help_code_body_1">Istnieje wiele różnych sposobów stylizowania kodu za pomocą Markdown. Jeśli masz wbudowane bloki kodu, zawiń je w backticks:</string>
+ <string name="formatting_help_code_body_2">Markdown obsługuje również coś, co nazywa się szermierką kodu, co pozwala na wiele linii bez wcięć:</string>
+ <string name="formatting_help_code_body_3">A jeśli chcesz użyć podświetlania składni, uwzględnij język:</string>
+
+ <string name="formatting_help_unsupported_title">Niewspierane</string>
+ <string name="formatting_help_unsupported_body_1">Chociaż staramy się ciągle ulepszać obsługę Markdown, istnieje kilka funkcji, które nie są jeszcze obsługiwane przez Notes:</string>
+ <string name="formatting_help_unsupported_body_2">Tabele</string>
+ <string name="formatting_help_unsupported_body_3">Obrazy</string>
+ <string name="formatting_help_unsupported_body_4">Jeśli chcesz pomóc przy jednej z tych funkcji, skontaktuj się z nami za pośrednictwem GitHub lub e-mail.</string>
</resources>
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index 02beb388..cb310a61 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Editar</string>
<string name="action_edit_save">Salvar</string>
<string name="simple_about">Sobre</string>
+ <string name="simple_accounts">Contas</string>
<string name="simple_bold">Negrito</string>
<string name="simple_link">Link</string>
<string name="simple_italic">Itálico</string>
@@ -150,7 +151,12 @@
<string name="added_content">\"%1$s\" adicionado</string>
<string name="shared_text_empty">O texto compartilhado estava vazio</string>
<string name="append_to_note">Anexar à nota</string>
-
+ <string name="settings_branding">Marcação</string>
+ <string name="simple_security">Segurança</string>
+ <string name="simple_appearance">Aparência</string>
+ <string name="simple_synchronization">Sincronização</string>
+ <string name="share_multiple">Compartilhar o conteúdo de %1$d notas</string>
+ <string name="manage_accounts">Gerenciar contas</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
<item>Abrir em modo de edição</item>
@@ -184,4 +190,10 @@
<item quantity="one">%d selecionado</item>
<item quantity="other">%d selecionados</item>
</plurals>
-</resources>
+
+ <string name="formatting_help_text_title">Texto</string>
+ <string name="formatting_help_checkboxes_title">Caixas de seleção</string>
+ <string name="formatting_help_code_title">Código</string>
+ <string name="formatting_help_unsupported_title">Não suportado</string>
+ <string name="formatting_help_unsupported_body_3">Imagens</string>
+ </resources>
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index d060902e..afa808be 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Редактировать</string>
<string name="action_edit_save">Сохранить</string>
<string name="simple_about">О программе</string>
+ <string name="simple_accounts">Аккаунты</string>
<string name="simple_bold">Жирный</string>
<string name="simple_link">Ссылка</string>
<string name="simple_italic">Курсив</string>
@@ -150,7 +151,11 @@
<string name="added_content">Добавлена заметка «%1$s»</string>
<string name="shared_text_empty">Публикуемый текст пустой</string>
<string name="append_to_note">Добавить в заметку</string>
-
+ <string name="settings_branding">Брендирование</string>
+ <string name="simple_security">Безопасность</string>
+ <string name="simple_appearance">Внешний вид</string>
+ <string name="simple_synchronization">Синхронизация</string>
+ <string name="manage_accounts">Управление аккаунтами</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
<item>Открывать в режиме редактирования</item>
@@ -186,4 +191,10 @@
<item quantity="many">%d выбрано</item>
<item quantity="other">%d выбрано</item>
</plurals>
-</resources>
+
+ <string name="formatting_help_text_title">Текст</string>
+ <string name="formatting_help_checkboxes_title">Несколько из списка</string>
+ <string name="formatting_help_code_title">Код</string>
+ <string name="formatting_help_unsupported_title">Не поддерживается</string>
+ <string name="formatting_help_unsupported_body_3">Изображения</string>
+ </resources>
diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk-rSK/strings.xml
index 6cb7d40f..8ec751c7 100644
--- a/app/src/main/res/values-sk-rSK/strings.xml
+++ b/app/src/main/res/values-sk-rSK/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Upraviť</string>
<string name="action_edit_save">Uložiť</string>
<string name="simple_about">O aplikácii</string>
+ <string name="simple_accounts">Účty</string>
<string name="simple_bold">Tučné</string>
<string name="simple_link">Odkaz</string>
<string name="simple_italic">Kurzíva</string>
@@ -28,6 +29,9 @@
<string name="menu_preview">Náhľad</string>
<string name="menu_share">Sprístupniť</string>
+ <string name="search_in_category">Hľadať v %1$s</string>
+ <string name="search_in_all">Hľadať všetky poznámky</string>
+
<string name="change_category_title">Vybrať kategóriu</string>
<string name="listview_updated_today">Dnes</string>
@@ -150,6 +154,14 @@
<string name="added_content">Pridané \"%1$s\"</string>
<string name="shared_text_empty">Zdieľaný text bol prázdny</string>
<string name="append_to_note">Pripojiť k poznámke</string>
+ <string name="settings_branding">Použitie vlastného loga</string>
+ <string name="simple_security">Zabezpečenie</string>
+ <string name="simple_appearance">Vzhľad</string>
+ <string name="simple_synchronization">Synchronizácia</string>
+ <string name="simple_behavior">Chod</string>
+ <string name="share_multiple">Zdieľať obsah %1$d poznámok</string>
+ <string name="manage_accounts">Spravovať účty</string>
+ <string name="action_formatting_help">Formátovanie</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
@@ -186,4 +198,39 @@
<item quantity="many">%d vybraný</item>
<item quantity="other">%d vybraný</item>
</plurals>
+
+ <string name="formatting_help_divider" translateable="false">---</string>
+ <string name="formatting_help_codefence" translateable="false">```</string>
+ <string name="formatting_help_codefence_javascript" translateable="false">```javascript</string>
+ <string name="formatting_help_cbf_title">Kontextové formátovanie</string>
+ <string name="formatting_help_cbf_body_1">Hlavným cieľom aplikácie Notes je poskytnúť nástroj bez rozptyľovania. Svoje texty však budete môcť formátovať pomocou aplikácie Markdown. Pre rôzne príklady uvedené nižšie môžete použiť klávesové skratky, pomocou ktorých môžete svoje poznámky formátovať bez toho, aby ste museli zadávať kódy uvedené nižšie.</string>
+ <string name="formatting_help_text_title">Text</string>
+ <string name="formatting_help_lists_title">Zoznamy</string>
+ <string name="formatting_help_lists_body_1">Niekedy chcete číslované zoznamy:</string>
+ <string name="formatting_help_lists_body_2">Jeden</string>
+ <string name="formatting_help_lists_body_3">Dva</string>
+ <string name="formatting_help_lists_body_4">Tri</string>
+ <string name="formatting_help_lists_body_5">Niekedy chcete odrážky:</string>
+ <string name="formatting_help_lists_body_6">Riadok začnite pomlčkou</string>
+ <string name="formatting_help_lists_body_7">A ak máte vnorený bod, vložte pred pomlčku alebo hviezdičku dve medzery:</string>
+ <string name="formatting_help_lists_body_8">Ako toto</string>
+ <string name="formatting_help_lists_body_9">A toto</string>
+
+ <string name="formatting_help_checkboxes_title">Zaškrtávacie políčka</string>
+ <string name="formatting_help_checkboxes_body_1">Ak chcete vytvoriť zaškrtávacie políčko, použite zoznam nasledovaný hranatými zátvorkami</string>
+ <string name="formatting_help_checkboxes_body_2">Položka 1</string>
+ <string name="formatting_help_checkboxes_body_3">Položka 2</string>
+
+ <string name="formatting_help_structured_documents_title">Štrukturované dokumenty</string>
+ <string name="formatting_help_structured_documents_body_2">Toto je nadpis tretej úrovne</string>
+ <string name="formatting_help_code_title">Kód</string>
+ <string name="formatting_help_code_body_1">Tam, kde je to možné, ako upraviť štýl vrátane Markdown. Ak chcete vložiť kód, zalomte ich do spätných lomiek:</string>
+ <string name="formatting_help_code_body_2">Markdown tiež podporuje niečo, čo sa nazýva oplotenie kódu, čo umožňuje použiť viac riadkov bez odsadenia:</string>
+ <string name="formatting_help_code_body_3">Ak chcete použiť zvýraznenie syntaxe, uveďte jazyk:</string>
+
+ <string name="formatting_help_unsupported_title">Nepodporované</string>
+ <string name="formatting_help_unsupported_body_1">Aj keď sa pokúšame neustále zlepšovať podporu Markdown, existuje niekoľko funkcií, ktoré zatiaľ Poznámky nepodporujú:</string>
+ <string name="formatting_help_unsupported_body_2">Tabuľky</string>
+ <string name="formatting_help_unsupported_body_3">Obrázky</string>
+ <string name="formatting_help_unsupported_body_4">Ak máte záujem prispieť k podpore niektorej z týchto funkcií, kontaktujte nás prostredníctvom služby GitHub alebo e-mailom.</string>
</resources>
diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml
index f18649f9..2cf2022b 100644
--- a/app/src/main/res/values-sl/strings.xml
+++ b/app/src/main/res/values-sl/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Uredi</string>
<string name="action_edit_save">Shrani</string>
<string name="simple_about">O programu</string>
+ <string name="simple_accounts">Računi</string>
<string name="simple_bold">Krepko</string>
<string name="simple_link">Povezava</string>
<string name="simple_italic">Ležeče</string>
@@ -142,11 +143,19 @@
<string name="error_dialog_check_server">Prejet je napačen odziv s strežnika. Preverite, ali imate dostop do zabeležk prek spletnega vmesnika.</string>
<string name="error_dialog_check_server_logs">Prišlo je do napake z namestitvijo Nextcloud. Preverite zapis dnevnika na strežniku.</string>
<string name="error_dialog_check_maintenance">Preverite, ali je morda namestitev Nextcloud trenutno v vzdrževalnem načinu.</string>
+ <string name="error_dialog_insufficient_storage">Ni več prostora v shrambi. Izbrisati je treba nekaj datotek za nadaljevanje usklajevanja krajevnih datotek z oblakom.</string>
+ <string name="error_dialog_contact_us">V kolikor se napaka še naprej pojavlja, ne odlašajte in stopite v stik z nami. Podatke o možnostih stika so v bočnem oknu med opisi programa.</string>
<string name="error_dialog_we_need_info">Z ustrezno pomoč potrebujemo nekaj tehničnih podrobnosti sistema:</string>
<string name="error_dialog_server_app_enabled">Prepričajte se, da ste namestili in omogočili tudi program »Notes« na strežniku.</string>
<string name="error_dialog_redirect">S strežnika je prejet odziv s kodo stanja HTTP 302, kar kaže na to, da program Notes ni nameščen, ali pa je napačno nastavljen. Napaka se pojavi tudi pri nekaterih določilih v datoteki .htaccess oziroma programih, kot je odjemalec OID.</string>
+ <string name="added_content">Dodano »%1$s«</string>
+ <string name="shared_text_empty">Besedilo v souporabi je brez vsebine</string>
<string name="append_to_note">Pripni k zabeležki</string>
-
+ <string name="settings_branding">Prilagajanje oblikovanja</string>
+ <string name="simple_security">Varnost</string>
+ <string name="simple_appearance">Videz</string>
+ <string name="simple_synchronization">Usklajevanje</string>
+ <string name="manage_accounts">Upravljanje z računi</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
<item>Zabeležka se odpre v urejevalnem načinu</item>
@@ -182,4 +191,10 @@
<item quantity="few">%d izbrane</item>
<item quantity="other">%d izbranih</item>
</plurals>
-</resources>
+
+ <string name="formatting_help_text_title">Besedilo</string>
+ <string name="formatting_help_checkboxes_title">Izbirna polja</string>
+ <string name="formatting_help_code_title">Šifra</string>
+ <string name="formatting_help_unsupported_title">Nepodprto</string>
+ <string name="formatting_help_unsupported_body_3">Slike</string>
+ </resources>
diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml
index b285be7d..b70b2a0e 100644
--- a/app/src/main/res/values-sr/strings.xml
+++ b/app/src/main/res/values-sr/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Измени</string>
<string name="action_edit_save">Сачувај</string>
<string name="simple_about">О програму</string>
+ <string name="simple_accounts">Налози</string>
<string name="simple_bold">Подебљано</string>
<string name="simple_link">Веза</string>
<string name="simple_italic">Курзив</string>
@@ -50,6 +51,7 @@
<!-- Error -->
<string name="error_sync">Синхронизација није успела%1$s</string>
+ <string name="error_synchronization">Синхронизација није успела</string>
<string name="error_json">Да ли је апликација Белешки активирана на серверу?</string>
<string name="error_no_network">Нема мрежне везе</string>
<string name="error_files_app">Да ли имате инсталирану апликацију за фајлове?</string>
@@ -128,6 +130,20 @@
<string name="unlock_notes">Откључај белешке</string>
<string name="simple_beta">Бета</string>
<string name="could_not_copy_to_clipboard">Не могу да копирам у оставу</string>
+ <string name="error_dialog_title">О, не - шта сад? 🙁</string>
+ <string name="error_dialog_tip_token_mismatch_retry">Покушајте да форсирано затворите апликацију и стартујете је поново. Можда је била неисправна конекција ка Некстклауд апликацији.</string>
+ <string name="error_dialog_tip_files_outdated">Изгледа да је верзија Некстклауд апликације стара. Посетите Play Store или Ф-дроид да скинете најновију верзију.</string>
+ <string name="error_dialog_tip_files_delete_storage">Ако ово заустављање не помогне, очистите податке за обе апликације.</string>
+ <string name="error_dialog_timeout_instance">Није било одговора са сервера у задатом времену. Проверите да ли вам инстанца ради добро.</string>
+ <string name="error_dialog_check_server_logs">Постоји проблема са поставкама Вашег Некстклауда. Погледаје дневник у фајловима са сервера.</string>
+ <string name="error_dialog_check_maintenance">Проверите да ли Вам инстанца можда тренутно ради у режиму одржавања.</string>
+ <string name="error_dialog_insufficient_storage">На Некстклауд инстанци више нема простора. Обришите неке фајлове да синхронизујете локалне измене на облак.</string>
+ <string name="error_dialog_we_need_info">Потребне су нам следеће техничке информација да бисмо Вам помогли:</string>
+ <string name="settings_branding">Брендирање</string>
+ <string name="simple_security">Безбедност</string>
+ <string name="simple_appearance">Изглед</string>
+ <string name="simple_synchronization">Синхронизација</string>
+ <string name="manage_accounts">Управљање налозима</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
<item>Отвори у режиму уређивања</item>
diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml
index 692b4a02..7e8a9ff6 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Redigera</string>
<string name="action_edit_save">Spara</string>
<string name="simple_about">Om</string>
+ <string name="simple_accounts">Konton</string>
<string name="simple_bold">Fet</string>
<string name="simple_link">Länk</string>
<string name="simple_italic">Kursiv</string>
@@ -133,6 +134,11 @@
<string name="error_dialog_title">Å nej - Vad händer nu?🙁</string>
<string name="error_dialog_tip_token_mismatch_retry">Försök med att Tvinga appen att stänga och återstarta. En felaktig anslutning till Nextcloud-appen kan ha förekommit.</string>
<string name="error_dialog_tip_token_mismatch_clear_storage">Om problemet kvarstår, prova med att rensa lagringen på både appen Nextcloud och Nextcloud Notes.</string>
+ <string name="settings_branding">Varumärke</string>
+ <string name="simple_security">Säkerhet</string>
+ <string name="simple_appearance">Utseende</string>
+ <string name="simple_synchronization">Synkronisering</string>
+ <string name="manage_accounts">Hantera konton</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
<item>Öppna i redigera-läge</item>
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index f4a8aa6e..eb31685d 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">Düzenle</string>
<string name="action_edit_save">Kaydet</string>
<string name="simple_about">Hakkında</string>
+ <string name="simple_accounts">Hesaplar</string>
<string name="simple_bold">Koyu</string>
<string name="simple_link">Bağlantı</string>
<string name="simple_italic">Yatık</string>
@@ -28,6 +29,9 @@
<string name="menu_preview">Ön izleme</string>
<string name="menu_share">Paylaş</string>
+ <string name="search_in_category">%1$s içinde arama</string>
+ <string name="search_in_all">Tüm notlarda arama</string>
+
<string name="change_category_title">Bir kategori seçin</string>
<string name="listview_updated_today">Bugün</string>
@@ -150,6 +154,14 @@
<string name="added_content">\"%1$s\" eklendi</string>
<string name="shared_text_empty">Paylaşılan metin boş</string>
<string name="append_to_note">Nota ekle</string>
+ <string name="settings_branding">Markalama</string>
+ <string name="simple_security">Güvenlik</string>
+ <string name="simple_appearance">Görünüm</string>
+ <string name="simple_synchronization">Eşitleme</string>
+ <string name="simple_behavior">Davranış</string>
+ <string name="share_multiple">%1$d notun içeriğini paylaş</string>
+ <string name="manage_accounts">Hesap yönetimi</string>
+ <string name="action_formatting_help">Biçimlendirme</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
@@ -184,4 +196,48 @@
<item quantity="one">%d seçilmiş</item>
<item quantity="other">%d seçilmiş</item>
</plurals>
+
+ <string name="formatting_help_divider" translateable="false">---</string>
+ <string name="formatting_help_codefence_inline" translateable="false">`%1$s`</string>
+ <string name="formatting_help_codefence_inline_escaped" translateable="false">\\`%1$s\\`</string>
+ <string name="formatting_help_codefence" translateable="false">```</string>
+ <string name="formatting_help_codefence_javascript" translateable="false">```javascript</string>
+ <string name="formatting_help_cbf_title">Bağlama göre biçimlendirme</string>
+ <string name="formatting_help_cbf_body_1">Notlar uygulamasının önemli bir tasarım amacı, dikkat dağıtmayan bir araç sağlamaktır. Yine de metinlerinizi Markdown kullanarak biçimlendirebilirsiniz. Aşağıdaki örneklerden bazılarında kısayolları kullanarak notlarınızı aşağıdaki kodları yazmadan biçimlendirebilirsiniz.</string>
+ <string name="formatting_help_cbf_body_2">Yalnız bir metin bölümü seçerek ya da herhangi bir konumda imlece dokunarak varsayılan kayıtların yanında açılan menüden %1$s, %2$s, %3$s, %4$s gibi kayıtlar ya da %5$s seçenekleri kullanabilirsiniz.</string>
+
+ <string name="formatting_help_text_title">Metin</string>
+ <string name="formatting_help_text_body">Markdown ile bazı sözcükleri %1$skalın%1$s ya da %2$syatık%2$s yapmak çok kolaydır. Bazı sözcüklerin %3$süzerini çizebilir%3$s ve [Nextcloud bağlantısı](https://nextcloud.com) gibi bağlantı verebilirsiniz.</string>
+
+ <string name="formatting_help_lists_title">Listeler</string>
+ <string name="formatting_help_lists_body_1">Bazen listelerin numaralı olmasını istersiniz:</string>
+ <string name="formatting_help_lists_body_2">Bir</string>
+ <string name="formatting_help_lists_body_3">İki</string>
+ <string name="formatting_help_lists_body_4">Üç</string>
+ <string name="formatting_help_lists_body_5">Bazen listelerde madde imi kullanılmasını istersiniz:</string>
+ <string name="formatting_help_lists_body_6">Bir satıra tire ile başlayın</string>
+ <string name="formatting_help_lists_body_7">Alt imler için tire ya da yıldız önüne iki boşluk ekleyin:</string>
+ <string name="formatting_help_lists_body_8">Bunun gibi</string>
+ <string name="formatting_help_lists_body_9">Ve bunun gibi</string>
+
+ <string name="formatting_help_checkboxes_title">İşaret kutuları</string>
+ <string name="formatting_help_checkboxes_body_1">Bir işaret kutusu eklemek için köşeli parantezler ile biten bir liste kullanın</string>
+ <string name="formatting_help_checkboxes_body_2">1. öge</string>
+ <string name="formatting_help_checkboxes_body_3">2. öge</string>
+
+ <string name="formatting_help_structured_documents_title">Yapılandırılmış belgeler</string>
+ <string name="formatting_help_structured_documents_body_1">Bazen belgelerinizi yapılandırmak için farklı düzeylerde başlıklar kullanmak yararlı olabilir. Başlık oluşturmak için satırlara %1$s ile başlayın. Bir satırda %2$s gibi birden çok simge kullanılması başlık düzeyini ve boyutunu azaltır.</string>
+ <string name="formatting_help_structured_documents_body_2">Bu üçüncü düzey bir başlık</string>
+ <string name="formatting_help_structured_documents_body_3">Farklı başlık boyutları için bir %1$s ile altı %2$s arasında seçim yapabilirsiniz.</string>
+ <string name="formatting_help_structured_documents_body_4">Birinden alıntı yapmak isterseniz satırdan önce %1$s karakterini kullanın:</string>
+ <string name="formatting_help_code_title">Kod</string>
+ <string name="formatting_help_code_body_1">Markdown ile kod yazmanın birçok farklı yolu vardır. Satır arası kod bloklarınız varsa, bunları ters tırnaklar arasında yazın:</string>
+ <string name="formatting_help_code_body_2">Markdown ayrıca kod çiti olarak adlandırılan ve girinti olmadan birden fazla satıra izin veren bir şeyi destekler:</string>
+ <string name="formatting_help_code_body_3">Ve söz dizimi vurgulamasını kullanmak istiyorsanız, dili ekleyin:</string>
+
+ <string name="formatting_help_unsupported_title">Desteklenmiyor</string>
+ <string name="formatting_help_unsupported_body_1">Markdown desteğini sürekli olarak geliştirmeye çalışıyoruz. Ancak henüz Notes uygulamasının desteklemediği birkaç özellik var:</string>
+ <string name="formatting_help_unsupported_body_2">Tablolar</string>
+ <string name="formatting_help_unsupported_body_3">Görseller</string>
+ <string name="formatting_help_unsupported_body_4">Bu özelliklerden biri için destek olmak isterseniz, GitHub ya da e-posta üzerinden bizimle görüşün.</string>
</resources>
diff --git a/app/src/main/res/values-v23/styles.xml b/app/src/main/res/values-v23/styles.xml
new file mode 100644
index 00000000..812e48ee
--- /dev/null
+++ b/app/src/main/res/values-v23/styles.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <style name="AppTheme" parent="BaseTheme">
+ <item name="android:statusBarColor">?attr/colorPrimary</item>
+ <item name="android:windowLightStatusBar">@bool/isDayMode</item>
+ </style>
+
+ <style name="SplashTheme" parent="AppTheme">
+ <item name="android:windowBackground">@drawable/splashscreen</item>
+ <item name="android:statusBarColor">@color/defaultBrand</item>
+ <item name="android:windowLightStatusBar">false</item>
+ </style>
+</resources> \ No newline at end of file
diff --git a/app/src/main/res/values-v27/styles.xml b/app/src/main/res/values-v27/styles.xml
new file mode 100644
index 00000000..477789c3
--- /dev/null
+++ b/app/src/main/res/values-v27/styles.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <style name="AppTheme" parent="BaseTheme">
+ <item name="android:statusBarColor">?attr/colorPrimary</item>
+ <item name="android:windowLightStatusBar">@bool/isDayMode</item>
+ <item name="android:navigationBarColor">?attr/colorPrimary</item>
+ <item name="android:windowLightNavigationBar">@bool/isDayMode</item>
+ </style>
+
+ <style name="SplashTheme" parent="AppTheme">
+ <item name="android:windowBackground">@drawable/splashscreen</item>
+ <item name="android:statusBarColor">@color/defaultBrand</item>
+ <item name="android:windowLightStatusBar">false</item>
+ <item name="android:navigationBarColor">@color/defaultBrand</item>
+ <item name="android:windowLightNavigationBar">false</item>
+ </style>
+</resources> \ No newline at end of file
diff --git a/app/src/main/res/values-w1280dp/integers.xml b/app/src/main/res/values-w1280dp/integers.xml
new file mode 100644
index 00000000..0d3d9c7f
--- /dev/null
+++ b/app/src/main/res/values-w1280dp/integers.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <integer name="grid_view_span_count">5</integer>
+</resources>
diff --git a/app/src/main/res/values-w320dp/integers.xml b/app/src/main/res/values-w320dp/integers.xml
new file mode 100644
index 00000000..064f91e1
--- /dev/null
+++ b/app/src/main/res/values-w320dp/integers.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <integer name="grid_view_span_count">2</integer>
+</resources> \ No newline at end of file
diff --git a/app/src/main/res/values-w600dp/integers.xml b/app/src/main/res/values-w600dp/integers.xml
new file mode 100644
index 00000000..371e127f
--- /dev/null
+++ b/app/src/main/res/values-w600dp/integers.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <integer name="grid_view_span_count">3</integer>
+</resources> \ No newline at end of file
diff --git a/app/src/main/res/values-w800dp/integers.xml b/app/src/main/res/values-w800dp/integers.xml
new file mode 100644
index 00000000..782d4488
--- /dev/null
+++ b/app/src/main/res/values-w800dp/integers.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <integer name="grid_view_span_count">4</integer>
+</resources> \ No newline at end of file
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index c4f67bfe..8110d9f9 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">编辑</string>
<string name="action_edit_save">保存</string>
<string name="simple_about">关于</string>
+ <string name="simple_accounts">账号</string>
<string name="simple_bold">粗体</string>
<string name="simple_link">链接</string>
<string name="simple_italic">斜体</string>
@@ -140,6 +141,10 @@
<string name="error_dialog_insufficient_storage">您的 Nextcloud 实例已经没有可用的存储空间了。请删除一些文件来允许本地的变更同步到云。</string>
<string name="error_dialog_contact_us">如果问题持续存在,请不要犹豫来联系我们。您可以在侧边栏的 “关于” 部分找到我们的联系信息。</string>
<string name="error_dialog_we_need_info">我们需要以下技术信息来帮助您:</string>
+ <string name="simple_security">安全</string>
+ <string name="simple_appearance">外观</string>
+ <string name="simple_synchronization">同步</string>
+ <string name="manage_accounts">管理账号</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
<item>以编辑模式打开</item>
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index 4661cd19..3acdbb08 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -13,6 +13,7 @@
<string name="simple_edit">修改</string>
<string name="action_edit_save">儲存</string>
<string name="simple_about">關於</string>
+ <string name="simple_accounts">帳戶</string>
<string name="simple_bold">粗體</string>
<string name="simple_link">連結</string>
<string name="simple_italic">斜體</string>
@@ -127,6 +128,9 @@
<string name="simple_checkbox">核取方塊</string>
<string name="unlock_notes">解鎖筆記</string>
<string name="simple_beta">Beta 測試版</string>
+ <string name="simple_security">安全性</string>
+ <string name="simple_synchronization">同步</string>
+ <string name="manage_accounts">帳戶管理</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
<item>以編輯模式開啟</item>
diff --git a/app/src/main/res/values/booleans.xml b/app/src/main/res/values/booleans.xml
new file mode 100644
index 00000000..c47017c7
--- /dev/null
+++ b/app/src/main/res/values/booleans.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <bool name="isDayMode">true</bool>
+</resources>
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index db265c9f..c9c94fde 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -2,11 +2,16 @@
<resources>
<!-- Colors -->
- <color name="primary">#0082C9</color>
- <color name="primary_dark">#286090</color>
+ <color name="primary">#ffffff</color>
+ <color name="accent">#121212</color>
+
+ <color name="defaultBrand">#0082C9</color>
+
+ <color name="cursorHandles">#555566</color>
+ <color name="defaultTextHighlightBackground">#2233334a</color>
<color name="bg_highlighted">#eee</color>
- <color name="bg_normal">#ffffff</color>
+ <color name="bg_normal">@color/primary</color>
<color name="bg_attention">#d40000</color>
<color name="bg_warning">#ffcc00</color>
<color name="fg_default">#000000</color>
@@ -17,7 +22,7 @@
<color name="icon_color_default">#757575</color>
- <color name="bg_search_primary">@color/primary</color>
+ <color name="bg_search_primary">@color/defaultBrand</color>
<color name="bg_search_secondary">#eee</color>
<color name="widget_background">#dfffffff</color>
@@ -25,7 +30,7 @@
<color name="widget_fg_contrast">#ffffff</color>
<color name="category_background">@color/bg_normal</color>
- <color name="category_border">@color/primary</color>
+ <color name="category_border">@color/defaultBrand</color>
<!-- Dark Theme -->
<!-- Defined here until appwidgets can use night/colors -->
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index b615b358..3ffa7d38 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -5,6 +5,13 @@
<dimen name="spacer_1hx">4dp</dimen>
<dimen name="spacer_1x">8dp</dimen>
<dimen name="spacer_2x">16dp</dimen>
+ <dimen name="spacer_3x">24dp</dimen>
+ <dimen name="spacer_5x">40dp</dimen>
+ <dimen name="spacer_6x">48dp</dimen>
+
+ <!-- Drawer header -->
+ <dimen name="drawer_header_height">100dp</dimen>
+ <dimen name="drawer_header_logo_size">42dp</dimen>
<!-- Buttons -->
<dimen name="button_padding">@dimen/spacer_2x</dimen>
diff --git a/app/src/main/res/values/integers.xml b/app/src/main/res/values/integers.xml
new file mode 100644
index 00000000..ade19fa3
--- /dev/null
+++ b/app/src/main/res/values/integers.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <integer name="grid_view_span_count">1</integer>
+</resources> \ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 2593f4e5..91e560b3 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -14,6 +14,7 @@
<string name="simple_edit">Edit</string>
<string name="action_edit_save">Save</string>
<string name="simple_about">About</string>
+ <string name="simple_accounts">Accounts</string>
<string name="simple_bold">Bold</string>
<string name="simple_link">Link</string>
<string name="simple_italic">Italic</string>
@@ -29,6 +30,9 @@
<string name="menu_preview">Preview</string>
<string name="menu_share">Share</string>
+ <string name="search_in_category">Search in %1$s</string>
+ <string name="search_in_all">Search all notes</string>
+
<string name="change_category_title">Choose a category</string>
<string name="listview_updated_today">Today</string>
@@ -113,9 +117,12 @@
<string name="pref_key_note_mode" translatable="false">noteMode</string>
<string name="pref_key_theme" translatable="false">darkTheme</string>
<string name="pref_key_font" translatable="false">font</string>
+ <string name="pref_key_branding" translatable="false">branding</string>
+ <string name="pref_key_gridview" translatable="false">gridview</string>
<string name="pref_key_font_size" translatable="false">fontSize</string>
<string name="pref_key_wifi_only" translatable="false">wifiOnly</string>
<string name="pref_key_lock" translatable="false">lock</string>
+ <string name="pref_category_security" translatable="false">security</string>
<string name="pref_key_last_note_mode" translatable="false">lastNoteMode</string>
<string name="pref_key_background_sync" translatable="false">backgroundSync</string>
<string name="pref_value_mode_edit" translatable="false">edit</string>
@@ -185,6 +192,15 @@
<string name="added_content">Added "%1$s"</string>
<string name="shared_text_empty">Shared text was empty</string>
<string name="append_to_note">Append to note</string>
+ <string name="settings_branding">Branding</string>
+ <string name="settings_gridview">Grid view 🆕</string>
+ <string name="simple_security">Security</string>
+ <string name="simple_appearance">Appearance</string>
+ <string name="simple_synchronization">Synchronization</string>
+ <string name="simple_behavior">Behavior</string>
+ <string name="share_multiple">Share content of %1$d notes</string>
+ <string name="manage_accounts">Manage accounts</string>
+ <string name="action_formatting_help">Formatting</string>
<!-- Array: note modes -->
<string-array name="noteMode_entries">
@@ -219,4 +235,71 @@
<item quantity="one">%d selected</item>
<item quantity="other">%d selected</item>
</plurals>
+
+ <!-- Formatting help -->
+
+ <string name="formatting_help_title" translatable="false"># %1$s</string>
+ <string name="formatting_help_title_level_3" translatable="false">### %1$s</string>
+ <string name="formatting_help_divider" translateable="false">---</string>
+ <string name="formatting_help_codefence_inline" translateable="false">`%1$s`</string>
+ <string name="formatting_help_codefence_inline_escaped" translateable="false">\\`%1$s\\`</string>
+ <string name="formatting_help_codefence" translateable="false">```</string>
+ <string name="formatting_help_codefence_escaped" translatable="false">\\`\\`\\`</string>
+ <string name="formatting_help_javascript_1" translatable="false">if (isAwesome){</string>
+ <string name="formatting_help_javascript_2" translatable="false">return true</string>
+ <string name="formatting_help_javascript_3" translatable="false">}</string>
+ <string name="formatting_help_codefence_javascript_escaped" translatable="false">\\`\\`\\`javascript</string>
+ <string name="formatting_help_codefence_javascript" translateable="false">```javascript</string>
+ <string name="formatting_help_code_javascript_inline" translatable="false">var example = true</string>
+ <string name="formatting_help_ol" translatable="false">%1$d. %2$s</string>
+ <string name="formatting_help_ul" translatable="false">- %1$s</string>
+ <string name="formatting_help_checkbox_checked" translatable="false">- [x] %1$s</string>
+ <string name="formatting_help_checkbox_unchecked" translatable="false">- [ ] %1$s</string>
+ <string name="formatting_help_quote" translatable="false">&gt; %1$s</string>
+ <string name="formatting_help_quote_keyword" translatable="false">&gt;</string>
+ <string name="formatting_help_strike_through" translatable="false">~~</string>
+ <string name="formatting_help_bold" translatable="false">**</string>
+ <string name="formatting_help_italic" translatable="false">*</string>
+
+ <string name="formatting_help_cbf_title">Context based formatting</string>
+ <string name="formatting_help_cbf_body_1">A major design goal of the Notes app is to provide a distraction free tool. Though you will be able to format your texts with Markdown. For various of the below mentioned examples, you can use shortcuts so you can format your notes without typing in the codes below.</string>
+ <string name="formatting_help_cbf_body_2">Just select a range of text or tap on your cursor at any position and you will get a popup menu which contains next to the default entries %1$s, %2$s, %3$s entries like %4$s or %5$s.</string>
+
+ <string name="formatting_help_text_title">Text</string>
+ <string name="formatting_help_text_body">It\'s very easy to make some words %1$sbold%1$s and other words %2$sitalic%2$s with Markdown. You can %3$sstrike%3$s some words through and even [link to Nextcloud](https://nextcloud.com).</string>
+
+ <string name="formatting_help_lists_title">Lists</string>
+ <string name="formatting_help_lists_body_1">Sometimes you want numbered lists:</string>
+ <string name="formatting_help_lists_body_2">One</string>
+ <string name="formatting_help_lists_body_3">Two</string>
+ <string name="formatting_help_lists_body_4">Three</string>
+ <string name="formatting_help_lists_body_5">Sometimes you want bullet points:</string>
+ <string name="formatting_help_lists_body_6">Start a line with a dash</string>
+ <string name="formatting_help_lists_body_7">And if you have sub points, put two spaces before the dash or star:</string>
+ <string name="formatting_help_lists_body_8">Like this</string>
+ <string name="formatting_help_lists_body_9">And this</string>
+
+ <string name="formatting_help_checkboxes_title">Checkboxes</string>
+ <string name="formatting_help_checkboxes_body_1">To create a checkbox, use a list followed by brackets</string>
+ <string name="formatting_help_checkboxes_body_2">Item 1</string>
+ <string name="formatting_help_checkboxes_body_3">Item 2</string>
+
+ <string name="formatting_help_structured_documents_title">Structured documents</string>
+ <string name="formatting_help_structured_documents_body_1">Sometimes it\'s useful to have different levels of headings to structure your documents. Start lines with a %1$s to create headings. Multiple %2$s in a row denote smaller heading sizes.</string>
+ <string name="formatting_help_structured_documents_body_2">This is a third-tier heading</string>
+ <string name="formatting_help_structured_documents_body_3">You can use one %1$s all the way up to %2$s six for different heading sizes.</string>
+ <string name="formatting_help_structured_documents_body_4">If you\'d like to quote someone, use the %1$s character before the line:</string>
+ <string name="formatting_help_structured_documents_body_5">Imagination is more important than knowledge. Knowledge is limited. Imagination encircles the world.</string>
+ <string name="formatting_help_structured_documents_body_6">- Albert Einstein</string>
+
+ <string name="formatting_help_code_title">Code</string>
+ <string name="formatting_help_code_body_1">There are many different ways to style code with Markdown. If you have inline code blocks, wrap them in backticks:</string>
+ <string name="formatting_help_code_body_2">Markdown also supports something called code fencing, which allows for multiple lines without indentation:</string>
+ <string name="formatting_help_code_body_3">And if you\'d like to use syntax highlighting, include the language:</string>
+
+ <string name="formatting_help_unsupported_title">Unsupported</string>
+ <string name="formatting_help_unsupported_body_1">While we try to continuously improve the support for Markdown, there are a few features which are not yet supported by Notes:</string>
+ <string name="formatting_help_unsupported_body_2">Tables</string>
+ <string name="formatting_help_unsupported_body_3">Images</string>
+ <string name="formatting_help_unsupported_body_4">If you are interested in contributing support for one of those features, get in contact with us via GitHub or E-Mail.</string>
</resources>
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index edf7acee..ffce1eed 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,16 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="AppTheme" parent="@style/Theme.AppCompat.DayNight.NoActionBar">
+ <style name="BaseTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar.Bridge">
<item name="colorPrimary">@color/primary</item>
- <item name="colorPrimaryDark">@color/primary</item>
- <item name="colorAccent">@color/primary</item>
+ <item name="colorAccent">@color/accent</item>
+ <item name="android:actionModeBackground">?attr/colorPrimary</item>
+ <item name="colorControlNormal">?attr/colorAccent</item>
<item name="windowActionModeOverlay">true</item>
- <item name="android:colorBackground">@color/bg_normal</item>
</style>
- <style name="toolbarStyle" parent="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
- <item name="colorAccent">#fff</item>
+ <style name="AppTheme" parent="BaseTheme" />
+
+ <style name="textViewStyle">
+ <item name="colorAccent">@color/cursorHandles</item>
+ <item name="android:textColorHighlight">@color/defaultTextHighlightBackground</item>
</style>
<style name="fab">
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index c0d1d5ac..3050e2a8 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -1,66 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
- <SwitchPreference
- android:defaultValue="@string/pref_value_lock"
- android:icon="@drawable/ic_lock_grey600_24dp"
- android:key="@string/pref_key_lock"
- android:layout="@layout/item_pref"
- android:summary="@string/simple_beta"
- android:title="@string/settings_lock" />
+ <it.niedermann.owncloud.notes.branding.BrandedPreferenceCategory
+ app:layout="@layout/item_preference_category"
+ app:title="@string/simple_synchronization">
- <ListPreference
- android:defaultValue="@string/pref_value_mode_edit"
- android:entries="@array/noteMode_entries"
- android:entryValues="@array/noteMode_values"
- android:icon="@drawable/ic_remove_red_eye_grey_24dp"
- android:key="@string/pref_key_note_mode"
- android:layout="@layout/item_pref"
- android:summary="%s"
- android:title="@string/settings_note_mode" />
+ <it.niedermann.owncloud.notes.branding.BrandedSwitchPreference
+ android:defaultValue="@string/pref_value_wifi_and_mobile"
+ android:icon="@drawable/ic_network_wifi_grey600_24dp"
+ android:key="@string/pref_key_wifi_only"
+ android:layout="@layout/item_pref"
+ android:title="@string/settings_wifi_only" />
- <ListPreference
- android:defaultValue="@string/pref_value_theme_system_default"
- android:entries="@array/darkmode_entries"
- android:entryValues="@array/darkMode_values"
- android:summary="%s"
- android:icon="@drawable/ic_brightness_2_grey_24dp"
- android:key="@string/pref_key_theme"
- android:layout="@layout/item_pref"
- android:title="@string/settings_theme_title" />
+ <ListPreference
+ android:defaultValue="@string/pref_value_sync_off"
+ android:entries="@array/sync_entries"
+ android:entryValues="@array/sync_values"
+ android:icon="@drawable/ic_sync_black_24dp"
+ android:key="@string/pref_key_background_sync"
+ android:layout="@layout/item_pref"
+ android:summary="%s"
+ android:title="@string/settings_background_sync" />
+ </it.niedermann.owncloud.notes.branding.BrandedPreferenceCategory>
- <SwitchPreference
- android:defaultValue="@string/pref_value_font_normal"
- android:icon="@drawable/ic_text_format_grey600_24dp"
- android:key="@string/pref_key_font"
- android:layout="@layout/item_pref"
- android:title="@string/settings_font_title" />
+ <it.niedermann.owncloud.notes.branding.BrandedPreferenceCategory
+ app:layout="@layout/item_preference_category"
+ app:title="@string/simple_appearance">
- <ListPreference
- android:defaultValue="@string/pref_value_font_size_medium"
- android:entries="@array/fontSize_entries"
- android:entryValues="@array/fontSize_values"
- android:icon="@drawable/ic_format_size_black_24dp"
- android:key="@string/pref_key_font_size"
- android:layout="@layout/item_pref"
- android:summary="%s"
- android:title="@string/settings_font_size" />
+ <ListPreference
+ android:defaultValue="@string/pref_value_theme_system_default"
+ android:entries="@array/darkmode_entries"
+ android:entryValues="@array/darkMode_values"
+ android:icon="@drawable/ic_brightness_2_grey_24dp"
+ android:key="@string/pref_key_theme"
+ android:layout="@layout/item_pref"
+ android:summary="%s"
+ android:title="@string/settings_theme_title" />
- <SwitchPreference
- android:defaultValue="@string/pref_value_wifi_and_mobile"
- android:icon="@drawable/ic_network_wifi_grey600_24dp"
- android:key="@string/pref_key_wifi_only"
- android:layout="@layout/item_pref"
- android:title="@string/settings_wifi_only" />
+ <it.niedermann.owncloud.notes.branding.BrandedSwitchPreference
+ android:defaultValue="true"
+ android:icon="@drawable/ic_color_lens_grey600_24dp"
+ android:key="@string/pref_key_branding"
+ android:layout="@layout/item_pref"
+ android:title="@string/settings_branding" />
- <ListPreference
- android:defaultValue="@string/pref_value_sync_off"
- android:entries="@array/sync_entries"
- android:entryValues="@array/sync_values"
- android:icon="@drawable/ic_sync_black_24dp"
- android:key="@string/pref_key_background_sync"
- android:layout="@layout/item_pref"
- android:summary="%s"
- android:title="@string/settings_background_sync" />
+ <it.niedermann.owncloud.notes.branding.BrandedSwitchPreference
+ android:icon="@drawable/ic_baseline_dashboard_24"
+ android:key="@string/pref_key_gridview"
+ android:layout="@layout/item_pref"
+ android:summary="@string/simple_beta"
+ android:title="@string/settings_gridview" />
+
+ </it.niedermann.owncloud.notes.branding.BrandedPreferenceCategory>
+
+ <it.niedermann.owncloud.notes.branding.BrandedPreferenceCategory
+ app:layout="@layout/item_preference_category"
+ app:title="@string/simple_behavior">
+ <it.niedermann.owncloud.notes.branding.BrandedSwitchPreference
+ android:defaultValue="@string/pref_value_font_normal"
+ android:icon="@drawable/ic_text_format_grey600_24dp"
+ android:key="@string/pref_key_font"
+ android:layout="@layout/item_pref"
+ android:title="@string/settings_font_title" />
+ <ListPreference
+ android:defaultValue="@string/pref_value_mode_edit"
+ android:entries="@array/noteMode_entries"
+ android:entryValues="@array/noteMode_values"
+ android:icon="@drawable/ic_remove_red_eye_grey_24dp"
+ android:key="@string/pref_key_note_mode"
+ android:layout="@layout/item_pref"
+ android:summary="%s"
+ android:title="@string/settings_note_mode" />
+
+ <ListPreference
+ android:defaultValue="@string/pref_value_font_size_medium"
+ android:entries="@array/fontSize_entries"
+ android:entryValues="@array/fontSize_values"
+ android:icon="@drawable/ic_format_size_black_24dp"
+ android:key="@string/pref_key_font_size"
+ android:layout="@layout/item_pref"
+ android:summary="%s"
+ android:title="@string/settings_font_size" />
+ </it.niedermann.owncloud.notes.branding.BrandedPreferenceCategory>
+
+ <it.niedermann.owncloud.notes.branding.BrandedPreferenceCategory
+ android:key="@string/pref_category_security"
+ app:layout="@layout/item_preference_category"
+ app:title="@string/simple_security">
+ <it.niedermann.owncloud.notes.branding.BrandedSwitchPreference
+ android:defaultValue="@string/pref_value_lock"
+ android:icon="@drawable/ic_lock_grey600_24dp"
+ android:key="@string/pref_key_lock"
+ android:layout="@layout/item_pref"
+ android:summary="@string/simple_beta"
+ android:title="@string/settings_lock" />
+ </it.niedermann.owncloud.notes.branding.BrandedPreferenceCategory>
</PreferenceScreen>
diff --git a/fastlane/metadata/android/de-DE/changelogs/39.txt b/fastlane/metadata/android/de-DE/changelogs/39.txt
deleted file mode 100644
index 9b7726c8..00000000
--- a/fastlane/metadata/android/de-DE/changelogs/39.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-- In-Notiz-Suche (#106, #400)
-- Neue Einstellungsmöglichkeit: Monospace-Schriftart verwenden (#359)
-- Kontextbasierte Formatierung (#363)
-- Migration zu AndroidX (#492, #500)
-- Trennlinien in Listenansicht entfernt (#498, #524)
-- Markdown-Util benötigt hardcodierte Farbe für unsortierte Listen (#517)
diff --git a/fastlane/metadata/android/de-DE/changelogs/40.txt b/fastlane/metadata/android/de-DE/changelogs/40.txt
deleted file mode 100644
index cee63a8d..00000000
--- a/fastlane/metadata/android/de-DE/changelogs/40.txt
+++ /dev/null
@@ -1 +0,0 @@
-- Neue Einstellungsmöglichkeit: Nur bei WLAN synchronisieren (#519)
diff --git a/fastlane/metadata/android/de-DE/changelogs/41.txt b/fastlane/metadata/android/de-DE/changelogs/41.txt
deleted file mode 100644
index 468eaf8d..00000000
--- a/fastlane/metadata/android/de-DE/changelogs/41.txt
+++ /dev/null
@@ -1 +0,0 @@
-- Theme-Wechsel muss die MainActivity komplett neu erstellen (#529)
diff --git a/fastlane/metadata/android/de-DE/changelogs/42.txt b/fastlane/metadata/android/de-DE/changelogs/42.txt
deleted file mode 100644
index 0a47a4e3..00000000
--- a/fastlane/metadata/android/de-DE/changelogs/42.txt
+++ /dev/null
@@ -1 +0,0 @@
-- Übersetzungsfehler behoben (#536, #534)
diff --git a/fastlane/metadata/android/de-DE/changelogs/43.txt b/fastlane/metadata/android/de-DE/changelogs/43.txt
deleted file mode 100644
index 9d3cc78c..00000000
--- a/fastlane/metadata/android/de-DE/changelogs/43.txt
+++ /dev/null
@@ -1 +0,0 @@
-- Übersetzungen für da, nb, pl, sl, sr und sv aktualisiert (#541)
diff --git a/fastlane/metadata/android/de-DE/full_description.txt b/fastlane/metadata/android/de-DE/full_description.txt
deleted file mode 100644
index 600211f4..00000000
--- a/fastlane/metadata/android/de-DE/full_description.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-Companion App für Nextcloud Notes.
-
-🚀 Features
-
- * Multiple accounts 👥
- * Create, edit, share, search and delete notes 📝
- * Share text and links as new note into the app 📩
- * Toggling checkboxes in view mode ✅
- * Mark notes as favorite ⭐
- * Bulk delete 🗑️
- * In-note search 🔍
- * Render MarkDown ✨
- * Context based formatting 🧰
- * Dark mode 🌙
- * Einzel-Notizen- und Listen-Widget 📊
- * Translated in many languages 🌎
-
-
-🔗 Requirements
-
- * Nextcloud (https://nextcloud.com/)
- * Nextcloud Notes app (https://apps.nextcloud.com/apps/notes)
- * Nextcloud Android client (https://play.google.com/store/apps/details?id=com.nextcloud.client)
-
-
-👨‍👩‍👦 Join the team
-
- * https://github.com/stefan-niedermann/nextcloud-notes#family-join-the-team \ No newline at end of file
diff --git a/fastlane/metadata/android/de-DE/images/icon.png b/fastlane/metadata/android/de-DE/images/icon.png
deleted file mode 100644
index 9daba0f0..00000000
--- a/fastlane/metadata/android/de-DE/images/icon.png
+++ /dev/null
Binary files differ
diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/1.png b/fastlane/metadata/android/de-DE/images/phoneScreenshots/1.png
deleted file mode 100644
index 75eb46fa..00000000
--- a/fastlane/metadata/android/de-DE/images/phoneScreenshots/1.png
+++ /dev/null
Binary files differ
diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/2.png b/fastlane/metadata/android/de-DE/images/phoneScreenshots/2.png
deleted file mode 100644
index f9a56bb4..00000000
--- a/fastlane/metadata/android/de-DE/images/phoneScreenshots/2.png
+++ /dev/null
Binary files differ
diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/3.png b/fastlane/metadata/android/de-DE/images/phoneScreenshots/3.png
deleted file mode 100644
index b4ef4a64..00000000
--- a/fastlane/metadata/android/de-DE/images/phoneScreenshots/3.png
+++ /dev/null
Binary files differ
diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/4.png b/fastlane/metadata/android/de-DE/images/phoneScreenshots/4.png
deleted file mode 100644
index e8517e3c..00000000
--- a/fastlane/metadata/android/de-DE/images/phoneScreenshots/4.png
+++ /dev/null
Binary files differ
diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/5.png b/fastlane/metadata/android/de-DE/images/phoneScreenshots/5.png
deleted file mode 100644
index 6a294100..00000000
--- a/fastlane/metadata/android/de-DE/images/phoneScreenshots/5.png
+++ /dev/null
Binary files differ
diff --git a/fastlane/metadata/android/de-DE/short_description.txt b/fastlane/metadata/android/de-DE/short_description.txt
deleted file mode 100644
index 02ba2042..00000000
--- a/fastlane/metadata/android/de-DE/short_description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Lesen und Bearbeiten Sie Notizen in Nextcloud
diff --git a/fastlane/metadata/android/de-DE/title.txt b/fastlane/metadata/android/de-DE/title.txt
deleted file mode 100644
index 07628e5d..00000000
--- a/fastlane/metadata/android/de-DE/title.txt
+++ /dev/null
@@ -1 +0,0 @@
-Nextcloud Notes für Android
diff --git a/fastlane/metadata/android/en-US/changelogs/2012002.txt b/fastlane/metadata/android/en-US/changelogs/2012002.txt
new file mode 100644
index 00000000..18623e2e
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/2012002.txt
@@ -0,0 +1,5 @@
+- 📝 New app icon
+- 🐞 Note list widget should create a note in it's respective category (#817)
+- 🐞 "Link" functionality in text menu causes error (#841)
+- 🔧 Refactored some internals as groundwork for future development (#814 @Isaac-Graham, #754)
+- 🔧 Updated Single-Sign-On library to 0.5.1 and Glide to 4.11.0 \ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/2013000.txt b/fastlane/metadata/android/en-US/changelogs/2013000.txt
index 6de1994b..d19ccb8e 100644
--- a/fastlane/metadata/android/en-US/changelogs/2013000.txt
+++ b/fastlane/metadata/android/en-US/changelogs/2013000.txt
@@ -1,2 +1,6 @@
-- Note list widget should create a note in it's respective category (#817)
-- "Link" functionality in text menu causes error (#841) \ No newline at end of file
+- ✨ Redesign of UI based on the future Nextcloud Android app
+- 🎨 Branding of the Nextcloud instance can be applied (#762)
+- 📩 Bulk share content of multiple notes
+- 🔧 Move note list widget preferences to database (#832)
+- 🐞 Searching for ? character crashes the app (#846)
+- 🐞 Fix NullPointerException when server does not respond theming information or other capabilities (#854) \ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/2013001.txt b/fastlane/metadata/android/en-US/changelogs/2013001.txt
new file mode 100644
index 00000000..d19ccb8e
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/2013001.txt
@@ -0,0 +1,6 @@
+- ✨ Redesign of UI based on the future Nextcloud Android app
+- 🎨 Branding of the Nextcloud instance can be applied (#762)
+- 📩 Bulk share content of multiple notes
+- 🔧 Move note list widget preferences to database (#832)
+- 🐞 Searching for ? character crashes the app (#846)
+- 🐞 Fix NullPointerException when server does not respond theming information or other capabilities (#854) \ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/2013002.txt b/fastlane/metadata/android/en-US/changelogs/2013002.txt
new file mode 100644
index 00000000..d19ccb8e
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/2013002.txt
@@ -0,0 +1,6 @@
+- ✨ Redesign of UI based on the future Nextcloud Android app
+- 🎨 Branding of the Nextcloud instance can be applied (#762)
+- 📩 Bulk share content of multiple notes
+- 🔧 Move note list widget preferences to database (#832)
+- 🐞 Searching for ? character crashes the app (#846)
+- 🐞 Fix NullPointerException when server does not respond theming information or other capabilities (#854) \ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/2013003.txt b/fastlane/metadata/android/en-US/changelogs/2013003.txt
new file mode 100644
index 00000000..d19ccb8e
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/2013003.txt
@@ -0,0 +1,6 @@
+- ✨ Redesign of UI based on the future Nextcloud Android app
+- 🎨 Branding of the Nextcloud instance can be applied (#762)
+- 📩 Bulk share content of multiple notes
+- 🔧 Move note list widget preferences to database (#832)
+- 🐞 Searching for ? character crashes the app (#846)
+- 🐞 Fix NullPointerException when server does not respond theming information or other capabilities (#854) \ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/2014000.txt b/fastlane/metadata/android/en-US/changelogs/2014000.txt
new file mode 100644
index 00000000..31662e94
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/2014000.txt
@@ -0,0 +1,4 @@
+- 📌 Remember last scrolling position per note (#227)
+- 🎨 Apply brand to widget color
+- ❓ "Help: format" option in the menu (#116)
+- 🐞 Fix toggling checkboxes when note contains codefences with empty lines \ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/2014001.txt b/fastlane/metadata/android/en-US/changelogs/2014001.txt
new file mode 100644
index 00000000..81298cd9
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/2014001.txt
@@ -0,0 +1,2 @@
+- ✨ Title and category should be centered if no excerpt is given (#374)
+- 🐞 Crash when entering not-existing category (#863) \ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/2015000.txt b/fastlane/metadata/android/en-US/changelogs/2015000.txt
new file mode 100644
index 00000000..41cd1acc
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/2015000.txt
@@ -0,0 +1,15 @@
+2.15.0
+
+- 🆕 Grid view (beta)
+
+2.14.1
+
+- ✨ Title and category should be centered if no excerpt is given (#374)
+- 🐞 Crash when entering not-existing category (#863)
+
+2.14.0
+
+- 📌 Remember last scrolling position per note (#227)
+- 🎨 Apply brand to widget color
+- ❓ "Help: format" option in the menu (#116)
+- 🐞 Fix toggling checkboxes when note contains codefences with empty lines \ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/images/icon.png b/fastlane/metadata/android/en-US/images/icon.png
index 9daba0f0..c1e67d8b 100644
--- a/fastlane/metadata/android/en-US/images/icon.png
+++ b/fastlane/metadata/android/en-US/images/icon.png
Binary files differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png
index cd9103e3..c4651432 100644
--- a/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png
+++ b/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png
Binary files differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png
index ec1fa1af..5b23d5e1 100644
--- a/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png
+++ b/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png
Binary files differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png
index c0cbe195..1866ce54 100644
--- a/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png
+++ b/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png
Binary files differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png
index 04cb27c7..036290b9 100644
--- a/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png
+++ b/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png
Binary files differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png
index ef2e1c1e..45757524 100644
--- a/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png
+++ b/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png
Binary files differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png
deleted file mode 100644
index f10bfe5d..00000000
--- a/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png
+++ /dev/null
Binary files differ
diff --git a/fastlane/metadata/android/en-US/title.txt b/fastlane/metadata/android/en-US/title.txt
index 1c4ebbf2..e8a4d1e5 100644
--- a/fastlane/metadata/android/en-US/title.txt
+++ b/fastlane/metadata/android/en-US/title.txt
@@ -1 +1 @@
-Nextcloud Notes for Android
+Nextcloud Notes