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

github.com/stefan-niedermann/nextcloud-deck.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorStefan Niedermann <info@niedermann.it>2020-04-13 14:56:40 +0300
committerStefan Niedermann <info@niedermann.it>2020-04-13 14:56:40 +0300
commitcd413007944da05502e9b7cdcc615cecb9202b02 (patch)
tree1aa8051322eac9b7b828d01ca4189ff17a06e8ba /app
parent83860875c6111a2476d37f3ff046ca933e473707 (diff)
parentec7aca7c99c678551227bd51861ad8e661cd3718 (diff)
Merge branch 'master' into push-notifications-receiver
Diffstat (limited to 'app')
-rw-r--r--app/build.gradle14
-rw-r--r--app/play/release/output.json2
-rw-r--r--app/src/dev/res/drawable/ic_launcher_foreground.xml41
-rw-r--r--app/src/dev/res/xml/shortcuts.xml15
-rw-r--r--app/src/main/AndroidManifest.xml15
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/Application.java90
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/api/DeckAPI.java2
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/api/JsonToEntityParser.java41
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/model/Account.java74
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/model/Attachment.java3
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/model/Board.java3
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/model/Card.java36
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/model/full/FullCard.java2
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/model/ocs/Capabilities.java37
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/model/ocs/Version.java38
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/SyncManager.java16
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/ServerAdapter.java17
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DataBaseAdapter.java4
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DeckDatabase.java13
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/BoardDao.java3
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/CardDataProvider.java5
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/ImportAccountActivity.java2
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/MainActivity.java142
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/SelectCardActivity.java6
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/about/AboutActivity.java (renamed from app/src/main/java/it/niedermann/nextcloud/deck/ui/AboutActivity.java)19
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/about/AboutFragmentCreditsTab.java17
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/about/AboutFragmentLicenseTab.java27
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/attachments/AttachmentsActivity.java (renamed from app/src/main/java/it/niedermann/nextcloud/deck/ui/AttachmentsActivity.java)3
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/board/DeleteBoardDialogFragment.java64
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/board/DeleteBoardListener.java7
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/board/EditBoardDialogFragment.java19
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/board/accesscontrol/AccessControlDialogFragment.java15
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/Branded.java7
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedActivity.java168
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedAlertDialogBuilder.java44
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedDeleteAlertDialogBuilder.java26
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedDialogFragment.java20
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedSwitchPreference.java110
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardAdapter.java107
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/EditActivity.java (renamed from app/src/main/java/it/niedermann/nextcloud/deck/ui/EditActivity.java)256
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentAdapter.java23
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java24
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/DeleteAttachmentDialogFragment.java67
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CardCommentsEditDialogFragment.java13
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CardCommentsFragment.java24
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/details/CardDetailsFragment.java35
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/CrossTabDragAndDrop.java223
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/DragAndDropAdapter.java14
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/DragAndDropModel.java8
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/DragAndDropTab.java12
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/DragAndDropUtil.java18
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/DraggedItemLocalState.java95
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/ItemMovedByDragListener.java5
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/ScrollHelper.java46
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/AbstractAdapter.java41
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/AccountAdapter.java51
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/BoardAdapter.java48
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/PrepareCreateActivity.java197
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/SelectedListener.java13
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/StackAdapter.java46
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/SettingsActivity.java (renamed from app/src/main/java/it/niedermann/nextcloud/deck/ui/SettingsActivity.java)17
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/SettingsFragment.java32
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/DeleteStackDialogFragment.java64
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/DeleteStackListener.java5
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/EditStackDialogFragment.java18
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/StackFragment.java2
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/tiles/EditCardTileService.java12
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/view/LabelChip.java53
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/view/LabelLayout.java83
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/util/ColorUtil.java41
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/util/DeleteDialogBuilder.java14
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/util/DrawerMenuUtil.java32
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/util/ExceptionUtil.java33
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/util/TabLayoutHelper.java456
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/util/ViewUtil.java12
-rw-r--r--app/src/main/res/drawable/ic_check_grey600_24dp.xml5
-rw-r--r--app/src/main/res/layout/activity_edit.xml42
-rw-r--r--app/src/main/res/layout/activity_exception.xml27
-rw-r--r--app/src/main/res/layout/activity_import_account.xml2
-rw-r--r--app/src/main/res/layout/activity_main.xml7
-rw-r--r--app/src/main/res/layout/activity_prepare_create.xml90
-rw-r--r--app/src/main/res/layout/dialog_add_comment.xml2
-rw-r--r--app/src/main/res/layout/dialog_board_create.xml2
-rw-r--r--app/src/main/res/layout/dialog_board_share.xml4
-rw-r--r--app/src/main/res/layout/dialog_stack_create.xml2
-rw-r--r--app/src/main/res/layout/fragment_about_contribution_tab.xml2
-rw-r--r--app/src/main/res/layout/fragment_about_credits_tab.xml4
-rw-r--r--app/src/main/res/layout/fragment_about_license_tab.xml8
-rw-r--r--app/src/main/res/layout/fragment_card_edit_tab_activities.xml2
-rw-r--r--app/src/main/res/layout/fragment_card_edit_tab_attachments.xml2
-rw-r--r--app/src/main/res/layout/fragment_card_edit_tab_comments.xml14
-rw-r--r--app/src/main/res/layout/fragment_card_edit_tab_details.xml36
-rw-r--r--app/src/main/res/layout/fragment_stack.xml4
-rw-r--r--app/src/main/res/layout/item_access_control.xml24
-rw-r--r--app/src/main/res/layout/item_access_control_owner.xml18
-rw-r--r--app/src/main/res/layout/item_activity.xml6
-rw-r--r--app/src/main/res/layout/item_attachment_default.xml8
-rw-r--r--app/src/main/res/layout/item_autocomplete_dropdown.xml6
-rw-r--r--app/src/main/res/layout/item_board.xml2
-rw-r--r--app/src/main/res/layout/item_card.xml189
-rw-r--r--app/src/main/res/layout/item_comment.xml8
-rw-r--r--app/src/main/res/layout/item_prepare_create_account.xml45
-rw-r--r--app/src/main/res/layout/item_prepare_create_board.xml32
-rw-r--r--app/src/main/res/layout/item_prepare_create_stack.xml17
-rw-r--r--app/src/main/res/layout/nav_header_main.xml34
-rw-r--r--app/src/main/res/layout/widget_color_chooser.xml2
-rw-r--r--app/src/main/res/layout/widget_empty_content_view.xml10
-rw-r--r--app/src/main/res/values-cs-rCZ/strings.xml5
-rw-r--r--app/src/main/res/values-de/strings.xml5
-rw-r--r--app/src/main/res/values-el/strings.xml5
-rw-r--r--app/src/main/res/values-es/strings.xml2
-rw-r--r--app/src/main/res/values-eu/strings.xml5
-rw-r--r--app/src/main/res/values-fr/strings.xml2
-rw-r--r--app/src/main/res/values-gl/strings.xml5
-rw-r--r--app/src/main/res/values-it/strings.xml5
-rw-r--r--app/src/main/res/values-night/colors.xml4
-rw-r--r--app/src/main/res/values-nl/strings.xml5
-rw-r--r--app/src/main/res/values-pl/strings.xml7
-rw-r--r--app/src/main/res/values-pt-rBR/strings.xml4
-rw-r--r--app/src/main/res/values-ru/strings.xml2
-rw-r--r--app/src/main/res/values-sk-rSK/strings.xml4
-rw-r--r--app/src/main/res/values-sl/strings.xml4
-rw-r--r--app/src/main/res/values-sr/strings.xml25
-rw-r--r--app/src/main/res/values-sv/strings.xml2
-rw-r--r--app/src/main/res/values-tr/strings.xml25
-rw-r--r--app/src/main/res/values-w820dp/dimens.xml6
-rw-r--r--app/src/main/res/values-zh-rTW/strings.xml7
-rw-r--r--app/src/main/res/values/colors.xml4
-rw-r--r--app/src/main/res/values/customization.xml12
-rw-r--r--app/src/main/res/values/dimens.xml16
-rw-r--r--app/src/main/res/values/setup.xml3
-rw-r--r--app/src/main/res/values/strings.xml4
-rw-r--r--app/src/main/res/values/styles.xml30
-rw-r--r--app/src/main/res/xml/settings.xml4
-rw-r--r--app/src/main/res/xml/shortcuts.xml14
-rw-r--r--app/src/play/res/xml/shortcuts.xml15
136 files changed, 2535 insertions, 1759 deletions
diff --git a/app/build.gradle b/app/build.gradle
index 1d60202a0..d23f70975 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -6,8 +6,8 @@ android {
applicationId "it.niedermann.nextcloud.deck"
minSdkVersion 15
targetSdkVersion 29
- versionCode 5002
- versionName "0.5.2"
+ versionCode 6000
+ versionName "0.6.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
javaCompileOptions {
@@ -80,12 +80,16 @@ dependencies {
// Flexbox
implementation 'com.google.android:flexbox:2.0.1'
- // Tab-Layout-Helper
- implementation 'com.h6ah4i.android.tablayouthelper:tablayouthelper:1.0.0'
-
// Custom Color Picker
implementation 'com.github.skydoves:colorpickerpreference:2.0.0'
+ // Cross tab drag'n'drop
+ implementation project(path: ':cross-tab-drag-and-drop')
+
+ // TabLayoutHelper
+ implementation project(path: ':tab-layout-helper')
+
+
// -------------------------
// --- Backend-Libraries ---
// -------------------------
diff --git a/app/play/release/output.json b/app/play/release/output.json
index d810d23c9..265ba2c28 100644
--- a/app/play/release/output.json
+++ b/app/play/release/output.json
@@ -1 +1 @@
-[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":5000,"versionName":"0.5.0","enabled":true,"outputFile":"app-play-release.apk","fullName":"playRelease","baseName":"play-release","dirName":""},"path":"app-play-release.apk","properties":{}}] \ No newline at end of file
+[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":6000,"versionName":"0.6.0","enabled":true,"outputFile":"app-play-release.apk","fullName":"playRelease","baseName":"play-release","dirName":""},"path":"app-play-release.apk","properties":{}}] \ No newline at end of file
diff --git a/app/src/dev/res/drawable/ic_launcher_foreground.xml b/app/src/dev/res/drawable/ic_launcher_foreground.xml
index b182bc780..3f9e12f05 100644
--- a/app/src/dev/res/drawable/ic_launcher_foreground.xml
+++ b/app/src/dev/res/drawable/ic_launcher_foreground.xml
@@ -2,27 +2,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
- android:viewportWidth="43.243244"
- android:viewportHeight="43.243244">
- <group
- android:translateX="13.621622"
- android:translateY="13.621622">
- <path
- android:pathData="M2,7L14,7A1,1 0,0 1,15 8L15,14A1,1 0,0 1,14 15L2,15A1,1 0,0 1,1 14L1,8A1,1 0,0 1,2 7z"
- android:fillColor="#fff" />
- <path
- android:pathData="M2.5,5L13.5,5A0.5,0.5 0,0 1,14 5.5L14,5.5A0.5,0.5 0,0 1,13.5 6L2.5,6A0.5,0.5 0,0 1,2 5.5L2,5.5A0.5,0.5 0,0 1,2.5 5z"
- android:fillColor="#fff" />
- <path
- android:pathData="M3.5,3L12.5,3A0.5,0.5 0,0 1,13 3.5L13,3.5A0.5,0.5 0,0 1,12.5 4L3.5,4A0.5,0.5 0,0 1,3 3.5L3,3.5A0.5,0.5 0,0 1,3.5 3z"
- android:fillColor="#fff" />
- <path
- android:pathData="M4.5,1L11.5,1A0.5,0.5 0,0 1,12 1.5L12,1.5A0.5,0.5 0,0 1,11.5 2L4.5,2A0.5,0.5 0,0 1,4 1.5L4,1.5A0.5,0.5 0,0 1,4.5 1z"
- android:fillColor="#fff" />
+ android:viewportWidth="38.268356"
+ android:viewportHeight="38.268356">
+ <group android:translateX="-2.4874432"
+ android:translateY="-2.4874432">
+ <group
+ android:translateX="13.621622"
+ android:translateY="13.621622">
+ <path
+ android:pathData="M2,7L14,7A1,1 0,0 1,15 8L15,14A1,1 0,0 1,14 15L2,15A1,1 0,0 1,1 14L1,8A1,1 0,0 1,2 7z"
+ android:fillColor="#fff" />
+ <path
+ android:pathData="M2.5,5L13.5,5A0.5,0.5 0,0 1,14 5.5L14,5.5A0.5,0.5 0,0 1,13.5 6L2.5,6A0.5,0.5 0,0 1,2 5.5L2,5.5A0.5,0.5 0,0 1,2.5 5z"
+ android:fillColor="#fff" />
+ <path
+ android:pathData="M3.5,3L12.5,3A0.5,0.5 0,0 1,13 3.5L13,3.5A0.5,0.5 0,0 1,12.5 4L3.5,4A0.5,0.5 0,0 1,3 3.5L3,3.5A0.5,0.5 0,0 1,3.5 3z"
+ android:fillColor="#fff" />
+ <path
+ android:pathData="M4.5,1L11.5,1A0.5,0.5 0,0 1,12 1.5L12,1.5A0.5,0.5 0,0 1,11.5 2L4.5,2A0.5,0.5 0,0 1,4 1.5L4,1.5A0.5,0.5 0,0 1,4.5 1z"
+ android:fillColor="#fff" />
+ </group>
</group>
<group
- android:translateX="14.5"
- android:translateY="21.2"
+ android:translateX="12.3"
+ android:translateY="18.8"
android:scaleX=".14"
android:scaleY=".14">
<path
diff --git a/app/src/dev/res/xml/shortcuts.xml b/app/src/dev/res/xml/shortcuts.xml
new file mode 100644
index 000000000..ec5df899c
--- /dev/null
+++ b/app/src/dev/res/xml/shortcuts.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
+ <shortcut
+ android:enabled="true"
+ android:icon="@drawable/ic_add_grey_24dp"
+ android:shortcutId="it.niedermann.nextcloud.deck"
+ android:shortcutLongLabel="@string/add_card"
+ android:shortcutShortLabel="@string/simple_add">
+ <intent
+ android:action="android.intent.action.VIEW"
+ android:targetClass="it.niedermann.nextcloud.deck.ui.preparecreate.PrepareCreateActivity"
+ android:targetPackage="it.niedermann.nextcloud.deck.dev" />
+ <categories android:name="android.shortcut.conversation" />
+ </shortcut>
+</shortcuts> \ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 21ae51972..432c2da98 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -57,18 +57,18 @@
</activity>
<activity
- android:name=".ui.EditActivity"
+ android:name=".ui.card.EditActivity"
android:label="@string/edit"
android:parentActivityName="it.niedermann.nextcloud.deck.ui.MainActivity"
android:theme="@style/AppTheme" />
<activity
- android:name=".ui.AttachmentsActivity"
- android:parentActivityName="it.niedermann.nextcloud.deck.ui.EditActivity"
+ android:name=".ui.attachments.AttachmentsActivity"
+ android:parentActivityName="it.niedermann.nextcloud.deck.ui.card.EditActivity"
android:theme="@style/TransparentTheme" />
<activity
- android:name=".ui.SettingsActivity"
+ android:name=".ui.settings.SettingsActivity"
android:label="@string/simple_settings"
android:parentActivityName="it.niedermann.nextcloud.deck.ui.MainActivity"
android:theme="@style/AppTheme" />
@@ -79,7 +79,12 @@
android:theme="@style/AppTheme" />
<activity
- android:name=".ui.AboutActivity"
+ android:name=".ui.preparecreate.PrepareCreateActivity"
+ android:label="@string/simple_select"
+ android:theme="@style/AppTheme" />
+
+ <activity
+ android:name=".ui.about.AboutActivity"
android:label="@string/about"
android:parentActivityName="it.niedermann.nextcloud.deck.ui.MainActivity"
android:theme="@style/AppTheme" />
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/Application.java b/app/src/main/java/it/niedermann/nextcloud/deck/Application.java
index 47abc97d9..61a715f38 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/Application.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/Application.java
@@ -3,13 +3,19 @@ package it.niedermann.nextcloud.deck;
import android.content.Context;
import android.content.SharedPreferences;
+import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
+import androidx.preference.PreferenceManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import it.niedermann.nextcloud.deck.ui.branding.Branded;
import static androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO;
import static androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES;
import static androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode;
import static androidx.multidex.MultiDex.install;
-import androidx.preference.PreferenceManager;
public class Application extends android.app.Application {
@@ -17,18 +23,38 @@ public class Application extends android.app.Application {
public static final long NO_BOARD_ID = -1L;
public static final long NO_STACK_ID = -1L;
+ private static boolean enableBrand;
+
+ @NonNull
+ private static List<Branded> brandedComponents = new ArrayList<>();
+
@Override
public void onCreate() {
setAppTheme(getAppTheme(getApplicationContext()));
+
+ enableBrand = getApplicationContext().getResources().getBoolean(R.bool.enable_brand);
+ if (enableBrand) {
+ @ColorInt final int mainColor = readBrandMainColor(getApplicationContext());
+ @ColorInt final int textColor = readBrandTextColor(getApplicationContext());
+ applyBrand(mainColor, textColor);
+ }
super.onCreate();
}
+ // --------
+ // Multidex
+ // --------
+
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
install(this);
}
+ // -----------------
+ // Day / Night theme
+ // -----------------
+
public static void setAppTheme(Boolean darkTheme) {
setDefaultNightMode(darkTheme ? MODE_NIGHT_YES : MODE_NIGHT_NO);
}
@@ -38,6 +64,68 @@ public class Application extends android.app.Application {
return prefs.getBoolean(context.getString(R.string.pref_key_dark_theme), false);
}
+ // --------
+ // Branding
+ // --------
+
+ public static void registerBrandedComponent(@NonNull Context context, @NonNull Branded brandedComponent) {
+ if (enableBrand && !brandedComponents.contains(brandedComponent)) {
+ brandedComponents.add(brandedComponent);
+
+ @ColorInt final int mainColor = readBrandMainColor(context);
+ @ColorInt final int textColor = readBrandTextColor(context);
+ brandedComponent.applyBrand(mainColor, textColor);
+ }
+ }
+
+ public static void deregisterBrandedComponent(@NonNull Branded brandedComponent) {
+ brandedComponents.remove(brandedComponent);
+ }
+
+ public static void setBrand(@NonNull Context context, @ColorInt int mainColor, @ColorInt int textColor) {
+ @ColorInt final int currentMainColor = readBrandMainColor(context);
+ @ColorInt final int currentTextColor = readBrandTextColor(context);
+ if (mainColor != currentMainColor || textColor != currentTextColor) {
+ if (enableBrand) {
+ applyBrand(mainColor, textColor);
+ }
+ saveBrandColors(context, mainColor, textColor);
+ }
+ }
+
+ public static void applyBrand(@ColorInt int mainColor, @ColorInt int textColor) {
+ for (Branded themableComponent : brandedComponents) {
+ themableComponent.applyBrand(mainColor, textColor);
+ }
+ }
+
+ @ColorInt
+ public static int readBrandMainColor(@NonNull Context context) {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
+ DeckLog.log("--- Read: shared_preference_theme_main");
+ return sharedPreferences.getInt(context.getString(R.string.shared_preference_theme_main), context.getApplicationContext().getResources().getColor(R.color.primary));
+ }
+
+ @ColorInt
+ public static int readBrandTextColor(@NonNull Context context) {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
+ DeckLog.log("--- Read: shared_preference_theme_text");
+ return sharedPreferences.getInt(context.getString(R.string.shared_preference_theme_text), context.getApplicationContext().getResources().getColor(android.R.color.white));
+ }
+
+ public static void saveBrandColors(@NonNull Context context, @ColorInt int mainColor, @ColorInt int textColor) {
+ SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
+ DeckLog.log("--- Write: shared_preference_theme_main" + " | " + mainColor);
+ DeckLog.log("--- Write: shared_preference_theme_text" + " | " + textColor);
+ editor.putInt(context.getString(R.string.shared_preference_theme_main), mainColor);
+ editor.putInt(context.getString(R.string.shared_preference_theme_text), textColor);
+ editor.apply();
+ }
+
+ // --------------------------------------
+ // Current account / board / stack states
+ // --------------------------------------
+
public static void saveCurrentAccountId(@NonNull Context context, long accountId) {
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
DeckLog.log("--- Write: shared_preference_last_account" + " | " + accountId);
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/api/DeckAPI.java b/app/src/main/java/it/niedermann/nextcloud/deck/api/DeckAPI.java
index f34148cb1..9883608c2 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/api/DeckAPI.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/api/DeckAPI.java
@@ -86,7 +86,7 @@ public interface DeckAPI {
Observable assignLabelToCard(@Path("boardId") long boardId, @Path("stackId") long stackId, @Path("cardId") long cardId, @Field("labelId") long labelId);
@FormUrlEncoded
- @PUT("boards/{boardId}/stacks/{stackId}/cards/{cardId}/onLabelRemoved")
+ @PUT("boards/{boardId}/stacks/{stackId}/cards/{cardId}/removeLabel")
Observable unassignLabelFromCard(@Path("boardId") long boardId, @Path("stackId") long stackId, @Path("cardId") long cardId, @Field("labelId") long labelId);
@FormUrlEncoded
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/api/JsonToEntityParser.java b/app/src/main/java/it/niedermann/nextcloud/deck/api/JsonToEntityParser.java
index ad777be88..99b9555b9 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/api/JsonToEntityParser.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/api/JsonToEntityParser.java
@@ -10,8 +10,6 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
import it.niedermann.nextcloud.deck.DeckLog;
import it.niedermann.nextcloud.deck.model.AccessControl;
@@ -34,7 +32,6 @@ import it.niedermann.nextcloud.deck.model.ocs.comment.OcsComment;
public class JsonToEntityParser {
private static SimpleDateFormat formatter = new SimpleDateFormat(GsonConfig.DATE_PATTERN);
- private static final Pattern NUMBER_EXTRACTION_PATTERN = Pattern.compile("[0-9]+");
static {
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
@@ -312,13 +309,6 @@ public class JsonToEntityParser {
return user;
}
- private static String extractNumber(String containsNumbers) {
- Matcher matcher = NUMBER_EXTRACTION_PATTERN.matcher(containsNumbers);
- if (matcher.find()){
- return matcher.group();
- }
- return "0";
- }
protected static Capabilities parseCapabilities(JsonObject e) {
DeckLog.verbose(e.toString());
@@ -326,18 +316,19 @@ public class JsonToEntityParser {
if (e.has("ocs")){
JsonObject ocs = e.getAsJsonObject("ocs");
+ if (ocs.has("meta")) {
+ int statuscode = ocs.getAsJsonObject("meta").get("statuscode").getAsInt();
+ capabilities.setMaintenanceEnabled(statuscode==503);
+
+ }
if (ocs.has("data")) {
JsonObject data = ocs.getAsJsonObject("data");
if (data.has("version")) {
JsonObject version = data.getAsJsonObject("version");
- int major = Integer.parseInt(extractNumber(version.get("major").getAsString()));
- int minor = Integer.parseInt(extractNumber(version.get("minor").getAsString()));
- int micro = Integer.parseInt(extractNumber(version.get("micro").getAsString()));
- Version v = new Version(version.toString(), major, minor, micro);
+ Version v = Version.of(version.get("string").getAsString());
capabilities.setNextcloudVersion(v);
}
- int major = 0, minor = 0, micro = 0;
String version = "";
if (data.has("capabilities")) {
JsonObject caps = data.getAsJsonObject("capabilities");
@@ -345,22 +336,16 @@ public class JsonToEntityParser {
JsonObject deck = caps.getAsJsonObject("deck");
if (deck.has("version")) {
version = deck.get("version").getAsString();
- if (version != null && !version.trim().isEmpty()){
- String[] split = version.split("\\.");
- if (split.length > 0){
- major = Integer.parseInt(extractNumber(split[0]));
- if (split.length > 1) {
- minor = Integer.parseInt(extractNumber(split[1]));
- if (split.length > 2) {
- micro = Integer.parseInt(extractNumber(split[2]));
- }
- }
- }
- }
+
}
}
+ if (caps.has("theming")) {
+ JsonObject theming = caps.getAsJsonObject("theming");
+ capabilities.setColor(theming.get("color").getAsString());
+ capabilities.setTextColor(theming.get("color-text").getAsString());
+ }
}
- capabilities.setDeckVersion(new Version(version, major, minor, micro));
+ capabilities.setDeckVersion(Version.of(version));
}
}
return capabilities;
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/model/Account.java b/app/src/main/java/it/niedermann/nextcloud/deck/model/Account.java
index ce8dbaf7b..63f9d8846 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/model/Account.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/model/Account.java
@@ -1,6 +1,7 @@
package it.niedermann.nextcloud.deck.model;
import androidx.annotation.NonNull;
+import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.Index;
@@ -8,6 +9,9 @@ import androidx.room.PrimaryKey;
import java.io.Serializable;
+import it.niedermann.nextcloud.deck.model.ocs.Capabilities;
+import it.niedermann.nextcloud.deck.model.ocs.Version;
+
@Entity(indices = {@Index(value = "name", unique = true)})
public class Account implements Serializable {
@Ignore
@@ -25,6 +29,22 @@ public class Account implements Serializable {
@NonNull
private String url;
+ @NonNull
+ @ColumnInfo(defaultValue = "#0082c9")
+ private String color = "#0082c9";
+
+ @NonNull
+ @ColumnInfo(defaultValue = "#ffffff")
+ private String textColor = "#ffffff";
+
+ @NonNull
+ @ColumnInfo(defaultValue = "0.6.4")
+ private String serverDeckVersion = "0.6.4";
+
+ @NonNull
+ @ColumnInfo(defaultValue = "0")
+ private boolean maintenanceEnabled = false;
+
@Ignore
public Account(Long id, @NonNull String name, @NonNull String userName, @NonNull String url) {
this(name, userName, url);
@@ -46,6 +66,17 @@ public class Account implements Serializable {
public Account() {
}
+ public void applyCapabilities(Capabilities capabilities) {
+ maintenanceEnabled = capabilities.isMaintenanceEnabled();
+ if (!isMaintenanceEnabled()) {
+ color = capabilities.getColor();
+ textColor = capabilities.getTextColor();
+ if (capabilities.getDeckVersion()!=null) {
+ serverDeckVersion = capabilities.getDeckVersion().getOriginalVersion();
+ }
+ }
+ }
+
public Long getId() {
return id;
}
@@ -81,6 +112,49 @@ public class Account implements Serializable {
this.url = url;
}
+ public static long getSerialVersionUID() {
+ return serialVersionUID;
+ }
+
+ @NonNull
+ public String getColor() {
+ return color;
+ }
+
+ public void setColor(@NonNull String color) {
+ this.color = color;
+ }
+
+ @NonNull
+ public String getTextColor() {
+ return textColor;
+ }
+
+ public void setTextColor(@NonNull String textColor) {
+ this.textColor = textColor;
+ }
+
+ public Version getServerDeckVersionAsObject() {
+ return Version.of(serverDeckVersion);
+ }
+
+ @NonNull
+ public String getServerDeckVersion() {
+ return serverDeckVersion;
+ }
+
+ public void setServerDeckVersion(@NonNull String serverDeckVersion) {
+ this.serverDeckVersion = serverDeckVersion;
+ }
+
+ public boolean isMaintenanceEnabled() {
+ return maintenanceEnabled;
+ }
+
+ public void setMaintenanceEnabled(boolean maintenanceEnabled) {
+ this.maintenanceEnabled = maintenanceEnabled;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/model/Attachment.java b/app/src/main/java/it/niedermann/nextcloud/deck/model/Attachment.java
index 432f2c1ca..1020e5cb3 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/model/Attachment.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/model/Attachment.java
@@ -10,6 +10,7 @@ import androidx.room.ForeignKey;
import androidx.room.Index;
import java.io.File;
+import java.io.Serializable;
import java.util.Date;
import it.niedermann.nextcloud.deck.model.interfaces.AbstractRemoteEntity;
@@ -25,7 +26,7 @@ import it.niedermann.nextcloud.deck.model.interfaces.AbstractRemoteEntity;
)
}
)
-public class Attachment extends AbstractRemoteEntity implements Comparable<Attachment> {
+public class Attachment extends AbstractRemoteEntity implements Comparable<Attachment>, Serializable {
private long cardId;
private String type = "deck_file";
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/model/Board.java b/app/src/main/java/it/niedermann/nextcloud/deck/model/Board.java
index b75b54339..810f4e575 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/model/Board.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/model/Board.java
@@ -5,6 +5,7 @@ import androidx.room.ForeignKey;
import androidx.room.Ignore;
import androidx.room.Index;
+import java.io.Serializable;
import java.util.Date;
import it.niedermann.nextcloud.deck.model.enums.DBStatus;
@@ -21,7 +22,7 @@ import it.niedermann.nextcloud.deck.model.interfaces.AbstractRemoteEntity;
)
}
)
-public class Board extends AbstractRemoteEntity {
+public class Board extends AbstractRemoteEntity implements Serializable {
public Board() {
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/model/Card.java b/app/src/main/java/it/niedermann/nextcloud/deck/model/Card.java
index 8340622bc..732ccfc50 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/model/Card.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/model/Card.java
@@ -9,6 +9,8 @@ import androidx.room.Index;
import com.google.gson.annotations.SerializedName;
import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import it.niedermann.nextcloud.deck.model.enums.DBStatus;
import it.niedermann.nextcloud.deck.model.interfaces.AbstractRemoteEntity;
@@ -28,6 +30,20 @@ import it.niedermann.nextcloud.deck.model.interfaces.AbstractRemoteEntity;
)
public class Card extends AbstractRemoteEntity {
+ private static Pattern PATTERN_MD_TASK = Pattern.compile("\\[([xX ])]");
+ public class TaskStatus {
+ public int taskCount;
+ public int doneCount;
+
+ public TaskStatus(int taskCount, int doneCount) {
+ this.taskCount = taskCount;
+ this.doneCount = doneCount;
+ }
+ }
+
+ @Ignore
+ private TaskStatus taskStatus = null;
+
private String title;
private String description;
@NonNull
@@ -38,7 +54,6 @@ public class Card extends AbstractRemoteEntity {
private int attachmentCount;
private Long userId;
- @NonNull
private int order;
private boolean archived;
@SerializedName("duedate")
@@ -74,6 +89,24 @@ public class Card extends AbstractRemoteEntity {
this.commentsUnread = card.getCommentsUnread();
}
+ public TaskStatus getTaskStatus(){
+ if (taskStatus == null){
+ int count = 0, done = 0;
+ if (description != null) {
+ Matcher matcher = PATTERN_MD_TASK.matcher(description);
+ while (matcher.find()){
+ count++;
+ char c = matcher.group().charAt(1);
+ if (c == 'x' || c == 'X'){
+ done++;
+ }
+ }
+ }
+ taskStatus = new TaskStatus(count, done);
+ }
+ return taskStatus;
+ }
+
public boolean isNotified() {
return notified;
}
@@ -112,6 +145,7 @@ public class Card extends AbstractRemoteEntity {
public void setDescription(String description) {
this.description = description;
+ this.taskStatus = null;
}
public Long getStackId() {
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/model/full/FullCard.java b/app/src/main/java/it/niedermann/nextcloud/deck/model/full/FullCard.java
index a4eb98a50..41303cac6 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/model/full/FullCard.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/model/full/FullCard.java
@@ -12,6 +12,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import it.niedermann.android.crosstabdnd.DragAndDropModel;
import it.niedermann.nextcloud.deck.model.Attachment;
import it.niedermann.nextcloud.deck.model.Card;
import it.niedermann.nextcloud.deck.model.JoinCardWithLabel;
@@ -20,7 +21,6 @@ import it.niedermann.nextcloud.deck.model.Label;
import it.niedermann.nextcloud.deck.model.User;
import it.niedermann.nextcloud.deck.model.interfaces.IRemoteEntity;
import it.niedermann.nextcloud.deck.model.ocs.comment.DeckComment;
-import it.niedermann.nextcloud.deck.ui.dnd.DragAndDropModel;
public class FullCard implements IRemoteEntity, DragAndDropModel {
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/model/ocs/Capabilities.java b/app/src/main/java/it/niedermann/nextcloud/deck/model/ocs/Capabilities.java
index e94ce4f6f..9ff4d7945 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/model/ocs/Capabilities.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/model/ocs/Capabilities.java
@@ -1,14 +1,13 @@
package it.niedermann.nextcloud.deck.model.ocs;
-import java.util.HashMap;
-import java.util.Map;
-
public class Capabilities {
- // accountID - Capabiliy
- public static final Map<Long, Capabilities> CACHE = new HashMap<>();
- Version deckVersion;
- Version nextcloudVersion;
+ private Version deckVersion;
+ private Version nextcloudVersion;
+
+ private String color = "#0082c9";
+ private String textColor = "#ffffff";
+ private boolean maintenanceEnabled = false;
public Capabilities() {
}
@@ -28,4 +27,28 @@ public class Capabilities {
public void setNextcloudVersion(Version nextcloudVersion) {
this.nextcloudVersion = nextcloudVersion;
}
+
+ public String getColor() {
+ return color;
+ }
+
+ public void setColor(String color) {
+ this.color = color;
+ }
+
+ public String getTextColor() {
+ return textColor;
+ }
+
+ public void setTextColor(String textColor) {
+ this.textColor = textColor;
+ }
+
+ public boolean isMaintenanceEnabled() {
+ return maintenanceEnabled;
+ }
+
+ public void setMaintenanceEnabled(boolean maintenanceEnabled) {
+ this.maintenanceEnabled = maintenanceEnabled;
+ }
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/model/ocs/Version.java b/app/src/main/java/it/niedermann/nextcloud/deck/model/ocs/Version.java
index 6589c9c8b..ab964bdef 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/model/ocs/Version.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/model/ocs/Version.java
@@ -2,11 +2,16 @@ package it.niedermann.nextcloud.deck.model.ocs;
import org.jetbrains.annotations.NotNull;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
public class Version implements Comparable<Version> {
- private String originalVersion;
- private int major;
- private int minor;
- private int patch;
+ private static final Pattern NUMBER_EXTRACTION_PATTERN = Pattern.compile("[0-9]+");
+
+ private String originalVersion = "?";
+ private int major = 0;
+ private int minor = 0;
+ private int patch = 0;
public Version(String originalVersion, int major, int minor, int patch) {
this(major, minor, patch);
@@ -55,6 +60,31 @@ public class Version implements Comparable<Version> {
this.originalVersion = originalVersion;
}
+ public static Version of(String versionString) {
+ int major = 0, minor = 0, micro = 0;
+ if (versionString != null) {
+ String[] split = versionString.split("\\.");
+ if (split.length > 0){
+ major = extractNumber(split[0]);
+ if (split.length > 1) {
+ minor = extractNumber(split[1]);
+ if (split.length > 2) {
+ micro = extractNumber(split[2]);
+ }
+ }
+ }
+ }
+ return new Version(versionString, major, minor, micro);
+ }
+
+ private static int extractNumber(String containsNumbers) {
+ Matcher matcher = NUMBER_EXTRACTION_PATTERN.matcher(containsNumbers);
+ if (matcher.find()){
+ return Integer.parseInt(matcher.group());
+ }
+ return 0;
+ }
+
/**
*
* @param compare another version object
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/SyncManager.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/SyncManager.java
index c9a35c809..a03c09239 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/SyncManager.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/SyncManager.java
@@ -239,14 +239,26 @@ public class SyncManager {
return dataBaseAdapter.readAccounts();
}
- public void getServerVersion(IResponseCallback<Capabilities> callback) {
- serverAdapter.getCapabilities(callback);
+ public void refreshCapabilities(IResponseCallback<Capabilities> callback) {
+ serverAdapter.getCapabilities(new IResponseCallback<Capabilities>(callback.getAccount()) {
+ @Override
+ public void onResponse(Capabilities response) {
+ Account acc = dataBaseAdapter.getAccountByIdDirectly(account.getId());
+ acc.applyCapabilities(response);
+ dataBaseAdapter.updateAccount(acc);
+ callback.onResponse(response);
+ }
+ });
}
public LiveData<List<Board>> getBoards(long accountId) {
return dataBaseAdapter.getBoards(accountId);
}
+ public LiveData<List<Board>> getBoardsWithEditPermission(long accountId) {
+ return dataBaseAdapter.getBoardsWithEditPermission(accountId);
+ }
+
public LiveData<FullBoard> createBoard(long accountId, Board board) {
MutableLiveData<FullBoard> liveData = new MutableLiveData<>();
doAsync(() -> {
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/ServerAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/ServerAdapter.java
index d9316537a..1f54dc0e2 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/ServerAdapter.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/ServerAdapter.java
@@ -147,23 +147,8 @@ public class ServerAdapter {
responseCallback);
}
public void getCapabilities(IResponseCallback<Capabilities> responseCallback) {
- if (Capabilities.CACHE.containsKey(responseCallback.getAccount().getId())) {
- responseCallback.onResponse(Capabilities.CACHE.get(responseCallback.getAccount().getId()));
- return;
- }
ensureInternetConnection();
- RequestHelper.request(sourceActivity, provider, () -> provider.getNextcloudAPI().getCapabilities(), new IResponseCallback<Capabilities>(responseCallback.getAccount()) {
- @Override
- public void onResponse(Capabilities response) {
- Capabilities.CACHE.put(responseCallback.getAccount().getId(), response);
- responseCallback.onResponse(response);
- }
-
- @Override
- public void onError(Throwable throwable) {
- responseCallback.onError(throwable);
- }
- });
+ RequestHelper.request(sourceActivity, provider, () -> provider.getNextcloudAPI().getCapabilities(), responseCallback);
}
public void getActivitiesForCard(long cardId, IResponseCallback<List<it.niedermann.nextcloud.deck.model.ocs.Activity>> responseCallback) {
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DataBaseAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DataBaseAdapter.java
index e2278bfd9..e68546df9 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DataBaseAdapter.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DataBaseAdapter.java
@@ -311,6 +311,10 @@ public class DataBaseAdapter {
return LiveDataHelper.onlyIfChanged(db.getBoardDao().getBoardsForAccount(accountId));
}
+ public LiveData<List<Board>> getBoardsWithEditPermission(long accountId) {
+ return LiveDataHelper.onlyIfChanged(db.getBoardDao().getBoardsWithEditPermissionsForAccount(accountId));
+ }
+
public WrappedLiveData<Board> createBoard(long accountId, Board board) {
return LiveDataHelper.wrapInLiveData(() -> {
board.setAccountId(accountId);
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DeckDatabase.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DeckDatabase.java
index 86576f951..a22159445 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DeckDatabase.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DeckDatabase.java
@@ -68,7 +68,7 @@ import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao.UserDao;
Mention.class,
},
exportSchema = false,
- version = 9
+ version = 10
)
@TypeConverters({DateTypeConverter.class})
public abstract class DeckDatabase extends RoomDatabase {
@@ -92,6 +92,16 @@ public abstract class DeckDatabase extends RoomDatabase {
}
};
+ private static final Migration MIGRATION_9_10 = new Migration(9, 10) {
+ @Override
+ public void migrate(SupportSQLiteDatabase database) {
+ database.execSQL("ALTER TABLE `Account` ADD `color` TEXT NOT NULL DEFAULT '#0082c9'");
+ database.execSQL("ALTER TABLE `Account` ADD `textColor` TEXT NOT NULL DEFAULT '#ffffff'");
+ database.execSQL("ALTER TABLE `Account` ADD `serverDeckVersion` TEXT NOT NULL DEFAULT '0.6.4'");
+ database.execSQL("ALTER TABLE `Account` ADD `maintenanceEnabled` INTEGER NOT NULL DEFAULT 0");
+ }
+ };
+
public static final RoomDatabase.Callback ON_CREATE_CALLBACK = new RoomDatabase.Callback() {
@@ -117,6 +127,7 @@ public abstract class DeckDatabase extends RoomDatabase {
DECK_DB_NAME)
//FIXME: remove destructive Migration as soon as schema is stable!
.addMigrations(MIGRATION_8_9)
+ .addMigrations(MIGRATION_9_10)
.fallbackToDestructiveMigration()
.addCallback(ON_CREATE_CALLBACK)
.build();
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/BoardDao.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/BoardDao.java
index f749c40b2..9e23ec524 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/BoardDao.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/dao/BoardDao.java
@@ -48,4 +48,7 @@ public interface BoardDao extends GenericDao<Board> {
@Transaction
@Query("SELECT * FROM board WHERE accountId = :accountId")
List<FullBoard> getAllFullBoards(long accountId);
+
+ @Query("SELECT * FROM board WHERE accountId = :accountId and permissionEdit = 1 and (deletedAt = 0 or deletedAt is null) and status <> 3 order by title asc")
+ LiveData<List<Board>> getBoardsWithEditPermissionsForAccount(long accountId);
} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/CardDataProvider.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/CardDataProvider.java
index 4aa6cb452..b5c158fae 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/CardDataProvider.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/CardDataProvider.java
@@ -19,7 +19,6 @@ import it.niedermann.nextcloud.deck.model.User;
import it.niedermann.nextcloud.deck.model.enums.DBStatus;
import it.niedermann.nextcloud.deck.model.full.FullCard;
import it.niedermann.nextcloud.deck.model.full.FullStack;
-import it.niedermann.nextcloud.deck.model.ocs.Capabilities;
import it.niedermann.nextcloud.deck.model.ocs.Version;
import it.niedermann.nextcloud.deck.model.propagation.CardUpdate;
import it.niedermann.nextcloud.deck.persistence.sync.adapters.ServerAdapter;
@@ -137,9 +136,7 @@ public class CardDataProvider extends AbstractSyncDataProvider<FullCard> {
}
syncHelper.doSyncFor(new AttachmentDataProvider(this, board, stack.getStack(), existingEntity, attachments));
- // TODO comments min version - can be removed when app min version == 1.0.0
- Capabilities capabilities = Capabilities.CACHE.get(callback.getAccount().getId());
- if (capabilities != null && capabilities.getDeckVersion().isGreaterOrEqualTo(new Version("1.0.0", 1, 0, 0))) {
+ if (callback.getAccount().getServerDeckVersionAsObject().isGreaterOrEqualTo(new Version("1.0.0", 1, 0, 0))) {
DeckLog.verbose("Comments - Version is OK, SYNC");
syncHelper.doSyncFor(new DeckCommentsDataProvider(this, existingEntity.getCard()));
} else {
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/ImportAccountActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/ImportAccountActivity.java
index 1a1b0b45c..571bb1d57 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/ImportAccountActivity.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/ImportAccountActivity.java
@@ -142,7 +142,7 @@ public class ImportAccountActivity extends AppCompatActivity {
editor.commit();
try {
- syncManager.getServerVersion(new IResponseCallback<Capabilities>(createdAccount) {
+ syncManager.refreshCapabilities(new IResponseCallback<Capabilities>(createdAccount) {
@Override
public void onResponse(Capabilities response) {
if (response.getDeckVersion().compareTo(new Version("", minimumServerAppMajor, minimumServerAppMinor, minimumServerAppPatch)) < 0) {
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/MainActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/MainActivity.java
index 4553596d4..2daef95fa 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/MainActivity.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/MainActivity.java
@@ -4,6 +4,9 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteConstraintException;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkInfo;
@@ -17,12 +20,11 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
+import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.ActionBarDrawerToggle;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.view.GravityCompat;
import androidx.lifecycle.LiveData;
@@ -44,6 +46,9 @@ import com.nextcloud.android.sso.ui.UiExceptionManager;
import java.util.ArrayList;
import java.util.List;
+import it.niedermann.android.crosstabdnd.CrossTabDragAndDrop;
+import it.niedermann.android.tablayouthelper.TabLayoutHelper;
+import it.niedermann.android.tablayouthelper.TabTitleGenerator;
import it.niedermann.nextcloud.deck.Application;
import it.niedermann.nextcloud.deck.DeckLog;
import it.niedermann.nextcloud.deck.R;
@@ -62,22 +67,26 @@ import it.niedermann.nextcloud.deck.model.ocs.Version;
import it.niedermann.nextcloud.deck.persistence.sync.SyncManager;
import it.niedermann.nextcloud.deck.persistence.sync.SyncWorker;
import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.WrappedLiveData;
+import it.niedermann.nextcloud.deck.ui.about.AboutActivity;
+import it.niedermann.nextcloud.deck.ui.board.DeleteBoardListener;
import it.niedermann.nextcloud.deck.ui.board.EditBoardDialogFragment;
import it.niedermann.nextcloud.deck.ui.board.EditBoardListener;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedActivity;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedAlertDialogBuilder;
import it.niedermann.nextcloud.deck.ui.card.CardAdapter;
-import it.niedermann.nextcloud.deck.ui.dnd.CrossTabDragAndDrop;
+import it.niedermann.nextcloud.deck.ui.card.EditActivity;
import it.niedermann.nextcloud.deck.ui.exception.ExceptionHandler;
+import it.niedermann.nextcloud.deck.ui.settings.SettingsActivity;
+import it.niedermann.nextcloud.deck.ui.stack.DeleteStackDialogFragment;
+import it.niedermann.nextcloud.deck.ui.stack.DeleteStackListener;
import it.niedermann.nextcloud.deck.ui.stack.EditStackDialogFragment;
import it.niedermann.nextcloud.deck.ui.stack.EditStackListener;
import it.niedermann.nextcloud.deck.ui.stack.OnScrollListener;
import it.niedermann.nextcloud.deck.ui.stack.StackAdapter;
import it.niedermann.nextcloud.deck.ui.stack.StackFragment;
-import it.niedermann.nextcloud.deck.util.DeleteDialogBuilder;
import it.niedermann.nextcloud.deck.util.DrawerMenuUtil;
import it.niedermann.nextcloud.deck.util.DrawerMenuUtil.DrawerAccountListener;
-import it.niedermann.nextcloud.deck.util.DrawerMenuUtil.DrawerBoardListener;
import it.niedermann.nextcloud.deck.util.ExceptionUtil;
-import it.niedermann.nextcloud.deck.util.TabLayoutHelper;
import it.niedermann.nextcloud.deck.util.ViewUtil;
import static androidx.lifecycle.Transformations.switchMap;
@@ -96,7 +105,7 @@ import static it.niedermann.nextcloud.deck.util.DrawerMenuUtil.MENU_ID_ADD_ACCOU
import static it.niedermann.nextcloud.deck.util.DrawerMenuUtil.MENU_ID_ADD_BOARD;
import static it.niedermann.nextcloud.deck.util.DrawerMenuUtil.MENU_ID_SETTINGS;
-public class MainActivity extends AppCompatActivity implements EditStackListener, EditBoardListener, OnScrollListener, OnNavigationItemSelectedListener, DrawerAccountListener, DrawerBoardListener {
+public class MainActivity extends BrandedActivity implements DeleteStackListener, EditStackListener, DeleteBoardListener, EditBoardListener, OnScrollListener, OnNavigationItemSelectedListener, DrawerAccountListener {
protected ActivityMainBinding binding;
protected NavHeaderMainBinding headerBinding;
@@ -158,7 +167,7 @@ public class MainActivity extends AppCompatActivity implements EditStackListener
setSupportActionBar(binding.toolbar);
accountIsGettingImportedSnackbar = Snackbar.make(binding.coordinatorLayout, R.string.account_is_getting_imported, Snackbar.LENGTH_INDEFINITE);
- ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, binding.drawerLayout, binding.toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
+ final ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, binding.drawerLayout, binding.toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
binding.drawerLayout.addDrawerListener(toggle);
toggle.syncState();
@@ -175,8 +184,8 @@ public class MainActivity extends AppCompatActivity implements EditStackListener
return null;
}
}).observe(this, (List<Account> accounts) -> {
- if (accounts == null) {
- throw new IllegalStateException("hasAccounts() returns true, but readAccounts() returns null");
+ if (accounts == null || accounts.size() == 0) {
+ throw new IllegalStateException("hasAccounts() returns true, but readAccounts() returns null or has no entry");
}
accountsList = accounts;
@@ -297,6 +306,14 @@ public class MainActivity extends AppCompatActivity implements EditStackListener
DeckLog.info("Do not clear Glide caches, because the user currently does not have a working internet connection");
}
} else DeckLog.warn("ConnectivityManager is null");
+ new Thread(() -> {
+ syncManager.refreshCapabilities(new IResponseCallback<Capabilities>(currentAccount) {
+ @Override
+ public void onResponse(Capabilities response) {
+ runOnUiThread(() -> Application.setBrand(MainActivity.this, Color.parseColor(response.getColor()), Color.parseColor(response.getTextColor())));
+ }
+ });
+ }).start();
syncManager.synchronize(new IResponseCallback<Boolean>(currentAccount) {
@Override
public void onResponse(Boolean response) {
@@ -315,19 +332,44 @@ public class MainActivity extends AppCompatActivity implements EditStackListener
});
});
- //TODO limit this call only to lower API levels like KitKat because they crash without
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
@Override
- protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
- super.onRestoreInstanceState(savedInstanceState);
+ public void applyBrand(@ColorInt int mainColor, @ColorInt int textColor) {
+ super.applyBrand(mainColor, textColor);
+ applyBrandToPrimaryToolbar(mainColor, textColor, binding.toolbar);
+ applyBrandToPrimaryTabLayout(mainColor, textColor, binding.stackTitles);
+ applyBrandToFAB(mainColor, textColor, binding.fab);
+
+ binding.addStackButton.setBackgroundColor(mainColor);
+ binding.addStackButton.setColorFilter(textColor);
+
+ headerBinding.drawerHeaderView.setBackgroundColor(mainColor);
+ headerBinding.drawerAppTitle.setTextColor(textColor);
+ headerBinding.drawerAppTitle.setShadowLayer(2, 0.5f, 0, mainColor);
+ headerBinding.drawerUsernameFull.setTextColor(textColor);
+ headerBinding.drawerUsernameFull.setShadowLayer(2, 0.5f, 0, mainColor);
+
+ final Drawable overflowDrawable = headerBinding.drawerAccountChooserToggle.getDrawable();
+ if (overflowDrawable != null) {
+ overflowDrawable.setColorFilter(textColor, PorterDuff.Mode.SRC_ATOP);
+ headerBinding.drawerAccountChooserToggle.setImageDrawable(overflowDrawable);
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (tabLayoutHelper != null) {
+ tabLayoutHelper.release();
+ }
}
@Override
public void onCreateStack(String stackName) {
observeOnce(syncManager.getStacksForBoard(currentAccount.getId(), currentBoardId), MainActivity.this, fullStacks -> {
- Stack s = new Stack(stackName, currentBoardId);
+ final Stack s = new Stack(stackName, currentBoardId);
int heighestOrder = 0;
for (FullStack fullStack : fullStacks) {
int currentStackOrder = fullStack.stack.getOrder();
@@ -336,12 +378,8 @@ public class MainActivity extends AppCompatActivity implements EditStackListener
}
}
s.setOrder(heighestOrder);
- //TODO: returns liveData of the created stack (once!) as desired
- // original to do: should return ID of the created stack, so one can immediately switch to the new board after creation
- DeckLog.log("Create Stack with account id = " + currentAccount.getId());
- syncManager.createStack(currentAccount.getId(), s).observe(MainActivity.this, (stack) -> {
- binding.viewPager.setCurrentItem(stackAdapter.getItemCount());
- });
+ DeckLog.info("Create Stack with account id = " + currentAccount.getId());
+ syncManager.createStack(currentAccount.getId(), s).observe(MainActivity.this, (stack) -> binding.viewPager.setCurrentItem(stackAdapter.getItemCount()));
});
}
@@ -377,6 +415,7 @@ public class MainActivity extends AppCompatActivity implements EditStackListener
protected void setCurrentAccount(@NonNull Account account) {
this.currentAccount = account;
SingleAccountHelper.setCurrentAccount(getApplicationContext(), this.currentAccount.getName());
+ Application.setBrand(MainActivity.this, Color.parseColor(currentAccount.getColor()), Color.parseColor(currentAccount.getTextColor()));
syncManager = new SyncManager(this);
Application.saveCurrentAccountId(this, this.currentAccount.getId());
@@ -471,7 +510,14 @@ public class MainActivity extends AppCompatActivity implements EditStackListener
}
}
final int stackPositionInAdapterClone = stackPositionInAdapter;
- TabLayoutHelper.TabTitleGenerator tabTitleGenerator = position -> fullStacks.size() > position ? fullStacks.get(position).getStack().getTitle() : "ERROR";
+ TabTitleGenerator tabTitleGenerator = position -> {
+ if (fullStacks.size() > position) {
+ return fullStacks.get(position).getStack().getTitle();
+ } else {
+ DeckLog.logError(new IllegalStateException("Could not generate tab title for position " + position + " because list size is only " + fullStacks.size()));
+ return "ERROR";
+ }
+ };
TabLayoutMediator newMediator = new TabLayoutMediator(binding.stackTitles, binding.viewPager, (tab, position) -> tab.setText(tabTitleGenerator.getTitle(position)));
runOnUiThread(() -> {
if (mediator != null) {
@@ -486,10 +532,9 @@ public class MainActivity extends AppCompatActivity implements EditStackListener
});
}
- private void updateTabLayoutHelper(TabLayoutHelper.TabTitleGenerator tabTitleGenerator) {
+ private void updateTabLayoutHelper(@NonNull TabTitleGenerator tabTitleGenerator) {
if (this.tabLayoutHelper == null) {
this.tabLayoutHelper = new TabLayoutHelper(binding.stackTitles, binding.viewPager, tabTitleGenerator);
- tabLayoutHelper.setAutoAdjustTabModeEnabled(true);
} else {
tabLayoutHelper.setTabTitleGenerator(tabTitleGenerator);
}
@@ -509,7 +554,7 @@ public class MainActivity extends AppCompatActivity implements EditStackListener
binding.navigationView.setItemIconTintList(null);
Menu menu = binding.navigationView.getMenu();
menu.clear();
- DrawerMenuUtil.inflateBoards(this, menu, currentAccount.getId(), currentBoardId, this.boardsList);
+ DrawerMenuUtil.inflateBoards(this, menu, currentAccount.getId(), this.boardsList);
}
@Override
@@ -572,25 +617,15 @@ public class MainActivity extends AppCompatActivity implements EditStackListener
@Override
public boolean onOptionsItemSelected(MenuItem item) {
+ final long stackId = stackAdapter.getItem(binding.viewPager.getCurrentItem()).getLocalId();
switch (item.getItemId()) {
case R.id.delete_list:
- new DeleteDialogBuilder(this)
- .setTitle(R.string.delete_list)
- .setMessage(R.string.do_you_want_to_delete_the_current_list)
- .setPositiveButton(R.string.simple_delete, (dialog, whichButton) -> {
- long stackId = stackAdapter.getItem(binding.viewPager.getCurrentItem()).getLocalId();
- observeOnce(syncManager.getStack(currentAccount.getId(), stackId), MainActivity.this, fullStack -> {
- DeckLog.log("Delete stack #" + fullStack.getLocalId() + ": " + fullStack.getStack().getTitle());
- syncManager.deleteStack(fullStack.getStack());
- });
- })
- .setNegativeButton(android.R.string.cancel, null).show();
+ DeleteStackDialogFragment.newInstance(stackId).show(getSupportFragmentManager(), DeleteStackDialogFragment.class.getCanonicalName());
return true;
case R.id.rename_list:
- long stackId = stackAdapter.getItem(binding.viewPager.getCurrentItem()).getLocalId();
observeOnce(syncManager.getStack(currentAccount.getId(), stackId), MainActivity.this, fullStack ->
EditStackDialogFragment.newInstance(fullStack.getLocalId(), fullStack.getStack().getTitle())
- .show(getSupportFragmentManager(), getString(R.string.rename_list)));
+ .show(getSupportFragmentManager(), EditStackDialogFragment.class.getCanonicalName()));
return true;
default:
return super.onOptionsItemSelected(item);
@@ -656,12 +691,12 @@ public class MainActivity extends AppCompatActivity implements EditStackListener
this.currentAccount = createdAccount;
try {
- syncManager.getServerVersion(new IResponseCallback<Capabilities>(createdAccount) {
+ syncManager.refreshCapabilities(new IResponseCallback<Capabilities>(createdAccount) {
@Override
public void onResponse(Capabilities response) {
if (response.getDeckVersion().compareTo(new Version(minimumServerAppMajor, minimumServerAppMinor, minimumServerAppPatch)) < 0) {
deckVersionTooLowSnackbar = Snackbar.make(binding.coordinatorLayout, R.string.your_deck_version_is_too_old, Snackbar.LENGTH_INDEFINITE).setAction(R.string.simple_more, v -> {
- new AlertDialog.Builder(MainActivity.this, Application.getAppTheme(getApplicationContext()) ? R.style.DialogDarkTheme : R.style.ThemeOverlay_AppCompat_Dialog_Alert)
+ new BrandedAlertDialogBuilder(MainActivity.this)
.setTitle(R.string.update_deck)
.setMessage(R.string.deck_outdated_please_update)
.setPositiveButton(R.string.simple_update, (dialog, whichButton) -> {
@@ -682,7 +717,7 @@ public class MainActivity extends AppCompatActivity implements EditStackListener
}
});
} catch (OfflineException e) {
- new AlertDialog.Builder(MainActivity.this)
+ new BrandedAlertDialogBuilder(MainActivity.this)
.setMessage(R.string.you_have_to_be_connected_to_the_internet_in_order_to_add_an_account)
.setPositiveButton(R.string.simple_close, null)
.show();
@@ -765,19 +800,28 @@ public class MainActivity extends AppCompatActivity implements EditStackListener
}
@Override
- public void onBoardChosen(@NonNull Board board) {
- setCurrentBoard(board);
+ public void onStackDeleted(Long stackLocalId) {
+ long stackId = stackAdapter.getItem(binding.viewPager.getCurrentItem()).getLocalId();
+ observeOnce(syncManager.getStack(currentAccount.getId(), stackId), MainActivity.this, fullStack -> {
+ DeckLog.log("Delete stack #" + fullStack.getLocalId() + ": " + fullStack.getStack().getTitle());
+ syncManager.deleteStack(fullStack.getStack());
+ });
}
@Override
- public void onBoardDeleted(@NonNull Board board) {
+ public void onBoardDeleted(Board board) {
+ final int index = this.boardsList.indexOf(board);
+ if (board.getLocalId() == currentBoardId) {
+ if (index > 0) { // Select first board after deletion
+ setCurrentBoard(this.boardsList.get(0));
+ } else if (this.boardsList.size() > 1) { // Select second board after deletion
+ setCurrentBoard(this.boardsList.get(1));
+ } else { // No other board is available, open create dialog
+ clearCurrentBoard();
+ EditBoardDialogFragment.newInstance().show(getSupportFragmentManager(), addBoard);
+ }
+ }
syncManager.deleteBoard(board);
binding.drawerLayout.closeDrawer(GravityCompat.START);
}
-
- @Override
- public void onLastBoardDeleted() {
- clearCurrentBoard();
- EditBoardDialogFragment.newInstance().show(getSupportFragmentManager(), addBoard);
- }
} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/SelectCardActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/SelectCardActivity.java
index 682a1b136..83bf799eb 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/SelectCardActivity.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/SelectCardActivity.java
@@ -20,7 +20,7 @@ import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.model.Attachment;
import it.niedermann.nextcloud.deck.model.Board;
import it.niedermann.nextcloud.deck.model.full.FullCard;
-import it.niedermann.nextcloud.deck.ui.card.CardAdapter;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedAlertDialogBuilder;
import it.niedermann.nextcloud.deck.ui.card.SelectCardListener;
import it.niedermann.nextcloud.deck.util.ExceptionUtil;
import it.niedermann.nextcloud.deck.util.FileUtils;
@@ -62,7 +62,7 @@ public class SelectCardActivity extends MainActivity implements SelectCardListen
}
} catch (IllegalArgumentException e) {
DeckLog.logError(e);
- new AlertDialog.Builder(this)
+ new BrandedAlertDialogBuilder(this)
.setTitle(R.string.error)
.setMessage(R.string.operation_not_yet_supported)
.setPositiveButton(R.string.simple_close, (a, b) -> finish())
@@ -98,7 +98,7 @@ public class SelectCardActivity extends MainActivity implements SelectCardListen
private void handleException(Throwable throwable) {
DeckLog.logError(throwable);
String debugInfos = ExceptionUtil.getDebugInfos(this, throwable);
- AlertDialog dialog = new AlertDialog.Builder(this)
+ AlertDialog dialog = new BrandedAlertDialogBuilder(this)
.setTitle(R.string.error)
.setMessage(debugInfos)
.setPositiveButton(android.R.string.copy, (a, b) -> {
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/AboutActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/about/AboutActivity.java
index b30e28c68..27dddabab 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/AboutActivity.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/about/AboutActivity.java
@@ -1,10 +1,9 @@
-package it.niedermann.nextcloud.deck.ui;
+package it.niedermann.nextcloud.deck.ui.about;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Lifecycle;
@@ -16,15 +15,14 @@ import it.niedermann.nextcloud.deck.Application;
import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.databinding.ActivityAboutBinding;
import it.niedermann.nextcloud.deck.model.Account;
-import it.niedermann.nextcloud.deck.ui.about.AboutFragmentContributingTab;
-import it.niedermann.nextcloud.deck.ui.about.AboutFragmentCreditsTab;
-import it.niedermann.nextcloud.deck.ui.about.AboutFragmentLicenseTab;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedActivity;
import it.niedermann.nextcloud.deck.ui.exception.ExceptionHandler;
import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_ACCOUNT;
-public class AboutActivity extends AppCompatActivity {
+public class AboutActivity extends BrandedActivity {
+ private ActivityAboutBinding binding;
private final static int[] tabTitles = new int[]{
R.string.about_credits_tab_title,
R.string.about_contribution_tab_title,
@@ -37,7 +35,7 @@ public class AboutActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler(this));
- ActivityAboutBinding binding = ActivityAboutBinding.inflate(getLayoutInflater());
+ binding = ActivityAboutBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
@@ -83,4 +81,11 @@ public class AboutActivity extends AppCompatActivity {
finish(); // close this activity as oppose to navigating up
return true;
}
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ super.applyBrand(mainColor, textColor);
+ applyBrandToPrimaryToolbar(mainColor, textColor, binding.toolbar);
+ applyBrandToPrimaryTabLayout(mainColor, textColor, binding.tabLayout);
+ }
} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/about/AboutFragmentCreditsTab.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/about/AboutFragmentCreditsTab.java
index d7aab83d5..122ea42f2 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/about/AboutFragmentCreditsTab.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/about/AboutFragmentCreditsTab.java
@@ -14,12 +14,8 @@ import androidx.preference.PreferenceManager;
import it.niedermann.nextcloud.deck.BuildConfig;
import it.niedermann.nextcloud.deck.R;
-import it.niedermann.nextcloud.deck.api.IResponseCallback;
import it.niedermann.nextcloud.deck.databinding.FragmentAboutCreditsTabBinding;
-import it.niedermann.nextcloud.deck.exceptions.OfflineException;
import it.niedermann.nextcloud.deck.model.Account;
-import it.niedermann.nextcloud.deck.model.ocs.Capabilities;
-import it.niedermann.nextcloud.deck.persistence.sync.SyncManager;
import it.niedermann.nextcloud.deck.util.DateUtil;
import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_ACCOUNT;
@@ -41,18 +37,9 @@ public class AboutFragmentCreditsTab extends Fragment {
// VERSIONS
binding.aboutVersion.setText(getString(R.string.about_version, strong(BuildConfig.VERSION_NAME)));
- SyncManager syncManager = new SyncManager(requireActivity());
if (getArguments() != null && getArguments().containsKey(BUNDLE_KEY_ACCOUNT)) {
- try {
- syncManager.getServerVersion(new IResponseCallback<Capabilities>((Account) getArguments().getSerializable(BUNDLE_KEY_ACCOUNT)) {
- @Override
- public void onResponse(Capabilities response) {
- requireActivity().runOnUiThread(() -> binding.aboutServerAppVersion.setText(strong(response.getDeckVersion().getOriginalVersion())));
- }
- });
- } catch (OfflineException e) {
- binding.aboutServerAppVersion.setText(disabled(getString(R.string.you_are_currently_offline), requireContext()));
- }
+ Account account = (Account) requireArguments().getSerializable(BUNDLE_KEY_ACCOUNT);
+ requireActivity().runOnUiThread(() -> binding.aboutServerAppVersion.setText(strong(account == null ? getString(R.string.simple_error) : account.getServerDeckVersion())));
} else {
binding.aboutServerAppVersionContainer.setVisibility(View.GONE);
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/about/AboutFragmentLicenseTab.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/about/AboutFragmentLicenseTab.java
index 09481a865..7a8a8f868 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/about/AboutFragmentLicenseTab.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/about/AboutFragmentLicenseTab.java
@@ -10,19 +10,42 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
+import it.niedermann.nextcloud.deck.Application;
import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.databinding.FragmentAboutLicenseTabBinding;
+import it.niedermann.nextcloud.deck.ui.branding.Branded;
import static it.niedermann.nextcloud.deck.util.SpannableUtil.setTextWithURL;
-public class AboutFragmentLicenseTab extends Fragment {
+public class AboutFragmentLicenseTab extends Fragment implements Branded {
+
+ private FragmentAboutLicenseTabBinding binding;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- FragmentAboutLicenseTabBinding binding = FragmentAboutLicenseTabBinding.inflate(inflater, container, false);
+ binding = FragmentAboutLicenseTabBinding.inflate(inflater, container, false);
+ Application.registerBrandedComponent(requireContext(), this);
setTextWithURL(binding.aboutIconsDisclaimerAppIcon, getResources(), R.string.about_icons_disclaimer_app_icon, R.string.about_app_icon_author_link_label, R.string.url_about_icon_author);
setTextWithURL(binding.aboutIconsDisclaimerMdiIcons, getResources(), R.string.about_icons_disclaimer_mdi_icons, R.string.about_icons_disclaimer_mdi, R.string.url_about_icons_disclaimer_mdi);
binding.aboutAppLicenseButton.setOnClickListener((v) -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.url_license)))));
return binding.getRoot();
}
+
+ @Override
+ public void onResume() {
+ Application.registerBrandedComponent(requireContext(), this);
+ super.onResume();
+ }
+
+ @Override
+ public void onPause() {
+ Application.deregisterBrandedComponent(this);
+ super.onPause();
+ }
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ binding.aboutAppLicenseButton.setBackgroundColor(mainColor);
+ binding.aboutAppLicenseButton.setTextColor(textColor);
+ }
} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/AttachmentsActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/attachments/AttachmentsActivity.java
index a3a68b405..8fc715c4c 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/AttachmentsActivity.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/attachments/AttachmentsActivity.java
@@ -1,4 +1,4 @@
-package it.niedermann.nextcloud.deck.ui;
+package it.niedermann.nextcloud.deck.ui.attachments;
import android.os.Bundle;
import android.view.MotionEvent;
@@ -18,7 +18,6 @@ import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.databinding.ActivityAttachmentsBinding;
import it.niedermann.nextcloud.deck.model.Attachment;
import it.niedermann.nextcloud.deck.persistence.sync.SyncManager;
-import it.niedermann.nextcloud.deck.ui.attachments.AttachmentAdapter;
import it.niedermann.nextcloud.deck.ui.exception.ExceptionHandler;
import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_ACCOUNT_ID;
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/DeleteBoardDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/DeleteBoardDialogFragment.java
new file mode 100644
index 000000000..a22c05c2f
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/DeleteBoardDialogFragment.java
@@ -0,0 +1,64 @@
+package it.niedermann.nextcloud.deck.ui.board;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.DialogFragment;
+
+import it.niedermann.nextcloud.deck.R;
+import it.niedermann.nextcloud.deck.model.Board;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedDeleteAlertDialogBuilder;
+
+public class DeleteBoardDialogFragment extends DialogFragment {
+
+ private static final String KEY_BOARD = "board";
+
+ private DeleteBoardListener deleteBoardListener;
+ private Board board;
+
+ /**
+ * Use newInstance()-Method
+ */
+ public DeleteBoardDialogFragment() {
+ }
+
+ @Override
+ public void onAttach(@NonNull Context context) {
+ super.onAttach(context);
+ if (context instanceof DeleteBoardListener) {
+ this.deleteBoardListener = (DeleteBoardListener) context;
+ } else {
+ throw new ClassCastException("Caller must implement " + DeleteBoardListener.class.getCanonicalName());
+ }
+
+ if (getArguments() == null || !getArguments().containsKey(KEY_BOARD)) {
+ throw new IllegalArgumentException("Please provide at least " + KEY_BOARD + " as an argument");
+ } else {
+ this.board = (Board) getArguments().getSerializable(KEY_BOARD);
+ }
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ AlertDialog.Builder builder = new BrandedDeleteAlertDialogBuilder(requireContext())
+ .setTitle(getString(R.string.delete_something, board.getTitle()))
+ .setMessage(R.string.delete_board_message)
+ .setPositiveButton(R.string.simple_delete, (dialog, which) -> deleteBoardListener.onBoardDeleted(board))
+ .setNegativeButton(android.R.string.cancel, null);
+ return builder.create();
+ }
+
+ public static DialogFragment newInstance(Board board) {
+ DeleteBoardDialogFragment dialog = new DeleteBoardDialogFragment();
+
+ Bundle args = new Bundle();
+ args.putSerializable(KEY_BOARD, board);
+ dialog.setArguments(args);
+
+ return dialog;
+ }
+}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/DeleteBoardListener.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/DeleteBoardListener.java
new file mode 100644
index 000000000..e9fb53652
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/DeleteBoardListener.java
@@ -0,0 +1,7 @@
+package it.niedermann.nextcloud.deck.ui.board;
+
+import it.niedermann.nextcloud.deck.model.Board;
+
+public interface DeleteBoardListener {
+ void onBoardDeleted(Board board);
+} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/EditBoardDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/EditBoardDialogFragment.java
index 0340fa1fb..900c473ca 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/EditBoardDialogFragment.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/EditBoardDialogFragment.java
@@ -6,17 +6,18 @@ import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
-import androidx.fragment.app.DialogFragment;
-import it.niedermann.nextcloud.deck.Application;
import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.databinding.DialogBoardCreateBinding;
import it.niedermann.nextcloud.deck.model.full.FullBoard;
import it.niedermann.nextcloud.deck.persistence.sync.SyncManager;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedActivity;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedAlertDialogBuilder;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedDialogFragment;
import static it.niedermann.nextcloud.deck.Application.NO_BOARD_ID;
-public class EditBoardDialogFragment extends DialogFragment {
+public class EditBoardDialogFragment extends BrandedDialogFragment {
private DialogBoardCreateBinding binding;
@@ -28,7 +29,9 @@ public class EditBoardDialogFragment extends DialogFragment {
private FullBoard fullBoard = null;
/**
- * Use newInstance()-Method
+ * Use newInstance()-Method(dialog, which) -> {
+ * // Do something else
+ * }
*/
public EditBoardDialogFragment() {
}
@@ -51,7 +54,7 @@ public class EditBoardDialogFragment extends DialogFragment {
long boardId = requireArguments().getLong(KEY_BOARD_ID);
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(requireContext(), Application.getAppTheme(getContext()) ? R.style.DialogDarkTheme : R.style.ThemeOverlay_AppCompat_Dialog_Alert);
+ AlertDialog.Builder dialogBuilder = new BrandedAlertDialogBuilder(requireContext());
if (boardId == NO_BOARD_ID) {
dialogBuilder.setTitle(R.string.add_board);
@@ -102,6 +105,8 @@ public class EditBoardDialogFragment extends DialogFragment {
return dialog;
}
-
-
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ BrandedActivity.applyBrandToEditText(mainColor, textColor, binding.input);
+ }
} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/accesscontrol/AccessControlDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/accesscontrol/AccessControlDialogFragment.java
index 853d1c4e2..c7dbfd7d6 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/accesscontrol/AccessControlDialogFragment.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/accesscontrol/AccessControlDialogFragment.java
@@ -4,25 +4,27 @@ import android.app.Dialog;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
-import androidx.fragment.app.DialogFragment;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
-import it.niedermann.nextcloud.deck.Application;
import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.databinding.DialogBoardShareBinding;
import it.niedermann.nextcloud.deck.model.AccessControl;
import it.niedermann.nextcloud.deck.model.User;
import it.niedermann.nextcloud.deck.model.full.FullBoard;
import it.niedermann.nextcloud.deck.persistence.sync.SyncManager;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedActivity;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedAlertDialogBuilder;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedDialogFragment;
import it.niedermann.nextcloud.deck.ui.card.UserAutoCompleteAdapter;
-public class AccessControlDialogFragment extends DialogFragment implements AccessControlChangedListener, AdapterView.OnItemClickListener {
+public class AccessControlDialogFragment extends BrandedDialogFragment implements AccessControlChangedListener, OnItemClickListener {
private DialogBoardShareBinding binding;
@@ -48,7 +50,7 @@ public class AccessControlDialogFragment extends DialogFragment implements Acces
boardId = requireArguments().getLong(KEY_BOARD_ID);
accountId = requireArguments().getLong(KEY_ACCOUNT_ID);
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(requireContext(), Application.getAppTheme(getContext()) ? R.style.DialogDarkTheme : R.style.ThemeOverlay_AppCompat_Dialog_Alert);
+ AlertDialog.Builder dialogBuilder = new BrandedAlertDialogBuilder(requireContext());
if (boardId == 0L || accountId == 0L) {
throw new IllegalArgumentException("accountId and boardId must be provided");
@@ -109,4 +111,9 @@ public class AccessControlDialogFragment extends DialogFragment implements Acces
binding.people.setText("");
userAutoCompleteAdapter.exclude(user);
}
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ BrandedActivity.applyBrandToEditText(mainColor, textColor, binding.people);
+ }
} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/Branded.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/Branded.java
new file mode 100644
index 000000000..9d9d2d3db
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/Branded.java
@@ -0,0 +1,7 @@
+package it.niedermann.nextcloud.deck.ui.branding;
+
+import androidx.annotation.ColorInt;
+
+public interface Branded {
+ void applyBrand(@ColorInt int mainColor, @ColorInt int textColor);
+ } \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedActivity.java
new file mode 100644
index 000000000..032c35004
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedActivity.java
@@ -0,0 +1,168 @@
+package it.niedermann.nextcloud.deck.ui.branding;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.view.Menu;
+import android.view.View;
+import android.view.Window;
+import android.widget.EditText;
+
+import androidx.annotation.CallSuper;
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+import androidx.core.graphics.drawable.DrawableCompat;
+
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
+import com.google.android.material.tabs.TabLayout;
+
+import it.niedermann.nextcloud.deck.Application;
+import it.niedermann.nextcloud.deck.DeckLog;
+
+import static android.os.Build.VERSION.SDK_INT;
+import static android.os.Build.VERSION_CODES.LOLLIPOP;
+import static android.os.Build.VERSION_CODES.M;
+import static it.niedermann.nextcloud.deck.util.ColorUtil.contrastRatioIsSufficient;
+import static it.niedermann.nextcloud.deck.util.ColorUtil.isColorDark;
+
+public abstract class BrandedActivity extends AppCompatActivity implements Branded {
+
+ /**
+ * Member variable needed for onCreateOptionsMenu()-callback
+ */
+ @Nullable
+ @ColorInt
+ private Integer textColor = null;
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ Application.registerBrandedComponent(this, this);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ Application.deregisterBrandedComponent(this);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ Application.deregisterBrandedComponent(this);
+ }
+
+ @CallSuper
+ @Override
+ public void applyBrand(@ColorInt int mainColor, @ColorInt int textColor) {
+ this.textColor = textColor;
+ if (SDK_INT >= LOLLIPOP) { // Set status bar color
+ final Window window = getWindow();
+ window.setStatusBarColor(mainColor);
+ if (SDK_INT >= M) { // Set icon and text color of status bar
+ final View decorView = window.getDecorView();
+ if (isColorDark(mainColor)) {
+ int flags = decorView.getSystemUiVisibility();
+ flags &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+ decorView.setSystemUiVisibility(flags);
+ } else {
+ decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ if (this.textColor != null) {
+ for (int i = 0; i < menu.size(); i++) {
+ Drawable drawable = menu.getItem(i).getIcon();
+ if (drawable != null) {
+ drawable = DrawableCompat.wrap(drawable);
+ DrawableCompat.setTint(drawable, this.textColor);
+ menu.getItem(i).setIcon(drawable);
+ }
+ }
+ }
+ return super.onCreateOptionsMenu(menu);
+ }
+
+ protected static void applyBrandToPrimaryToolbar(@ColorInt int mainColor, @ColorInt int textColor, @NonNull Toolbar toolbar) {
+ toolbar.setBackgroundColor(mainColor);
+ toolbar.setTitleTextColor(textColor);
+ final Drawable overflowDrawable = toolbar.getOverflowIcon();
+ if (overflowDrawable != null) {
+ overflowDrawable.setColorFilter(textColor, PorterDuff.Mode.SRC_ATOP);
+ toolbar.setOverflowIcon(overflowDrawable);
+ }
+
+ final Drawable navigationDrawable = toolbar.getNavigationIcon();
+ if (navigationDrawable != null) {
+ navigationDrawable.setColorFilter(textColor, PorterDuff.Mode.SRC_ATOP);
+ toolbar.setNavigationIcon(navigationDrawable);
+ }
+ }
+
+ protected static void applyBrandToPrimaryTabLayout(@ColorInt int mainColor, @ColorInt int textColor, @NonNull TabLayout tabLayout) {
+ tabLayout.setBackgroundColor(mainColor);
+ tabLayout.setTabTextColors(textColor, textColor);
+ tabLayout.setTabIconTint(ColorStateList.valueOf(textColor));
+ tabLayout.setSelectedTabIndicatorColor(textColor);
+ }
+
+ public static void applyBrandToFAB(@ColorInt int mainColor, @ColorInt int textColor, @NonNull FloatingActionButton fab) {
+ fab.setSupportBackgroundTintList(ColorStateList.valueOf(mainColor));
+ fab.setColorFilter(textColor);
+ }
+
+ public static void applyBrandToEditText(@ColorInt int mainColor, @ColorInt int textColor, @NonNull EditText editText) {
+ final Drawable background = editText.getBackground();
+ final ColorFilter oldColorFilter = DrawableCompat.getColorFilter(background);
+ final View.OnFocusChangeListener oldOnFocusChangeListener = editText.getOnFocusChangeListener();
+
+ @ColorInt final int finalMainColor = getColorDependingOnTheme(editText.getContext(), mainColor);
+
+ final boolean isFocused = editText.isFocused();
+ if (isFocused) {
+ editText.clearFocus();
+ }
+ final int highlightColor = Color.argb(77, Color.red(finalMainColor), Color.green(finalMainColor), Color.blue(finalMainColor));
+ editText.setHighlightColor(highlightColor);
+ editText.setOnFocusChangeListener((v, hasFocus) -> {
+ if (hasFocus) {
+ background.setColorFilter(finalMainColor, PorterDuff.Mode.SRC_ATOP);
+ } else {
+ background.setColorFilter(oldColorFilter);
+ }
+ if (oldOnFocusChangeListener != null) {
+ oldOnFocusChangeListener.onFocusChange(v, hasFocus);
+ }
+ });
+ if (isFocused) {
+ editText.requestFocus();
+ }
+ }
+
+ /**
+ * 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 getColorDependingOnTheme(@NonNull Context context, @ColorInt int mainColor) {
+ final boolean isDarkTheme = Application.getAppTheme(context);
+ if (isDarkTheme && !contrastRatioIsSufficient(mainColor, Color.BLACK)) {
+ DeckLog.verbose("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, Color.WHITE)) {
+ DeckLog.verbose("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;
+ }
+ }
+}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedAlertDialogBuilder.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedAlertDialogBuilder.java
new file mode 100644
index 000000000..e77050486
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedAlertDialogBuilder.java
@@ -0,0 +1,44 @@
+package it.niedermann.nextcloud.deck.ui.branding;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.widget.Button;
+
+import androidx.annotation.CallSuper;
+import androidx.appcompat.app.AlertDialog;
+
+import org.jetbrains.annotations.NotNull;
+
+import it.niedermann.nextcloud.deck.Application;
+
+public class BrandedAlertDialogBuilder extends AlertDialog.Builder implements Branded {
+
+ protected AlertDialog dialog;
+
+ public BrandedAlertDialogBuilder(Context context) {
+ super(context);
+ }
+
+ @NotNull
+ @Override
+ public AlertDialog create() {
+ this.dialog = super.create();
+ dialog.setOnShowListener(dialog -> Application.registerBrandedComponent(getContext(), this));
+ 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(BrandedActivity.getColorDependingOnTheme(button.getContext(), mainColor));
+ }
+ }
+ Application.deregisterBrandedComponent(this);
+ }
+}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedDeleteAlertDialogBuilder.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedDeleteAlertDialogBuilder.java
new file mode 100644
index 000000000..29cac691f
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedDeleteAlertDialogBuilder.java
@@ -0,0 +1,26 @@
+package it.niedermann.nextcloud.deck.ui.branding;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.widget.Button;
+
+import androidx.annotation.CallSuper;
+
+import it.niedermann.nextcloud.deck.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.danger));
+ }
+ }
+}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedDialogFragment.java
new file mode 100644
index 000000000..8c7804def
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedDialogFragment.java
@@ -0,0 +1,20 @@
+package it.niedermann.nextcloud.deck.ui.branding;
+
+import androidx.fragment.app.DialogFragment;
+
+import it.niedermann.nextcloud.deck.Application;
+
+public abstract class BrandedDialogFragment extends DialogFragment implements Branded {
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ Application.registerBrandedComponent(requireContext(), this);
+ }
+
+ @Override
+ public void onPause() {
+ Application.deregisterBrandedComponent(this);
+ super.onPause();
+ }
+}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedSwitchPreference.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedSwitchPreference.java
new file mode 100644
index 000000000..a2ca9e38a
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedSwitchPreference.java
@@ -0,0 +1,110 @@
+package it.niedermann.nextcloud.deck.ui.branding;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+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.nextcloud.deck.R;
+
+import static android.os.Build.VERSION.SDK_INT;
+import static android.os.Build.VERSION_CODES.JELLY_BEAN;
+import static it.niedermann.nextcloud.deck.ui.branding.BrandedActivity.getColorDependingOnTheme;
+
+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) {
+ this.mainColor = mainColor;
+ this.textColor = textColor;
+ // 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 = getColorDependingOnTheme(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_secondary)}
+ ));
+ 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_secondary)}
+ ));
+ }
+ }
+
+ /**
+ * 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/nextcloud/deck/ui/card/CardAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardAdapter.java
index 0322669ba..a417ea3c1 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardAdapter.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardAdapter.java
@@ -4,9 +4,6 @@ import android.annotation.SuppressLint;
import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
-import android.content.res.ColorStateList;
-import android.graphics.Color;
-import android.os.Build;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@@ -19,19 +16,19 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.appcompat.app.AlertDialog;
-import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.LifecycleOwner;
import androidx.recyclerview.widget.RecyclerView;
-import com.google.android.material.chip.Chip;
-import com.google.android.material.chip.ChipGroup;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
+import it.niedermann.android.crosstabdnd.DragAndDropAdapter;
+import it.niedermann.android.crosstabdnd.DraggedItemLocalState;
import it.niedermann.nextcloud.deck.DeckLog;
import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.databinding.ItemCardBinding;
@@ -45,10 +42,7 @@ import it.niedermann.nextcloud.deck.model.full.FullCard;
import it.niedermann.nextcloud.deck.model.full.FullStack;
import it.niedermann.nextcloud.deck.persistence.sync.SyncManager;
import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.LiveDataHelper;
-import it.niedermann.nextcloud.deck.ui.EditActivity;
-import it.niedermann.nextcloud.deck.ui.dnd.DragAndDropAdapter;
-import it.niedermann.nextcloud.deck.ui.dnd.DraggedItemLocalState;
-import it.niedermann.nextcloud.deck.util.ColorUtil;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedAlertDialogBuilder;
import it.niedermann.nextcloud.deck.util.DateUtil;
import it.niedermann.nextcloud.deck.util.DimensionUtil;
import it.niedermann.nextcloud.deck.util.ViewUtil;
@@ -73,8 +67,6 @@ public class CardAdapter extends RecyclerView.Adapter<ItemCardViewHolder> implem
private LifecycleOwner lifecycleOwner;
private List<FullStack> availableStacks = new ArrayList<>();
private int maxAvatarCount;
- private int maxLabelsShown;
- private int maxLabelsChars;
private String counterMaxValue;
public CardAdapter(@NonNull Account account, long boardId, long stackId, boolean canEdit, @NonNull SyncManager syncManager, @NonNull Fragment fragment, @Nullable SelectCardListener selectCardListener) {
@@ -99,8 +91,6 @@ public class CardAdapter extends RecyclerView.Adapter<ItemCardViewHolder> implem
final Context context = viewGroup.getContext();
maxAvatarCount = context.getResources().getInteger(R.integer.max_avatar_count);
- maxLabelsShown = context.getResources().getInteger(R.integer.max_labels_shown);
- maxLabelsChars = context.getResources().getInteger(R.integer.max_labels_chars);
counterMaxValue = context.getString(R.string.counter_max_value);
LayoutInflater layoutInflater = LayoutInflater.from(context);
@@ -119,6 +109,7 @@ public class CardAdapter extends RecyclerView.Adapter<ItemCardViewHolder> implem
Intent intent = new Intent(v.getContext(), EditActivity.class);
intent.putExtra(BUNDLE_KEY_ACCOUNT_ID, card.getAccountId());
intent.putExtra(BUNDLE_KEY_BOARD_ID, boardId);
+ intent.putExtra(BUNDLE_KEY_STACK_ID, card.getCard().getStackId());
intent.putExtra(BUNDLE_KEY_LOCAL_ID, card.getLocalId());
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
@@ -136,28 +127,18 @@ public class CardAdapter extends RecyclerView.Adapter<ItemCardViewHolder> implem
new DraggedItemLocalState<>(card, viewHolder.binding.card, this, position), // no need to use local data
0 // flags (not currently used, set to 0)
);
- DeckLog.log("onLongClickListener");
+ DeckLog.log("Starting drag and drop");
return true;
});
setupMoveMenu(card.getAccountId(), boardId);
} else {
viewHolder.binding.cardMenu.setVisibility(View.GONE);
}
- viewHolder.binding.cardTitle.setText(card.getCard().getTitle());
- String description = card.getCard().getDescription();
- if (description != null && description.length() > 0) {
- viewHolder.binding.cardDescription.setText(card.getCard().getDescription());
- viewHolder.binding.cardDescription.setVisibility(View.VISIBLE);
- } else {
- viewHolder.binding.cardDescription.setVisibility(View.GONE);
- }
-
- boolean showDetails = false;
+ viewHolder.binding.cardTitle.setText(card.getCard().getTitle().trim());
if (card.getAssignedUsers() != null && card.getAssignedUsers().size() > 0) {
setupAvatars(viewHolder.binding.peopleList, card);
viewHolder.binding.peopleList.setVisibility(View.VISIBLE);
- showDetails = true;
} else {
viewHolder.binding.peopleList.setVisibility(View.GONE);
}
@@ -167,7 +148,6 @@ public class CardAdapter extends RecyclerView.Adapter<ItemCardViewHolder> implem
if (card.getCard().getDueDate() != null) {
setupDueDate(viewHolder.binding.cardDueDate, card.getCard());
viewHolder.binding.cardDueDate.setVisibility(View.VISIBLE);
- showDetails = true;
} else {
viewHolder.binding.cardDueDate.setVisibility(View.GONE);
}
@@ -178,9 +158,7 @@ public class CardAdapter extends RecyclerView.Adapter<ItemCardViewHolder> implem
viewHolder.binding.cardCountAttachments.setVisibility(View.GONE);
} else {
setupCounter(viewHolder.binding.cardCountAttachments, attachmentsCount);
-
viewHolder.binding.cardCountAttachments.setVisibility(View.VISIBLE);
- showDetails = true;
}
final int commentsCount = card.getCommentCount();
@@ -191,22 +169,23 @@ public class CardAdapter extends RecyclerView.Adapter<ItemCardViewHolder> implem
setupCounter(viewHolder.binding.cardCountComments, commentsCount);
viewHolder.binding.cardCountComments.setVisibility(View.VISIBLE);
- showDetails = true;
}
- viewHolder.binding.labels.removeAllViews();
- if (card.getLabels() != null && card.getLabels().size() > 0) {
- setupLabels(viewHolder.binding.labels, card.getLabels());
+ List<Label> labels = card.getLabels();
+ if (labels != null && labels.size() > 0) {
+ viewHolder.binding.labels.updateLabels(labels);
viewHolder.binding.labels.setVisibility(View.VISIBLE);
- showDetails = true;
} else {
+ viewHolder.binding.labels.removeAllViews();
viewHolder.binding.labels.setVisibility(View.GONE);
}
- if (showDetails) {
- viewHolder.binding.cardDetailsContainer.setVisibility(View.VISIBLE);
+ Card.TaskStatus taskStatus = card.getCard().getTaskStatus();
+ if (taskStatus.taskCount > 0) {
+ viewHolder.binding.cardCountTasks.setText(context.getResources().getString(R.string.task_count, String.valueOf(taskStatus.doneCount), String.valueOf(taskStatus.taskCount)));
+ viewHolder.binding.cardCountTasks.setVisibility(View.VISIBLE);
} else {
- viewHolder.binding.cardDetailsContainer.setVisibility(View.GONE);
+ viewHolder.binding.cardCountTasks.setVisibility(View.GONE);
}
viewHolder.binding.cardMenu.setOnClickListener(v -> onOverflowIconClicked(v, card));
@@ -216,45 +195,6 @@ public class CardAdapter extends RecyclerView.Adapter<ItemCardViewHolder> implem
syncManager.getStacksForBoard(accountId, boardId).observe(lifecycleOwner, (stacks) -> availableStacks = stacks);
}
- private void setupLabels(@NonNull ChipGroup labels, List<Label> labelList) {
- final Context context = labels.getContext();
- Chip chip;
- for (int i = 0; i < labelList.size(); i++) {
- if (i > maxLabelsShown - 1 && labelList.size() > maxLabelsShown) {
- chip = new Chip(context);
- chip.setChipIcon(ContextCompat.getDrawable(context, R.drawable.ic_more_horiz_black_24dp));
- chip.setEnsureMinTouchTargetSize(false);
- chip.setTextStartPadding(0);
- chip.setTextEndPadding(0);
- labels.addView(chip);
- break;
- }
- Label label = labelList.get(i);
- chip = new Chip(context);
- chip.setEnsureMinTouchTargetSize(false);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- chip.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
- }
- String labelTitle = label.getTitle();
- if (labelTitle.length() > maxLabelsChars - 1) {
- chip.setText(labelTitle.substring(0, maxLabelsChars));
- } else {
- chip.setText(labelTitle.substring(0, 1));
- }
-
- try {
- int labelColor = Color.parseColor("#" + label.getColor());
- ColorStateList c = ColorStateList.valueOf(labelColor);
- chip.setChipBackgroundColor(c);
- chip.setTextColor(ColorUtil.getForegroundColorForBackgroundColor(labelColor));
- } catch (IllegalArgumentException e) {
- DeckLog.logError(e);
- }
-
- labels.addView(chip);
- }
- }
-
private void setupCounter(@NonNull TextView textView, int count) {
if (count > 99) {
textView.setText(counterMaxValue);
@@ -265,13 +205,13 @@ public class CardAdapter extends RecyclerView.Adapter<ItemCardViewHolder> implem
}
}
- private void setupDueDate(@NonNull TextView cardDueDate, Card card) {
+ private void setupDueDate(@NonNull TextView cardDueDate, @NotNull Card card) {
final Context context = cardDueDate.getContext();
cardDueDate.setText(DateUtil.getRelativeDateTimeString(context, card.getDueDate().getTime()));
ViewUtil.themeDueDate(context, cardDueDate, card.getDueDate());
}
- private void setupAvatars(@NonNull RelativeLayout peopleList, FullCard card) {
+ private void setupAvatars(@NonNull RelativeLayout peopleList, @NotNull FullCard card) {
final Context context = peopleList.getContext();
int avatarSize = DimensionUtil.getAvatarDimension(context, R.dimen.avatar_size_small);
peopleList.removeAllViews();
@@ -320,7 +260,7 @@ public class CardAdapter extends RecyclerView.Adapter<ItemCardViewHolder> implem
notifyItemRemoved(position);
}
- private void onOverflowIconClicked(View view, FullCard card) {
+ private void onOverflowIconClicked(@NotNull View view, FullCard card) {
final Context context = view.getContext();
PopupMenu popup = new PopupMenu(context, view);
popup.inflate(R.menu.card_menu);
@@ -330,7 +270,7 @@ public class CardAdapter extends RecyclerView.Adapter<ItemCardViewHolder> implem
popup.show();
}
- private void prepareOptionsMenu(Menu menu, FullCard card) {
+ private void prepareOptionsMenu(Menu menu, @NotNull FullCard card) {
if (containsUser(card.getAssignedUsers(), account.getUserName())) {
menu.removeItem(menu.findItem(R.id.action_card_assign).getItemId());
} else {
@@ -344,6 +284,7 @@ public class CardAdapter extends RecyclerView.Adapter<ItemCardViewHolder> implem
notifyDataSetChanged();
}
+ @Contract("null, _ -> false")
private boolean containsUser(List<User> userList, String username) {
if (userList != null) {
for (User user : userList) {
@@ -355,7 +296,7 @@ public class CardAdapter extends RecyclerView.Adapter<ItemCardViewHolder> implem
return false;
}
- private boolean optionsItemSelected(Context context, MenuItem item, FullCard card) {
+ private boolean optionsItemSelected(Context context, @NotNull MenuItem item, FullCard card) {
switch (item.getItemId()) {
case R.id.action_card_assign: {
new Thread(() -> syncManager.assignUserToCard(syncManager.getUserByUidDirectly(card.getCard().getAccountId(), account.getUserName()), card.getCard())).start();
@@ -376,7 +317,7 @@ public class CardAdapter extends RecyclerView.Adapter<ItemCardViewHolder> implem
}
}
final FullCard newCard = card;
- new AlertDialog.Builder(context)
+ new BrandedAlertDialogBuilder(context)
.setSingleChoiceItems(items, currentStackItem, (dialog, which) -> {
dialog.cancel();
newCard.getCard().setStackId(availableStacks.get(which).getStack().getLocalId());
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/EditActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/EditActivity.java
index 72be33780..b4e8dbc1f 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/EditActivity.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/EditActivity.java
@@ -1,6 +1,10 @@
-package it.niedermann.nextcloud.deck.ui;
+package it.niedermann.nextcloud.deck.ui.card;
-import android.content.SharedPreferences;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
@@ -9,44 +13,31 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.SpinnerAdapter;
+import android.widget.EditText;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.preference.PreferenceManager;
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+import androidx.core.graphics.drawable.DrawableCompat;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
-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.ArrayList;
import java.util.Date;
-import java.util.List;
import it.niedermann.nextcloud.deck.Application;
-import it.niedermann.nextcloud.deck.DeckLog;
import it.niedermann.nextcloud.deck.R;
-import it.niedermann.nextcloud.deck.api.IResponseCallback;
import it.niedermann.nextcloud.deck.databinding.ActivityEditBinding;
-import it.niedermann.nextcloud.deck.exceptions.OfflineException;
-import it.niedermann.nextcloud.deck.model.Account;
import it.niedermann.nextcloud.deck.model.Attachment;
-import it.niedermann.nextcloud.deck.model.Board;
import it.niedermann.nextcloud.deck.model.Card;
import it.niedermann.nextcloud.deck.model.Label;
import it.niedermann.nextcloud.deck.model.User;
import it.niedermann.nextcloud.deck.model.full.FullCard;
-import it.niedermann.nextcloud.deck.model.ocs.Capabilities;
import it.niedermann.nextcloud.deck.model.ocs.Version;
import it.niedermann.nextcloud.deck.model.ocs.comment.DeckComment;
import it.niedermann.nextcloud.deck.persistence.sync.SyncManager;
-import it.niedermann.nextcloud.deck.ui.board.BoardAdapter;
-import it.niedermann.nextcloud.deck.ui.card.CardTabAdapter;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedActivity;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedAlertDialogBuilder;
import it.niedermann.nextcloud.deck.ui.card.attachments.NewCardAttachmentHandler;
import it.niedermann.nextcloud.deck.ui.card.comments.CommentAddedListener;
import it.niedermann.nextcloud.deck.ui.card.comments.CommentDeletedListener;
@@ -61,7 +52,7 @@ import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_LOCAL_
import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_STACK_ID;
import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.NO_LOCAL_ID;
-public class EditActivity extends AppCompatActivity implements CardDetailsListener, CommentAddedListener, CommentDeletedListener, NewCardAttachmentHandler, OnItemSelectedListener {
+public class EditActivity extends BrandedActivity implements CardDetailsListener, CommentAddedListener, CommentDeletedListener, NewCardAttachmentHandler {
private ActivityEditBinding binding;
private SyncManager syncManager;
@@ -107,88 +98,60 @@ public class EditActivity extends AppCompatActivity implements CardDetailsListen
@Override
public void onCreate(Bundle savedInstanceState) {
- setTheme(Application.getAppTheme(this) ? R.style.DarkAppTheme : R.style.AppTheme);
super.onCreate(savedInstanceState);
+
Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler(this));
+ setTheme(Application.getAppTheme(this) ? R.style.DarkAppTheme : R.style.AppTheme);
binding = ActivityEditBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
- Bundle extras = getIntent().getExtras();
- if (extras == null) {
- throw new IllegalArgumentException("Provide localId");
+ Bundle args = getIntent().getExtras();
+
+ if (args == null || !args.containsKey(BUNDLE_KEY_ACCOUNT_ID) || !args.containsKey(BUNDLE_KEY_BOARD_ID)) {
+ throw new IllegalArgumentException("Provide at least " + BUNDLE_KEY_ACCOUNT_ID + " and " + BUNDLE_KEY_BOARD_ID + " so we know where to create this new card.");
}
- accountId = extras.getLong(BUNDLE_KEY_ACCOUNT_ID);
- boardId = extras.getLong(BUNDLE_KEY_BOARD_ID);
- stackId = extras.getLong(BUNDLE_KEY_STACK_ID);
- localId = extras.getLong(BUNDLE_KEY_LOCAL_ID);
- syncManager = new SyncManager(this);
- createMode = NO_LOCAL_ID.equals(localId);
- if (boardId == 0L) {
- try {
- createMode = true;
- SingleSignOnAccount ssoa = SingleAccountHelper.getCurrentSingleSignOnAccount(this);
- syncManager.readAccount(ssoa.name).observe(this, (Account account) -> {
- accountId = account.getId();
- binding.selectBoardWrapper.setVisibility(View.VISIBLE);
- syncManager.getBoards(account.getId()).observe(this, (List<Board> boardsList) -> {
- for (Board board : boardsList) {
- if (!board.isPermissionEdit()) {
- boardsList.remove(board);
- }
- }
- Board[] boardsArray = new Board[boardsList.size()];
- boardsArray = boardsList.toArray(boardsArray);
- SpinnerAdapter adapter = new BoardAdapter(this, boardsArray);
- binding.boardSelector.setAdapter(adapter);
-
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
- long lastBoardId = sharedPreferences.getLong(getString(R.string.shared_preference_last_board_for_account_) + accountId, 0L);
- DeckLog.log("--- Read: shared_preference_last_board_for_account_" + account.getId() + " | " + lastBoardId);
- if (lastBoardId != 0L) {
- for (int i = 0; i < boardsArray.length; i++) {
- if (boardsArray[i].getLocalId() == lastBoardId) {
- binding.boardSelector.setSelection(i);
- }
- }
- }
- binding.boardSelector.setOnItemSelectedListener(this);
- });
- });
- } catch (NextcloudFilesAppAccountNotFoundException | NoCurrentAccountSelectedException e) {
- e.printStackTrace();
- }
- } else {
- if (accountId == 0L) {
- throw new IllegalArgumentException("No accountId given");
+ accountId = args.getLong(BUNDLE_KEY_ACCOUNT_ID);
+ boardId = args.getLong(BUNDLE_KEY_BOARD_ID);
+ localId = args.getLong(BUNDLE_KEY_LOCAL_ID, NO_LOCAL_ID);
+
+ if (localId == NO_LOCAL_ID) {
+ createMode = true;
+ if (args.containsKey(BUNDLE_KEY_STACK_ID)) {
+ stackId = args.getLong(BUNDLE_KEY_STACK_ID);
+ } else {
+ throw new IllegalArgumentException("When creating a card, passing the " + BUNDLE_KEY_STACK_ID + " is mandatory");
}
- observeOnce(syncManager.getFullBoardById(accountId, boardId), EditActivity.this, (fullBoard -> {
- canEdit = fullBoard.getBoard().isPermissionEdit();
- invalidateOptionsMenu();
- if (createMode) {
- fullCard = new FullCard();
- originalCard = new FullCard();
- fullCard.setLabels(new ArrayList<>());
- fullCard.setAssignedUsers(new ArrayList<>());
- fullCard.setAttachments(new ArrayList<>());
- Card card = new Card();
- card.setStackId(stackId);
- fullCard.setCard(card);
+ }
+
+ syncManager = new SyncManager(this);
+
+ observeOnce(syncManager.getFullBoardById(accountId, boardId), EditActivity.this, (fullBoard -> {
+ canEdit = fullBoard.getBoard().isPermissionEdit();
+ invalidateOptionsMenu();
+ if (createMode) {
+ fullCard = new FullCard();
+ originalCard = new FullCard();
+ fullCard.setLabels(new ArrayList<>());
+ fullCard.setAssignedUsers(new ArrayList<>());
+ fullCard.setAttachments(new ArrayList<>());
+ Card card = new Card();
+ card.setStackId(stackId);
+ fullCard.setCard(card);
+ setupViewPager();
+ setupTitle(createMode);
+ } else {
+ observeOnce(syncManager.getCardByLocalId(accountId, localId), EditActivity.this, (next) -> {
+ fullCard = next;
+ originalCard = new FullCard(fullCard);
setupViewPager();
setupTitle(createMode);
- } else {
- observeOnce(syncManager.getCardByLocalId(accountId, localId), EditActivity.this, (next) -> {
- fullCard = next;
- originalCard = new FullCard(fullCard);
- setupViewPager();
- setupTitle(createMode);
- });
- }
- }));
- }
+ });
+ }
+ }));
}
@Override
@@ -217,7 +180,7 @@ public class EditActivity extends AppCompatActivity implements CardDetailsListen
fullCard.getCard().setTitle(CardUtil.generateTitleFromDescription(fullCard.getCard().getDescription()));
}
if (fullCard.getCard().getTitle().isEmpty()) {
- new AlertDialog.Builder(this)
+ new BrandedAlertDialogBuilder(this)
.setTitle(R.string.title_is_mandatory)
.setMessage(R.string.provide_at_least_a_title_or_description)
.setPositiveButton(android.R.string.ok, null)
@@ -265,27 +228,14 @@ public class EditActivity extends AppCompatActivity implements CardDetailsListen
// Comments API only available starting with version 1.0.0-alpha1
if (!createMode) {
syncManager.readAccount(accountId).observe(this, (account) -> {
- try {
- syncManager.getServerVersion(new IResponseCallback<Capabilities>(account) {
- @Override
- public void onResponse(Capabilities response) {
- hasCommentsAbility = ((response.getDeckVersion().compareTo(new Version("1.0.0", 1, 0, 0)) >= 0));
- if (hasCommentsAbility) {
- runOnUiThread(() -> {
- mediator.detach();
- adapter.enableComments();
- binding.pager.setOffscreenPageLimit(3);
- mediator.attach();
- });
- }
- }
-
- @Override
- public void onError(Throwable throwable) {
- super.onError(throwable);
- }
+ hasCommentsAbility = ((account.getServerDeckVersionAsObject().compareTo(new Version("1.0.0", 1, 0, 0)) >= 0));
+ if (hasCommentsAbility) {
+ runOnUiThread(() -> {
+ mediator.detach();
+ adapter.enableComments();
+ binding.pager.setOffscreenPageLimit(3);
+ mediator.attach();
});
- } catch (OfflineException ignored) {
}
});
}
@@ -301,7 +251,7 @@ public class EditActivity extends AppCompatActivity implements CardDetailsListen
binding.title.setSelection(fullCard.getCard().getTitle().length());
}
}
- binding.titleTextInputLayout.setHint(getString(createMode ? R.string.simple_add : R.string.edit));
+ binding.title.setHint(getString(createMode ? R.string.simple_add : R.string.edit));
binding.title.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
@@ -317,7 +267,7 @@ public class EditActivity extends AppCompatActivity implements CardDetailsListen
}
});
} else {
- binding.titleTextInputLayout.setHintEnabled(false);
+// binding.titleTextInputLayout.setHintEnabled(false);
binding.title.setEnabled(false);
}
}
@@ -366,7 +316,7 @@ public class EditActivity extends AppCompatActivity implements CardDetailsListen
@Override
public void finish() {
if (!fullCard.equals(originalCard) && canEdit) {
- new AlertDialog.Builder(this)
+ new BrandedAlertDialogBuilder(this)
.setTitle(R.string.simple_save)
.setMessage(R.string.do_you_want_to_save_your_changes)
.setPositiveButton(R.string.simple_save, (dialog, whichButton) -> saveAndFinish())
@@ -377,43 +327,6 @@ public class EditActivity extends AppCompatActivity implements CardDetailsListen
}
@Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- boardId = ((Board) binding.boardSelector.getItemAtPosition(position)).getLocalId();
- observeOnce(syncManager.getFullBoardById(accountId, boardId), EditActivity.this, (fullBoard -> {
- canEdit = fullBoard.getBoard().isPermissionEdit();
-
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
- long savedStackId = sharedPreferences.getLong(getString(R.string.shared_preference_last_stack_for_account_and_board_) + accountId + "_" + boardId, 0L);
- DeckLog.log("--- Read: shared_preference_last_stack_for_account_and_board" + accountId + "_" + boardId + " | " + savedStackId);
- if (savedStackId == 0L) {
- observeOnce(syncManager.getStacksForBoard(accountId, boardId), EditActivity.this, (stacks -> {
- if (stacks != null && stacks.size() > 0) {
- stackId = stacks.get(0).getLocalId();
- }
- }));
- } else {
- stackId = savedStackId;
- }
- if (fullCard == null) {
- invalidateOptionsMenu();
- fullCard = new FullCard();
- fullCard.setLabels(new ArrayList<>());
- fullCard.setAssignedUsers(new ArrayList<>());
- Card card = new Card();
- card.setStackId(stackId);
- fullCard.setCard(card);
- setupViewPager();
- setupTitle(createMode);
- }
- }));
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
-
- }
-
- @Override
public void onCommentAdded(DeckComment comment) {
syncManager.addCommentToCard(accountId, boardId, localId, comment);
}
@@ -432,4 +345,43 @@ public class EditActivity extends AppCompatActivity implements CardDetailsListen
public void onCommentDeleted(Long localCommentId) {
syncManager.deleteComment(this.accountId, this.localId, localCommentId);
}
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ super.applyBrand(mainColor, textColor);
+ applyBrandToPrimaryToolbar(mainColor, textColor, binding.toolbar);
+ applyBrandToPrimaryTabLayout(mainColor, textColor, binding.tabLayout);
+ applyBrandToTitle(textColor, binding.title);
+ }
+
+ private static void applyBrandToTitle(@ColorInt int textColor, @NonNull EditText editText) {
+ final int highlightColor = Color.argb(77, Color.red(textColor), Color.green(textColor), Color.blue(textColor));
+ editText.setHighlightColor(highlightColor);
+ editText.setTextColor(textColor);
+ DrawableCompat.setTintList(editText.getBackground(), ColorStateList.valueOf(textColor));
+
+ final Drawable background = editText.getBackground();
+ final ColorFilter oldColorFilter = DrawableCompat.getColorFilter(background);
+ final View.OnFocusChangeListener oldOnFocusChangeListener = editText.getOnFocusChangeListener();
+
+ final boolean isFocused = editText.isFocused();
+ if (isFocused) {
+ editText.clearFocus();
+ }
+ editText.setOnFocusChangeListener((v, hasFocus) -> {
+ if (hasFocus) {
+ editText.setHintTextColor(textColor);
+ editText.setTextColor(textColor);
+ background.setColorFilter(textColor, PorterDuff.Mode.SRC_ATOP);
+ } else {
+ background.setColorFilter(oldColorFilter);
+ }
+ if (oldOnFocusChangeListener != null) {
+ oldOnFocusChangeListener.onFocusChange(v, hasFocus);
+ }
+ });
+ if (isFocused) {
+ editText.requestFocus();
+ }
+ }
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentAdapter.java
index 24de7eaae..2780dbe1e 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentAdapter.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentAdapter.java
@@ -14,6 +14,7 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityOptionsCompat;
+import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
@@ -27,12 +28,11 @@ import it.niedermann.nextcloud.deck.databinding.ItemAttachmentImageBinding;
import it.niedermann.nextcloud.deck.model.Account;
import it.niedermann.nextcloud.deck.model.Attachment;
import it.niedermann.nextcloud.deck.model.enums.DBStatus;
-import it.niedermann.nextcloud.deck.ui.AttachmentsActivity;
+import it.niedermann.nextcloud.deck.ui.attachments.AttachmentsActivity;
import it.niedermann.nextcloud.deck.util.AttachmentUtil;
import it.niedermann.nextcloud.deck.util.DateUtil;
-import it.niedermann.nextcloud.deck.util.DeleteDialogBuilder;
-import static it.niedermann.nextcloud.deck.ui.AttachmentsActivity.BUNDLE_KEY_CURRENT_ATTACHMENT_LOCAL_ID;
+import static it.niedermann.nextcloud.deck.ui.attachments.AttachmentsActivity.BUNDLE_KEY_CURRENT_ATTACHMENT_LOCAL_ID;
import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_ACCOUNT_ID;
import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_LOCAL_ID;
import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.NO_LOCAL_ID;
@@ -50,22 +50,22 @@ public class CardAttachmentAdapter extends RecyclerView.Adapter<AttachmentViewHo
private Long cardRemoteId = null;
private final long cardLocalId;
@NonNull
- private List<Attachment> attachments = new ArrayList<>();
+ FragmentManager fragmentManager;
@NonNull
- private final AttachmentDeletedListener attachmentDeletedListener;
+ private List<Attachment> attachments = new ArrayList<>();
@Nullable
private final AttachmentClickedListener attachmentClickedListener;
CardAttachmentAdapter(
+ @NonNull FragmentManager fragmentManager,
@NonNull MenuInflater menuInflater,
- @NonNull AttachmentDeletedListener attachmentDeletedListener,
@Nullable AttachmentClickedListener attachmentClickedListener,
@NonNull Account account,
long cardLocalId
) {
super();
+ this.fragmentManager = fragmentManager;
this.menuInflater = menuInflater;
- this.attachmentDeletedListener = attachmentDeletedListener;
this.attachmentClickedListener = attachmentClickedListener;
this.account = account;
this.cardLocalId = cardLocalId;
@@ -104,12 +104,7 @@ public class CardAttachmentAdapter extends RecyclerView.Adapter<AttachmentViewHo
holder.itemView.setOnCreateContextMenuListener((menu, v, menuInfo) -> {
menuInflater.inflate(R.menu.attachment_menu, menu);
menu.findItem(R.id.delete).setOnMenuItemClickListener(item -> {
- new DeleteDialogBuilder(context)
- .setTitle(context.getString(R.string.delete_something, attachment.getFilename()))
- .setMessage(R.string.attachment_delete_message)
- .setNegativeButton(android.R.string.cancel, null)
- .setPositiveButton(R.string.simple_delete, (dialog, which) -> attachmentDeletedListener.onAttachmentDeleted(attachment))
- .show();
+ DeleteAttachmentDialogFragment.newInstance(attachment).show(fragmentManager, DeleteAttachmentDialogFragment.class.getCanonicalName());
return false;
});
if (uri == null) {
@@ -191,7 +186,7 @@ public class CardAttachmentAdapter extends RecyclerView.Adapter<AttachmentViewHo
return attachments.size();
}
- public void setAttachments(@NonNull List<Attachment> attachments, long cardRemoteId) {
+ public void setAttachments(@NonNull List<Attachment> attachments, @Nullable Long cardRemoteId) {
this.cardRemoteId = cardRemoteId;
this.attachments = attachments;
notifyDataSetChanged();
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java
index 1647bb91c..b338fec72 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java
@@ -24,14 +24,17 @@ import java.util.Date;
import java.util.List;
import java.util.Map;
+import it.niedermann.nextcloud.deck.Application;
import it.niedermann.nextcloud.deck.DeckLog;
import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.databinding.FragmentCardEditTabAttachmentsBinding;
import it.niedermann.nextcloud.deck.model.Account;
import it.niedermann.nextcloud.deck.model.Attachment;
import it.niedermann.nextcloud.deck.persistence.sync.SyncManager;
+import it.niedermann.nextcloud.deck.ui.branding.Branded;
import it.niedermann.nextcloud.deck.util.FileUtils;
+import static it.niedermann.nextcloud.deck.ui.branding.BrandedActivity.applyBrandToFAB;
import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_ACCOUNT_ID;
import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_BOARD_ID;
import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_CAN_EDIT;
@@ -40,7 +43,7 @@ import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.NO_LOCAL_ID;
import static it.niedermann.nextcloud.deck.ui.card.attachments.CardAttachmentAdapter.VIEW_TYPE_DEFAULT;
import static it.niedermann.nextcloud.deck.ui.card.attachments.CardAttachmentAdapter.VIEW_TYPE_IMAGE;
-public class CardAttachmentsFragment extends Fragment implements AttachmentDeletedListener, AttachmentClickedListener {
+public class CardAttachmentsFragment extends Fragment implements AttachmentDeletedListener, AttachmentClickedListener, Branded {
private FragmentCardEditTabAttachmentsBinding binding;
private static final int REQUEST_CODE_ADD_ATTACHMENT = 1;
@@ -72,9 +75,9 @@ public class CardAttachmentsFragment extends Fragment implements AttachmentDelet
syncManager = new SyncManager(requireActivity());
syncManager.readAccount(accountId).observe(getViewLifecycleOwner(), (Account account) -> {
adapter = new CardAttachmentAdapter(
+ getChildFragmentManager(),
requireActivity().getMenuInflater(),
this,
- this,
account,
cardId);
binding.attachmentsList.setAdapter(adapter);
@@ -150,6 +153,18 @@ public class CardAttachmentsFragment extends Fragment implements AttachmentDelet
}
@Override
+ public void onResume() {
+ super.onResume();
+ Application.registerBrandedComponent(requireContext(), this);
+ }
+
+ @Override
+ public void onPause() {
+ Application.deregisterBrandedComponent(this);
+ super.onPause();
+ }
+
+ @Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_ADD_ATTACHMENT && resultCode == Activity.RESULT_OK) {
@@ -247,4 +262,9 @@ public class CardAttachmentsFragment extends Fragment implements AttachmentDelet
this.binding.attachmentsList.setVisibility(View.VISIBLE);
}
}
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ applyBrandToFAB(mainColor, textColor, binding.fab);
+ }
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/DeleteAttachmentDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/DeleteAttachmentDialogFragment.java
new file mode 100644
index 000000000..4e5676f05
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/DeleteAttachmentDialogFragment.java
@@ -0,0 +1,67 @@
+package it.niedermann.nextcloud.deck.ui.card.attachments;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.DialogFragment;
+
+import it.niedermann.nextcloud.deck.R;
+import it.niedermann.nextcloud.deck.model.Attachment;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedDeleteAlertDialogBuilder;
+
+public class DeleteAttachmentDialogFragment extends DialogFragment {
+
+ private static final String KEY_ATTACHMENT = "attachment";
+
+ private AttachmentDeletedListener deleteAttachmentListener;
+ private Attachment attachment;
+
+
+ /**
+ * Use newInstance()-Method
+ */
+ public DeleteAttachmentDialogFragment() {
+ }
+
+ @Override
+ public void onAttach(@NonNull Context context) {
+ super.onAttach(context);
+ if (getParentFragment() instanceof AttachmentDeletedListener) {
+ this.deleteAttachmentListener = (AttachmentDeletedListener) getParentFragment();
+ } else if (context instanceof AttachmentDeletedListener) {
+ this.deleteAttachmentListener = (AttachmentDeletedListener) context;
+ } else {
+ throw new ClassCastException("Context or parent fragment must implement " + AttachmentDeletedListener.class.getCanonicalName());
+ }
+
+ if (getArguments() == null || !getArguments().containsKey(KEY_ATTACHMENT)) {
+ throw new IllegalArgumentException("Please provide at least " + KEY_ATTACHMENT + " as an argument");
+ } else {
+ this.attachment = (Attachment) getArguments().getSerializable(KEY_ATTACHMENT);
+ }
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ AlertDialog.Builder builder = new BrandedDeleteAlertDialogBuilder(requireContext())
+ .setTitle(getString(R.string.delete_something, attachment.getFilename()))
+ .setMessage(R.string.attachment_delete_message)
+ .setPositiveButton(R.string.simple_delete, (dialog, whichButton) -> deleteAttachmentListener.onAttachmentDeleted(attachment))
+ .setNegativeButton(android.R.string.cancel, null);
+ return builder.create();
+ }
+
+ public static DialogFragment newInstance(Attachment attachment) {
+ DeleteAttachmentDialogFragment dialog = new DeleteAttachmentDialogFragment();
+
+ Bundle args = new Bundle();
+ args.putSerializable(KEY_ATTACHMENT, attachment);
+ dialog.setArguments(args);
+
+ return dialog;
+ }
+}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CardCommentsEditDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CardCommentsEditDialogFragment.java
index 6bd231a49..2502cc705 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CardCommentsEditDialogFragment.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CardCommentsEditDialogFragment.java
@@ -10,15 +10,17 @@ import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import java.util.Objects;
import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.databinding.DialogAddCommentBinding;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedActivity;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedAlertDialogBuilder;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedDialogFragment;
-public class CardCommentsEditDialogFragment extends DialogFragment {
+public class CardCommentsEditDialogFragment extends BrandedDialogFragment {
private static final String BUNDLE_KEY_COMMENT_ID = "commentId";
private static final String BUNDLE_KEY_COMMENT_MESSAGE = "commentMessage";
private CommentEditedListener addCommentListener;
@@ -53,7 +55,7 @@ public class CardCommentsEditDialogFragment extends DialogFragment {
public Dialog onCreateDialog(Bundle savedInstanceState) {
binding = DialogAddCommentBinding.inflate(requireActivity().getLayoutInflater());
- return new AlertDialog.Builder(requireActivity())
+ return new BrandedAlertDialogBuilder(requireActivity())
.setView(binding.getRoot())
.setTitle(R.string.simple_comment)
.setNegativeButton(android.R.string.cancel, null)
@@ -80,5 +82,10 @@ public class CardCommentsEditDialogFragment extends DialogFragment {
fragment.setArguments(bundle);
return fragment;
}
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ BrandedActivity.applyBrandToEditText(mainColor, textColor, binding.input);
+ }
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CardCommentsFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CardCommentsFragment.java
index 34aebb529..b202c97b0 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CardCommentsFragment.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CardCommentsFragment.java
@@ -13,17 +13,21 @@ import androidx.fragment.app.Fragment;
import java.util.Date;
+import it.niedermann.nextcloud.deck.Application;
import it.niedermann.nextcloud.deck.databinding.FragmentCardEditTabCommentsBinding;
import it.niedermann.nextcloud.deck.model.ocs.comment.DeckComment;
import it.niedermann.nextcloud.deck.persistence.sync.SyncManager;
+import it.niedermann.nextcloud.deck.ui.branding.Branded;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
+import static it.niedermann.nextcloud.deck.ui.branding.BrandedActivity.applyBrandToEditText;
+import static it.niedermann.nextcloud.deck.ui.branding.BrandedActivity.applyBrandToFAB;
import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_ACCOUNT_ID;
import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_CAN_EDIT;
import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_LOCAL_ID;
-public class CardCommentsFragment extends Fragment implements CommentEditedListener {
+public class CardCommentsFragment extends Fragment implements Branded, CommentEditedListener {
private FragmentCardEditTabCommentsBinding binding;
private SyncManager syncManager;
@@ -110,4 +114,22 @@ public class CardCommentsFragment extends Fragment implements CommentEditedListe
public void onCommentEdited(Long id, String comment) {
syncManager.updateComment(accountId, localId, id, comment);
}
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ Application.registerBrandedComponent(requireContext(), this);
+ }
+
+ @Override
+ public void onPause() {
+ Application.deregisterBrandedComponent(this);
+ super.onPause();
+ }
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ applyBrandToEditText(mainColor, textColor, binding.message);
+ applyBrandToFAB(mainColor, textColor, binding.fab);
+ }
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/details/CardDetailsFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/details/CardDetailsFragment.java
index c967de267..df580bd46 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/details/CardDetailsFragment.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/details/CardDetailsFragment.java
@@ -2,6 +2,7 @@ package it.niedermann.nextcloud.deck.ui.card.details;
import android.app.DatePickerDialog;
import android.app.TimePickerDialog;
+import android.app.TimePickerDialog.OnTimeSetListener;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
@@ -37,6 +38,7 @@ import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
+import it.niedermann.nextcloud.deck.Application;
import it.niedermann.nextcloud.deck.DeckLog;
import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.databinding.FragmentCardEditTabDetailsBinding;
@@ -45,6 +47,7 @@ import it.niedermann.nextcloud.deck.model.Label;
import it.niedermann.nextcloud.deck.model.User;
import it.niedermann.nextcloud.deck.model.full.FullCard;
import it.niedermann.nextcloud.deck.persistence.sync.SyncManager;
+import it.niedermann.nextcloud.deck.ui.branding.Branded;
import it.niedermann.nextcloud.deck.ui.card.LabelAutoCompleteAdapter;
import it.niedermann.nextcloud.deck.ui.card.UserAutoCompleteAdapter;
import it.niedermann.nextcloud.deck.util.ColorUtil;
@@ -52,15 +55,16 @@ import it.niedermann.nextcloud.deck.util.DimensionUtil;
import it.niedermann.nextcloud.deck.util.MarkDownUtil;
import it.niedermann.nextcloud.deck.util.ViewUtil;
+import static android.app.DatePickerDialog.OnDateSetListener;
import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.LiveDataHelper.observeOnce;
+import static it.niedermann.nextcloud.deck.ui.branding.BrandedActivity.applyBrandToEditText;
import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_ACCOUNT_ID;
import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_BOARD_ID;
import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_CAN_EDIT;
import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_LOCAL_ID;
import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.NO_LOCAL_ID;
-public class CardDetailsFragment extends Fragment implements DatePickerDialog.OnDateSetListener,
- TimePickerDialog.OnTimeSetListener {
+public class CardDetailsFragment extends Fragment implements Branded, OnDateSetListener, OnTimeSetListener {
private FragmentCardEditTabDetailsBinding binding;
@@ -139,7 +143,7 @@ public class CardDetailsFragment extends Fragment implements DatePickerDialog.On
avatarSize = DimensionUtil.getAvatarDimension(requireContext());
avatarLayoutParams = new LinearLayout.LayoutParams(avatarSize, avatarSize);
- avatarLayoutParams.setMargins(0, 0, getContext().getResources().getDimensionPixelSize(R.dimen.standard_half_padding), 0);
+ avatarLayoutParams.setMargins(0, 0, requireContext().getResources().getDimensionPixelSize(R.dimen.spacer_1x), 0);
try {
baseUrl = syncManager.getServerUrl();
@@ -186,7 +190,7 @@ public class CardDetailsFragment extends Fragment implements DatePickerDialog.On
private TimePickerDialog createTimePickerDialogFromDate(
@NonNull Context context,
- @Nullable TimePickerDialog.OnTimeSetListener listener,
+ @Nullable OnTimeSetListener listener,
@Nullable Date date
) {
int hourOfDay = 0;
@@ -201,7 +205,7 @@ public class CardDetailsFragment extends Fragment implements DatePickerDialog.On
private DatePickerDialog createDatePickerDialogFromDate(
@NonNull Context context,
- @Nullable DatePickerDialog.OnDateSetListener listener,
+ @Nullable OnDateSetListener listener,
@Nullable Date date
) {
int year;
@@ -429,4 +433,25 @@ public class CardDetailsFragment extends Fragment implements DatePickerDialog.On
binding.clearDueDate.setVisibility(View.VISIBLE);
}
}
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ Application.registerBrandedComponent(requireContext(), this);
+ }
+
+ @Override
+ public void onPause() {
+ Application.deregisterBrandedComponent(this);
+ super.onPause();
+ }
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ applyBrandToEditText(mainColor, textColor, binding.labels);
+ applyBrandToEditText(mainColor, textColor, binding.dueDateDate);
+ applyBrandToEditText(mainColor, textColor, binding.dueDateTime);
+ applyBrandToEditText(mainColor, textColor, binding.people);
+ applyBrandToEditText(mainColor, textColor, binding.description);
+ }
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/CrossTabDragAndDrop.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/CrossTabDragAndDrop.java
deleted file mode 100644
index 9c50f3659..000000000
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/CrossTabDragAndDrop.java
+++ /dev/null
@@ -1,223 +0,0 @@
-package it.niedermann.nextcloud.deck.ui.dnd;
-
-import android.content.res.Resources;
-import android.util.Log;
-import android.view.DragEvent;
-import android.view.View;
-
-import androidx.annotation.NonNull;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentManager;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.viewpager2.widget.ViewPager2;
-
-import com.google.android.material.tabs.TabLayout;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-
-import it.niedermann.nextcloud.deck.R;
-
-public class CrossTabDragAndDrop<
- TabFragment extends Fragment & DragAndDropTab<ItemAdapter>,
- ItemAdapter extends RecyclerView.Adapter<?> & DragAndDropAdapter<ItemModel>,
- ItemModel extends DragAndDropModel
- > {
-
- private static final String TAG = CrossTabDragAndDrop.class.getCanonicalName();
- private static final ScrollHelper SCROLL_HELPER = new ScrollHelper();
-
- private final float pxToReact;
- private final float pxToReactTopBottom;
- private final int dragAndDropMsToReact;
- private final int dragAndDropMsToReactTopBottom;
- private final int displayX;
- private long lastSwap = 0;
- private long lastMove = 0;
-
- private final Set<ItemMovedByDragListener<ItemModel>> moveListenerList = new HashSet<>(1);
-
- public CrossTabDragAndDrop(@NonNull Resources resources) {
- this.displayX = resources.getDisplayMetrics().widthPixels;
- final float density = resources.getDisplayMetrics().density;
- this.pxToReact = resources.getInteger(R.integer.drag_n_drop_dp_to_react) * density;
- this.pxToReactTopBottom = resources.getInteger(R.integer.drag_n_drop_dp_to_react_top_bottom) * density;
- this.dragAndDropMsToReact = resources.getInteger(R.integer.drag_n_drop_ms_to_react);
- this.dragAndDropMsToReactTopBottom = resources.getInteger(R.integer.drag_n_drop_dp_to_react_top_bottom);
- }
-
- public void register(final ViewPager2 viewPager, TabLayout stackLayout, FragmentManager fm) {
- viewPager.setOnDragListener((View v, DragEvent dragEvent) -> {
- DraggedItemLocalState<TabFragment, ItemAdapter, ItemModel> draggedItemLocalState = (DraggedItemLocalState<TabFragment, ItemAdapter, ItemModel>) dragEvent.getLocalState();
- View draggedView = draggedItemLocalState.getDraggedView();
- switch (dragEvent.getAction()) {
- case DragEvent.ACTION_DRAG_STARTED: {
- draggedView.setVisibility(View.INVISIBLE);
- draggedItemLocalState.onDragStart(viewPager, fm);
- break;
- }
- case DragEvent.ACTION_DRAG_LOCATION: {
- RecyclerView currentRecyclerView = draggedItemLocalState.getRecyclerView();
- ItemAdapter itemAdapter = draggedItemLocalState.getItemAdapter();
-
- long now = System.currentTimeMillis();
- if (lastSwap + dragAndDropMsToReact < now) { // don't change Tabs so fast!
- int oldTabPosition = viewPager.getCurrentItem();
-
- boolean shouldSwitchTab = true;
-
- int newTabPosition = -1;
- // change tab? if yes, which direction?
- if (dragEvent.getX() <= pxToReact) {
- newTabPosition = oldTabPosition - 1;
- } else if (dragEvent.getX() >= displayX - pxToReact) {
- newTabPosition = oldTabPosition + 1;
- } else {
- shouldSwitchTab = false;
- }
-
- if (shouldSwitchTab && isMovePossible(viewPager, newTabPosition)) {
- removeItem(currentRecyclerView, draggedView, itemAdapter);
- detectAndKillDuplicatesInNeighbourTab(viewPager, draggedItemLocalState.getDraggedItemModel(), fm, oldTabPosition, newTabPosition);
- switchTab(dragEvent, viewPager, stackLayout, fm, draggedItemLocalState, now, newTabPosition);
-
- return true;
- }
- }
-
- //scroll if needed
- if (dragEvent.getY() <= pxToReactTopBottom) {
- SCROLL_HELPER.startScroll(currentRecyclerView, ScrollHelper.ScrollDirection.UP);
- } else if (dragEvent.getY() >= currentRecyclerView.getBottom() - pxToReactTopBottom) {
- SCROLL_HELPER.startScroll(currentRecyclerView, ScrollHelper.ScrollDirection.DOWN);
- } else {
- SCROLL_HELPER.stopScroll();
- }
-
- if (lastMove + dragAndDropMsToReactTopBottom < now) {
- //push around the other items
- pushAroundItems(draggedView, currentRecyclerView, dragEvent, itemAdapter, draggedItemLocalState, now);
- }
- break;
- }
- case DragEvent.ACTION_DRAG_ENDED:
- case DragEvent.ACTION_DROP: {
- draggedItemLocalState.getRecyclerView().removeOnChildAttachStateChangeListener(draggedItemLocalState.getInsertedListener());
- SCROLL_HELPER.stopScroll();
- draggedView.setVisibility(View.VISIBLE);
- // Clean up the original dragged view, so the next onBindViewHolder() will not display the view at the position of the original dragged view as View.INVISIBLE
- draggedItemLocalState.getOriginalDraggedView().setVisibility(View.VISIBLE);
- notifyListeners(draggedItemLocalState);
- break;
- }
- }
- return true;
- });
- }
-
- private void switchTab(DragEvent dragEvent, ViewPager2 viewPager, TabLayout stackLayout, FragmentManager fm, final DraggedItemLocalState<TabFragment, ItemAdapter, ItemModel> draggedItemLocalState, long now, int newPosition) {
- viewPager.setCurrentItem(newPosition);
- draggedItemLocalState.onTabChanged(viewPager, fm);
- Objects.requireNonNull(stackLayout.getTabAt(newPosition)).select();
-
- final RecyclerView recyclerView = draggedItemLocalState.getRecyclerView();
- final ItemAdapter itemAdapter = draggedItemLocalState.getItemAdapter();
-
- RecyclerView.OnChildAttachStateChangeListener onChildAttachStateChangeListener = new RecyclerView.OnChildAttachStateChangeListener() {
- @Override
- public void onChildViewAttachedToWindow(@NonNull View view) {
- recyclerView.removeOnChildAttachStateChangeListener(this);
- draggedItemLocalState.setInsertedListener(null);
- view.setVisibility(View.INVISIBLE);
- draggedItemLocalState.setDraggedView(view);
- pushAroundItems(view, recyclerView, dragEvent, itemAdapter, (DraggedItemLocalState<TabFragment, ItemAdapter, ItemModel>) draggedItemLocalState, now);
- }
-
- @Override
- public void onChildViewDetachedFromWindow(@NonNull View view) {/* do nothing */}
- };
- draggedItemLocalState.setInsertedListener(onChildAttachStateChangeListener);
- recyclerView.addOnChildAttachStateChangeListener(onChildAttachStateChangeListener);
-
- //insert item in new tab
- View firstVisibleView = recyclerView.getChildAt(0);
- int positionToInsert = firstVisibleView == null ? 0 : recyclerView.getChildAdapterPosition(firstVisibleView) + 1;
- itemAdapter.insertItem(draggedItemLocalState.getDraggedItemModel(), positionToInsert);
-
- lastSwap = now;
- }
-
- private void pushAroundItems(@NonNull View view, RecyclerView recyclerView, DragEvent dragEvent, ItemAdapter itemAdapter, DraggedItemLocalState<TabFragment, ItemAdapter, ItemModel> draggedItemLocalState, long now) {
- View viewUnder = recyclerView.findChildViewUnder(dragEvent.getX(), dragEvent.getY());
-
- if (viewUnder != null) {
- int toPositon = recyclerView.getChildAdapterPosition(viewUnder);
- if (toPositon != -1) {
- int fromPosition = recyclerView.getChildAdapterPosition(view);
- if (fromPosition != -1 && fromPosition != toPositon) {
- recyclerView.post(() -> {
- itemAdapter.moveItem(fromPosition, toPositon);
- draggedItemLocalState.setPositionInItemAdapter(toPositon);
- });
- lastMove = now;
- }
- }
- }
- }
-
- private static boolean isMovePossible(ViewPager2 viewPager, int newPosition) {
- return newPosition < Objects.requireNonNull(viewPager.getAdapter()).getItemCount() && newPosition >= 0;
- }
-
- private void detectAndKillDuplicatesInNeighbourTab(ViewPager2 viewPager, ItemModel itemToFind, FragmentManager fm, int oldTabPosition, int newTabPosition) {
- int tabPositionToCheck = newTabPosition > oldTabPosition ? newTabPosition + 1 : newTabPosition - 1;
-
- if (isMovePossible(viewPager, tabPositionToCheck)) {
- viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
- @Override
- public void onPageSelected(int position) {
- super.onPageSelected(position);
- viewPager.unregisterOnPageChangeCallback(this);
- ItemAdapter itemAdapter = DragAndDropUtil.<TabFragment>getTabFragment(fm, Objects.requireNonNull(viewPager.getAdapter()).getItemId(tabPositionToCheck)).getAdapter();
- itemAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
- @Override
- public void onChanged() {
- super.onChanged();
- itemAdapter.unregisterAdapterDataObserver(this);
- List<ItemModel> itemList = itemAdapter.getItemList();
- for (int i = 0; i < itemList.size(); i++) {
- ItemModel c = itemList.get(i);
- if (itemToFind.getComparableId().equals(c.getComparableId())) {
- itemAdapter.removeItem(i);
- itemAdapter.notifyItemRemoved(i);
- Log.v(TAG, "DnD removed dupe at tab " + tabPositionToCheck + ": " + c.toString());
- break;
- }
- }
- }
- });
- }
- });
- }
- }
-
- private void removeItem(RecyclerView currentRecyclerView, View view, ItemAdapter itemAdapter) {
- int oldItemPosition = currentRecyclerView.getChildAdapterPosition(view);
-
- if (oldItemPosition != -1) {
- itemAdapter.removeItem(oldItemPosition);
- }
- }
-
- private void notifyListeners(DraggedItemLocalState draggedItemLocalState) {
- for (ItemMovedByDragListener listener : moveListenerList) {
- listener.onItemMoved(draggedItemLocalState.getDraggedItemModel(), draggedItemLocalState.getCurrentTabId(), draggedItemLocalState.getPositionInItemAdapter());
- }
- }
-
- public void addItemMovedByDragListener(ItemMovedByDragListener<ItemModel> listener) {
- moveListenerList.add(listener);
- }
-}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/DragAndDropAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/DragAndDropAdapter.java
deleted file mode 100644
index 5d8a036dd..000000000
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/DragAndDropAdapter.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package it.niedermann.nextcloud.deck.ui.dnd;
-
-import java.util.List;
-
-public interface DragAndDropAdapter<Model> {
-
- void removeItem(int position);
-
- void moveItem(int fromPosition, int toPosition);
-
- void insertItem(Model item, int position);
-
- List<Model> getItemList();
-}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/DragAndDropModel.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/DragAndDropModel.java
deleted file mode 100644
index c4b0493c2..000000000
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/DragAndDropModel.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package it.niedermann.nextcloud.deck.ui.dnd;
-
-import androidx.annotation.NonNull;
-
-public interface DragAndDropModel {
- @NonNull
- Long getComparableId();
-}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/DragAndDropTab.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/DragAndDropTab.java
deleted file mode 100644
index 13633e02d..000000000
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/DragAndDropTab.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package it.niedermann.nextcloud.deck.ui.dnd;
-
-import androidx.recyclerview.widget.RecyclerView;
-
-public interface DragAndDropTab<ItemAdapter extends RecyclerView.Adapter<?> & DragAndDropAdapter<?>> {
-
- ItemAdapter getAdapter();
-
- RecyclerView getRecyclerView();
-}
-
-
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/DragAndDropUtil.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/DragAndDropUtil.java
deleted file mode 100644
index 0c861d17b..000000000
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/DragAndDropUtil.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package it.niedermann.nextcloud.deck.ui.dnd;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.fragment.app.FragmentManager;
-
-// Public util
-@SuppressWarnings("WeakerAccess")
-public class DragAndDropUtil {
-
- private DragAndDropUtil() {
- // Util class
- }
-
- protected static <T> T getTabFragment(@NonNull FragmentManager fm, @Nullable Long currentStackId) throws IllegalArgumentException {
- return (T) fm.findFragmentByTag("f" + currentStackId);
- }
-}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/DraggedItemLocalState.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/DraggedItemLocalState.java
deleted file mode 100644
index cd3ab58a3..000000000
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/DraggedItemLocalState.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package it.niedermann.nextcloud.deck.ui.dnd;
-
-import android.view.View;
-
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentManager;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.viewpager2.widget.ViewPager2;
-
-import java.util.Objects;
-
-@SuppressWarnings("WeakerAccess")
-public class DraggedItemLocalState<
- TabFragment extends Fragment & DragAndDropTab<ItemAdapter>,
- ItemAdapter extends RecyclerView.Adapter<?> & DragAndDropAdapter<ItemModel>,
- ItemModel> {
- private ItemModel draggedCard;
- /** The original dragged view */
- private final View originalDraggedView;
- /** The currently dragged view (can change when the tab changes */
- private View draggedView;
- private ItemAdapter itemAdapter;
- private int positionInCardAdapter;
- private RecyclerView.OnChildAttachStateChangeListener insertedListener = null;
- private RecyclerView recyclerView = null;
- private long currentTabId;
-
- public DraggedItemLocalState(ItemModel draggedCard, View draggedView, ItemAdapter itemAdapter, int positionInCardAdapter) {
- this.draggedCard = draggedCard;
- this.draggedView = draggedView;
- this.originalDraggedView = draggedView;
- this.itemAdapter = itemAdapter;
- this.positionInCardAdapter = positionInCardAdapter;
- }
-
- protected void onDragStart(ViewPager2 viewPager, FragmentManager fm) {
- this.currentTabId = Objects.requireNonNull(viewPager.getAdapter()).getItemId(viewPager.getCurrentItem());
- this.recyclerView = DragAndDropUtil.<TabFragment>getTabFragment(fm, currentTabId).getRecyclerView();
- }
-
- protected void onTabChanged(ViewPager2 viewPager, FragmentManager fm) {
- if (insertedListener != null) {
- this.recyclerView.removeOnChildAttachStateChangeListener(insertedListener);
- this.insertedListener = null;
- }
- this.currentTabId = Objects.requireNonNull(viewPager.getAdapter()).getItemId(viewPager.getCurrentItem());
- this.recyclerView = DragAndDropUtil.<TabFragment>getTabFragment(fm, currentTabId).getRecyclerView();
- this.itemAdapter = (ItemAdapter) recyclerView.getAdapter();
- }
-
- protected long getCurrentTabId() {
- return currentTabId;
- }
-
- protected ItemModel getDraggedItemModel() {
- return draggedCard;
- }
-
- protected View getOriginalDraggedView() {
- return originalDraggedView;
- }
-
- protected View getDraggedView() {
- return draggedView;
- }
-
- protected void setDraggedView(View draggedView) {
- this.draggedView = draggedView;
- }
-
- protected ItemAdapter getItemAdapter() {
- return itemAdapter;
- }
-
- protected int getPositionInItemAdapter() {
- return positionInCardAdapter;
- }
-
- protected void setPositionInItemAdapter(int positionInCardAdapter) {
- this.positionInCardAdapter = positionInCardAdapter;
- }
-
- protected void setInsertedListener(RecyclerView.OnChildAttachStateChangeListener insertedListener) {
- this.insertedListener = insertedListener;
- }
-
- public RecyclerView.OnChildAttachStateChangeListener getInsertedListener() {
- return insertedListener;
- }
-
- protected RecyclerView getRecyclerView() {
- return recyclerView;
- }
-
-}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/ItemMovedByDragListener.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/ItemMovedByDragListener.java
deleted file mode 100644
index 8c00a1a26..000000000
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/ItemMovedByDragListener.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package it.niedermann.nextcloud.deck.ui.dnd;
-
-public interface ItemMovedByDragListener<ItemModel> {
- void onItemMoved(ItemModel movedItem, long tabId, int position);
-} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/ScrollHelper.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/ScrollHelper.java
deleted file mode 100644
index 2fb52e733..000000000
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/dnd/ScrollHelper.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package it.niedermann.nextcloud.deck.ui.dnd;
-
-import android.os.Handler;
-
-import androidx.recyclerview.widget.RecyclerView;
-
-@SuppressWarnings("WeakerAccess")
-public class ScrollHelper implements Runnable {
-
- private static final int SROLL_SPEED = 200;
-
- public enum ScrollDirection {
- UP,
- DOWN
- }
-
- private boolean shouldScroll = false;
- private ScrollDirection scrollDirection;
- private RecyclerView currentRecyclerView;
- private Handler handler = new Handler();
-
- public void startScroll(RecyclerView recyclerView, ScrollDirection scrollDirection) {
- this.scrollDirection = scrollDirection;
- this.currentRecyclerView = recyclerView;
- if (!shouldScroll) {
- this.shouldScroll = true;
- handler.post(this);
- }
- }
-
- public void stopScroll() {
- this.shouldScroll = false;
- }
-
- @Override
- public void run() {
- if (scrollDirection == ScrollDirection.UP) {
- currentRecyclerView.smoothScrollBy(0, SROLL_SPEED * -1);
- } else {
- currentRecyclerView.smoothScrollBy(0, SROLL_SPEED);
- }
- if (shouldScroll) {
- handler.postDelayed(this, 100);
- }
- }
-} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/AbstractAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/AbstractAdapter.java
new file mode 100644
index 000000000..3cfdfdfa6
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/AbstractAdapter.java
@@ -0,0 +1,41 @@
+package it.niedermann.nextcloud.deck.ui.preparecreate;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.Objects;
+
+public abstract class AbstractAdapter<T> extends ArrayAdapter<T> {
+
+ @NonNull
+ protected final LayoutInflater inflater;
+
+ @SuppressWarnings("WeakerAccess")
+ public AbstractAdapter(@NonNull Context context, int resource) {
+ super(context, resource);
+ inflater = LayoutInflater.from(context);
+ }
+
+ protected abstract long getItemId(@NonNull T item);
+
+ @Override
+ public final long getItemId(int position) {
+ return getItemId(Objects.requireNonNull(getItem(position)));
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ @Override
+ public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
+ return getView(position, convertView, parent);
+ }
+}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/AccountAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/AccountAdapter.java
new file mode 100644
index 000000000..a0c8e9f4f
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/AccountAdapter.java
@@ -0,0 +1,51 @@
+package it.niedermann.nextcloud.deck.ui.preparecreate;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+
+import org.jetbrains.annotations.NotNull;
+
+import it.niedermann.nextcloud.deck.DeckLog;
+import it.niedermann.nextcloud.deck.R;
+import it.niedermann.nextcloud.deck.databinding.ItemPrepareCreateAccountBinding;
+import it.niedermann.nextcloud.deck.model.Account;
+import it.niedermann.nextcloud.deck.util.ViewUtil;
+
+import static it.niedermann.nextcloud.deck.util.DimensionUtil.getAvatarDimension;
+
+public class AccountAdapter extends AbstractAdapter<Account> {
+
+ @SuppressWarnings("WeakerAccess")
+ public AccountAdapter(@NonNull Context context) {
+ super(context, R.layout.item_prepare_create_account);
+ }
+
+ @Override
+ protected long getItemId(@NonNull Account item) {
+ return item.getId();
+ }
+
+ @NotNull
+ @Override
+ public View getView(int position, View convertView, @NotNull ViewGroup parent) {
+ final ItemPrepareCreateAccountBinding binding;
+ if (convertView == null) {
+ binding = ItemPrepareCreateAccountBinding.inflate(inflater, parent, false);
+ } else {
+ binding = ItemPrepareCreateAccountBinding.bind(convertView);
+ }
+
+ final Account item = getItem(position);
+ if (item != null) {
+ binding.username.setText(item.getUserName());
+ binding.instance.setText(item.getUrl());
+ ViewUtil.addAvatar(binding.avatar.getContext(), binding.avatar, item.getUrl(), item.getUserName(), getAvatarDimension(binding.avatar.getContext(), R.dimen.icon_size_details), R.drawable.ic_person_grey600_24dp);
+ } else {
+ DeckLog.logError(new IllegalArgumentException("No item for position " + position));
+ }
+ return binding.getRoot();
+ }
+}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/BoardAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/BoardAdapter.java
new file mode 100644
index 000000000..190c55e4b
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/BoardAdapter.java
@@ -0,0 +1,48 @@
+package it.niedermann.nextcloud.deck.ui.preparecreate;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+
+import org.jetbrains.annotations.NotNull;
+
+import it.niedermann.nextcloud.deck.DeckLog;
+import it.niedermann.nextcloud.deck.R;
+import it.niedermann.nextcloud.deck.databinding.ItemPrepareCreateBoardBinding;
+import it.niedermann.nextcloud.deck.model.Board;
+import it.niedermann.nextcloud.deck.util.ViewUtil;
+
+public class BoardAdapter extends AbstractAdapter<Board> {
+
+ @SuppressWarnings("WeakerAccess")
+ public BoardAdapter(@NonNull Context context) {
+ super(context, R.layout.item_prepare_create_board);
+ }
+
+ @Override
+ protected long getItemId(@NonNull Board item) {
+ return item.getLocalId();
+ }
+
+ @NotNull
+ @Override
+ public View getView(int position, View convertView, @NotNull ViewGroup parent) {
+ final ItemPrepareCreateBoardBinding binding;
+ if (convertView == null) {
+ binding = ItemPrepareCreateBoardBinding.inflate(inflater, parent, false);
+ } else {
+ binding = ItemPrepareCreateBoardBinding.bind(convertView);
+ }
+
+ final Board item = getItem(position);
+ if (item != null) {
+ binding.boardTitle.setText(item.getTitle());
+ binding.avatar.setImageDrawable(ViewUtil.getTintedImageView(binding.avatar.getContext(), R.drawable.circle_grey600_36dp, "#" + item.getColor()));
+ } else {
+ DeckLog.logError(new IllegalArgumentException("No item for position " + position));
+ }
+ return binding.getRoot();
+ }
+}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/PrepareCreateActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/PrepareCreateActivity.java
new file mode 100644
index 000000000..03f1b6d92
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/PrepareCreateActivity.java
@@ -0,0 +1,197 @@
+package it.niedermann.nextcloud.deck.ui.preparecreate;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.widget.ArrayAdapter;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.Observer;
+
+import java.util.List;
+
+import it.niedermann.nextcloud.deck.Application;
+import it.niedermann.nextcloud.deck.R;
+import it.niedermann.nextcloud.deck.databinding.ActivityPrepareCreateBinding;
+import it.niedermann.nextcloud.deck.model.Account;
+import it.niedermann.nextcloud.deck.model.Board;
+import it.niedermann.nextcloud.deck.model.full.FullStack;
+import it.niedermann.nextcloud.deck.persistence.sync.SyncManager;
+import it.niedermann.nextcloud.deck.ui.ImportAccountActivity;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedActivity;
+import it.niedermann.nextcloud.deck.ui.card.EditActivity;
+import it.niedermann.nextcloud.deck.ui.exception.ExceptionHandler;
+
+import static androidx.lifecycle.Transformations.switchMap;
+import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_ACCOUNT_ID;
+import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_BOARD_ID;
+import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_LOCAL_ID;
+import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_STACK_ID;
+import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.NO_LOCAL_ID;
+
+public class PrepareCreateActivity extends BrandedActivity {
+
+ private ActivityPrepareCreateBinding binding;
+
+ private SyncManager syncManager;
+
+ private long lastAccountId;
+ private long lastBoardId;
+ private long lastStackId;
+
+ private ArrayAdapter<Account> accountAdapter;
+ private ArrayAdapter<Board> boardAdapter;
+ private ArrayAdapter<FullStack> stackAdapter;
+
+ @Nullable
+ private LiveData<List<Board>> boardsLiveData;
+ @NonNull
+ private Observer<List<Board>> boardsObserver = (boards) -> {
+ boardAdapter.clear();
+ boardAdapter.addAll(boards);
+ binding.boardSelect.setEnabled(true);
+
+ if (boards.size() > 0) {
+ binding.boardSelect.setEnabled(true);
+
+ for (Board board : boards) {
+ if (board.getLocalId() == lastBoardId) {
+ binding.boardSelect.setSelection(boardAdapter.getPosition(board));
+ break;
+ }
+ }
+ } else {
+ binding.boardSelect.setEnabled(false);
+ binding.submit.setEnabled(false);
+ }
+ };
+
+ @Nullable
+ private LiveData<List<FullStack>> stacksLiveData;
+ @NonNull
+ private Observer<List<FullStack>> stacksObserver = (fullStacks) -> {
+ stackAdapter.clear();
+ stackAdapter.addAll(fullStacks);
+
+ if (fullStacks.size() > 0) {
+ binding.stackSelect.setEnabled(true);
+ binding.submit.setEnabled(true);
+
+ for (FullStack fullStack : fullStacks) {
+ if (fullStack.getLocalId() == lastStackId) {
+ binding.stackSelect.setSelection(stackAdapter.getPosition(fullStack));
+ break;
+ }
+ }
+ } else {
+ binding.stackSelect.setEnabled(false);
+ binding.submit.setEnabled(false);
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(this));
+ setTheme(Application.getAppTheme(this) ? R.style.DarkAppTheme : R.style.AppTheme);
+
+ binding = ActivityPrepareCreateBinding.inflate(getLayoutInflater());
+ setContentView(binding.getRoot());
+ setSupportActionBar(binding.toolbar);
+
+ accountAdapter = new AccountAdapter(this);
+ binding.accountSelect.setAdapter(accountAdapter);
+ binding.accountSelect.setEnabled(false);
+ boardAdapter = new BoardAdapter(this);
+ binding.boardSelect.setAdapter(boardAdapter);
+ binding.stackSelect.setEnabled(false);
+ stackAdapter = new StackAdapter(this);
+ binding.stackSelect.setAdapter(stackAdapter);
+ binding.stackSelect.setEnabled(false);
+
+ syncManager = new SyncManager(this);
+
+ switchMap(syncManager.hasAccounts(), hasAccounts -> {
+ if (hasAccounts) {
+ return syncManager.readAccounts();
+ } else {
+ startActivityForResult(new Intent(this, ImportAccountActivity.class), ImportAccountActivity.REQUEST_CODE_IMPORT_ACCOUNT);
+ return null;
+ }
+ }).observe(this, (List<Account> accounts) -> {
+ if (accounts == null || accounts.size() == 0) {
+ throw new IllegalStateException("hasAccounts() returns true, but readAccounts() returns null or has no entry");
+ }
+
+ lastAccountId = Application.readCurrentAccountId(this);
+ lastBoardId = Application.readCurrentBoardId(this, lastAccountId);
+ lastStackId = Application.readCurrentStackId(this, lastAccountId, lastBoardId);
+
+ accountAdapter.clear();
+ accountAdapter.addAll(accounts);
+ binding.accountSelect.setEnabled(true);
+
+ for (Account account : accounts) {
+ if (account.getId() == lastAccountId) {
+ binding.accountSelect.setSelection(accountAdapter.getPosition(account));
+ break;
+ }
+ }
+ });
+
+ binding.accountSelect.setOnItemSelectedListener((SelectedListener) (parent, view, position, id) ->
+ updateLiveDataSource(boardsLiveData, boardsObserver, syncManager.getBoardsWithEditPermission(parent.getSelectedItemId())));
+
+ binding.boardSelect.setOnItemSelectedListener((SelectedListener) (parent, view, position, id) ->
+ updateLiveDataSource(stacksLiveData, stacksObserver, syncManager.getStacksForBoard(binding.accountSelect.getSelectedItemId(), parent.getSelectedItemId())));
+
+ binding.cancel.setOnClickListener((v) -> finish());
+ binding.submit.setOnClickListener((v) -> onSubmit());
+ }
+
+ /**
+ * Updates the source of the given liveData and de- and reregisters the given observer.
+ */
+ private <T> void updateLiveDataSource(@Nullable LiveData<T> liveData, Observer<T> observer, LiveData<T> newSource) {
+ if (liveData != null) {
+ liveData.removeObserver(observer);
+ }
+ liveData = newSource;
+ liveData.observe(PrepareCreateActivity.this, observer);
+ }
+
+ /**
+ * Starts EditActivity and passes parameters.
+ */
+ private void onSubmit() {
+ final long accountId = binding.accountSelect.getSelectedItemId();
+ final long boardId = binding.boardSelect.getSelectedItemId();
+ final long stackId = binding.stackSelect.getSelectedItemId();
+
+ Intent intent = new Intent(getApplicationContext(), EditActivity.class);
+
+ intent.putExtra(BUNDLE_KEY_ACCOUNT_ID, accountId);
+ intent.putExtra(BUNDLE_KEY_BOARD_ID, boardId);
+ intent.putExtra(BUNDLE_KEY_STACK_ID, stackId);
+ intent.putExtra(BUNDLE_KEY_LOCAL_ID, NO_LOCAL_ID);
+
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
+
+ Application.saveCurrentAccountId(this, accountId);
+ Application.saveCurrentBoardId(this, accountId, boardId);
+ Application.saveCurrentStackId(this, accountId, boardId, stackId);
+
+ finish();
+ }
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ super.applyBrand(mainColor, textColor);
+ applyBrandToPrimaryToolbar(mainColor, textColor, binding.toolbar);
+ binding.submit.setBackgroundColor(mainColor);
+ binding.submit.setTextColor(textColor);
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/SelectedListener.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/SelectedListener.java
new file mode 100644
index 000000000..ccc4e08ef
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/SelectedListener.java
@@ -0,0 +1,13 @@
+package it.niedermann.nextcloud.deck.ui.preparecreate;
+
+import android.widget.AdapterView;
+
+/**
+ * Default interface implementation
+ */
+public interface SelectedListener extends AdapterView.OnItemSelectedListener {
+ @Override
+ default void onNothingSelected(AdapterView<?> parent) {
+ // Nothing to do here...
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/StackAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/StackAdapter.java
new file mode 100644
index 000000000..89c702075
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/StackAdapter.java
@@ -0,0 +1,46 @@
+package it.niedermann.nextcloud.deck.ui.preparecreate;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+
+import org.jetbrains.annotations.NotNull;
+
+import it.niedermann.nextcloud.deck.DeckLog;
+import it.niedermann.nextcloud.deck.R;
+import it.niedermann.nextcloud.deck.databinding.ItemPrepareCreateStackBinding;
+import it.niedermann.nextcloud.deck.model.full.FullStack;
+
+public class StackAdapter extends AbstractAdapter<FullStack> {
+
+ @SuppressWarnings("WeakerAccess")
+ public StackAdapter(@NonNull Context context) {
+ super(context, R.layout.item_prepare_create_stack);
+ }
+
+ @Override
+ protected long getItemId(@NonNull FullStack item) {
+ return item.getLocalId();
+ }
+
+ @NotNull
+ @Override
+ public View getView(int position, View convertView, @NotNull ViewGroup parent) {
+ final ItemPrepareCreateStackBinding binding;
+ if (convertView == null) {
+ binding = ItemPrepareCreateStackBinding.inflate(inflater, parent, false);
+ } else {
+ binding = ItemPrepareCreateStackBinding.bind(convertView);
+ }
+
+ final FullStack item = getItem(position);
+ if (item != null) {
+ binding.stackTitle.setText(item.getStack().getTitle());
+ } else {
+ DeckLog.logError(new IllegalArgumentException("No item for position " + position));
+ }
+ return binding.getRoot();
+ }
+}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/SettingsActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/SettingsActivity.java
index 62909f8cb..32a9a1849 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/SettingsActivity.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/SettingsActivity.java
@@ -1,17 +1,18 @@
-package it.niedermann.nextcloud.deck.ui;
+package it.niedermann.nextcloud.deck.ui.settings;
import android.os.Bundle;
import androidx.annotation.Nullable;
-import androidx.appcompat.app.AppCompatActivity;
import it.niedermann.nextcloud.deck.Application;
import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.databinding.ActivitySettingsBinding;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedActivity;
import it.niedermann.nextcloud.deck.ui.exception.ExceptionHandler;
-import it.niedermann.nextcloud.deck.ui.settings.SettingsFragment;
-public class SettingsActivity extends AppCompatActivity {
+public class SettingsActivity extends BrandedActivity {
+
+ private ActivitySettingsBinding binding;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -19,7 +20,7 @@ public class SettingsActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler(this));
- ActivitySettingsBinding binding = ActivitySettingsBinding.inflate(getLayoutInflater());
+ binding = ActivitySettingsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
@@ -36,4 +37,10 @@ public class SettingsActivity extends AppCompatActivity {
finish(); // close this activity as oppose to navigating up
return true;
}
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ super.applyBrand(mainColor, textColor);
+ applyBrandToPrimaryToolbar(mainColor, textColor, binding.toolbar);
+ }
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/SettingsFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/SettingsFragment.java
index beb552513..5ca6aab99 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/SettingsFragment.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/SettingsFragment.java
@@ -2,24 +2,31 @@ package it.niedermann.nextcloud.deck.ui.settings;
import android.app.Activity;
import android.os.Bundle;
+import android.view.View;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
-import androidx.preference.SwitchPreference;
import it.niedermann.nextcloud.deck.Application;
import it.niedermann.nextcloud.deck.DeckLog;
import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.persistence.sync.SyncWorker;
+import it.niedermann.nextcloud.deck.ui.branding.Branded;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedSwitchPreference;
-public class SettingsFragment extends PreferenceFragmentCompat {
+public class SettingsFragment extends PreferenceFragmentCompat implements Branded {
+
+ private BrandedSwitchPreference wifiOnlyPref;
+ private BrandedSwitchPreference themePref;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.settings, rootKey);
- final SwitchPreference wifiOnlyPref = findPreference(getString(R.string.pref_key_wifi_only));
+ wifiOnlyPref = findPreference(getString(R.string.pref_key_wifi_only));
if (wifiOnlyPref != null) {
wifiOnlyPref.setOnPreferenceChangeListener((Preference preference, Object newValue) -> {
Boolean syncOnWifiOnly = (Boolean) newValue;
@@ -30,7 +37,7 @@ public class SettingsFragment extends PreferenceFragmentCompat {
DeckLog.error("Could not find preference with key: \"" + getString(R.string.pref_key_wifi_only) + "\"");
}
- final SwitchPreference themePref = findPreference(getString(R.string.pref_key_dark_theme));
+ themePref = findPreference(getString(R.string.pref_key_dark_theme));
if (themePref != null) {
themePref.setOnPreferenceChangeListener((Preference preference, Object newValue) -> {
Boolean darkTheme = (Boolean) newValue;
@@ -53,6 +60,23 @@ public class SettingsFragment extends PreferenceFragmentCompat {
} else {
DeckLog.error("Could not find preference with key: \"" + getString(R.string.pref_key_background_sync) + "\"");
}
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ Application.registerBrandedComponent(requireContext(), this);
+ }
+ @Override
+ public void onDestroy() {
+ Application.deregisterBrandedComponent(this);
+ super.onDestroy();
+ }
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ wifiOnlyPref.applyBrand(mainColor, textColor);
+ themePref.applyBrand(mainColor, textColor);
}
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/DeleteStackDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/DeleteStackDialogFragment.java
new file mode 100644
index 000000000..e0a741b00
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/DeleteStackDialogFragment.java
@@ -0,0 +1,64 @@
+package it.niedermann.nextcloud.deck.ui.stack;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.DialogFragment;
+
+import it.niedermann.nextcloud.deck.R;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedDeleteAlertDialogBuilder;
+
+public class DeleteStackDialogFragment extends DialogFragment {
+
+ private static final String KEY_STACK_ID = "stack_id";
+
+ private DeleteStackListener deleteStackListener;
+ private Long stackId;
+
+
+ /**
+ * Use newInstance()-Method
+ */
+ public DeleteStackDialogFragment() {
+ }
+
+ @Override
+ public void onAttach(@NonNull Context context) {
+ super.onAttach(context);
+ if (context instanceof DeleteStackListener) {
+ this.deleteStackListener = (DeleteStackListener) context;
+ } else {
+ throw new ClassCastException("Caller must implement " + DeleteStackListener.class.getCanonicalName());
+ }
+
+ if (getArguments() == null || !getArguments().containsKey(KEY_STACK_ID)) {
+ throw new IllegalArgumentException("Please provide at least stack id as an argument");
+ } else {
+ this.stackId = getArguments().getLong(KEY_STACK_ID);
+ }
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ AlertDialog.Builder builder = new BrandedDeleteAlertDialogBuilder(requireContext())
+ .setTitle(R.string.delete_list)
+ .setMessage(R.string.do_you_want_to_delete_the_current_list)
+ .setPositiveButton(R.string.simple_delete, (dialog, whichButton) -> deleteStackListener.onStackDeleted(stackId))
+ .setNegativeButton(android.R.string.cancel, null);
+ return builder.create();
+ }
+
+ public static DialogFragment newInstance(long stackId) {
+ DeleteStackDialogFragment dialog = new DeleteStackDialogFragment();
+
+ Bundle args = new Bundle();
+ args.putLong(KEY_STACK_ID, stackId);
+ dialog.setArguments(args);
+
+ return dialog;
+ }
+}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/DeleteStackListener.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/DeleteStackListener.java
new file mode 100644
index 000000000..dfd1b4497
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/DeleteStackListener.java
@@ -0,0 +1,5 @@
+package it.niedermann.nextcloud.deck.ui.stack;
+
+public interface DeleteStackListener {
+ void onStackDeleted(Long stackLocalId);
+} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/EditStackDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/EditStackDialogFragment.java
index 0992e0837..f71d66c92 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/EditStackDialogFragment.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/EditStackDialogFragment.java
@@ -11,17 +11,18 @@ import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
-import androidx.fragment.app.DialogFragment;
import java.util.Objects;
-import it.niedermann.nextcloud.deck.Application;
import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.databinding.DialogStackCreateBinding;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedActivity;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedAlertDialogBuilder;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedDialogFragment;
import static it.niedermann.nextcloud.deck.Application.NO_STACK_ID;
-public class EditStackDialogFragment extends DialogFragment {
+public class EditStackDialogFragment extends BrandedDialogFragment {
private static final String KEY_STACK_ID = "board_id";
private static final String KEY_OLD_TITLE = "old_title";
private long stackId = NO_STACK_ID;
@@ -50,11 +51,9 @@ public class EditStackDialogFragment extends DialogFragment {
public Dialog onCreateDialog(Bundle savedInstanceState) {
binding = DialogStackCreateBinding.inflate(requireActivity().getLayoutInflater());
- AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity(), Application.getAppTheme(getContext()) ? R.style.DialogDarkTheme : R.style.ThemeOverlay_AppCompat_Dialog_Alert)
+ AlertDialog.Builder builder = new BrandedAlertDialogBuilder(requireActivity())
.setView(binding.getRoot())
- .setNegativeButton(android.R.string.cancel, (dialog, which) -> {
- // Do something else
- });
+ .setNegativeButton(android.R.string.cancel, null);
if (getArguments() == null) {
throw new IllegalArgumentException("Please add at least stack id to the arguments");
}
@@ -92,4 +91,9 @@ public class EditStackDialogFragment extends DialogFragment {
return dialog;
}
+
+ @Override
+ public void applyBrand(int mainColor, int textColor) {
+ BrandedActivity.applyBrandToEditText(mainColor, textColor, binding.input);
+ }
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/StackFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/StackFragment.java
index bc99031fb..594c00e0e 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/StackFragment.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/stack/StackFragment.java
@@ -13,13 +13,13 @@ import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
+import it.niedermann.android.crosstabdnd.DragAndDropTab;
import it.niedermann.nextcloud.deck.databinding.FragmentStackBinding;
import it.niedermann.nextcloud.deck.model.Account;
import it.niedermann.nextcloud.deck.model.full.FullCard;
import it.niedermann.nextcloud.deck.persistence.sync.SyncManager;
import it.niedermann.nextcloud.deck.ui.card.CardAdapter;
import it.niedermann.nextcloud.deck.ui.card.SelectCardListener;
-import it.niedermann.nextcloud.deck.ui.dnd.DragAndDropTab;
public class StackFragment extends Fragment implements DragAndDropTab<CardAdapter> {
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/tiles/EditCardTileService.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/tiles/EditCardTileService.java
index 1bc7a4433..09abbfa7a 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/tiles/EditCardTileService.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/tiles/EditCardTileService.java
@@ -6,11 +6,7 @@ import android.os.Build;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
-import it.niedermann.nextcloud.deck.ui.EditActivity;
-
-import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_ACCOUNT_ID;
-import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_BOARD_ID;
-import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_LOCAL_ID;
+import it.niedermann.nextcloud.deck.ui.preparecreate.PrepareCreateActivity;
@TargetApi(Build.VERSION_CODES.N)
public class EditCardTileService extends TileService {
@@ -24,11 +20,7 @@ public class EditCardTileService extends TileService {
@Override
public void onClick() {
- Intent intent = new Intent(getApplicationContext(), EditActivity.class);
- // create new note intent
- intent.putExtra(BUNDLE_KEY_ACCOUNT_ID, -1);
- intent.putExtra(BUNDLE_KEY_BOARD_ID, -1);
- intent.putExtra(BUNDLE_KEY_LOCAL_ID, -1);
+ Intent intent = new Intent(getApplicationContext(), PrepareCreateActivity.class);
// ensure it won't open twice if already running
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
// ask to unlock the screen if locked, then start new note intent
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/view/LabelChip.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/view/LabelChip.java
new file mode 100644
index 000000000..861624a70
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/view/LabelChip.java
@@ -0,0 +1,53 @@
+package it.niedermann.nextcloud.deck.ui.view;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.text.TextUtils;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+
+import com.google.android.flexbox.FlexboxLayout;
+import com.google.android.material.chip.Chip;
+
+import it.niedermann.nextcloud.deck.DeckLog;
+import it.niedermann.nextcloud.deck.R;
+import it.niedermann.nextcloud.deck.model.Label;
+import it.niedermann.nextcloud.deck.util.ColorUtil;
+
+@SuppressLint("ViewConstructor")
+public class LabelChip extends Chip {
+
+ private final Label label;
+
+ public LabelChip(@NonNull Context context, @NonNull Label label) {
+ super(context);
+ this.label = label;
+
+ FlexboxLayout.LayoutParams params = new FlexboxLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ );
+
+ params.setMargins(0, 0, Math.round(context.getResources().getDimension(R.dimen.spacer_1x)), 0);
+ setLayoutParams(params);
+
+ setText(label.getTitle());
+ setEllipsize(TextUtils.TruncateAt.END);
+
+ try {
+ int labelColor = Color.parseColor("#" + label.getColor());
+ ColorStateList c = ColorStateList.valueOf(labelColor);
+ setChipBackgroundColor(c);
+ setTextColor(ColorUtil.getForegroundColorForBackgroundColor(labelColor));
+ } catch (IllegalArgumentException e) {
+ DeckLog.logError(e);
+ }
+ }
+
+ public Long getLabelLocalId() {
+ return this.label.getLocalId();
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/view/LabelLayout.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/view/LabelLayout.java
new file mode 100644
index 000000000..24a44d932
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/view/LabelLayout.java
@@ -0,0 +1,83 @@
+package it.niedermann.nextcloud.deck.ui.view;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import androidx.annotation.NonNull;
+
+import com.google.android.flexbox.FlexboxLayout;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import it.niedermann.nextcloud.deck.DeckLog;
+import it.niedermann.nextcloud.deck.model.Label;
+
+public class LabelLayout extends FlexboxLayout {
+
+ private List<LabelChip> chipList = new LinkedList<>();
+
+ public LabelLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ /**
+ * Instead of clearing and adding all labels, one can use this method to avoid flickering
+ */
+ public void updateLabels(@NonNull List<Label> labels) {
+ removeObsoleteLabels(labels);
+ addNewLabels(labels);
+ }
+
+ @Override
+ public void removeAllViews() {
+ super.removeAllViews();
+ this.chipList.clear();
+ }
+
+ @Override
+ public void removeViewAt(int index) {
+ // TODO this should also remove the item from chipList
+ DeckLog.logError(new UnsupportedOperationException("Not implemented yet"));
+ super.removeViewAt(index);
+ }
+
+ /**
+ * Remove all labels from the view which are not in the labels list
+ */
+ private void removeObsoleteLabels(List<Label> labels) {
+ chipList:
+ for (int i = 0; i < chipList.size(); i++) {
+ LabelChip currentChip = chipList.get(i);
+ final Long existingLabelLocalId = currentChip.getLabelLocalId();
+ for (Label label : labels) {
+ if (existingLabelLocalId.equals(label.getLocalId())) {
+ continue chipList;
+ }
+ }
+ super.removeViewAt(i);
+ chipList.remove(currentChip);
+ i--;
+ }
+ }
+
+ /**
+ * Add all labels to the view which are not yet in the view but in the labels list
+ */
+ private void addNewLabels(List<Label> labels) {
+ int oldLabelSize = chipList.size();
+ labelList:
+ for (Label label : labels) {
+ for (int i = 0; i < oldLabelSize; i++) {
+ final LabelChip currentChip = chipList.get(i);
+ final Long existingLabelLocalId = currentChip.getLabelLocalId();
+ if (existingLabelLocalId.equals(label.getLocalId())) {
+ continue labelList;
+ }
+ }
+ LabelChip chip = new LabelChip(getContext(), label);
+ addView(chip);
+ chipList.add(chip);
+ }
+ }
+}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/util/ColorUtil.java b/app/src/main/java/it/niedermann/nextcloud/deck/util/ColorUtil.java
index b12cbc538..9a219c156 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/util/ColorUtil.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/util/ColorUtil.java
@@ -1,28 +1,45 @@
package it.niedermann.nextcloud.deck.util;
import android.graphics.Color;
+
import androidx.annotation.ColorInt;
-/**
- * Helper implementation to deal with color related functionality.
- */
+@SuppressWarnings("WeakerAccess")
public final class ColorUtil {
- private ColorUtil() {}
+ private ColorUtil() {
+ }
- public static @ColorInt int getForegroundColorForBackgroundColor(int color) {
+ @ColorInt
+ public static int getForegroundColorForBackgroundColor(@ColorInt int color) {
if (android.R.color.transparent == color)
return Color.BLACK;
+ else if (isColorDark(color))
+ return Color.WHITE;
+ else
+ return Color.BLACK;
+ }
+
+ public static boolean isColorDark(@ColorInt int color) {
+ return getBrightness(color) < 200;
+ }
- int[] rgb = {Color.red(color), Color.green(color), Color.blue(color)};
+ public static int getBrightness(@ColorInt int color) {
+ final int[] rgb = {Color.red(color), Color.green(color), Color.blue(color)};
- int brightness = (int) Math.sqrt(rgb[0] * rgb[0] * .241 + rgb[1]
+ return (int) Math.sqrt(rgb[0] * rgb[0] * .241 + rgb[1]
* rgb[1] * .691 + rgb[2] * rgb[2] * .068);
+ }
- // light color -> use dark color
- if (brightness >= 200) {
- return Color.BLACK;
- }
+ public static double getContrastRatio(@ColorInt int colorOne, @ColorInt int colorTwo) {
+ final int brightnessOne = getBrightness(colorOne);
+ final int brightnessTwo = getBrightness(colorTwo);
+
+ return (brightnessOne > brightnessTwo)
+ ? (double) brightnessOne / (double) brightnessTwo
+ : (double) brightnessTwo / (double) brightnessOne;
+ }
- return Color.WHITE;
+ public static boolean contrastRatioIsSufficient(@ColorInt int colorOne, @ColorInt int colorTwo) {
+ return getContrastRatio(colorOne, colorTwo) > 1.5f;
}
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/util/DeleteDialogBuilder.java b/app/src/main/java/it/niedermann/nextcloud/deck/util/DeleteDialogBuilder.java
deleted file mode 100644
index ed8e027f9..000000000
--- a/app/src/main/java/it/niedermann/nextcloud/deck/util/DeleteDialogBuilder.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package it.niedermann.nextcloud.deck.util;
-
-import android.app.AlertDialog;
-import android.content.Context;
-
-import it.niedermann.nextcloud.deck.Application;
-import it.niedermann.nextcloud.deck.R;
-
-public class DeleteDialogBuilder extends AlertDialog.Builder {
-
- public DeleteDialogBuilder(Context context) {
- super(context, Application.getAppTheme(context) ? R.style.DeleteDialogDarkTheme : R.style.DeleteDialogTheme);
- }
-}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/util/DrawerMenuUtil.java b/app/src/main/java/it/niedermann/nextcloud/deck/util/DrawerMenuUtil.java
index 31b081e31..ce0b1ec00 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/util/DrawerMenuUtil.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/util/DrawerMenuUtil.java
@@ -28,6 +28,7 @@ import it.niedermann.nextcloud.deck.DeckLog;
import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.model.Account;
import it.niedermann.nextcloud.deck.model.Board;
+import it.niedermann.nextcloud.deck.ui.board.DeleteBoardDialogFragment;
import it.niedermann.nextcloud.deck.ui.board.EditBoardDialogFragment;
import it.niedermann.nextcloud.deck.ui.board.accesscontrol.AccessControlDialogFragment;
@@ -101,11 +102,10 @@ public class DrawerMenuUtil {
menu.add(Menu.NONE, MENU_ID_ADD_ACCOUNT, Menu.NONE, context.getString(R.string.add_account)).setIcon(R.drawable.ic_person_add_black_24dp);
}
- public static <T extends FragmentActivity & DrawerBoardListener> void inflateBoards(
+ public static <T extends FragmentActivity> void inflateBoards(
@NonNull T context,
@NonNull Menu menu,
@NonNull Long currentAccountId,
- long currentBoardId,
@NonNull List<Board> boards) {
final String addBoard = context.getString(R.string.add_board);
final String simpleBoards = context.getString(R.string.simple_boards);
@@ -143,23 +143,7 @@ public class DrawerMenuUtil {
Toast.makeText(context, "Archiving boards is not yet supported.", Toast.LENGTH_LONG).show();
return true;
case R.id.delete_board:
- new DeleteDialogBuilder(context)
- .setTitle(context.getString(R.string.delete_something, board.getTitle()))
- .setMessage(R.string.delete_board_message)
- .setPositiveButton(R.string.simple_delete, (dialog, which) -> {
- if (board.getLocalId() == currentBoardId) {
- if (currentIndex > 0) { // Select first board after deletion
- context.onBoardChosen(boards.get(0));
- } else if (boards.size() > 1) { // Select second board after deletion
- context.onBoardChosen(boards.get(1));
- } else { // No other board is available, open create dialog
- context.onLastBoardDeleted();
- }
- }
- context.onBoardDeleted(board);
- })
- .setNegativeButton(android.R.string.cancel, null)
- .show();
+ DeleteBoardDialogFragment.newInstance(board).show(context.getSupportFragmentManager(), DeleteBoardDialogFragment.class.getCanonicalName());
return true;
default:
return false;
@@ -188,14 +172,4 @@ public class DrawerMenuUtil {
void onAccountDeleted(@NonNull Long accountId);
}
-
- public interface DrawerBoardListener {
- void onBoardChosen(@NonNull Board board);
-
- void onBoardDeleted(@NonNull Board board);
-
- default void onLastBoardDeleted() {
- // Optional
- }
- }
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/util/ExceptionUtil.java b/app/src/main/java/it/niedermann/nextcloud/deck/util/ExceptionUtil.java
index c8774eac1..189233fbe 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/util/ExceptionUtil.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/util/ExceptionUtil.java
@@ -2,9 +2,9 @@ package it.niedermann.nextcloud.deck.util;
import android.app.Activity;
import android.content.Context;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Typeface;
+import android.os.Build;
import android.view.View;
import android.widget.TextView;
@@ -20,7 +20,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import it.niedermann.nextcloud.deck.BuildConfig;
import it.niedermann.nextcloud.deck.R;
+import it.niedermann.nextcloud.deck.ui.branding.BrandedAlertDialogBuilder;
import static it.niedermann.nextcloud.deck.util.ClipboardUtil.copyToClipboard;
@@ -50,16 +52,10 @@ public class ExceptionUtil {
}
private static String getAppVersions(Context context) {
- String versions = "";
- try {
- PackageInfo pInfo = context.getApplicationContext().getPackageManager().getPackageInfo(context.getApplicationContext().getPackageName(), 0);
- versions += "App Version: " + pInfo.versionName;
- versions += "\nApp Version Code: " + pInfo.versionCode;
- versions += "\nApp ID: " + context.getPackageName();
- } catch (PackageManager.NameNotFoundException e) {
- versions += "\nApp Version: " + e.getMessage();
- e.printStackTrace();
- }
+ String versions = ""
+ + "App Version: " + BuildConfig.VERSION_NAME + "\n"
+ + "App Version Code: " + BuildConfig.VERSION_CODE + "\n"
+ + "App Flavor: " + BuildConfig.FLAVOR + "\n";
try {
versions += "\nFiles App Version Code: " + VersionCheckHelper.getNextcloudFilesVersionCode(context);
@@ -72,10 +68,11 @@ public class ExceptionUtil {
private static String getDeviceInfos() {
return ""
- + "\nOS Version: " + System.getProperty("os.version") + "(" + android.os.Build.VERSION.INCREMENTAL + ")"
- + "\nOS API Level: " + android.os.Build.VERSION.SDK_INT
- + "\nDevice: " + android.os.Build.DEVICE
- + "\nModel (and Product): " + android.os.Build.MODEL + " (" + android.os.Build.PRODUCT + ")";
+ + "\nOS Version: " + System.getProperty("os.version") + "(" + Build.VERSION.INCREMENTAL + ")"
+ + "\nOS API Level: " + Build.VERSION.SDK_INT
+ + "\nDevice: " + Build.DEVICE
+ + "\nManufacturer: " + Build.MANUFACTURER
+ + "\nModel (and Product): " + Build.MODEL + " (" + Build.PRODUCT + ")";
}
private static String getStacktraceOf(Throwable e) {
@@ -90,7 +87,7 @@ public class ExceptionUtil {
case 302: {
Snackbar.make(targetView, R.string.server_misconfigured, Snackbar.LENGTH_LONG)
.setAction(R.string.simple_more, v -> {
- AlertDialog dialog = new AlertDialog.Builder(activity)
+ AlertDialog dialog = new BrandedAlertDialogBuilder(activity)
.setTitle(R.string.server_misconfigured)
.setMessage(activity.getString(R.string.server_misconfigured_explanation) + "\n\n\n" + debugInfos)
.setPositiveButton(android.R.string.copy, (a, b) -> {
@@ -108,7 +105,7 @@ public class ExceptionUtil {
case 503: {
Snackbar.make(targetView, R.string.server_error, Snackbar.LENGTH_LONG)
.setAction(R.string.simple_more, v -> {
- AlertDialog dialog = new AlertDialog.Builder(activity)
+ AlertDialog dialog = new BrandedAlertDialogBuilder(activity)
.setTitle(R.string.server_error)
.setMessage(activity.getString(R.string.server_error_explanation) + "\n\n\n" + debugInfos)
.setPositiveButton(android.R.string.copy, (a, b) -> {
@@ -126,7 +123,7 @@ public class ExceptionUtil {
default: {
Snackbar.make(targetView, R.string.error, Snackbar.LENGTH_LONG)
.setAction(R.string.simple_more, v -> {
- AlertDialog dialog = new AlertDialog.Builder(activity)
+ AlertDialog dialog = new BrandedAlertDialogBuilder(activity)
.setTitle(R.string.server_error)
.setMessage(debugInfos)
.setPositiveButton(android.R.string.copy, (a, b) -> {
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/util/TabLayoutHelper.java b/app/src/main/java/it/niedermann/nextcloud/deck/util/TabLayoutHelper.java
deleted file mode 100644
index afbe4a39c..000000000
--- a/app/src/main/java/it/niedermann/nextcloud/deck/util/TabLayoutHelper.java
+++ /dev/null
@@ -1,456 +0,0 @@
-/*
- * Copyright (C) 2015 Haruki Hasegawa
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package it.niedermann.nextcloud.deck.util;
-
-import android.view.Gravity;
-import android.view.View;
-import android.widget.LinearLayout;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.core.view.ViewCompat;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.viewpager2.widget.ViewPager2;
-
-import com.google.android.material.tabs.TabLayout;
-
-import java.lang.ref.WeakReference;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-import it.niedermann.nextcloud.deck.DeckLog;
-
-
-public class TabLayoutHelper {
- private TabLayout mTabLayout;
- private TabTitleGenerator mTabTitleGenerator;
- private ViewPager2 mViewPager;
-
- private TabLayout.OnTabSelectedListener mInternalOnTabSelectedListener;
- private FixedTabLayoutOnPageChangeListener mInternalTabLayoutOnPageChangeListener;
- private RecyclerView.AdapterDataObserver mInternalDataSetObserver;
- private Runnable mAdjustTabModeRunnable;
- private Runnable mSetTabsFromPagerAdapterRunnable;
- private Runnable mUpdateScrollPositionRunnable;
- private boolean mAutoAdjustTabMode = false;
- private boolean mDuringSetTabsFromPagerAdapter;
-
- /**
- * Constructor.
- *
- * @param tabLayout TabLayout instance
- * @param viewPager ViewPager2 instance
- * @param tabTitleGenerator TabTitleGenerator instance
- */
- public TabLayoutHelper(@NonNull TabLayout tabLayout, @NonNull ViewPager2 viewPager, @NonNull TabTitleGenerator tabTitleGenerator) {
- RecyclerView.Adapter adapter = viewPager.getAdapter();
-
- if (adapter == null) {
- throw new IllegalArgumentException("ViewPager does not have a PagerAdapter set");
- }
-
- mTabLayout = tabLayout;
- mViewPager = viewPager;
- mTabTitleGenerator = tabTitleGenerator;
-
-
- mInternalDataSetObserver = new RecyclerView.AdapterDataObserver() {
- @Override
- public void onChanged() {
- handleOnDataSetChanged();
- }
- };
-
- mInternalOnTabSelectedListener = new TabLayout.OnTabSelectedListener() {
- @Override
- public void onTabSelected(TabLayout.Tab tab) {
- handleOnTabSelected(tab);
- }
-
- @Override
- public void onTabUnselected(TabLayout.Tab tab) {
- // Do nothing
- }
-
- @Override
- public void onTabReselected(TabLayout.Tab tab) {
- // Do nothing
- }
- };
-
- mInternalTabLayoutOnPageChangeListener = new FixedTabLayoutOnPageChangeListener(mTabLayout);
-
-
- viewPager.getAdapter().registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
- @Override
- public void onChanged() {
- setTabsFromPagerAdapter(mTabLayout, viewPager.getAdapter(), viewPager.getCurrentItem());
- }
- });
-
- setupWithViewPager(mTabLayout, mViewPager);
- }
-
- //
- // public methods
- //
-
- /**
- * Sets auto tab mode adjustment enabled
- *
- * @param enabled True for enabled, otherwise false.
- */
- public void setAutoAdjustTabModeEnabled(boolean enabled) {
- if (mAutoAdjustTabMode == enabled) {
- return;
- }
- mAutoAdjustTabMode = enabled;
-
- if (mAutoAdjustTabMode) {
- adjustTabMode(-1);
- } else {
- cancelPendingAdjustTabMode();
- }
- }
-
- /**
- * Unregister internal listener objects, release object references, etc.
- * This method should be called in order to avoid memory leaks.
- */
- public void release() {
- cancelPendingAdjustTabMode();
- cancelPendingSetTabsFromPagerAdapter();
- cancelPendingUpdateScrollPosition();
-
- if (mInternalDataSetObserver != null) {
- mInternalDataSetObserver = null;
- }
- if (mInternalOnTabSelectedListener != null) {
- mTabLayout.removeOnTabSelectedListener(mInternalOnTabSelectedListener);
- mInternalOnTabSelectedListener = null;
- }
- if (mInternalTabLayoutOnPageChangeListener != null) {
- mInternalTabLayoutOnPageChangeListener = null;
- }
- mViewPager = null;
- mTabLayout = null;
- }
-
- /**
- * Override this method if you want to use custom tab layout.
- *
- * @param tabLayout TabLayout
- * @param position Position of the item
- * @return TabLayout.Tab
- */
- private TabLayout.Tab onCreateTab(TabLayout tabLayout, int position) {
- TabLayout.Tab tab = tabLayout.newTab();
- tab.setText(mTabTitleGenerator.getTitle(position));
- return tab;
- }
-
- public void setTabTitleGenerator(TabTitleGenerator mTabTitleGenerator) {
- this.mTabTitleGenerator = mTabTitleGenerator;
- }
-
- /**
- * Override this method if you want to use custom tab layout
- *
- * @param tab Tab
- */
- private void onUpdateTab(TabLayout.Tab tab) {
- if (tab.getCustomView() == null) {
- tab.setCustomView(null); // invokes update() method internally.
- }
- }
-
- //
- // internal methods
- //
- private void handleOnDataSetChanged() {
- cancelPendingUpdateScrollPosition();
- cancelPendingSetTabsFromPagerAdapter();
-
- if (mSetTabsFromPagerAdapterRunnable == null) {
- mSetTabsFromPagerAdapterRunnable = () -> setTabsFromPagerAdapter(mTabLayout, mViewPager.getAdapter(), mViewPager.getCurrentItem());
- }
-
- mTabLayout.post(mSetTabsFromPagerAdapterRunnable);
- }
-
- private void handleOnTabSelected(TabLayout.Tab tab) {
- if (mDuringSetTabsFromPagerAdapter) {
- return;
- }
- mViewPager.setCurrentItem(tab.getPosition());
- cancelPendingUpdateScrollPosition();
- }
-
- private void cancelPendingAdjustTabMode() {
- if (mAdjustTabModeRunnable != null) {
- mTabLayout.removeCallbacks(mAdjustTabModeRunnable);
- mAdjustTabModeRunnable = null;
- }
- }
-
- private void cancelPendingSetTabsFromPagerAdapter() {
- if (mSetTabsFromPagerAdapterRunnable != null) {
- mTabLayout.removeCallbacks(mSetTabsFromPagerAdapterRunnable);
- mSetTabsFromPagerAdapterRunnable = null;
- }
- }
-
- private void cancelPendingUpdateScrollPosition() {
- if (mUpdateScrollPositionRunnable != null) {
- mTabLayout.removeCallbacks(mUpdateScrollPositionRunnable);
- mUpdateScrollPositionRunnable = null;
- }
- }
-
- private void adjustTabMode(final int prevScrollX) {
- final int prevScrollXMinZero = prevScrollX < 0 ? mTabLayout.getScrollX() : prevScrollX;
-
- if (mAdjustTabModeRunnable != null) {
- return;
- }
-
- if (ViewCompat.isLaidOut(mTabLayout)) {
- adjustTabModeInternal(mTabLayout, prevScrollXMinZero);
- } else {
- mAdjustTabModeRunnable = () -> {
- mAdjustTabModeRunnable = null;
- adjustTabModeInternal(mTabLayout, prevScrollXMinZero);
- };
- mTabLayout.post(mAdjustTabModeRunnable);
- }
- }
-
- private TabLayout.Tab createNewTab(TabLayout tabLayout, int position) {
- return onCreateTab(tabLayout, position);
- }
-
- private void setupWithViewPager(@NonNull TabLayout tabLayout, @NonNull ViewPager2 viewPager) {
- final RecyclerView.Adapter adapter = viewPager.getAdapter();
- if (adapter == null) {
- throw new IllegalArgumentException("ViewPager does not have a PagerAdapter set");
- }
-
- setTabsFromPagerAdapter(tabLayout, adapter, viewPager.getCurrentItem());
-
- viewPager.getAdapter().registerAdapterDataObserver(mInternalDataSetObserver);
-
- viewPager.registerOnPageChangeCallback(mInternalTabLayoutOnPageChangeListener);
-
- tabLayout.addOnTabSelectedListener(mInternalOnTabSelectedListener);
- }
-
- private void setTabsFromPagerAdapter(@NonNull TabLayout tabLayout, @Nullable RecyclerView.Adapter adapter, final int currentItem) {
- try {
- mDuringSetTabsFromPagerAdapter = true;
-
- int prevScrollX = tabLayout.getScrollX();
-
- // remove all tabs
- tabLayout.removeAllTabs();
-
- // add tabs
- if (adapter != null) {
- int count = adapter.getItemCount();
- for (int i = 0; i < count; i++) {
- TabLayout.Tab tab = createNewTab(tabLayout, i);
- tabLayout.addTab(tab, false);
- updateTab(tab);
- }
-
- // select current tab
- final int currentItemPosition = Math.min(currentItem, count - 1);
- TabLayout.Tab tab = tabLayout.getTabAt(currentItemPosition);
- if (currentItemPosition >= 0 && tab != null) {
- tab.select();
- }
- }
-
- // adjust tab mode & gravity
- if (mAutoAdjustTabMode) {
- adjustTabMode(prevScrollX);
- } else {
- // restore scroll position if needed
- int curTabMode = tabLayout.getTabMode();
- if (curTabMode == TabLayout.MODE_SCROLLABLE) {
- tabLayout.scrollTo(prevScrollX, 0);
- }
- }
- } finally {
- mDuringSetTabsFromPagerAdapter = false;
- }
- }
-
- private void updateTab(TabLayout.Tab tab) {
- onUpdateTab(tab);
- }
-
- private int determineTabMode(@NonNull TabLayout tabLayout) {
- LinearLayout slidingTabStrip = (LinearLayout) tabLayout.getChildAt(0);
-
- int childCount = slidingTabStrip.getChildCount();
-
- // NOTE: slidingTabStrip.getMeasuredWidth() method does not return correct width!
- // Need to measure each tabs and calculate the sum of them.
-
- int tabLayoutWidth = tabLayout.getMeasuredWidth() - tabLayout.getPaddingLeft() - tabLayout.getPaddingRight();
- int tabLayoutHeight = tabLayout.getMeasuredHeight() - tabLayout.getPaddingTop() - tabLayout.getPaddingBottom();
-
- if (childCount == 0) {
- return TabLayout.MODE_FIXED;
- }
-
- int stripWidth = 0;
- int maxWidthTab = 0;
- int tabHeightMeasureSpec = View.MeasureSpec.makeMeasureSpec(tabLayoutHeight, View.MeasureSpec.EXACTLY);
-
- for (int i = 0; i < childCount; i++) {
- View tabView = slidingTabStrip.getChildAt(i);
- tabView.measure(View.MeasureSpec.UNSPECIFIED, tabHeightMeasureSpec);
- int tabWidth = tabView.getMeasuredWidth();
- stripWidth += tabWidth;
- maxWidthTab = Math.max(maxWidthTab, tabWidth);
- }
-
- return ((stripWidth < tabLayoutWidth) && (maxWidthTab < (tabLayoutWidth / childCount)))
- ? TabLayout.MODE_FIXED : TabLayout.MODE_SCROLLABLE;
- }
-
- private void adjustTabModeInternal(@NonNull TabLayout tabLayout, int prevScrollX) {
- int prevTabMode = tabLayout.getTabMode();
-
- tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
- tabLayout.setTabGravity(TabLayout.GRAVITY_CENTER);
-
- int newTabMode = determineTabMode(tabLayout);
-
- cancelPendingUpdateScrollPosition();
-
- if (newTabMode == TabLayout.MODE_FIXED) {
- tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
- tabLayout.setTabMode(TabLayout.MODE_FIXED);
- } else {
- LinearLayout slidingTabStrip = (LinearLayout) tabLayout.getChildAt(0);
- slidingTabStrip.setGravity(Gravity.CENTER_HORIZONTAL);
- if (prevTabMode == TabLayout.MODE_SCROLLABLE) {
- // restore scroll position
- tabLayout.scrollTo(prevScrollX, 0);
- } else {
- // scroll to current selected tab
- mUpdateScrollPositionRunnable = () -> {
- mUpdateScrollPositionRunnable = null;
- updateScrollPosition();
- };
- mTabLayout.post(mUpdateScrollPositionRunnable);
- }
- }
- }
-
- private void updateScrollPosition() {
- mTabLayout.setScrollPosition(mTabLayout.getSelectedTabPosition(), 0, false);
- }
-
- protected static class FixedTabLayoutOnPageChangeListener extends ViewPager2.OnPageChangeCallback {
- private final WeakReference<TabLayout> mTabLayoutRef;
- private int mPreviousScrollState;
- private int mScrollState;
-
- FixedTabLayoutOnPageChangeListener(TabLayout tabLayout) {
- mTabLayoutRef = new WeakReference<>(tabLayout);
- }
-
- @Override
- public void onPageScrollStateChanged(int state) {
- mPreviousScrollState = mScrollState;
- mScrollState = state;
- }
-
- @Override
- public void onPageScrolled(int position, float positionOffset,
- int positionOffsetPixels) {
- final TabLayout tabLayout = mTabLayoutRef.get();
- if (tabLayout != null && shouldUpdateScrollPosition()) {
- // Update the scroll position, only update the text selection if we're being
- // dragged (or we're settling after a drag)
- tabLayout.setScrollPosition(position, positionOffset, true);
- }
- }
-
- @Override
- public void onPageSelected(int position) {
- final TabLayout tabLayout = mTabLayoutRef.get();
- if (tabLayout != null && tabLayout.getSelectedTabPosition() != position) {
- // Select the tab, only updating the indicator if we're not being dragged/settled
- // (since onPageScrolled will handle that).
- Internal.selectTab(tabLayout, tabLayout.getTabAt(position),
- mScrollState == ViewPager2.SCROLL_STATE_IDLE);
- }
- }
-
- private boolean shouldUpdateScrollPosition() {
- return (mScrollState == ViewPager2.SCROLL_STATE_DRAGGING) ||
- ((mScrollState == ViewPager2.SCROLL_STATE_SETTLING) && (mPreviousScrollState == ViewPager2.SCROLL_STATE_DRAGGING));
- }
- }
-
-
- private static class Internal {
- private static final Method mMethodSelectTab;
-
- static {
- mMethodSelectTab = getAccessiblePrivateMethod(TabLayout.class, "selectTab", TabLayout.Tab.class, boolean.class);
- }
-
- @SuppressWarnings("SameParameterValue")
- private static Method getAccessiblePrivateMethod(Class<?> targetClass, String methodName, Class<?>... params) throws RuntimeException {
- try {
- Method m = targetClass.getDeclaredMethod(methodName, params);
- m.setAccessible(true);
- return m;
- } catch (NoSuchMethodException e) {
- throw new IllegalStateException(e);
- }
- }
-
- private static void selectTab(TabLayout tabLayout, TabLayout.Tab tab, boolean updateIndicator) {
- try {
- mMethodSelectTab.invoke(tabLayout, tab, updateIndicator);
- } catch (IllegalAccessException e) {
- DeckLog.logError(new IllegalStateException(e));
- } catch (InvocationTargetException e) {
- throw handleInvocationTargetException(e);
- }
- }
-
- private static RuntimeException handleInvocationTargetException(InvocationTargetException e) {
- Throwable targetException = e.getTargetException();
- if (targetException instanceof RuntimeException) {
- throw (RuntimeException) targetException;
- } else {
- throw new IllegalStateException(targetException);
- }
- }
- }
-
- public interface TabTitleGenerator {
- String getTitle(int position);
- }
-}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/util/ViewUtil.java b/app/src/main/java/it/niedermann/nextcloud/deck/util/ViewUtil.java
index 784244283..eb804ab42 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/util/ViewUtil.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/util/ViewUtil.java
@@ -1,6 +1,7 @@
package it.niedermann.nextcloud.deck.util;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -8,7 +9,9 @@ import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
import androidx.core.graphics.drawable.DrawableCompat;
+import androidx.core.widget.TextViewCompat;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
@@ -23,10 +26,12 @@ public final class ViewUtil {
}
public static void addAvatar(Context context, ImageView avatar, String baseUrl, String userId, @DrawableRes int errorResource) {
+ // TODO get context from ImageView?
addAvatar(context, avatar, baseUrl, userId, DimensionUtil.getAvatarDimension(context), errorResource);
}
public static void addAvatar(Context context, ImageView avatar, String baseUrl, String userId, int avatarSize, @DrawableRes int errorResource) {
+ // TODO get context from ImageView?
String uri = baseUrl + "/index.php/avatar/" + Uri.encode(userId) + "/" + avatarSize;
Glide.with(context)
.load(uri)
@@ -39,7 +44,7 @@ public final class ViewUtil {
long diff = DateUtil.getDayDifference(new Date(), dueDate);
int backgroundDrawable = 0;
- int textColor = Application.getAppTheme(context) ? R.color.dark_fg_primary : R.color.black;
+ int textColor = Application.getAppTheme(context) ? R.color.dark_fg_primary : R.color.grey600;
if (diff == 1) {
// due date: tomorrow
@@ -55,9 +60,10 @@ public final class ViewUtil {
cardDueDate.setBackgroundResource(backgroundDrawable);
cardDueDate.setTextColor(context.getResources().getColor(textColor));
+ TextViewCompat.setCompoundDrawableTintList(cardDueDate, ColorStateList.valueOf(context.getResources().getColor(textColor)));
}
- public static Drawable getTintedImageView(Context context, int imageId, String color) {
+ public static Drawable getTintedImageView(@NonNull Context context, @DrawableRes int imageId, @NonNull String color) {
Drawable drawable;
Drawable wrapped;
drawable = context.getResources().getDrawable(imageId);
@@ -66,7 +72,7 @@ public final class ViewUtil {
return drawable;
}
- public static Drawable getTintedImageView(Context context, int imageId, int colorId) {
+ public static Drawable getTintedImageView(@NonNull Context context, @DrawableRes int imageId, int colorId) {
return getTintedImageView(context, imageId, context.getResources().getString(colorId));
}
}
diff --git a/app/src/main/res/drawable/ic_check_grey600_24dp.xml b/app/src/main/res/drawable/ic_check_grey600_24dp.xml
new file mode 100644
index 000000000..ec3888fa7
--- /dev/null
+++ b/app/src/main/res/drawable/ic_check_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="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
+</vector>
diff --git a/app/src/main/res/layout/activity_edit.xml b/app/src/main/res/layout/activity_edit.xml
index e7ade7b14..1ae29b930 100644
--- a/app/src/main/res/layout/activity_edit.xml
+++ b/app/src/main/res/layout/activity_edit.xml
@@ -14,59 +14,23 @@
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- app:navigationIcon="@drawable/ic_close_white_24dp"
- app:titleTextColor="@android:color/white">
-
- <com.google.android.material.textfield.TextInputLayout
- android:id="@+id/titleTextInputLayout"
- style="@style/AppTheme.EditText"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- app:theme="@style/AppTheme.EditText"
- tools:hint="Edit">
+ app:navigationIcon="@drawable/ic_close_white_24dp">
<EditText
android:id="@+id/title"
- style="@style/AppTheme.EditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ app:theme="@style/AppTheme.EditText"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:importantForAutofill="no"
android:inputType="textMultiLine"
android:maxLength="100"
android:maxLines="5"
- app:theme="@style/AppTheme.EditText"
- tools:text="Fancy card title" />
-
- </com.google.android.material.textfield.TextInputLayout>
+ tools:text="@tools:sample/lorem" />
</androidx.appcompat.widget.Toolbar>
- <LinearLayout
- android:id="@+id/selectBoardWrapper"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:visibility="gone"
- tools:visibility="visible">
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:labelFor="@id/boardSelector"
- android:padding="@dimen/standard_padding"
- android:text="@string/simple_select"
- android:textColor="@android:color/white" />
-
- <androidx.appcompat.widget.AppCompatSpinner
- android:id="@+id/boardSelector"
- android:layout_width="match_parent"
- android:layout_height="?android:attr/actionBarSize"
- android:theme="@style/Spinner"
- tools:listitem="@layout/item_board" />
- </LinearLayout>
-
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
diff --git a/app/src/main/res/layout/activity_exception.xml b/app/src/main/res/layout/activity_exception.xml
index 36f438f8f..f78ddc318 100644
--- a/app/src/main/res/layout/activity_exception.xml
+++ b/app/src/main/res/layout/activity_exception.xml
@@ -16,13 +16,13 @@
android:layout_height="?android:actionBarSize"
app:titleTextColor="@android:color/white"
tools:title="@string/simple_exception" />
-
+
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="@dimen/standard_margin">
+ android:padding="@dimen/spacer_2x">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/message"
@@ -41,32 +41,37 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
- android:fontFamily="monospace"
- android:padding="@dimen/standard_margin"
+ android:padding="@dimen/spacer_2x"
android:scrollbars="horizontal|vertical"
- android:textIsSelectable="true" />
+ android:textIsSelectable="true"
+ app:fontFamily="monospace" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
android:orientation="horizontal"
- android:padding="@dimen/standard_margin"
+ android:padding="@dimen/spacer_2x"
android:weightSum="1.0">
- <Button
+ <com.google.android.material.button.MaterialButton
android:id="@+id/close"
- style="@android:style/Widget.DeviceDefault.Button.Borderless"
+ style="@style/Widget.AppCompat.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/spacer_1x"
+ android:layout_marginRight="@dimen/spacer_1x"
android:layout_weight=".5"
- android:text="@string/simple_close" />
+ android:text="@string/simple_close"
+ app:backgroundTint="@android:color/white" />
- <Button
+ <com.google.android.material.button.MaterialButton
android:id="@+id/copy"
- style="@style/PrimaryCTAButton"
+ style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/spacer_1x"
+ android:layout_marginLeft="@dimen/spacer_1x"
android:layout_weight=".5"
android:text="@string/simple_copy" />
diff --git a/app/src/main/res/layout/activity_import_account.xml b/app/src/main/res/layout/activity_import_account.xml
index d7f9fd08f..cdce39b42 100644
--- a/app/src/main/res/layout/activity_import_account.xml
+++ b/app/src/main/res/layout/activity_import_account.xml
@@ -12,7 +12,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:padding="@dimen/standard_padding">
+ android:padding="@dimen/spacer_2x">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/image"
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 1da3a9d0c..b11c8aaf9 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -74,7 +74,6 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:theme="@style/ThemeOverlay.AppCompat.Dark"
app:tabGravity="center"
app:tabIndicatorColor="@color/accent"
app:tabMode="fixed"
@@ -84,9 +83,11 @@
android:id="@+id/add_stack_button"
android:layout_width="48dp"
android:layout_height="match_parent"
- android:background="?android:selectableItemBackground"
+ android:background="@android:color/transparent"
android:contentDescription="@null"
- app:srcCompat="@drawable/ic_add_white_24dp" />
+ android:foreground="?android:selectableItemBackground"
+ app:srcCompat="@drawable/ic_add_white_24dp"
+ tools:ignore="UnusedAttribute" />
</LinearLayout>
</com.google.android.material.appbar.AppBarLayout>
diff --git a/app/src/main/res/layout/activity_prepare_create.xml b/app/src/main/res/layout/activity_prepare_create.xml
new file mode 100644
index 000000000..4d99fa898
--- /dev/null
+++ b/app/src/main/res/layout/activity_prepare_create.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout 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"
+ tools:showIn="@layout/activity_prepare_create">
+
+ <com.google.android.material.appbar.AppBarLayout
+ android:id="@+id/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="?android:actionBarSize"
+ app:title="@string/add_card"
+ app:titleTextColor="@android:color/white" />
+ </com.google.android.material.appbar.AppBarLayout>
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_above="@+id/buttonBar"
+ android:layout_below="@id/appBarLayout"
+ android:padding="@dimen/spacer_2x">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <androidx.appcompat.widget.AppCompatSpinner
+ android:id="@+id/account_select"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:prompt="@string/choose_account"
+ android:spinnerMode="dialog"
+ tools:listitem="@layout/item_prepare_create_account" />
+
+ <androidx.appcompat.widget.AppCompatSpinner
+ android:id="@+id/board_select"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:prompt="@string/choose_board"
+ android:spinnerMode="dialog"
+ tools:listitem="@layout/item_board" />
+
+ <androidx.appcompat.widget.AppCompatSpinner
+ android:id="@+id/stack_select"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:prompt="@string/choose_list"
+ android:spinnerMode="dialog"
+ tools:listitem="@layout/item_board" />
+ </LinearLayout>
+ </ScrollView>
+
+ <LinearLayout
+ android:id="@+id/buttonBar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:orientation="horizontal"
+ android:padding="@dimen/spacer_2x"
+ android:weightSum="1.0">
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/cancel"
+ style="@style/Widget.AppCompat.Button"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/spacer_1x"
+ android:layout_marginRight="@dimen/spacer_1x"
+ android:layout_weight=".5"
+ android:text="@android:string/cancel"
+ app:backgroundTint="@android:color/white" />
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/submit"
+ style="@style/Widget.AppCompat.Button.Colored"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/spacer_1x"
+ android:layout_marginLeft="@dimen/spacer_1x"
+ android:layout_weight=".5"
+ android:text="@string/add_card" />
+ </LinearLayout>
+</RelativeLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_add_comment.xml b/app/src/main/res/layout/dialog_add_comment.xml
index 55ddc60d6..c1fe90feb 100644
--- a/app/src/main/res/layout/dialog_add_comment.xml
+++ b/app/src/main/res/layout/dialog_add_comment.xml
@@ -2,7 +2,7 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="@dimen/standard_margin">
+ android:padding="@dimen/spacer_2x">
<EditText
android:id="@+id/input"
diff --git a/app/src/main/res/layout/dialog_board_create.xml b/app/src/main/res/layout/dialog_board_create.xml
index 12da2508e..321a9c1f0 100644
--- a/app/src/main/res/layout/dialog_board_create.xml
+++ b/app/src/main/res/layout/dialog_board_create.xml
@@ -4,7 +4,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:padding="@dimen/standard_margin">
+ android:padding="@dimen/spacer_2x">
<EditText
android:id="@+id/input"
diff --git a/app/src/main/res/layout/dialog_board_share.xml b/app/src/main/res/layout/dialog_board_share.xml
index 221ae65b5..fb7f146b7 100644
--- a/app/src/main/res/layout/dialog_board_share.xml
+++ b/app/src/main/res/layout/dialog_board_share.xml
@@ -11,7 +11,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="1"
- android:layout_margin="@dimen/standard_padding"
+ android:layout_margin="@dimen/spacer_2x"
android:layout_marginBottom="0dp"
android:hint="@string/hint_assign_people"
android:inputType="text" />
@@ -20,7 +20,7 @@
android:id="@+id/peopleList"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:padding="@dimen/standard_padding"
+ android:padding="@dimen/spacer_2x"
android:paddingTop="0dp"
android:scrollbarStyle="outsideOverlay"
android:scrollbars="vertical"
diff --git a/app/src/main/res/layout/dialog_stack_create.xml b/app/src/main/res/layout/dialog_stack_create.xml
index c4e2ac569..32db9b8c0 100644
--- a/app/src/main/res/layout/dialog_stack_create.xml
+++ b/app/src/main/res/layout/dialog_stack_create.xml
@@ -2,7 +2,7 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="@dimen/standard_margin">
+ android:padding="@dimen/spacer_2x">
<EditText
android:id="@+id/input"
diff --git a/app/src/main/res/layout/fragment_about_contribution_tab.xml b/app/src/main/res/layout/fragment_about_contribution_tab.xml
index 5049e1273..dde29fd18 100644
--- a/app/src/main/res/layout/fragment_about_contribution_tab.xml
+++ b/app/src/main/res/layout/fragment_about_contribution_tab.xml
@@ -7,7 +7,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:padding="@dimen/activity_horizontal_margin">
+ android:padding="@dimen/spacer_2x">
<TextView
style="?android:attr/listSeparatorTextViewStyle"
diff --git a/app/src/main/res/layout/fragment_about_credits_tab.xml b/app/src/main/res/layout/fragment_about_credits_tab.xml
index 7f3b8537e..db2fc4aa6 100644
--- a/app/src/main/res/layout/fragment_about_credits_tab.xml
+++ b/app/src/main/res/layout/fragment_about_credits_tab.xml
@@ -8,7 +8,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:padding="@dimen/activity_horizontal_margin">
+ android:padding="@dimen/spacer_2x">
<TextView
android:layout_width="wrap_content"
@@ -17,7 +17,7 @@
android:layout_marginTop="30dp"
android:layout_marginBottom="30dp"
android:drawableTop="@mipmap/ic_launcher"
- android:drawablePadding="@dimen/standard_padding"
+ android:drawablePadding="@dimen/spacer_2x"
android:text="@string/app_name"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="26sp" />
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 dc1b4e020..0e9af23da 100644
--- a/app/src/main/res/layout/fragment_about_license_tab.xml
+++ b/app/src/main/res/layout/fragment_about_license_tab.xml
@@ -7,7 +7,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:padding="@dimen/activity_horizontal_margin">
+ android:padding="@dimen/spacer_2x">
<TextView
style="?android:attr/listSeparatorTextViewStyle"
@@ -22,9 +22,9 @@
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/PrimaryCTAButton"
+ style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/about_app_license_button" />
@@ -33,7 +33,7 @@
style="?android:attr/listSeparatorTextViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/standard_margin"
+ android:layout_marginTop="@dimen/spacer_2x"
android:text="@string/about_icons_disclaimer_title" />
<TextView
diff --git a/app/src/main/res/layout/fragment_card_edit_tab_activities.xml b/app/src/main/res/layout/fragment_card_edit_tab_activities.xml
index cd00b0974..a78e6ba39 100644
--- a/app/src/main/res/layout/fragment_card_edit_tab_activities.xml
+++ b/app/src/main/res/layout/fragment_card_edit_tab_activities.xml
@@ -5,7 +5,7 @@
android:id="@+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:context=".ui.EditActivity">
+ tools:context=".ui.card.EditActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/activities_list"
diff --git a/app/src/main/res/layout/fragment_card_edit_tab_attachments.xml b/app/src/main/res/layout/fragment_card_edit_tab_attachments.xml
index 0da1958c6..b2e5df74a 100644
--- a/app/src/main/res/layout/fragment_card_edit_tab_attachments.xml
+++ b/app/src/main/res/layout/fragment_card_edit_tab_attachments.xml
@@ -5,7 +5,7 @@
android:id="@+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:context=".ui.EditActivity">
+ tools:context=".ui.card.EditActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/attachments_list"
diff --git a/app/src/main/res/layout/fragment_card_edit_tab_comments.xml b/app/src/main/res/layout/fragment_card_edit_tab_comments.xml
index 76623a13c..a5d5d3c76 100644
--- a/app/src/main/res/layout/fragment_card_edit_tab_comments.xml
+++ b/app/src/main/res/layout/fragment_card_edit_tab_comments.xml
@@ -32,13 +32,13 @@
android:background="?android:attr/colorBackground"
android:clipToPadding="false"
android:orientation="horizontal"
- android:padding="@dimen/standard_margin">
+ android:padding="@dimen/spacer_2x">
<ImageView
android:layout_width="@dimen/icon_size_details"
android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/standard_margin"
- android:layout_marginRight="@dimen/standard_margin"
+ android:layout_marginEnd="@dimen/spacer_2x"
+ android:layout_marginRight="@dimen/spacer_2x"
android:contentDescription="@null"
android:tint="@color/grey600"
app:srcCompat="@drawable/ic_comment_white_24dp" />
@@ -48,16 +48,16 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:layout_marginStart="@dimen/standard_margin"
- android:layout_marginLeft="@dimen/standard_margin"
+ android:layout_marginStart="@dimen/spacer_2x"
+ android:layout_marginLeft="@dimen/spacer_2x"
android:layout_weight="1"
android:autofillHints="@null"
android:hint="@string/add_comment"
android:imeOptions="actionSend"
android:inputType="text"
android:maxLength="@integer/comment_max_length"
- android:paddingEnd="@dimen/standard_half_padding"
- android:paddingRight="@dimen/standard_half_padding"
+ android:paddingEnd="@dimen/spacer_1x"
+ android:paddingRight="@dimen/spacer_1x"
tools:ignore="RtlSymmetry">
<requestFocus />
diff --git a/app/src/main/res/layout/fragment_card_edit_tab_details.xml b/app/src/main/res/layout/fragment_card_edit_tab_details.xml
index 648bdffd5..d70fdb8b7 100644
--- a/app/src/main/res/layout/fragment_card_edit_tab_details.xml
+++ b/app/src/main/res/layout/fragment_card_edit_tab_details.xml
@@ -9,19 +9,19 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:padding="@dimen/standard_padding">
+ android:padding="@dimen/spacer_2x">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/standard_margin"
+ android:layout_marginTop="@dimen/spacer_2x"
android:orientation="horizontal">
<ImageView
android:layout_width="@dimen/icon_size_details"
android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/standard_margin"
- android:layout_marginRight="@dimen/standard_margin"
+ android:layout_marginEnd="@dimen/spacer_2x"
+ android:layout_marginRight="@dimen/spacer_2x"
android:contentDescription="@null"
app:srcCompat="@drawable/ic_label_grey600_24dp" />
@@ -46,14 +46,14 @@
android:id="@+id/colorPicker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/standard_margin">
+ android:layout_marginTop="@dimen/spacer_2x">
<ImageView
android:layout_width="@dimen/icon_size_details"
android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/standard_margin"
- android:layout_marginRight="@dimen/standard_margin"
+ android:layout_marginEnd="@dimen/spacer_2x"
+ android:layout_marginRight="@dimen/spacer_2x"
android:contentDescription="@null"
app:srcCompat="@drawable/calendar_blank_grey600_24dp" />
@@ -91,24 +91,24 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:contentDescription="@string/label_clear_due_date"
- android:paddingStart="@dimen/standard_half_padding"
- android:paddingLeft="@dimen/standard_half_padding"
- android:paddingEnd="@dimen/standard_half_padding"
- android:paddingRight="@dimen/standard_half_padding"
+ android:paddingStart="@dimen/spacer_1x"
+ android:paddingLeft="@dimen/spacer_1x"
+ android:paddingEnd="@dimen/spacer_1x"
+ android:paddingRight="@dimen/spacer_1x"
app:srcCompat="@drawable/ic_close_circle_grey600" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/standard_margin"
+ android:layout_marginTop="@dimen/spacer_2x"
android:orientation="horizontal">
<ImageView
android:layout_width="@dimen/icon_size_details"
android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/standard_margin"
- android:layout_marginRight="@dimen/standard_margin"
+ android:layout_marginEnd="@dimen/spacer_2x"
+ android:layout_marginRight="@dimen/spacer_2x"
android:contentDescription="@null"
app:srcCompat="@drawable/ic_person_grey600_24dp" />
@@ -132,15 +132,15 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/standard_margin"
+ android:layout_marginTop="@dimen/spacer_2x"
android:orientation="horizontal">
<ImageView
android:layout_width="@dimen/icon_size_details"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
- android:layout_marginEnd="@dimen/standard_margin"
- android:layout_marginRight="@dimen/standard_margin"
+ android:layout_marginEnd="@dimen/spacer_2x"
+ android:layout_marginRight="@dimen/spacer_2x"
android:contentDescription="@null"
app:srcCompat="@drawable/ic_format_align_left_black_24dp" />
@@ -163,7 +163,7 @@
android:id="@+id/commentsFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/standard_margin" />
+ android:layout_marginTop="@dimen/spacer_2x" />
</RelativeLayout>
diff --git a/app/src/main/res/layout/fragment_stack.xml b/app/src/main/res/layout/fragment_stack.xml
index 3010f59fd..d4cbd2ee8 100644
--- a/app/src/main/res/layout/fragment_stack.xml
+++ b/app/src/main/res/layout/fragment_stack.xml
@@ -19,8 +19,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
- android:paddingTop="@dimen/standard_half_padding"
- android:paddingBottom="@dimen/standard_half_padding"
+ android:paddingTop="@dimen/spacer_1x"
+ android:paddingBottom="@dimen/spacer_1x"
android:scrollbarStyle="outsideOverlay"
android:scrollbars="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
diff --git a/app/src/main/res/layout/item_access_control.xml b/app/src/main/res/layout/item_access_control.xml
index 0589b5d9e..ce0fc4ef3 100644
--- a/app/src/main/res/layout/item_access_control.xml
+++ b/app/src/main/res/layout/item_access_control.xml
@@ -5,16 +5,17 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:padding="@dimen/standard_padding">
+ android:padding="@dimen/spacer_2x">
<ImageView
android:id="@+id/avatar"
android:layout_width="@dimen/avatar_size"
android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/standard_margin"
- android:layout_marginRight="@dimen/standard_margin"
+ android:layout_marginEnd="@dimen/spacer_2x"
+ android:layout_marginRight="@dimen/spacer_2x"
android:contentDescription="@null"
- app:srcCompat="@drawable/ic_person_grey600_24dp" />
+ app:srcCompat="@drawable/ic_person_grey600_24dp"
+ tools:srcCompat="@tools:sample/avatars" />
<LinearLayout
android:layout_width="match_parent"
@@ -24,28 +25,29 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/standard_half_margin"
+ android:layout_marginBottom="@dimen/spacer_1x"
android:orientation="horizontal">
<TextView
android:id="@+id/username"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_weight="1"
android:layout_gravity="center"
+ android:layout_weight="1"
android:textSize="16sp"
tools:drawableEnd="@drawable/ic_sync_blue_24dp"
- tools:text="Username" />
+ tools:text="@tools:sample/full_names" />
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="0dp"
android:layout_gravity="center"
android:background="?android:selectableItemBackground"
+ android:padding="0dp"
app:srcCompat="@drawable/ic_delete_black_24dp" />
</LinearLayout>
+
<com.google.android.flexbox.FlexboxLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -59,14 +61,14 @@
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/edit"
- app:switchPadding="@dimen/standard_half_margin" />
+ app:switchPadding="@dimen/spacer_1x" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/permission_share"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/simple_share"
- app:switchPadding="@dimen/standard_half_margin" />
+ app:switchPadding="@dimen/spacer_1x" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/permission_manage"
@@ -74,7 +76,7 @@
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/simple_manage"
- app:switchPadding="@dimen/standard_half_margin" />
+ app:switchPadding="@dimen/spacer_1x" />
</com.google.android.flexbox.FlexboxLayout>
</LinearLayout>
diff --git a/app/src/main/res/layout/item_access_control_owner.xml b/app/src/main/res/layout/item_access_control_owner.xml
index 368f52480..786bdc1ca 100644
--- a/app/src/main/res/layout/item_access_control_owner.xml
+++ b/app/src/main/res/layout/item_access_control_owner.xml
@@ -5,16 +5,17 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:padding="@dimen/standard_padding">
+ android:padding="@dimen/spacer_2x">
<ImageView
android:id="@+id/avatar"
android:layout_width="@dimen/avatar_size"
android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/standard_margin"
- android:layout_marginRight="@dimen/standard_margin"
+ android:layout_marginEnd="@dimen/spacer_2x"
+ android:layout_marginRight="@dimen/spacer_2x"
android:contentDescription="@null"
- app:srcCompat="@drawable/ic_person_grey600_24dp" />
+ app:srcCompat="@drawable/ic_person_grey600_24dp"
+ tools:srcCompat="@tools:sample/avatars" />
<LinearLayout
android:layout_width="match_parent"
@@ -25,19 +26,18 @@
android:id="@+id/owner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_weight="1"
android:layout_gravity="center"
+ android:layout_weight="1"
android:textSize="16sp"
- tools:text="Username" />
+ tools:text="@tools:sample/full_names" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_weight="1"
android:layout_gravity="center"
- android:textColor="@color/fg_secondary"
+ android:layout_weight="1"
android:text="@string/owner"
- tools:text="Username" />
+ android:textColor="@color/fg_secondary" />
</LinearLayout>
</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/item_activity.xml b/app/src/main/res/layout/item_activity.xml
index b27076dfb..486e808a0 100644
--- a/app/src/main/res/layout/item_activity.xml
+++ b/app/src/main/res/layout/item_activity.xml
@@ -6,7 +6,7 @@
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:orientation="vertical"
- android:padding="@dimen/standard_padding">
+ android:padding="@dimen/spacer_2x">
<TextView
android:id="@+id/date"
@@ -26,8 +26,8 @@
android:id="@+id/type"
android:layout_width="@dimen/avatar_size"
android:layout_height="@dimen/avatar_size"
- android:layout_marginEnd="@dimen/standard_margin"
- android:layout_marginRight="@dimen/standard_margin"
+ android:layout_marginEnd="@dimen/spacer_2x"
+ android:layout_marginRight="@dimen/spacer_2x"
app:srcCompat="@drawable/type_change_36dp" />
<TextView
diff --git a/app/src/main/res/layout/item_attachment_default.xml b/app/src/main/res/layout/item_attachment_default.xml
index f58783559..a8cc154e3 100644
--- a/app/src/main/res/layout/item_attachment_default.xml
+++ b/app/src/main/res/layout/item_attachment_default.xml
@@ -6,20 +6,20 @@
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:orientation="horizontal"
- android:padding="@dimen/standard_padding">
+ android:padding="@dimen/spacer_2x">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/standard_half_margin"
- android:layout_marginRight="@dimen/standard_half_margin">
+ android:layout_marginEnd="@dimen/spacer_1x"
+ android:layout_marginRight="@dimen/spacer_1x">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/preview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:layout_margin="@dimen/standard_half_margin"
+ android:layout_margin="@dimen/spacer_1x"
app:srcCompat="@drawable/ic_attach_file_grey600_24dp" />
<androidx.appcompat.widget.AppCompatImageView
diff --git a/app/src/main/res/layout/item_autocomplete_dropdown.xml b/app/src/main/res/layout/item_autocomplete_dropdown.xml
index fc3e51a7a..7369d52b8 100644
--- a/app/src/main/res/layout/item_autocomplete_dropdown.xml
+++ b/app/src/main/res/layout/item_autocomplete_dropdown.xml
@@ -9,7 +9,7 @@
android:id="@+id/icon"
android:layout_width="40dp"
android:layout_height="40dp"
- android:layout_margin="@dimen/standard_margin"
+ android:layout_margin="@dimen/spacer_2x"
android:contentDescription="@null"
tools:src="@drawable/ic_label_grey600_24dp" />
@@ -22,8 +22,8 @@
android:gravity="center_vertical"
android:paddingStart="0dp"
android:paddingLeft="0dp"
- android:paddingEnd="@dimen/standard_padding"
- android:paddingRight="@dimen/standard_padding"
+ android:paddingEnd="@dimen/spacer_2x"
+ android:paddingRight="@dimen/spacer_2x"
android:textSize="18sp"
tools:text="Label" />
diff --git a/app/src/main/res/layout/item_board.xml b/app/src/main/res/layout/item_board.xml
index 495b98bad..57e5bcbc3 100644
--- a/app/src/main/res/layout/item_board.xml
+++ b/app/src/main/res/layout/item_board.xml
@@ -2,7 +2,7 @@
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/boardName"
- android:padding="@dimen/standard_padding"
+ android:padding="@dimen/spacer_2x"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
diff --git a/app/src/main/res/layout/item_card.xml b/app/src/main/res/layout/item_card.xml
index 6ccdac785..29e0228c3 100644
--- a/app/src/main/res/layout/item_card.xml
+++ b/app/src/main/res/layout/item_card.xml
@@ -5,161 +5,158 @@
android:id="@+id/card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/standard_margin"
- android:layout_marginLeft="@dimen/standard_margin"
- android:layout_marginTop="@dimen/standard_half_margin"
- android:layout_marginEnd="@dimen/standard_margin"
- android:layout_marginRight="@dimen/standard_margin"
- android:layout_marginBottom="@dimen/standard_half_margin"
+ android:layout_marginStart="@dimen/spacer_2x"
+ android:layout_marginLeft="@dimen/spacer_2x"
+ android:layout_marginTop="@dimen/spacer_1x"
+ android:layout_marginEnd="@dimen/spacer_2x"
+ android:layout_marginRight="@dimen/spacer_2x"
+ android:layout_marginBottom="@dimen/spacer_1x"
android:focusable="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:paddingStart="@dimen/standard_padding"
- android:paddingLeft="@dimen/standard_padding"
- android:paddingTop="@dimen/standard_half_padding"
- android:paddingEnd="@dimen/standard_padding"
- android:paddingRight="@dimen/standard_padding"
- android:paddingBottom="@dimen/standard_half_padding">
+ android:paddingTop="@dimen/spacer_1x"
+ android:paddingBottom="@dimen/spacer_1x">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal">
+ android:orientation="horizontal"
+ android:paddingStart="@dimen/spacer_2x"
+ android:paddingLeft="@dimen/spacer_2x"
+ android:paddingEnd="@dimen/spacer_2x"
+ android:paddingRight="@dimen/spacer_2x">
<TextView
android:id="@+id/card_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:layout_marginTop="4sp"
android:layout_weight="1"
- android:ellipsize="end"
- android:maxLines="1"
- android:padding="@dimen/standard_quarter_padding"
- android:paddingStart="0dp"
- android:paddingLeft="0dp"
android:textSize="18sp"
tools:ignore="RtlSymmetry"
- tools:text="This is a really longCard Title" />
+ tools:text="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut l" />
<ImageView
android:id="@+id/not_synced_yet"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginStart="8dp"
- android:layout_marginLeft="8dp"
- android:layout_marginEnd="8dp"
- android:layout_marginRight="8dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8sp"
android:contentDescription="@string/not_synced_yet"
android:visibility="gone"
app:srcCompat="@drawable/ic_sync_blue_24dp"
tools:visibility="visible" />
- <TextView
- android:id="@+id/card_due_date"
+ <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:background="@drawable/due_tomorrow_background"
- android:maxLines="1"
- android:minLines="0"
- android:padding="@dimen/standard_quarter_padding"
- tools:text="tomorrow" />
+ android:orientation="horizontal"
+ android:paddingStart="@dimen/spacer_1hx"
+ android:paddingLeft="@dimen/spacer_1hx"
+ tools:ignore="RtlSymmetry">
- <ImageView
- android:id="@+id/card_menu"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="?attr/selectableItemBackground"
- android:contentDescription="@string/label_menu"
- android:padding="@dimen/standard_quarter_padding"
- app:srcCompat="@drawable/ic_menu" />
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/card_due_date"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@drawable/due_tomorrow_background"
+ android:drawablePadding="@dimen/spacer_1hx"
+ android:gravity="center"
+ android:padding="@dimen/spacer_1hx"
+ android:textColor="@color/fg_secondary"
+ app:drawableStartCompat="@drawable/calendar_blank_grey600_24dp"
+ tools:text="tomorrow" />
+
+ </LinearLayout>
</LinearLayout>
- <TextView
- android:id="@+id/card_description"
+ <it.niedermann.nextcloud.deck.ui.view.LabelLayout
+ android:id="@+id/labels"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:ellipsize="end"
- android:maxLines="1"
- android:paddingStart="0dp"
- android:paddingLeft="0dp"
- android:paddingTop="@dimen/standard_quarter_padding"
- android:paddingEnd="@dimen/standard_padding"
- android:paddingRight="@dimen/standard_padding"
- android:paddingBottom="@dimen/standard_half_padding"
- android:textColor="@color/fg_secondary"
- android:textSize="16sp"
- tools:text="This is a card description" />
+ android:layout_marginTop="@dimen/spacer_1x"
+ android:animateLayoutChanges="true"
+ android:paddingStart="@dimen/spacer_2x"
+ android:paddingLeft="@dimen/spacer_2x"
+ android:paddingEnd="@dimen/spacer_2x"
+ android:paddingRight="@dimen/spacer_2x"
+ app:flexWrap="nowrap"
+ tools:layout_height="@dimen/avatar_size" />
<LinearLayout
- android:id="@+id/card_details_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/standard_quarter_margin"
- android:layout_marginBottom="@dimen/standard_quarter_margin"
- android:orientation="horizontal">
+ android:layout_marginTop="@dimen/spacer_1x"
+ android:baselineAligned="false"
+ android:paddingStart="@dimen/spacer_1x"
+ android:paddingLeft="@dimen/spacer_1x"
+ android:paddingEnd="@dimen/spacer_1x"
+ android:paddingRight="@dimen/spacer_1x">
- <com.google.android.material.chip.ChipGroup
- android:id="@+id/labels"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/standard_half_margin"
- android:layout_marginRight="@dimen/standard_half_margin"
- android:layout_weight="1"
- android:animateLayoutChanges="true"
- tools:layout_height="match_parent" />
-
- <RelativeLayout
+ <LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_weight="1"
- android:gravity="end">
+ android:layout_weight="1">
<androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/card_count_attachments"
+ android:id="@+id/card_count_comments"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:drawablePadding="@dimen/spacer_1hx"
android:gravity="center_vertical"
- android:maxLines="1"
- android:minLines="0"
- android:padding="@dimen/standard_quarter_padding"
- app:drawableLeftCompat="@drawable/ic_attach_file_grey600_24dp"
- app:drawableStartCompat="@drawable/ic_attach_file_grey600_24dp"
- tools:text="1" />
+ android:padding="@dimen/spacer_1hx"
+ app:drawableLeftCompat="@drawable/ic_comment_white_24dp"
+ app:drawableStartCompat="@drawable/ic_comment_white_24dp"
+ app:drawableTint="@color/grey600"
+ tools:text="2" />
<androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/card_count_comments"
+ android:id="@+id/card_count_tasks"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_toEndOf="@+id/card_count_attachments"
- android:layout_toRightOf="@id/card_count_attachments"
- android:drawablePadding="@dimen/standard_quarter_padding"
android:gravity="center_vertical"
- android:maxLines="1"
- android:minLines="0"
- android:padding="@dimen/standard_quarter_padding"
- app:drawableLeftCompat="@drawable/ic_comment_white_24dp"
- app:drawableStartCompat="@drawable/ic_comment_white_24dp"
- app:drawableTint="@color/grey600"
- tools:text="1" />
+ android:padding="@dimen/spacer_1hx"
+ app:drawableLeftCompat="@drawable/ic_check_grey600_24dp"
+ app:drawableStartCompat="@drawable/ic_check_grey600_24dp"
+ tools:text="1/2" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/card_count_attachments"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:padding="@dimen/spacer_1hx"
+ app:drawableLeftCompat="@drawable/ic_attach_file_grey600_24dp"
+ app:drawableStartCompat="@drawable/ic_attach_file_grey600_24dp"
+ tools:text="3" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
<RelativeLayout
android:id="@+id/peopleList"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/standard_half_padding"
- android:layout_marginLeft="@dimen/standard_half_padding"
- android:layout_marginEnd="0dp"
- android:layout_marginRight="0dp"
- android:layout_toEndOf="@+id/card_count_comments"
- android:layout_toRightOf="@id/card_count_comments"
+ 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:gravity="end"
android:orientation="horizontal" />
- </RelativeLayout>
+ <ImageView
+ android:id="@+id/card_menu"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="?attr/selectableItemBackgroundBorderless"
+ android:contentDescription="@string/label_menu"
+ android:padding="@dimen/spacer_1hx"
+ app:srcCompat="@drawable/ic_menu" />
+ </LinearLayout>
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView> \ No newline at end of file
diff --git a/app/src/main/res/layout/item_comment.xml b/app/src/main/res/layout/item_comment.xml
index c98b65141..dc983564c 100644
--- a/app/src/main/res/layout/item_comment.xml
+++ b/app/src/main/res/layout/item_comment.xml
@@ -6,21 +6,21 @@
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:orientation="horizontal"
- android:padding="@dimen/standard_padding">
+ android:padding="@dimen/spacer_2x">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/standard_half_margin"
- android:layout_marginRight="@dimen/standard_half_margin">
+ android:layout_marginEnd="@dimen/spacer_1x"
+ android:layout_marginRight="@dimen/spacer_1x">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/avatar"
android:layout_width="@dimen/avatar_size"
android:layout_height="@dimen/avatar_size"
android:layout_gravity="center"
- android:layout_margin="@dimen/standard_half_margin"
+ android:layout_margin="@dimen/spacer_1x"
android:contentDescription="@null"
app:srcCompat="@drawable/ic_person_grey600_24dp"
tools:srcCompat="@tools:sample/avatars" />
diff --git a/app/src/main/res/layout/item_prepare_create_account.xml b/app/src/main/res/layout/item_prepare_create_account.xml
new file mode 100644
index 000000000..389aeda72
--- /dev/null
+++ b/app/src/main/res/layout/item_prepare_create_account.xml
@@ -0,0 +1,45 @@
+<?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="horizontal"
+ android:padding="@dimen/spacer_2x">
+
+ <ImageView
+ android:id="@+id/avatar"
+ android:layout_width="@dimen/avatar_size"
+ android:layout_height="@dimen/avatar_size"
+ android:layout_marginEnd="@dimen/spacer_2x"
+ android:layout_marginRight="@dimen/spacer_2x"
+ android:contentDescription="@null"
+ app:srcCompat="@drawable/ic_person_grey600_24dp"
+ tools:srcCompat="@tools:sample/avatars" />
+
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/username"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:textSize="16sp"
+ tools:text="@tools:sample/full_names" />
+
+ <TextView
+ android:id="@+id/instance"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:text="@string/owner"
+ android:textColor="@color/fg_secondary" />
+ </LinearLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/item_prepare_create_board.xml b/app/src/main/res/layout/item_prepare_create_board.xml
new file mode 100644
index 000000000..f846693a8
--- /dev/null
+++ b/app/src/main/res/layout/item_prepare_create_board.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="wrap_content"
+ android:orientation="horizontal"
+ android:padding="@dimen/spacer_2x"
+ tools:ignore="UseCompoundDrawables">
+
+ <ImageView
+ android:id="@+id/avatar"
+ android:layout_width="@dimen/avatar_size"
+ android:layout_height="@dimen/avatar_size"
+ android:layout_marginEnd="@dimen/spacer_2x"
+ android:layout_marginRight="@dimen/spacer_2x"
+ android:contentDescription="@null"
+ app:srcCompat="@drawable/circle_grey600_36dp"
+ tools:tint="@color/board_default_color" />
+
+ <TextView
+ android:id="@+id/board_title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:ellipsize="middle"
+ android:singleLine="true"
+ android:textSize="16sp"
+ tools:text="@tools:sample/lorem/random" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/item_prepare_create_stack.xml b/app/src/main/res/layout/item_prepare_create_stack.xml
new file mode 100644
index 000000000..9674eb1cd
--- /dev/null
+++ b/app/src/main/res/layout/item_prepare_create_stack.xml
@@ -0,0 +1,17 @@
+<?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="@+id/stackTitle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ellipsize="middle"
+ android:paddingStart="72dp"
+ android:paddingLeft="72dp"
+ android:paddingTop="@dimen/spacer_2x"
+ android:paddingEnd="@dimen/spacer_2x"
+ android:paddingRight="@dimen/spacer_2x"
+ android:paddingBottom="@dimen/spacer_2x"
+ android:singleLine="true"
+ android:textSize="16sp"
+ tools:text="@tools:sample/full_names" />
+
diff --git a/app/src/main/res/layout/nav_header_main.xml b/app/src/main/res/layout/nav_header_main.xml
index 37533984a..84accd92c 100644
--- a/app/src/main/res/layout/nav_header_main.xml
+++ b/app/src/main/res/layout/nav_header_main.xml
@@ -1,6 +1,7 @@
<?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/drawer_header_view"
android:layout_width="match_parent"
android:layout_height="@dimen/nav_header_height"
@@ -12,30 +13,29 @@
android:layout_height="match_parent"
android:contentDescription="@string/drawer_header_background"
android:scaleType="centerCrop"
- app:srcCompat="@drawable/background"/>
+ app:srcCompat="@drawable/background" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
- android:paddingLeft="@dimen/standard_padding"
- android:paddingTop="@dimen/standard_padding"
- android:paddingRight="@dimen/standard_padding"
- android:paddingBottom="@dimen/zero">
+ android:paddingLeft="@dimen/spacer_2x"
+ android:paddingTop="@dimen/spacer_2x"
+ android:paddingRight="@dimen/spacer_2x">
<FrameLayout
android:id="@+id/drawer_user_avatars"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
- android:layout_marginBottom="@dimen/standard_half_margin">
+ android:layout_marginBottom="@dimen/spacer_1x">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/drawer_current_account"
android:layout_width="@dimen/nav_drawer_header_avatar"
android:layout_height="@dimen/nav_drawer_header_avatar"
android:contentDescription="@string/drawer_current_account"
- app:srcCompat="@mipmap/ic_launcher_round"/>
+ app:srcCompat="@mipmap/ic_launcher_round" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/drawer_account_middle"
@@ -46,7 +46,7 @@
android:layout_marginRight="@dimen/nav_drawer_header_avatar_second_account_margin"
android:contentDescription="@string/drawer_middle_account"
android:visibility="gone"
- app:srcCompat="@mipmap/ic_launcher_round"/>
+ app:srcCompat="@mipmap/ic_launcher_round" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/drawer_account_end"
@@ -55,7 +55,7 @@
android:layout_gravity="end"
android:contentDescription="@string/drawer_end_account"
android:visibility="gone"
- app:srcCompat="@mipmap/ic_launcher_round"/>
+ app:srcCompat="@mipmap/ic_launcher_round" />
</FrameLayout>
@@ -71,24 +71,24 @@
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:orientation="vertical"
- android:paddingStart="@dimen/zero"
- android:paddingLeft="@dimen/zero"
- android:paddingEnd="@dimen/standard_half_padding"
- android:paddingRight="@dimen/standard_half_padding">
+ android:paddingEnd="@dimen/spacer_1x"
+ android:paddingRight="@dimen/spacer_1x"
+ tools:ignore="RtlSymmetry">
<TextView
+ android:id="@+id/drawer_app_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
- android:shadowColor="@color/black"
+ android:shadowColor="@android:color/black"
android:shadowDx="0.5"
android:shadowDy="0"
android:shadowRadius="2"
android:text="@string/app_name"
android:textColor="@android:color/white"
android:textSize="@dimen/drawer_header_text"
- android:textStyle="bold"/>
+ android:textStyle="bold" />
<TextView
android:id="@+id/drawer_username_full"
@@ -97,13 +97,13 @@
android:ellipsize="end"
android:lines="1"
android:maxLines="1"
- android:shadowColor="@color/black"
+ android:shadowColor="@android:color/black"
android:shadowDx="0.5"
android:shadowDy="0"
android:shadowRadius="2"
android:text="@string/app_name"
android:textColor="@android:color/white"
- android:textSize="@dimen/drawer_header_subtext"/>
+ android:textSize="@dimen/drawer_header_subtext" />
</LinearLayout>
diff --git a/app/src/main/res/layout/widget_color_chooser.xml b/app/src/main/res/layout/widget_color_chooser.xml
index 86edea8ec..3f5073e19 100644
--- a/app/src/main/res/layout/widget_color_chooser.xml
+++ b/app/src/main/res/layout/widget_color_chooser.xml
@@ -9,7 +9,7 @@
android:id="@+id/colorPicker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/standard_margin"
+ android:layout_marginTop="@dimen/spacer_2x"
app:alignItems="stretch"
app:flexWrap="wrap"
app:justifyContent="space_between" />
diff --git a/app/src/main/res/layout/widget_empty_content_view.xml b/app/src/main/res/layout/widget_empty_content_view.xml
index c3d7cb0bc..1133b5c7e 100644
--- a/app/src/main/res/layout/widget_empty_content_view.xml
+++ b/app/src/main/res/layout/widget_empty_content_view.xml
@@ -4,7 +4,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:padding="@dimen/standard_padding">
+ android:padding="@dimen/spacer_2x">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/image"
@@ -34,10 +34,10 @@
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:layout_centerHorizontal="true"
- android:paddingStart="@dimen/standard_padding"
- android:paddingLeft="@dimen/standard_padding"
- android:paddingEnd="@dimen/standard_padding"
- android:paddingRight="@dimen/standard_padding"
+ android:paddingStart="@dimen/spacer_2x"
+ android:paddingLeft="@dimen/spacer_2x"
+ android:paddingEnd="@dimen/spacer_2x"
+ android:paddingRight="@dimen/spacer_2x"
android:textAlignment="center"
hint:text="@string/app_name" />
</RelativeLayout> \ No newline at end of file
diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml
index e3bc42526..9cadaa793 100644
--- a/app/src/main/res/values-cs-rCZ/strings.xml
+++ b/app/src/main/res/values-cs-rCZ/strings.xml
@@ -149,4 +149,9 @@
<string name="add_comment">Přidat komentář</string>
<string name="card_edit_comments">Komentáře</string>
<string name="no_comments_yet">Zatím žádné komentáře</string>
+ <string name="no_boards">Zatím žádné tabule</string>
+ <string name="add_a_new_board_using_the_button">Novou tabuli přidáte pomocí tlačítka +</string>
+ <string name="choose_board">Zvolit tabuli</string>
+ <string name="choose_list">Zvolit seznam</string>
+ <string name="task_count">%1$s/%2$s</string>
</resources>
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 20f9cec5a..3c1ccae3f 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -149,4 +149,9 @@
<string name="add_comment">Kommentar hinzufügen</string>
<string name="card_edit_comments">Kommentare</string>
<string name="no_comments_yet">Noch keine Kommentare vorhanden</string>
+ <string name="no_boards">Noch keine Boards vorhanden</string>
+ <string name="add_a_new_board_using_the_button">Ein neues Board mit der +-Taste hinzufügen</string>
+ <string name="choose_board">Board auswählen</string>
+ <string name="choose_list">Liste auswählen</string>
+ <string name="task_count">%1$s/%2$s</string>
</resources>
diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml
index 124ef8030..679780bd3 100644
--- a/app/src/main/res/values-el/strings.xml
+++ b/app/src/main/res/values-el/strings.xml
@@ -149,4 +149,9 @@
<string name="add_comment">Προσθήκη σχολίου</string>
<string name="card_edit_comments">Σχόλια</string>
<string name="no_comments_yet">Δεν υπάρχουν ακόμα σχόλια</string>
+ <string name="no_boards">Κανένας πίνακας ακόμη</string>
+ <string name="add_a_new_board_using_the_button">Προσθέστε νέο πίνακα με το κουμπί +</string>
+ <string name="choose_board">Επιλογή πίνακα</string>
+ <string name="choose_list">Επιλογή λίστας</string>
+ <string name="task_count">%1$s/%2$s</string>
</resources>
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 44ff3d8bc..98fc59f29 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -149,4 +149,4 @@
<string name="add_comment">Agregar comentario</string>
<string name="card_edit_comments">Comentarios</string>
<string name="no_comments_yet">Todavía no hay comentarios.</string>
-</resources>
+ </resources>
diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml
index a0f6c56ce..9cfbc22e9 100644
--- a/app/src/main/res/values-eu/strings.xml
+++ b/app/src/main/res/values-eu/strings.xml
@@ -149,4 +149,9 @@
<string name="add_comment">Gehitu iruzkina</string>
<string name="card_edit_comments">Iruzkinak</string>
<string name="no_comments_yet">Iruzkinik ez oraindik</string>
+ <string name="no_boards">Ez dago mahairik oraindik</string>
+ <string name="add_a_new_board_using_the_button">Gehitu mahai berri bat + botoia erabiliz</string>
+ <string name="choose_board">Aukeratu mahaia</string>
+ <string name="choose_list">Aukeratu zerrenda</string>
+ <string name="task_count">%2$s(e)tik %1$s</string>
</resources>
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 67729e3ab..60c714f2c 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -150,4 +150,4 @@
<string name="add_comment">Ajouter un commentaire</string>
<string name="card_edit_comments">Commentaires</string>
<string name="no_comments_yet">Aucun commentaire pour l\'instant</string>
-</resources>
+ </resources>
diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml
index ebf7dffe2..4c3df7510 100644
--- a/app/src/main/res/values-gl/strings.xml
+++ b/app/src/main/res/values-gl/strings.xml
@@ -149,4 +149,9 @@
<string name="add_comment">Engadir comentario</string>
<string name="card_edit_comments">Comentarios</string>
<string name="no_comments_yet">Aínda non hai comentarios</string>
+ <string name="no_boards">Aínda non hai taboleiros</string>
+ <string name="add_a_new_board_using_the_button">Engadir un novo taboleiro co botón +</string>
+ <string name="choose_board">Escolla o taboleiro</string>
+ <string name="choose_list">Escolla a lista</string>
+ <string name="task_count">%1$s/%2$s</string>
</resources>
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index 403ae651c..4458a1798 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -149,4 +149,9 @@
<string name="add_comment">Aggiungi commento</string>
<string name="card_edit_comments">Commenti</string>
<string name="no_comments_yet">Ancora nessun commento</string>
+ <string name="no_boards">Ancora nessuna lavagna</string>
+ <string name="add_a_new_board_using_the_button">Aggiungi una nuova lavagna utilizzando il pulsante +</string>
+ <string name="choose_board">Scegli lavagna</string>
+ <string name="choose_list">Scegli elenco</string>
+ <string name="task_count">%1$s/%2$s</string>
</resources>
diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml
new file mode 100644
index 000000000..b1076478b
--- /dev/null
+++ b/app/src/main/res/values-night/colors.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="fg_secondary">#666</color>
+</resources>
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index f13447be3..8908cc8d6 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -149,4 +149,9 @@
<string name="add_comment">Reactie toevoegen</string>
<string name="card_edit_comments">Reacties</string>
<string name="no_comments_yet">Nog geen reacties</string>
+ <string name="no_boards">Nog geen borden</string>
+ <string name="add_a_new_board_using_the_button">Voeg een nieuw bord toe met de \'+\' knop</string>
+ <string name="choose_board">Kies bord</string>
+ <string name="choose_list">Kies lijst</string>
+ <string name="task_count">%1$s/%2$s</string>
</resources>
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index ba68c8666..e33249dc8 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -97,7 +97,7 @@
<string name="simple_discard">odrzuć</string>
<string name="do_you_want_to_delete_the_current_list">Czy chcesz usunąć bieżącą listę?</string>
<string name="add_a_new_list_using_the_button">Dodaj nową listę za pomocą przycisku +</string>
- <string name="add_a_new_card_using_the_button">Dodaj nową kartę za pomocą przycisku +.</string>
+ <string name="add_a_new_card_using_the_button">Dodaj nową kartę za pomocą przycisku +</string>
<string name="update_deck">Zaktualizuj deck</string>
<string name="your_deck_version_is_too_old">Twoja wersja deck jest nieaktualna</string>
<string name="deck_outdated_please_update">Twoja wersja deck jest nieaktualna. Zaktualizuj, aby używać tej aplikacji na Androida jako klienta.</string>
@@ -149,4 +149,9 @@
<string name="add_comment">Dodaj komentarz</string>
<string name="card_edit_comments">Komentarze</string>
<string name="no_comments_yet">Brak komentarzy</string>
+ <string name="no_boards">Brak tablic</string>
+ <string name="add_a_new_board_using_the_button">Dodaj nową tablicę za pomocą przycisku +</string>
+ <string name="choose_board">Wybierz tablicę</string>
+ <string name="choose_list">Wybierz listę</string>
+ <string name="task_count">%1$s/%2$s</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 2bf5b3979..8b8bbc331 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -149,4 +149,6 @@
<string name="add_comment">Adicionar comentário</string>
<string name="card_edit_comments">Comentários</string>
<string name="no_comments_yet">Nenhum comentário ainda</string>
-</resources>
+ <string name="no_boards">Sem painéis ainda</string>
+ <string name="add_a_new_board_using_the_button">Adicionar um novo painel usando o botão +</string>
+ </resources>
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 32edc862c..18d7422b5 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -149,4 +149,4 @@
<string name="add_comment">Добавить комментарий</string>
<string name="card_edit_comments">Комментарии</string>
<string name="no_comments_yet">Пока никто не прокомментировал</string>
-</resources>
+ </resources>
diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk-rSK/strings.xml
index a6a57453d..7f423df0a 100644
--- a/app/src/main/res/values-sk-rSK/strings.xml
+++ b/app/src/main/res/values-sk-rSK/strings.xml
@@ -149,4 +149,6 @@
<string name="add_comment">Pridať komentár</string>
<string name="card_edit_comments">Komentáre</string>
<string name="no_comments_yet">Zatiaľ žiadne komentáre</string>
-</resources>
+ <string name="no_boards">Zatiaľ žiadne nástenky</string>
+ <string name="add_a_new_board_using_the_button">Pridajte novú nástenku pomocou tlačidla +</string>
+ </resources>
diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml
index aaa1e9b9b..110292d01 100644
--- a/app/src/main/res/values-sl/strings.xml
+++ b/app/src/main/res/values-sl/strings.xml
@@ -149,4 +149,6 @@
<string name="add_comment">Dodaj opombo</string>
<string name="card_edit_comments">Opombe</string>
<string name="no_comments_yet">Ni še dodane nobene opombe</string>
-</resources>
+ <string name="no_boards">Ni še vpisanih zbirk</string>
+ <string name="add_a_new_board_using_the_button">Novo zbirko je mogoče dodati z gumbom +</string>
+ </resources>
diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml
index e4e35e025..bf93706af 100644
--- a/app/src/main/res/values-sr/strings.xml
+++ b/app/src/main/res/values-sr/strings.xml
@@ -59,6 +59,8 @@
<string name="activity">Активност</string>
+ <string name="add_list">Додај списак</string>
+ <string name="rename_list">Преименуј списак</string>
<string name="delete_list">Обриши списак</string>
<string name="label_menu">мени</string>
@@ -73,6 +75,7 @@
<string name="label_add">Додај %1$s</string>
<string name="error">Дошло је до грешке</string>
+ <string name="operation_not_yet_supported">Није још подржано</string>
<string name="simple_copy">копирај</string>
<string name="simple_exception">Изузетак</string>
<string name="copied_to_clipboard">Копирано у клипборд</string>
@@ -89,14 +92,18 @@
<string name="account_already_added">Налог је већ додат</string>
<string name="account_is_getting_imported">Налог се увози</string>
<string name="not_synced_yet">Још није синхронизовано</string>
+ <string name="no_lists_yet">Нема још спискова</string>
<string name="do_you_want_to_save_your_changes">Да ли желите да сачувате измене?</string>
<string name="simple_discard">одбаци</string>
+ <string name="do_you_want_to_delete_the_current_list">Да ли желите да обришете тренутни списак?</string>
+ <string name="add_a_new_list_using_the_button">Додај нови списак користећи + дугме</string>
<string name="add_a_new_card_using_the_button">Додајте нову картицу на + дугме</string>
<string name="update_deck">Ажурирај шпил</string>
<string name="your_deck_version_is_too_old">Ваша верзија Шпила је превише стара</string>
<string name="deck_outdated_please_update">Верзија апликације Шпил је стара. Ажурирајте да бисте користили ову Андроид апликацију као клијента.</string>
<string name="simple_update">Ажурирај</string>
<string name="simple_delete">Обриши</string>
+ <string name="delete_board_message">Ово ће трајно да уклони ову таблу укључујући све спискове и картице.</string>
<string name="simple_rename">Преименуј</string>
<string name="simple_settings">Поставке</string>
<string name="settings_theme_title">Тамна тема</string>
@@ -129,6 +136,22 @@
<string name="please_add_an_account_first">Прво додајте налог</string>
<string name="title_is_mandatory">Наслов је обавезан</string>
<string name="provide_at_least_a_title_or_description">Дајте бар наслов или опис</string>
+ <string name="welcome_text">Добродошли у %1$s</string>
+ <string name="save_card_before_attachment">Картица мора да се сачува пре него што може да јој се дода прилог.</string>
+ <string name="server_misconfigured">Сервер није добро конфигурисан</string>
+ <string name="server_misconfigured_explanation">Сервер је одговорио са HTTP 302 кодом, што значи да немате инсталирану Deck апликацију или да Вам сервер није правилно конфигурисан. Ово може да буде проузорковано произвољним додавањима у .htaccess фајлу или другим Некстклауд апликацијама као што је OID Client. Можете наћи наше контакт информације за подршку у секцији О програму.</string>
<string name="server_error">Грешка на серверу</string>
+ <string name="server_error_explanation">Сервер је одговорио са HTTP 503 кодом. Ово може да значи да је сервер у режиму одржавања. Контактирајте администратора или нас за подршку. Можете наћи наше контакт информације за подршку у секцији О програму. </string>
+ <string name="share_add_to_card">Додај на картицу</string>
+ <string name="share_success">Успешно додат %1$s на %2$s</string>
+ <string name="could_not_copy_to_clipboard">Не могу да копирам у оставу</string>
+ <string name="shared_error">Дељење садржаја од апликација треће стране још није у потпуности подржано. Пробајте прво да преузмете садржај у целости и онда га поделите из менаџера фајлова или из галерије.</string>
+ <string name="add_comment">Додај коментар</string>
<string name="card_edit_comments">Коментари</string>
- </resources>
+ <string name="no_comments_yet">Још нема коментара</string>
+ <string name="no_boards">Још нема табли</string>
+ <string name="add_a_new_board_using_the_button">Додајте нову таблу преко + дугмета</string>
+ <string name="choose_board">Одаберите таблу</string>
+ <string name="choose_list">Одаберите списак</string>
+ <string name="task_count">%1$s/%2$s</string>
+</resources>
diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml
index 48c21da83..afa942a49 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -149,4 +149,4 @@
<string name="add_comment">Lägg till kommentar</string>
<string name="card_edit_comments">Kommentarer</string>
<string name="no_comments_yet">Inga kommentarer än</string>
-</resources>
+ </resources>
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index 8abe9a0db..1c7dda468 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -59,6 +59,8 @@
<string name="activity">Etkinlik</string>
+ <string name="add_list">Liste ekle</string>
+ <string name="rename_list">Listeyi yeniden adlandır</string>
<string name="delete_list">Listeyi sil</string>
<string name="label_menu">menü</string>
@@ -73,6 +75,7 @@
<string name="label_add">%1$s ekle</string>
<string name="error">Bir sorun çıktı</string>
+ <string name="operation_not_yet_supported">Henüz desteklenmiyor</string>
<string name="simple_copy">kopyala</string>
<string name="simple_exception">İstisna</string>
<string name="copied_to_clipboard">Panoya kopyalandı</string>
@@ -89,14 +92,18 @@
<string name="account_already_added">Hesap zaten eklenmiş</string>
<string name="account_is_getting_imported">Hesap içe aktarılıyor</string>
<string name="not_synced_yet">Henüz eşitlenmemiş</string>
+ <string name="no_lists_yet">Henüz bir liste yok</string>
<string name="do_you_want_to_save_your_changes">Değişiklikleri kaydetmek ister misiniz?</string>
<string name="simple_discard">yok say</string>
+ <string name="do_you_want_to_delete_the_current_list">Geçerli listeyi silmek istiyor musunuz?</string>
+ <string name="add_a_new_list_using_the_button">+ düğmesini kullanarak yeni bir liste ekleyebilirsiniz</string>
<string name="add_a_new_card_using_the_button">+ düğmesini kullanarak yeni bir kart ekleyebilirsiniz</string>
<string name="update_deck">Tahtayı güncelle</string>
<string name="your_deck_version_is_too_old">Tahta sürümünüz çok eski</string>
<string name="deck_outdated_please_update">Tahta sürümünüz çok eski. Lütfen bu android uygulamasını istemci olarak kullanabilmek için deck sürümünü güncelleyin.</string>
<string name="simple_update">Güncelle</string>
<string name="simple_delete">Sil</string>
+ <string name="delete_board_message">Bu işlem içindeki tüm liste ve kartlarla birlikte bu panoyu silecek.</string>
<string name="simple_rename">Yeniden adlandır</string>
<string name="simple_settings">Ayarlar</string>
<string name="settings_theme_title">Koyu tema</string>
@@ -129,9 +136,19 @@
<string name="please_add_an_account_first">Lütfen önce bir hesap ekleyin</string>
<string name="title_is_mandatory">Başlığın yazılması zorunludur</string>
<string name="provide_at_least_a_title_or_description">Lütfen en azından başlığı ya da açıklamayı yazın</string>
+ <string name="welcome_text">%1$s panonuza hoşgeldiniz</string>
+ <string name="save_card_before_attachment">Ek dosyaları ekleyebilmek için kartın kaydedilmesi gerekiyor.</string>
+ <string name="server_misconfigured">Sunucu yapılandırması hatalı</string>
+ <string name="server_misconfigured_explanation">Sunucunuz, üzerine Deck uygulamasının kurulmadığı ya da bir şeyin yanlış yapılandırıldığı anlamına gelen HTTP 302 durum kodu ile yanıt verdi. Bu durum, bir .htaccess dosyasındaki özel kısıtlamalardan ya da OID İstemcisi gibi Nextcloud uygulamalarından kaynaklanabilir. Destek almak için iletişim bilgilerimizi hakkında bölümünde bulabilirsiniz.</string>
<string name="server_error">Sunucu sorunu</string>
- <string name="share_add_to_card">Sepete ekle</string>
+ <string name="server_error_explanation">Sunucunuz HTTP 503 durum kodu ile yanıt verdi. Bu durum sunucunun bakım kipinde olmasından kaynaklanabilir. Lütfen sorunu çözmek için sistem yöneticinizle ya da bizimle görüşün. Destek almak için iletişim bilgilerimizi hakkında bölümünde bulabilirsiniz.</string>
+ <string name="share_add_to_card">Karta ekle</string>
+ <string name="share_success">%1$s, %2$s üzerine eklendi</string>
+ <string name="could_not_copy_to_clipboard">Panoya kopyalanamadı</string>
+ <string name="shared_error">Üçüncü taraf uygulamalardaki içeriklerin paylaşılması henüz tam olarak desteklenmiyor. Lütfen önce indirmeyi ve sonra dosya yöneticisi ya da galeri ile paylaşmayı deneyin.</string>
<string name="add_comment">Yorum ekle</string>
- <string name="card_edit_comments">Açıklamalar</string>
- <string name="no_comments_yet">Henüz yorum yok</string>
-</resources>
+ <string name="card_edit_comments">Yorumlar</string>
+ <string name="no_comments_yet">Henüz bir yorum yok</string>
+ <string name="no_boards">Henüz bir pano yok</string>
+ <string name="add_a_new_board_using_the_button">+ düğmesini kullanarak yeni bir pano ekleyebilirsiniz</string>
+ </resources>
diff --git a/app/src/main/res/values-w820dp/dimens.xml b/app/src/main/res/values-w820dp/dimens.xml
deleted file mode 100644
index 63fc81644..000000000
--- a/app/src/main/res/values-w820dp/dimens.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<resources>
- <!-- Example customization of dimensions originally defined in res/values/dimens.xml
- (such as screen margins) for screens with more than 820dp of available width. This
- would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
- <dimen name="activity_horizontal_margin">64dp</dimen>
-</resources>
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index 17da8a8a9..d3b8502b1 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -39,6 +39,7 @@
<string name="about_app_license">此程式依照 GNU GENERAL PUBLIC LICENSE v3+ 方式授權使用</string>
<string name="about_app_license_button">檢視授權條款</string>
<string name="about_icons_disclaimer_title">圖示</string>
+ <string name="about_icons_disclaimer_app_icon">原始圖示請見%1$s</string>
<string name="about_icons_disclaimer_mdi">Material Design 圖示</string>
<string name="about_credits_tab_title">致謝</string>
<string name="about_contribution_tab_title">貢獻</string>
@@ -57,6 +58,8 @@
<string name="activity">活動</string>
+ <string name="add_list">新增清單</string>
+ <string name="rename_list">重新命名清單</string>
<string name="delete_list">刪除清單</string>
<string name="label_menu">選單</string>
@@ -71,6 +74,7 @@
<string name="label_add">新增%1$s</string>
<string name="error">發生錯誤</string>
+ <string name="operation_not_yet_supported">尚未支援</string>
<string name="simple_copy">複製</string>
<string name="simple_exception">例外</string>
<string name="copied_to_clipboard">已複製至剪貼簿</string>
@@ -87,8 +91,10 @@
<string name="account_already_added">已加入帳戶</string>
<string name="account_is_getting_imported">已匯入帳戶</string>
<string name="not_synced_yet">尚未同步完成</string>
+ <string name="no_lists_yet">尚無清單</string>
<string name="do_you_want_to_save_your_changes">您想要儲存您做出的變更嗎?</string>
<string name="simple_discard">放棄</string>
+ <string name="do_you_want_to_delete_the_current_list">您想刪除目前的清單嗎?</string>
<string name="add_a_new_card_using_the_button">用 + 按鈕新增卡片</string>
<string name="update_deck">更新 Deck</string>
<string name="your_deck_version_is_too_old">您的 Deck 版本過舊</string>
@@ -124,6 +130,7 @@
<string name="action_card_move_title">移動 %1$s</string>
<string name="simple_disabled">已停用</string>
<string name="simple_copied">已複製</string>
+ <string name="title_is_mandatory">必須有標題</string>
<string name="server_error">伺服器錯誤</string>
<string name="card_edit_comments">留言</string>
</resources>
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index b24e3d8cd..d1a7347a6 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -3,8 +3,8 @@
<color name="primary">#0082c9</color>
<color name="accent">#ffffff</color>
<color name="danger">#d40000</color>
- <color name="black">#000000</color>
<color name="fg_accent">#fff</color>
+ <color name="fg_primary">#333</color>
<color name="fg_secondary">#999</color>
<color name="grey600">#757575</color>
@@ -14,7 +14,7 @@
<!-- due date colors -->
<color name="due_tomorrow">#7fffc53a</color>
<color name="due_today">#7feca700</color>
- <color name="due_overdue">#d40000</color>
+ <color name="due_overdue">#ef6e6b</color>
<color name="overdue_text_color">#FFFFFF</color>
<!-- board color picker colors -->
diff --git a/app/src/main/res/values/customization.xml b/app/src/main/res/values/customization.xml
index 758d9fbff..6e7e42a47 100644
--- a/app/src/main/res/values/customization.xml
+++ b/app/src/main/res/values/customization.xml
@@ -1,23 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
+ <!-- Apply the brand of the instance for each account to UI elements -->
+ <bool name="enable_brand">false</bool>
<!-- How many avatars should be displayed in the card list view -->
<integer name="max_avatar_count">3</integer>
- <!-- How many labels are shown in the card list view before "..." -->
- <integer name="max_labels_shown">3</integer>
- <!-- How many characters of the labels are displayed at the card list view -->
- <integer name="max_labels_chars">2</integer>
<!-- How many users should be suggested when clicking on the assigned users input field -->
<integer name="max_users_suggested">3</integer>
<!-- How many labels should be suggested when clicking on the assigned labels input field -->
<integer name="max_labels_suggested">3</integer>
<!-- How many dp should one column in the attachments grid have -->
<integer name="max_dp_attachment_column">110</integer>
- <!-- How many microseconds should be waited before switching to another tab when dragging cards -->
- <integer name="drag_n_drop_ms_to_react">500</integer>
- <!-- How many dp from border should one be away before switching to another tab when dragging cards -->
- <integer name="drag_n_drop_dp_to_react">30</integer>
- <!-- How many dp from top / bottom border should one be away before scrolling top / down when dragging cards -->
- <integer name="drag_n_drop_dp_to_react_top_bottom">100</integer>
<!-- Maximum characters of a comment. Caution: Server allow maximum 1000 characters! -->
<integer name="comment_max_length">1000</integer>
</resources> \ No newline at end of file
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 0b0f8f27c..e7ba5a428 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -1,18 +1,14 @@
<resources>
- <!-- Default screen margins, per the Android Design guidelines. -->
- <dimen name="activity_horizontal_margin">16dp</dimen>
- <dimen name="standard_margin">16dp</dimen>
- <dimen name="standard_padding">16dp</dimen>
- <dimen name="standard_half_margin">8dp</dimen>
- <dimen name="standard_half_padding">8dp</dimen>
- <dimen name="standard_quarter_margin">4dp</dimen>
- <dimen name="standard_quarter_padding">4dp</dimen>
+ <dimen name="spacer_1hx">4dp</dimen>
+ <dimen name="spacer_1x">8dp</dimen>
+ <dimen name="spacer_2x">16dp</dimen>
+
<dimen name="nav_header_height">148dp</dimen>
- <dimen name="fab_margin">16dp</dimen>
+ <dimen name="fab_margin">@dimen/spacer_2x</dimen>
+
<dimen name="avatar_size">40dp</dimen>
<dimen name="avatar_size_small">32dp</dimen>
<dimen name="avatar_overlapping_small">20dp</dimen>
- <dimen name="zero">0dp</dimen>
<dimen name="icon_size_details">24dp</dimen>
<dimen name="nav_drawer_header_avatar">56dp</dimen>
<dimen name="nav_drawer_header_avatar_other_accounts_size">40dp</dimen>
diff --git a/app/src/main/res/values/setup.xml b/app/src/main/res/values/setup.xml
index 363ba7aba..a51735dc5 100644
--- a/app/src/main/res/values/setup.xml
+++ b/app/src/main/res/values/setup.xml
@@ -3,6 +3,9 @@
<string name="shared_preference_last_sync" translatable="false">it.niedermann.nextcloud.deck.last_sync</string>
<string name="shared_preference_last_background_sync" translatable="false">it.niedermann.nextcloud.deck.last_background_sync</string>
+ <string name="shared_preference_theme_main" translatable="false">it.niedermann.nextcloud.deck.theme_main</string>
+ <string name="shared_preference_theme_text" translatable="false">it.niedermann.nextcloud.deck.theme_text</string>
+
<string name="pref_key_wifi_only" translatable="false">wifiOnly</string>
<string name="pref_key_dark_theme" translatable="false">darkTheme</string>
<string name="pref_key_background_sync" translatable="false">backgroundSync</string>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 640bcc610..b0701b488 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -88,6 +88,7 @@
<string name="error">An error appeared</string>
<string name="operation_not_yet_supported">Not yet supported</string>
<string name="simple_copy">copy</string>
+ <string name="simple_error">Error</string>
<string name="simple_exception">Exception</string>
<string name="copied_to_clipboard">Copied to clipboard</string>
<string name="simple_close">close</string>
@@ -172,4 +173,7 @@
<string name="no_comments_yet">No comments yet</string>
<string name="no_boards">No boards yet</string>
<string name="add_a_new_board_using_the_button">Add a new board using the + button</string>
+ <string name="choose_board">Choose board</string>
+ <string name="choose_list">Choose list</string>
+ <string name="task_count">%1$s/%2$s</string>
</resources>
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 1e3be799f..bec19f14b 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -35,41 +35,11 @@
<item name="android:windowBackground">@drawable/splash_screen</item>
</style>
- <style name="PrimaryCTAButton" parent="android:Widget.DeviceDefault.Button">
- <item name="android:background">@color/primary</item>
- <item name="android:textColor">@color/fg_accent</item>
- <item name="android:elevation" tools:targetApi="lollipop">5dp</item>
- </style>
-
<style name="NavigationView">
<item name="android:ellipsize">middle</item>
<item name="android:listDivider">@null</item>
</style>
- <style name="DialogDarkTheme" parent="ThemeOverlay.AppCompat.Dialog.Alert">
- <item name="android:background">@android:color/background_dark</item>
- </style>
-
- <style name="DeleteDialogDarkTheme" parent="DialogDarkTheme">
- <item name="android:buttonBarPositiveButtonStyle" tools:targetApi="lollipop">
- @style/PositiveButtonStyle
- </item>
- </style>
-
- <style name="DeleteDialogTheme" parent="ThemeOverlay.AppCompat.Dialog.Alert">
- <item name="android:buttonBarPositiveButtonStyle" tools:targetApi="lollipop">
- @style/PositiveButtonStyle
- </item>
- </style>
-
- <style name="PositiveButtonStyle" parent="Widget.AppCompat.Button.ButtonBar.AlertDialog">
- <item name="android:textColor">@color/danger</item>
- </style>
-
- <style name="Spinner" parent="ThemeOverlay.AppCompat.Dark">
- <item name="android:textColor">@android:color/white</item>
- </style>
-
<style name="TransparentTheme" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/background_dark</item>
diff --git a/app/src/main/res/xml/settings.xml b/app/src/main/res/xml/settings.xml
index 6a24dce9e..69249ec38 100644
--- a/app/src/main/res/xml/settings.xml
+++ b/app/src/main/res/xml/settings.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
- <SwitchPreference
+ <it.niedermann.nextcloud.deck.ui.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"
@@ -16,7 +16,7 @@
android:summary="%s"
android:title="@string/settings_background_sync" />
- <SwitchPreference
+ <it.niedermann.nextcloud.deck.ui.branding.BrandedSwitchPreference
android:defaultValue="@string/pref_value_theme_light"
android:icon="@drawable/ic_brightness_2_grey600_24dp"
android:key="@string/pref_key_dark_theme"
diff --git a/app/src/main/res/xml/shortcuts.xml b/app/src/main/res/xml/shortcuts.xml
index 7350ea8db..f84b7363e 100644
--- a/app/src/main/res/xml/shortcuts.xml
+++ b/app/src/main/res/xml/shortcuts.xml
@@ -1,19 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<shortcut
- android:shortcutId="it.niedermann.nextcloud.deck"
android:enabled="true"
android:icon="@drawable/ic_add_grey_24dp"
- android:shortcutShortLabel="@string/simple_add"
- android:shortcutLongLabel="@string/add_card">
+ android:shortcutId="it.niedermann.nextcloud.deck"
+ android:shortcutLongLabel="@string/add_card"
+ android:shortcutShortLabel="@string/simple_add">
<intent
android:action="android.intent.action.VIEW"
- android:targetPackage="it.niedermann.nextcloud.deck"
- android:targetClass="it.niedermann.nextcloud.deck.ui.EditActivity">
- <extra android:name="localId" android:value="-1" />
- <extra android:name="boardId" android:value="-1" />
- <extra android:name="stackId" android:value="-1" />
- </intent>
+ android:targetClass="it.niedermann.nextcloud.deck.ui.preparecreate.PrepareCreateActivity"
+ android:targetPackage="it.niedermann.nextcloud.deck" />
<categories android:name="android.shortcut.conversation" />
</shortcut>
</shortcuts> \ No newline at end of file
diff --git a/app/src/play/res/xml/shortcuts.xml b/app/src/play/res/xml/shortcuts.xml
new file mode 100644
index 000000000..6c6471880
--- /dev/null
+++ b/app/src/play/res/xml/shortcuts.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
+ <shortcut
+ android:enabled="true"
+ android:icon="@drawable/ic_add_grey_24dp"
+ android:shortcutId="it.niedermann.nextcloud.deck"
+ android:shortcutLongLabel="@string/add_card"
+ android:shortcutShortLabel="@string/simple_add">
+ <intent
+ android:action="android.intent.action.VIEW"
+ android:targetClass="it.niedermann.nextcloud.deck.ui.preparecreate.PrepareCreateActivity"
+ android:targetPackage="it.niedermann.nextcloud.deck.play" />
+ <categories android:name="android.shortcut.conversation" />
+ </shortcut>
+</shortcuts>