diff options
author | Stefan Niedermann <info@niedermann.it> | 2020-07-04 14:34:40 +0300 |
---|---|---|
committer | Stefan Niedermann <info@niedermann.it> | 2020-07-04 14:34:40 +0300 |
commit | 0a4d8fc074b2fc06a48aab3242ec257014aa9b24 (patch) | |
tree | 0371dff5f87c00e4731029b768c892e697bc5f9c /app/src/main/java | |
parent | dd5dff7fd1a518fda4fce182f52334ef90e4dc73 (diff) | |
parent | f302d4ac2de08138064bf1b8aa3863fd3b05a1d0 (diff) |
Merge branch 'master' into 455-clone-boards
# Conflicts:
# app/src/main/res/values/strings.xml
Diffstat (limited to 'app/src/main/java')
57 files changed, 695 insertions, 642 deletions
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/Application.java b/app/src/main/java/it/niedermann/nextcloud/deck/DeckApplication.java index 6fbf7c8a2..ff492c226 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/Application.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/DeckApplication.java @@ -1,23 +1,20 @@ package it.niedermann.nextcloud.deck; +import android.app.Application; import android.content.Context; import android.content.SharedPreferences; -import android.graphics.Color; -import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.preference.PreferenceManager; import com.jakewharton.threetenabp.AndroidThreeTen; -import it.niedermann.nextcloud.deck.ui.branding.BrandedActivity; - 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; -public class Application extends android.app.Application { +public class DeckApplication extends Application { public static final long NO_ACCOUNT_ID = -1L; public static final long NO_BOARD_ID = -1L; @@ -25,7 +22,7 @@ public class Application extends android.app.Application { @Override public void onCreate() { - setAppTheme(getAppTheme(getApplicationContext())); + setAppTheme(isDarkTheme(getApplicationContext())); super.onCreate(); AndroidThreeTen.init(this); } @@ -48,56 +45,11 @@ public class Application extends android.app.Application { setDefaultNightMode(darkTheme ? MODE_NIGHT_YES : MODE_NIGHT_NO); } - public static boolean getAppTheme(@NonNull Context context) { + public static boolean isDarkTheme(@NonNull Context context) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); return prefs.getBoolean(context.getString(R.string.pref_key_dark_theme), false); } - // -------- - // Branding - // -------- - - public static boolean isBrandingEnabled(@NonNull Context context) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - return prefs.getBoolean(context.getString(R.string.pref_key_branding), true); - } - - @ColorInt - public static int readBrandMainColor(@NonNull Context context) { - if (Application.isBrandingEnabled(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)); - } else { - return context.getResources().getColor(R.color.primary); - } - } - - @ColorInt - public static int readBrandTextColor(@NonNull Context context) { - if (isBrandingEnabled(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)); - } else { - return Color.WHITE; - } - } - - public static void saveBrandColors(@NonNull Context context, @ColorInt int mainColor, @ColorInt int textColor) { - if (isBrandingEnabled(context) && context instanceof BrandedActivity) { - final BrandedActivity activity = (BrandedActivity) context; - activity.applyBrand(mainColor, textColor); - BrandedActivity.applyBrandToStatusbar(activity.getWindow(), mainColor, 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 // -------------------------------------- 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 ebcc17bdc..27c2bc7b6 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 @@ -96,12 +96,12 @@ public class SyncManager { } @AnyThread - private void doAsync(Runnable r) { + private void doAsync(@NonNull Runnable r) { new Thread(r).start(); } @AnyThread - public MutableLiveData<FullCard> synchronizeCardByRemoteId(long cardRemoteId, Account account) { + public MutableLiveData<FullCard> synchronizeCardByRemoteId(long cardRemoteId, @NonNull Account account) { MutableLiveData<FullCard> liveData = new MutableLiveData<>(); doAsync(() -> { Long accountId = account.getId(); @@ -128,7 +128,7 @@ public class SyncManager { // TODO if the card does not exist yet, try to synchronize it first, instead of directly returning null. If sync failed, return null. @AnyThread - public LiveData<Long> getLocalBoardIdByCardRemoteIdAndAccount(long cardRemoteId, Account account) { + public LiveData<Long> getLocalBoardIdByCardRemoteIdAndAccount(long cardRemoteId, @NonNull Account account) { return dataBaseAdapter.getLocalBoardIdByCardRemoteIdAndAccountId(cardRemoteId, account.getId()); } @@ -166,11 +166,12 @@ public class SyncManager { } @AnyThread - public void synchronize(IResponseCallback<Boolean> responseCallback) { - if (responseCallback == null || - responseCallback.getAccount() == null || - responseCallback.getAccount().getId() == null) { - throw new IllegalArgumentException("please provide an account ID."); + public void synchronize(@NonNull IResponseCallback<Boolean> responseCallback) { + if(responseCallback.getAccount() == null) { + throw new IllegalArgumentException(Account.class.getSimpleName() + " object in given " + IResponseCallback.class.getSimpleName() + " must not be null."); + } + if(responseCallback.getAccount().getId() == null) { + throw new IllegalArgumentException(Account.class.getSimpleName() + " object in given " + IResponseCallback.class.getSimpleName() + " must contain a valid id, but given id was null."); } doAsync(() -> refreshCapabilities(new IResponseCallback<Capabilities>(responseCallback.getAccount()) { @Override @@ -276,7 +277,7 @@ public class SyncManager { } @AnyThread - public WrappedLiveData<Account> createAccount(Account accout) { + public WrappedLiveData<Account> createAccount(@NonNull Account accout) { return dataBaseAdapter.createAccount(accout); } @@ -301,7 +302,7 @@ public class SyncManager { } @AnyThread - public LiveData<Account> readAccount(String name) { + public LiveData<Account> readAccount(@Nullable String name) { return dataBaseAdapter.readAccount(name); } @@ -344,7 +345,7 @@ public class SyncManager { } @AnyThread - public void refreshCapabilities(IResponseCallback<Capabilities> callback) { + public void refreshCapabilities(@NonNull IResponseCallback<Capabilities> callback) { doAsync(() -> { try { serverAdapter.getCapabilities(new IResponseCallback<Capabilities>(callback.getAccount()) { @@ -380,29 +381,33 @@ public class SyncManager { callback.onError(e); } - serverAdapter.getAllOcsUsers(new IResponseCallback<OcsUserList>(callback.getAccount()) { - @Override - public void onResponse(OcsUserList response) { - Long accountId = callback.getAccount().getId(); - for (String ocsUserName : response) { - User existingUser = dataBaseAdapter.getUserByUidDirectly(accountId, ocsUserName); - if (existingUser == null) { - // we don't know this user, lets get some details... - serverAdapter.getOcsUserDetails(ocsUserName, new IResponseCallback<OcsUser>(callback.getAccount()) { - @Override - public void onResponse(OcsUser response) { - User newUser = new User(); - newUser.setStatus(DBStatus.UP_TO_DATE.getId()); - newUser.setPrimaryKey(ocsUserName); - newUser.setUid(ocsUserName); - newUser.setDisplayname(response.getDisplayName()); - dataBaseAdapter.createUser(accountId, newUser); - } - }); + try { + serverAdapter.getAllOcsUsers(new IResponseCallback<OcsUserList>(callback.getAccount()) { + @Override + public void onResponse(OcsUserList response) { + Long accountId = callback.getAccount().getId(); + for (String ocsUserName : response) { + User existingUser = dataBaseAdapter.getUserByUidDirectly(accountId, ocsUserName); + if (existingUser == null) { + // we don't know this user, lets get some details... + serverAdapter.getOcsUserDetails(ocsUserName, new IResponseCallback<OcsUser>(callback.getAccount()) { + @Override + public void onResponse(OcsUser response) { + User newUser = new User(); + newUser.setStatus(DBStatus.UP_TO_DATE.getId()); + newUser.setPrimaryKey(ocsUserName); + newUser.setUid(ocsUserName); + newUser.setDisplayname(response.getDisplayName()); + dataBaseAdapter.createUser(accountId, newUser); + } + }); + } } } - } - }); + }); + } catch (OfflineException ignored) { + // Nothing to do here... + } }); } @@ -443,7 +448,7 @@ public class SyncManager { } @AnyThread - public LiveData<FullBoard> createBoard(long accountId, Board board) { + public LiveData<FullBoard> createBoard(long accountId, @NonNull Board board) { MutableLiveData<FullBoard> liveData = new MutableLiveData<>(); doAsync(() -> { Account account = dataBaseAdapter.getAccountByIdDirectly(accountId); @@ -555,7 +560,7 @@ public class SyncManager { } @AnyThread - public LiveData<List<it.niedermann.nextcloud.deck.model.ocs.Activity>> syncActivitiesForCard(Card card) { + public LiveData<List<it.niedermann.nextcloud.deck.model.ocs.Activity>> syncActivitiesForCard(@NonNull Card card) { doAsync(() -> { if (serverAdapter.hasInternetConnection()) { if (card.getId() != null) { @@ -575,7 +580,7 @@ public class SyncManager { } @AnyThread - public void addCommentToCard(long accountId, long cardId, DeckComment comment) { + public void addCommentToCard(long accountId, long cardId, @NonNull DeckComment comment) { doAsync(() -> { Account account = dataBaseAdapter.getAccountByIdDirectly(accountId); Card card = dataBaseAdapter.getCardByLocalIdDirectly(accountId, cardId); @@ -625,7 +630,7 @@ public class SyncManager { } @AnyThread - public WrappedLiveData<Void> deleteBoard(Board board) { + public WrappedLiveData<Void> deleteBoard(@NonNull Board board) { WrappedLiveData<Void> liveData = new WrappedLiveData<>(); doAsync(() -> { long accountId = board.getAccountId(); @@ -637,7 +642,7 @@ public class SyncManager { } @AnyThread - public WrappedLiveData<FullBoard> updateBoard(FullBoard board) { + public WrappedLiveData<FullBoard> updateBoard(@NonNull FullBoard board) { WrappedLiveData<FullBoard> liveData = new WrappedLiveData<>(); long accountId = board.getAccountId(); doAsync(() -> { @@ -692,7 +697,7 @@ public class SyncManager { } @AnyThread - public WrappedLiveData<AccessControl> updateAccessControl(AccessControl entity) { + public WrappedLiveData<AccessControl> updateAccessControl(@NonNull AccessControl entity) { WrappedLiveData<AccessControl> liveData = new WrappedLiveData<>(); doAsync(() -> { Account account = dataBaseAdapter.getAccountByIdDirectly(entity.getAccountId()); @@ -704,7 +709,7 @@ public class SyncManager { } @AnyThread - private <T> IResponseCallback<T> getCallbackToLiveDataConverter(Account account, WrappedLiveData<T> liveData) { + private <T> IResponseCallback<T> getCallbackToLiveDataConverter(Account account, @NonNull WrappedLiveData<T> liveData) { return new IResponseCallback<T>(account) { @Override public void onResponse(T response) { @@ -719,7 +724,7 @@ public class SyncManager { } @AnyThread - public WrappedLiveData<Void> deleteAccessControl(AccessControl entity) { + public WrappedLiveData<Void> deleteAccessControl(@NonNull AccessControl entity) { WrappedLiveData<Void> liveData = new WrappedLiveData<>(); doAsync(() -> { Account account = dataBaseAdapter.getAccountByIdDirectly(entity.getAccountId()); @@ -749,7 +754,7 @@ public class SyncManager { } @AnyThread - public WrappedLiveData<FullStack> createStack(long accountId, Stack stack) { + public WrappedLiveData<FullStack> createStack(long accountId, @NonNull Stack stack) { WrappedLiveData<FullStack> liveData = new WrappedLiveData<>(); doAsync(() -> { Account account = dataBaseAdapter.getAccountByIdDirectly(accountId); @@ -778,7 +783,7 @@ public class SyncManager { } @AnyThread - public WrappedLiveData<FullStack> updateStack(FullStack stack) { + public WrappedLiveData<FullStack> updateStack(@NonNull FullStack stack) { WrappedLiveData<FullStack> liveData = new WrappedLiveData<>(); doAsync(() -> { Account account = dataBaseAdapter.getAccountByIdDirectly(stack.getAccountId()); @@ -887,7 +892,7 @@ public class SyncManager { // } @AnyThread - public LiveData<FullCard> createFullCard(long accountId, long localBoardId, long localStackId, FullCard card) { + public LiveData<FullCard> createFullCard(long accountId, long localBoardId, long localStackId, @NonNull FullCard card) { MutableLiveData<FullCard> liveData = new MutableLiveData<>(); doAsync(() -> { Account account = dataBaseAdapter.getAccountByIdDirectly(accountId); @@ -936,7 +941,7 @@ public class SyncManager { } @AnyThread - public WrappedLiveData<Void> deleteCard(Card card) { + public WrappedLiveData<Void> deleteCard(@NonNull Card card) { WrappedLiveData<Void> liveData = new WrappedLiveData<>(); doAsync(() -> { FullCard fullCard = dataBaseAdapter.getFullCardByLocalIdDirectly(card.getAccountId(), card.getLocalId()); @@ -952,7 +957,7 @@ public class SyncManager { } @AnyThread - public WrappedLiveData<FullCard> archiveCard(FullCard card) { + public WrappedLiveData<FullCard> archiveCard(@NonNull FullCard card) { WrappedLiveData<FullCard> liveData = new WrappedLiveData<>(); doAsync(() -> { Account account = dataBaseAdapter.getAccountByIdDirectly(card.getAccountId()); @@ -964,12 +969,12 @@ public class SyncManager { return liveData; } - private void updateCardForArchive(Account account, FullStack stack, Board board, FullCard card, IResponseCallback<FullCard> callback) { + private void updateCardForArchive(Account account, FullStack stack, Board board, FullCard card, @NonNull IResponseCallback<FullCard> callback) { new DataPropagationHelper(serverAdapter, dataBaseAdapter).updateEntity(new CardDataProvider(null, board, stack), card, callback); } @AnyThread - public WrappedLiveData<FullCard> dearchiveCard(FullCard card) { + public WrappedLiveData<FullCard> dearchiveCard(@NonNull FullCard card) { WrappedLiveData<FullCard> liveData = new WrappedLiveData<>(); doAsync(() -> { Account account = dataBaseAdapter.getAccountByIdDirectly(card.getAccountId()); @@ -1020,7 +1025,7 @@ public class SyncManager { } @AnyThread - public void archiveBoard(Board board) { + public void archiveBoard(@NonNull Board board) { doAsync(() -> { FullBoard b = dataBaseAdapter.getFullBoardByLocalIdDirectly(board.getAccountId(), board.getLocalId()); b.getBoard().setArchived(true); @@ -1029,7 +1034,7 @@ public class SyncManager { } @AnyThread - public void dearchiveBoard(Board board) { + public void dearchiveBoard(@NonNull Board board) { doAsync(() -> { FullBoard b = dataBaseAdapter.getFullBoardByLocalIdDirectly(board.getAccountId(), board.getLocalId()); b.getBoard().setArchived(false); @@ -1038,7 +1043,7 @@ public class SyncManager { } @AnyThread - public WrappedLiveData<FullCard> updateCard(FullCard card) { + public WrappedLiveData<FullCard> updateCard(@NonNull FullCard card) { WrappedLiveData<FullCard> liveData = new WrappedLiveData<>(); doAsync(() -> { FullCard fullCardFromDB = dataBaseAdapter.getFullCardByLocalIdDirectly(card.getAccountId(), card.getLocalId()); @@ -1176,9 +1181,9 @@ public class SyncManager { // has user of targetaccount manage permissions? boolean hasManagePermission = targetBoard.getBoard().getOwnerId() == userOfTargetAccount.getLocalId(); List<AccessControl> aclOfTargetBoard = dataBaseAdapter.getAccessControlByLocalBoardIdDirectly(targetAccountId, targetBoard.getLocalId()); - if (!hasManagePermission){ + if (!hasManagePermission) { for (AccessControl accessControl : aclOfTargetBoard) { - if (accessControl.getUserId() == userOfTargetAccount.getLocalId() && accessControl.isPermissionManage()){ + if (accessControl.getUserId() == userOfTargetAccount.getLocalId() && accessControl.isPermissionManage()) { hasManagePermission = true; break; } @@ -1190,7 +1195,7 @@ public class SyncManager { // already exists? Label existingMatch = null; for (Label targetBoardLabel : targetBoard.getLabels()) { - if (originalLabel.getTitle().trim().equalsIgnoreCase(targetBoardLabel.getTitle().trim())){ + if (originalLabel.getTitle().trim().equalsIgnoreCase(targetBoardLabel.getTitle().trim())) { existingMatch = targetBoardLabel; break; } @@ -1212,13 +1217,13 @@ public class SyncManager { // ### Clone assigned users Account originalAccount = dataBaseAdapter.getAccountByIdDirectly(originAccountId); // same instance? otherwise doesn't make sense - if (originalAccount.getUrl().equalsIgnoreCase(targetAccount.getUrl())){ + if (originalAccount.getUrl().equalsIgnoreCase(targetAccount.getUrl())) { for (User assignedUser : originalCard.getAssignedUsers()) { // has assignedUser at least view permissions? boolean hasViewPermission = targetBoard.getBoard().getOwnerId() == assignedUser.getLocalId(); - if (!hasViewPermission){ + if (!hasViewPermission) { for (AccessControl accessControl : aclOfTargetBoard) { - if (accessControl.getUserId() == userOfTargetAccount.getLocalId()){ + if (accessControl.getUserId() == userOfTargetAccount.getLocalId()) { // ACL exists, so viewing is granted hasViewPermission = true; break; @@ -1265,7 +1270,7 @@ public class SyncManager { } @AnyThread - public MutableLiveData<Label> createAndAssignLabelToCard(long accountId, Label label, long localCardId) { + public MutableLiveData<Label> createAndAssignLabelToCard(long accountId, @NonNull Label label, long localCardId) { MutableLiveData<Label> liveData = new MutableLiveData<>(); doAsync(() -> { Account account = dataBaseAdapter.getAccountByIdDirectly(accountId); @@ -1291,7 +1296,7 @@ public class SyncManager { } @AnyThread - public WrappedLiveData<Void> deleteLabel(Label label) { + public WrappedLiveData<Void> deleteLabel(@NonNull Label label) { WrappedLiveData<Void> liveData = new WrappedLiveData<>(); doAsync(() -> { Account account = dataBaseAdapter.getAccountByIdDirectly(label.getAccountId()); @@ -1303,7 +1308,7 @@ public class SyncManager { } @AnyThread - public WrappedLiveData<Label> updateLabel(Label label) { + public WrappedLiveData<Label> updateLabel(@NonNull Label label) { WrappedLiveData<Label> liveData = new WrappedLiveData<>(); doAsync(() -> { Account account = dataBaseAdapter.getAccountByIdDirectly(label.getAccountId()); @@ -1315,7 +1320,7 @@ public class SyncManager { } @AnyThread - public void assignUserToCard(User user, Card card) { + public void assignUserToCard(@NonNull User user, @NonNull Card card) { doAsync(() -> { final long localUserId = user.getLocalId(); final long localCardId = card.getLocalId(); @@ -1340,7 +1345,7 @@ public class SyncManager { } @AnyThread - public void assignLabelToCard(Label label, Card card) { + public void assignLabelToCard(@NonNull Label label, @NonNull Card card) { doAsync(() -> { final long localLabelId = label.getLocalId(); final long localCardId = card.getLocalId(); @@ -1364,7 +1369,7 @@ public class SyncManager { } @AnyThread - public void unassignLabelFromCard(Label label, Card card) { + public void unassignLabelFromCard(@NonNull Label label, @NonNull Card card) { doAsync(() -> { dataBaseAdapter.deleteJoinedLabelForCard(card.getLocalId(), label.getLocalId()); Stack stack = dataBaseAdapter.getStackByLocalIdDirectly(card.getStackId()); @@ -1382,7 +1387,7 @@ public class SyncManager { } @AnyThread - public void unassignUserFromCard(User user, Card card) { + public void unassignUserFromCard(@NonNull User user, @NonNull Card card) { doAsync(() -> { dataBaseAdapter.deleteJoinedUserForCard(card.getLocalId(), user.getLocalId()); if (serverAdapter.hasInternetConnection()) { @@ -1461,11 +1466,11 @@ public class SyncManager { return dataBaseAdapter.createUser(accountId, user); } - public void updateUser(long accountId, User user) { + public void updateUser(long accountId, @NonNull User user) { dataBaseAdapter.updateUser(accountId, user, true); } - public LiveData<List<Label>> searchNotYetAssignedLabelsByTitle(final long accountId, final long boardId, final long notYetAssignedToLocalCardId, String searchTerm) { + public LiveData<List<Label>> searchNotYetAssignedLabelsByTitle(final long accountId, final long boardId, final long notYetAssignedToLocalCardId, @NonNull String searchTerm) { return dataBaseAdapter.searchNotYetAssignedLabelsByTitle(accountId, boardId, notYetAssignedToLocalCardId, searchTerm); } @@ -1477,7 +1482,7 @@ public class SyncManager { * @see <a href="https://github.com/stefan-niedermann/nextcloud-deck/issues/360">reenable reorder</a> */ @AnyThread - public void reorder(long accountId, FullCard movedCard, long newStackId, int newIndex) { + public void reorder(long accountId, @NonNull FullCard movedCard, long newStackId, int newIndex) { doAsync(() -> { // read cards of new stack List<FullCard> cardsOfNewStack = dataBaseAdapter.getFullCardsForStackDirectly(accountId, newStackId); @@ -1562,7 +1567,7 @@ public class SyncManager { } - private void reorderLocally(List<FullCard> cardsOfNewStack, FullCard movedCard, long newStackId, int newOrder) { + private void reorderLocally(List<FullCard> cardsOfNewStack, @NonNull FullCard movedCard, long newStackId, int newOrder) { // set new stack and order Card movedInnerCard = movedCard.getCard(); int oldOrder = movedInnerCard.getOrder(); @@ -1620,7 +1625,7 @@ public class SyncManager { reorderAscending(movedInnerCard, changedCards, startingAtOrder); } - private void reorderAscending(Card movedCard, List<Card> cardsToReorganize, int startingAtOrder) { + private void reorderAscending(@NonNull Card movedCard, @NonNull List<Card> cardsToReorganize, int startingAtOrder) { Date now = new Date(); for (Card card : cardsToReorganize) { card.setOrder(startingAtOrder); @@ -1665,7 +1670,7 @@ public class SyncManager { } @AnyThread - public WrappedLiveData<Attachment> updateAttachmentForCard(long accountId, Attachment existing, @NonNull String mimeType, @NonNull File file) { + public WrappedLiveData<Attachment> updateAttachmentForCard(long accountId, @NonNull Attachment existing, @NonNull String mimeType, @NonNull File file) { WrappedLiveData<Attachment> liveData = new WrappedLiveData<>(); doAsync(() -> { Attachment attachment = populateAttachmentEntityForFile(existing, existing.getCardId(), mimeType, file); @@ -1693,7 +1698,7 @@ public class SyncManager { } @AnyThread - private static Attachment populateAttachmentEntityForFile(Attachment target, long localCardId, @NonNull String mimeType, @NonNull File file) { + private static Attachment populateAttachmentEntityForFile(@NonNull Attachment target, long localCardId, @NonNull String mimeType, @NonNull File file) { Attachment attachment = target; attachment.setCardId(localCardId); attachment.setMimetype(mimeType); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/SyncWorker.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/SyncWorker.java index 25c8b726b..f43cbd34f 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/SyncWorker.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/SyncWorker.java @@ -36,11 +36,11 @@ public class SyncWorker extends Worker { SharedPreferences.Editor sharedPreferencesEditor = sharedPreferences.edit(); SyncManager syncManager = new SyncManager(getApplicationContext(), null); if (syncManager.hasInternetConnection()) { - DeckLog.log("Starting background synchronization"); + DeckLog.info("Starting background synchronization"); sharedPreferencesEditor.putLong(getApplicationContext().getString(R.string.shared_preference_last_background_sync), System.currentTimeMillis()); sharedPreferencesEditor.apply(); boolean success = syncManager.synchronizeEverything(); - DeckLog.log("Finishing background synchronization with result " + success); + DeckLog.info("Finishing background synchronization with result " + success); return success ? Result.failure() : Result.success(); } return Result.success(); @@ -53,25 +53,30 @@ public class SyncWorker extends Worker { public static void update(@NonNull Context context, String preferenceValue) { deregister(context); - if (!context.getString(R.string.pref_value_background_sync_off).equals(preferenceValue)) { - int repeatInterval = 15; - TimeUnit unit = TimeUnit.MINUTES; - if (context.getString(R.string.pref_value_background_1_hour).equals(preferenceValue)) { - repeatInterval = 1; - unit = TimeUnit.HOURS; - } else if (context.getString(R.string.pref_value_background_6_hours).equals(preferenceValue)) { - repeatInterval = 6; - unit = TimeUnit.HOURS; - } + int repeatInterval = -1; + TimeUnit unit = null; + if (context.getString(R.string.pref_value_background_15_minutes).equals(preferenceValue)) { + repeatInterval = 15; + unit = TimeUnit.MINUTES; + } else if (context.getString(R.string.pref_value_background_1_hour).equals(preferenceValue)) { + repeatInterval = 1; + unit = TimeUnit.HOURS; + } else if (context.getString(R.string.pref_value_background_6_hours).equals(preferenceValue)) { + repeatInterval = 6; + unit = TimeUnit.HOURS; + } + if (unit == null) { + DeckLog.info("Do not register a new " + SyncWorker.class.getSimpleName() + " because setting " + preferenceValue + " is not a valid time frame"); + } else { final PeriodicWorkRequest work = new PeriodicWorkRequest.Builder(SyncWorker.class, repeatInterval, unit) .setConstraints(constraints).build(); - DeckLog.log("Registering worker running each " + repeatInterval + " " + unit); + DeckLog.info("Registering " + SyncWorker.class.getSimpleName() + " running each " + repeatInterval + " " + unit); WorkManager.getInstance(context.getApplicationContext()).enqueueUniquePeriodicWork(SyncWorker.WORKER_TAG, ExistingPeriodicWorkPolicy.REPLACE, work); } } private static void deregister(@NonNull Context context) { - DeckLog.log("Deregistering all workers with tag \"" + WORKER_TAG + "\""); + DeckLog.info("Deregistering all " + SyncWorker.class.getSimpleName() + " with tag \"" + WORKER_TAG + "\""); WorkManager.getInstance(context.getApplicationContext()).cancelAllWorkByTag(WORKER_TAG); } } 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 00ed709b8..2992bea65 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 @@ -3,6 +3,7 @@ package it.niedermann.nextcloud.deck.persistence.sync.adapters.db; import android.content.Context; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; import androidx.lifecycle.LiveData; import androidx.sqlite.db.SimpleSQLiteQuery; @@ -124,7 +125,7 @@ public class DataBaseAdapter { return db.getCardDao().getFullCardByLocalIdDirectly(accountId, localId); } - public void filterRelationsForCard(FullCard card) { + public void filterRelationsForCard(@Nullable FullCard card) { if (card != null) { if (card.getLabels() != null && !card.getLabels().isEmpty()) { List<Long> filteredIDs = db.getJoinCardWithLabelDao().filterDeleted(card.getLocalId(), getLocalIDs(card.getLabels())); @@ -137,7 +138,7 @@ public class DataBaseAdapter { } } - private <T> List<Long> getLocalIDs(List<? extends AbstractRemoteEntity> remoteEntityList) { + private <T> List<Long> getLocalIDs(@NonNull List<? extends AbstractRemoteEntity> remoteEntityList) { ArrayList<Long> ids = new ArrayList<>(remoteEntityList.size()); for (AbstractRemoteEntity entity : remoteEntityList) { ids.add(entity.getLocalId()); @@ -145,7 +146,7 @@ public class DataBaseAdapter { return ids; } - public void readRelationsForACL(List<AccessControl> acl) { + public void readRelationsForACL(@Nullable List<AccessControl> acl) { if (acl != null) { for (AccessControl accessControl : acl) { readRelationsForACL(accessControl); @@ -153,7 +154,7 @@ public class DataBaseAdapter { } } - public void readRelationsForACL(AccessControl acl) { + public void readRelationsForACL(@Nullable AccessControl acl) { if (acl != null) { if (acl.getUserId() != null) { acl.setUser(db.getUserDao().getUserByLocalIdDirectly(acl.getUserId())); @@ -161,7 +162,7 @@ public class DataBaseAdapter { } } - private void filterRelationsForCard(List<FullCard> card) { + private void filterRelationsForCard(@Nullable List<FullCard> card) { if (card == null) { return; } @@ -223,7 +224,7 @@ public class DataBaseAdapter { } - private void fillSqlWithListValues(StringBuilder query, List<Object> args, List<? extends IRemoteEntity> entities) { + private void fillSqlWithListValues(StringBuilder query, List<Object> args, @NonNull List<? extends IRemoteEntity> entities) { for (int i = 0; i < entities.size(); i++) { if (i > 0) { query.append(", "); @@ -263,7 +264,7 @@ public class DataBaseAdapter { return db.getLabelDao().getLabelByRemoteIdDirectly(accountId, remoteId); } - public long createLabel(long accountId, Label label) { + public long createLabel(long accountId, @NonNull Label label) { label.setAccountId(accountId); return db.getLabelDao().insert(label); } @@ -401,7 +402,7 @@ public class DataBaseAdapter { return distinctUntilChanged(db.getBoardDao().getBoardsWithEditPermissionsForAccount(accountId)); } - public WrappedLiveData<Board> createBoard(long accountId, Board board) { + public WrappedLiveData<Board> createBoard(long accountId, @NonNull Board board) { return LiveDataHelper.wrapInLiveData(() -> { board.setAccountId(accountId); long id = db.getBoardDao().insert(board); @@ -411,7 +412,7 @@ public class DataBaseAdapter { } @WorkerThread - public long createBoardDirectly(long accountId, Board board) { + public long createBoardDirectly(long accountId, @NonNull Board board) { board.setAccountId(accountId); return db.getBoardDao().insert(board); } @@ -503,7 +504,7 @@ public class DataBaseAdapter { db.getCardDao().delete(card); } - public void updateCard(Card card, boolean setStatus) { + public void updateCard(@NonNull Card card, boolean setStatus) { markAsEditedIfNeeded(card, setStatus); db.getCardDao().update(card); if (db.getSingleCardWidgetModelDao().containsCardLocalId(card.getLocalId())) { @@ -512,7 +513,7 @@ public class DataBaseAdapter { } } - public long createAccessControl(long accountId, AccessControl entity) { + public long createAccessControl(long accountId, @NonNull AccessControl entity) { entity.setAccountId(accountId); return db.getAccessControlDao().insert(entity); } @@ -617,13 +618,13 @@ public class DataBaseAdapter { return db.getAttachmentDao().getLocallyChangedAttachmentsDirectly(accountId); } - public long createAttachment(long accountId, Attachment attachment) { + public long createAttachment(long accountId, @NonNull Attachment attachment) { attachment.setAccountId(accountId); attachment.setCreatedAt(new Date()); return db.getAttachmentDao().insert(attachment); } - public void updateAttachment(long accountId, Attachment attachment, boolean setStatus) { + public void updateAttachment(long accountId, @NonNull Attachment attachment, boolean setStatus) { markAsEditedIfNeeded(attachment, setStatus); attachment.setAccountId(accountId); db.getAttachmentDao().update(attachment); @@ -639,7 +640,7 @@ public class DataBaseAdapter { } } - private void validateSearchTerm(String searchTerm) { + private void validateSearchTerm(@Nullable String searchTerm) { if (searchTerm == null || searchTerm.trim().length() < 1) { throw new IllegalArgumentException("please provide a proper search term! \"" + searchTerm + "\" doesn't seem right..."); } 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 82fb86c6e..0e86557fa 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 @@ -4,6 +4,7 @@ import android.content.Context; import android.database.Cursor; import androidx.annotation.NonNull; +import androidx.preference.PreferenceManager; import androidx.room.Database; import androidx.room.Room; import androidx.room.RoomDatabase; @@ -32,6 +33,7 @@ import it.niedermann.nextcloud.deck.model.ocs.Activity; import it.niedermann.nextcloud.deck.model.ocs.comment.DeckComment; import it.niedermann.nextcloud.deck.model.ocs.comment.Mention; import it.niedermann.nextcloud.deck.model.widget.singlecard.SingleCardWidgetModel; +import it.niedermann.nextcloud.deck.persistence.sync.SyncWorker; import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao.AccessControlDao; import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao.AccountDao; import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao.ActivityDao; @@ -73,7 +75,7 @@ import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao.UserDao; SingleCardWidgetModel.class, }, exportSchema = false, - version = 14 + version = 15 ) @TypeConverters({DateTypeConverter.class}) public abstract class DeckDatabase extends RoomDatabase { @@ -201,6 +203,19 @@ public abstract class DeckDatabase extends RoomDatabase { .addMigrations(MIGRATION_11_12) .addMigrations(MIGRATION_12_13) .addMigrations(MIGRATION_13_14) + .addMigrations(new Migration(14, 15) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase database) { + // https://github.com/stefan-niedermann/nextcloud-deck/issues/570 + SyncWorker.update(context); + // https://github.com/stefan-niedermann/nextcloud-deck/issues/525 + PreferenceManager + .getDefaultSharedPreferences(context) + .edit() + .remove("it.niedermann.nextcloud.deck.theme_text") + .apply(); + } + }) .fallbackToDestructiveMigration() .addCallback(ON_CREATE_CALLBACK) .build(); 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 ae7ab3683..854b99a6a 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 @@ -4,13 +4,17 @@ import android.annotation.SuppressLint; import android.content.Intent; import android.content.SharedPreferences; import android.database.sqlite.SQLiteConstraintException; +import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.StringRes; import androidx.appcompat.app.AppCompatActivity; +import androidx.core.content.ContextCompat; +import androidx.core.graphics.drawable.DrawableCompat; import androidx.preference.PreferenceManager; import com.nextcloud.android.sso.AccountImporter; @@ -81,6 +85,12 @@ public class ImportAccountActivity extends AppCompatActivity { AccountImporter.requestAndroidAccountPermissionsAndPickAccount(this); } }); + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + Drawable wrapDrawable = DrawableCompat.wrap(binding.progressCircular.getIndeterminateDrawable()); + DrawableCompat.setTint(wrapDrawable, ContextCompat.getColor(this, R.color.defaultBrand)); + binding.progressCircular.setIndeterminateDrawable(DrawableCompat.unwrap(wrapDrawable)); + } } @Override 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 c0df7c18e..f8a07f908 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 @@ -5,7 +5,6 @@ import android.content.Intent; import android.content.SharedPreferences; import android.database.sqlite.SQLiteConstraintException; import android.graphics.Color; -import android.graphics.drawable.Drawable; import android.net.ConnectivityManager; import android.net.Network; import android.net.NetworkInfo; @@ -26,6 +25,7 @@ import androidx.annotation.RequiresApi; import androidx.annotation.UiThread; import androidx.appcompat.app.ActionBarDrawerToggle; import androidx.appcompat.app.AppCompatDelegate; +import androidx.core.content.ContextCompat; import androidx.core.graphics.drawable.DrawableCompat; import androidx.core.util.Pair; import androidx.core.view.GravityCompat; @@ -53,7 +53,6 @@ import java.util.Objects; 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; import it.niedermann.nextcloud.deck.api.IResponseCallback; @@ -97,12 +96,23 @@ import it.niedermann.nextcloud.deck.ui.stack.StackAdapter; import it.niedermann.nextcloud.deck.ui.stack.StackFragment; import it.niedermann.nextcloud.deck.util.DrawerMenuUtil; -import static android.graphics.Color.parseColor; import static androidx.lifecycle.Transformations.switchMap; -import static it.niedermann.nextcloud.deck.Application.NO_ACCOUNT_ID; -import static it.niedermann.nextcloud.deck.Application.NO_BOARD_ID; -import static it.niedermann.nextcloud.deck.Application.NO_STACK_ID; +import static it.niedermann.nextcloud.deck.DeckApplication.NO_ACCOUNT_ID; +import static it.niedermann.nextcloud.deck.DeckApplication.NO_BOARD_ID; +import static it.niedermann.nextcloud.deck.DeckApplication.NO_STACK_ID; +import static it.niedermann.nextcloud.deck.DeckApplication.readCurrentAccountId; +import static it.niedermann.nextcloud.deck.DeckApplication.readCurrentBoardId; +import static it.niedermann.nextcloud.deck.DeckApplication.readCurrentStackId; +import static it.niedermann.nextcloud.deck.DeckApplication.saveCurrentAccountId; +import static it.niedermann.nextcloud.deck.DeckApplication.saveCurrentBoardId; +import static it.niedermann.nextcloud.deck.DeckApplication.saveCurrentStackId; import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.LiveDataHelper.observeOnce; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.applyBrandToFAB; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.applyBrandToPrimaryTabLayout; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.clearBrandColors; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.saveBrandColors; +import static it.niedermann.nextcloud.deck.util.ColorUtil.contrastRatioIsSufficient; +import static it.niedermann.nextcloud.deck.util.ColorUtil.contrastRatioIsSufficientBigAreas; import static it.niedermann.nextcloud.deck.util.DrawerMenuUtil.MENU_ID_ABOUT; import static it.niedermann.nextcloud.deck.util.DrawerMenuUtil.MENU_ID_ADD_BOARD; import static it.niedermann.nextcloud.deck.util.DrawerMenuUtil.MENU_ID_ARCHIVED_BOARDS; @@ -159,6 +169,8 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(this)); + setTheme(R.style.AppTheme); + binding = ActivityMainBinding.inflate(getLayoutInflater()); headerBinding = NavHeaderMainBinding.bind(binding.navigationView.getHeaderView(0)); setContentView(binding.getRoot()); @@ -190,18 +202,18 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener } }).observe(this, (List<Account> accounts) -> { if (accounts == null || accounts.size() == 0) { - // Last account has been deleted. hasAccounts LiveData will handle this, but we make sure, that branding is reset. - Application.saveBrandColors(this, getResources().getColor(R.color.primary), Color.WHITE); + // Last account has been deleted. hasAccounts LiveData will handle this, but we make sure, that branding is reset. + saveBrandColors(this, ContextCompat.getColor(this, R.color.defaultBrand)); return; } accountsList = accounts; - long lastAccountId = Application.readCurrentAccountId(this); + long lastAccountId = readCurrentAccountId(this); for (Account account : accountsList) { if (lastAccountId == account.getId() || lastAccountId == NO_ACCOUNT_ID) { - mainViewModel.setCurrentAccount(account, account.getServerDeckVersionAsObject().isSupported(this)); + mainViewModel.setCurrentAccount(account); if (!firstAccountAdded) { DeckLog.info("Syncing the current account on app start"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { @@ -229,13 +241,12 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener SingleAccountHelper.setCurrentAccount(getApplicationContext(), mainViewModel.getCurrentAccount().getName()); syncManager = new SyncManager(this); - Application.saveBrandColors(this, parseColor(mainViewModel.getCurrentAccount().getColor()), parseColor(mainViewModel.getCurrentAccount().getTextColor())); - Application.saveCurrentAccountId(this, mainViewModel.getCurrentAccount().getId()); + saveCurrentAccountId(this, mainViewModel.getCurrentAccount().getId()); if (mainViewModel.getCurrentAccount().isMaintenanceEnabled()) { refreshCapabilities(mainViewModel.getCurrentAccount()); } - lastBoardId = Application.readCurrentBoardId(this, mainViewModel.getCurrentAccount().getId()); + lastBoardId = readCurrentBoardId(this, mainViewModel.getCurrentAccount().getId()); if (boardsLiveData != null && boardsLiveDataObserver != null) { boardsLiveData.removeObserver(boardsLiveDataObserver); @@ -262,6 +273,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener setCurrentBoard(boardsList.get(0)); } } else { + clearBrandColors(this); clearCurrentBoard(); } @@ -277,13 +289,11 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener }; boardsLiveData.observe(this, boardsLiveDataObserver); - final Drawable placeholderAvatar = getResources().getDrawable(R.drawable.ic_baseline_account_circle_24); - DrawableCompat.setTint(placeholderAvatar, parseColor(currentAccount.getTextColor())); Glide .with(binding.accountSwitcher.getContext()) .load(currentAccount.getAvatarUrl(64)) - .placeholder(placeholderAvatar) - .error(placeholderAvatar) + .placeholder(R.drawable.ic_baseline_account_circle_24) + .error(R.drawable.ic_baseline_account_circle_24) .apply(RequestOptions.circleCropTransform()) .into(binding.accountSwitcher); @@ -345,7 +355,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener binding.viewPager.post(() -> { // stackAdapter size might differ from position when an account has been deleted if (stackAdapter.getItemCount() > position) { - Application.saveCurrentStackId(getApplicationContext(), mainViewModel.getCurrentAccount().getId(), mainViewModel.getCurrentBoardLocalId(), stackAdapter.getItem(position).getLocalId()); + saveCurrentStackId(getApplicationContext(), mainViewModel.getCurrentAccount().getId(), mainViewModel.getCurrentBoardLocalId(), stackAdapter.getItem(position).getLocalId()); } else { DeckLog.logError(new IllegalStateException("Tried to save current Stack which cannot be available (stackAdapter doesn't have this position)")); } @@ -411,23 +421,15 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener } @Override - public void applyBrand(@ColorInt int mainColor, @ColorInt int textColor) { - applyBrandToPrimaryToolbar(mainColor, textColor, binding.toolbar); - applyBrandToPrimaryTabLayout(mainColor, textColor, binding.stackTitles); - applyBrandToFAB(mainColor, textColor, binding.fab); - - // Is null as soon as the avatar has been set -// @Nullable -// Drawable accountSwitcherDrawable = binding.accountSwitcher.getDrawable(); -// if (accountSwitcherDrawable != null) { -// DrawableCompat.setTint(accountSwitcherDrawable, textColor); -// } - - binding.listMenuButton.setBackgroundColor(mainColor); - binding.listMenuButton.setColorFilter(textColor); - + public void applyBrand(@ColorInt int mainColor) { + applyBrandToPrimaryTabLayout(mainColor, binding.stackTitles); + applyBrandToFAB(mainColor, binding.fab); + // TODO We assume, that the background of the spinner is always white + binding.swipeRefreshLayout.setColorSchemeColors(contrastRatioIsSufficient(Color.WHITE, mainColor) ? mainColor : colorAccent); headerBinding.headerView.setBackgroundColor(mainColor); - headerBinding.appName.setTextColor(textColor); + @ColorInt final int headerTextColor = contrastRatioIsSufficientBigAreas(mainColor, Color.WHITE) ? Color.WHITE : Color.BLACK; + DrawableCompat.setTint(headerBinding.logo.getDrawable(), headerTextColor); + headerBinding.appName.setTextColor(headerTextColor); } @Override @@ -522,9 +524,6 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener if (mainViewModel.getCurrentAccount().getServerDeckVersionAsObject().isSupported(MainActivity.this) && !response.getDeckVersion().isSupported(MainActivity.this)) { recreate(); } - @ColorInt final int mainColor = parseColor(response.getColor()); - @ColorInt final int textColor = parseColor(response.getTextColor()); - runOnUiThread(() -> Application.saveBrandColors(MainActivity.this, mainColor, textColor)); } } @@ -551,11 +550,12 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener if (stacksLiveData != null) { stacksLiveData.removeObservers(this); } + saveBrandColors(this, Color.parseColor('#' + board.getColor())); mainViewModel.setCurrentBoard(board); filterViewModel.clearFilterInformation(); lastBoardId = board.getLocalId(); - Application.saveCurrentBoardId(this, mainViewModel.getCurrentAccount().getId(), mainViewModel.getCurrentBoardLocalId()); + saveCurrentBoardId(this, mainViewModel.getCurrentAccount().getId(), mainViewModel.getCurrentBoardLocalId()); binding.toolbar.setTitle(board.getTitle()); @@ -590,7 +590,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener int stackPositionInAdapter = 0; stackAdapter.setStacks(fullStacks); - long currentStackId = Application.readCurrentStackId(this, mainViewModel.getCurrentAccount().getId(), mainViewModel.getCurrentBoardLocalId()); + long currentStackId = readCurrentStackId(this, mainViewModel.getCurrentAccount().getId(), mainViewModel.getCurrentBoardLocalId()); for (int i = 0; i < currentBoardStacksCount; i++) { if (fullStacks.get(i).getLocalId() == currentStackId || currentStackId == NO_STACK_ID) { stackPositionInAdapter = i; @@ -797,7 +797,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener if (response.getDeckVersion().isSupported(getApplicationContext())) { runOnUiThread(() -> { syncManager = importSyncManager; - mainViewModel.setCurrentAccount(account, account.getServerDeckVersionAsObject().isSupported(MainActivity.this)); + mainViewModel.setCurrentAccount(account); final Snackbar importSnackbar = BrandedSnackbar.make(binding.coordinatorLayout, R.string.account_is_getting_imported, Snackbar.LENGTH_INDEFINITE); importSnackbar.show(); @@ -943,6 +943,7 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener } 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 + clearBrandColors(this); clearCurrentBoard(); EditBoardDialogFragment.newInstance().show(getSupportFragmentManager(), addBoard); } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/MainViewModel.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/MainViewModel.java index b9ba588df..e5bd4f482 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/MainViewModel.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/MainViewModel.java @@ -1,15 +1,18 @@ package it.niedermann.nextcloud.deck.ui; +import android.app.Application; + +import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.ViewModel; import it.niedermann.nextcloud.deck.model.Account; import it.niedermann.nextcloud.deck.model.Board; @SuppressWarnings("WeakerAccess") -public class MainViewModel extends ViewModel { +public class MainViewModel extends AndroidViewModel { private MutableLiveData<Account> currentAccount = new MutableLiveData<>(); private Board currentBoard; @@ -17,6 +20,10 @@ public class MainViewModel extends ViewModel { private boolean currentAccountIsSupportedVersion = false; + public MainViewModel(@NonNull Application application) { + super(application); + } + public Account getCurrentAccount() { return currentAccount.getValue(); } @@ -25,9 +32,9 @@ public class MainViewModel extends ViewModel { return this.currentAccount; } - public void setCurrentAccount(Account currentAccount, boolean versionIsSupported) { + public void setCurrentAccount(Account currentAccount) { this.currentAccount.setValue(currentAccount); - this.currentAccountIsSupportedVersion = versionIsSupported; + this.currentAccountIsSupportedVersion = currentAccount.getServerDeckVersionAsObject().isSupported(getApplication().getApplicationContext()); } public void setCurrentBoard(Board currentBoard) { diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/PushNotificationActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/PushNotificationActivity.java index f3d462c90..b0b0d68ae 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/PushNotificationActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/PushNotificationActivity.java @@ -1,40 +1,31 @@ package it.niedermann.nextcloud.deck.ui; import android.content.Intent; -import android.graphics.Color; import android.net.Uri; import android.text.TextUtils; import android.view.View; -import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.UiThread; import androidx.appcompat.app.AppCompatActivity; import com.nextcloud.android.sso.helper.SingleAccountHelper; -import it.niedermann.nextcloud.deck.Application; import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.ActivityPushNotificationBinding; import it.niedermann.nextcloud.deck.model.Account; import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; -import it.niedermann.nextcloud.deck.ui.branding.Branded; import it.niedermann.nextcloud.deck.ui.card.EditActivity; import it.niedermann.nextcloud.deck.ui.exception.ExceptionHandler; import static android.graphics.Color.parseColor; import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.LiveDataHelper.observeOnce; -import static it.niedermann.nextcloud.deck.ui.branding.BrandedActivity.applyBrandToPrimaryToolbar; -import static it.niedermann.nextcloud.deck.ui.branding.BrandedActivity.applyBrandToStatusbar; -import static it.niedermann.nextcloud.deck.ui.branding.BrandedActivity.getSecondaryForegroundColorDependingOnTheme; -public class PushNotificationActivity extends AppCompatActivity implements Branded { +public class PushNotificationActivity extends AppCompatActivity { private ActivityPushNotificationBinding binding; - private boolean brandingEnabled; - // Provided by Files app NotificationJob private static final String KEY_SUBJECT = "subject"; private static final String KEY_MESSAGE = "message"; @@ -56,8 +47,6 @@ public class PushNotificationActivity extends AppCompatActivity implements Brand setContentView(binding.getRoot()); setSupportActionBar(binding.toolbar); - brandingEnabled = Application.isBrandingEnabled(this); - binding.subject.setText(getIntent().getStringExtra(KEY_SUBJECT)); final String message = getIntent().getStringExtra(KEY_MESSAGE); @@ -82,13 +71,6 @@ public class PushNotificationActivity extends AppCompatActivity implements Brand if (account != null) { SingleAccountHelper.setCurrentAccount(this, account.getName()); final SyncManager syncManager = new SyncManager(this); - try { - if (brandingEnabled) { - applyBrand(parseColor(account.getColor()), parseColor(account.getTextColor())); - } - } catch (Throwable t) { - DeckLog.logError(t); - } DeckLog.verbose("account: " + account); observeOnce(syncManager.getLocalBoardIdByCardRemoteIdAndAccount(cardRemoteId, account), PushNotificationActivity.this, (boardLocalId -> { DeckLog.verbose("BoardLocalId " + boardLocalId); @@ -153,11 +135,6 @@ public class PushNotificationActivity extends AppCompatActivity implements Brand @UiThread private void launchEditActivity(@NonNull Account account, Long boardId, Long cardId) { - try { - Application.saveBrandColors(this, Color.parseColor(account.getColor()), Color.parseColor(account.getTextColor())); - } catch (Throwable t) { - DeckLog.logError(t); - } DeckLog.info("starting " + EditActivity.class.getSimpleName() + " with [" + account + ", " + boardId + ", " + cardId + "]"); startActivity(EditActivity.createEditCardIntent(this, account, boardId, cardId)); finish(); @@ -169,15 +146,6 @@ public class PushNotificationActivity extends AppCompatActivity implements Brand return true; } - @Override - public void applyBrand(@ColorInt int mainColor, @ColorInt int textColor) { - if (brandingEnabled) { - applyBrandToStatusbar(getWindow(), mainColor, textColor); - applyBrandToPrimaryToolbar(mainColor, textColor, binding.toolbar); - binding.cancel.setTextColor(getSecondaryForegroundColorDependingOnTheme(this, mainColor)); - } - } - public void applyBrandToSubmitButton(@NonNull Account account) { try { binding.submit.setBackgroundColor(parseColor(account.getColor())); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/about/AboutActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/about/AboutActivity.java index 943e48bd6..bf3734b72 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/about/AboutActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/about/AboutActivity.java @@ -19,6 +19,8 @@ import it.niedermann.nextcloud.deck.model.Account; import it.niedermann.nextcloud.deck.ui.branding.BrandedActivity; import it.niedermann.nextcloud.deck.ui.exception.ExceptionHandler; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.applyBrandToPrimaryTabLayout; + public class AboutActivity extends BrandedActivity { private static final String BUNDLE_KEY_ACCOUNT = "account"; @@ -82,9 +84,8 @@ public class AboutActivity extends BrandedActivity { } @Override - public void applyBrand(int mainColor, int textColor) { - applyBrandToPrimaryToolbar(mainColor, textColor, binding.toolbar); - applyBrandToPrimaryTabLayout(mainColor, textColor, binding.tabLayout); + public void applyBrand(int mainColor) { + applyBrandToPrimaryTabLayout(mainColor, binding.tabLayout); } @NonNull 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 f33b30ea3..c00ff212a 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 @@ -1,18 +1,26 @@ package it.niedermann.nextcloud.deck.ui.about; import android.content.Intent; +import android.content.res.ColorStateList; +import android.graphics.Color; import android.net.Uri; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.ColorInt; import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.core.graphics.drawable.DrawableCompat; import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.FragmentAboutLicenseTabBinding; import it.niedermann.nextcloud.deck.ui.branding.BrandedFragment; +import it.niedermann.nextcloud.deck.util.ColorUtil; +import static it.niedermann.nextcloud.deck.DeckApplication.isDarkTheme; +import static it.niedermann.nextcloud.deck.util.ColorUtil.contrastRatioIsSufficientBigAreas; import static it.niedermann.nextcloud.deck.util.SpannableUtil.setTextWithURL; public class AboutFragmentLicenseTab extends BrandedFragment { @@ -29,8 +37,11 @@ public class AboutFragmentLicenseTab extends BrandedFragment { } @Override - public void applyBrand(int mainColor, int textColor) { - binding.aboutAppLicenseButton.setBackgroundColor(mainColor); - binding.aboutAppLicenseButton.setTextColor(textColor); + public void applyBrand(int mainColor) { + @ColorInt final int finalMainColor = contrastRatioIsSufficientBigAreas(mainColor, ContextCompat.getColor(requireContext(), R.color.primary)) + ? mainColor + : isDarkTheme(requireContext()) ? Color.WHITE : Color.BLACK; + DrawableCompat.setTintList(binding.aboutAppLicenseButton.getBackground(), ColorStateList.valueOf(finalMainColor)); + binding.aboutAppLicenseButton.setTextColor(ColorUtil.getForegroundColorForBackgroundColor(finalMainColor)); } }
\ No newline at end of file diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/accountswitcher/AccountSwitcherDialog.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/accountswitcher/AccountSwitcherDialog.java index bae4720b9..592f2e8cc 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/accountswitcher/AccountSwitcherDialog.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/accountswitcher/AccountSwitcherDialog.java @@ -53,14 +53,15 @@ public class AccountSwitcherDialog extends BrandedDialogFragment { Glide.with(requireContext()) .load(viewModel.getCurrentAccount().getAvatarUrl(dpToPx(binding.currentAccountItemAvatar.getContext(), R.dimen.avatar_size))) - .error(R.drawable.ic_person_grey600_24dp) + .placeholder(R.drawable.ic_baseline_account_circle_24) + .error(R.drawable.ic_baseline_account_circle_24) .apply(RequestOptions.circleCropTransform()) .into(binding.currentAccountItemAvatar); binding.accountLayout.setOnClickListener((v) -> dismiss()); adapter = new AccountSwitcherAdapter((localAccount -> { - viewModel.setCurrentAccount(localAccount, localAccount.getServerDeckVersionAsObject().isSupported(requireContext())); + viewModel.setCurrentAccount(localAccount); dismiss(); })); @@ -97,7 +98,7 @@ public class AccountSwitcherDialog extends BrandedDialogFragment { } @Override - public void applyBrand(int mainColor, int textColor) { + public void applyBrand(int mainColor) { // applyBrandToLayerDrawable((LayerDrawable) binding.check.getDrawable(), R.id.area, mainColor); } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/accountswitcher/AccountSwitcherViewHolder.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/accountswitcher/AccountSwitcherViewHolder.java index 9de4185b1..9c93c422e 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/accountswitcher/AccountSwitcherViewHolder.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/accountswitcher/AccountSwitcherViewHolder.java @@ -31,7 +31,8 @@ public class AccountSwitcherViewHolder extends RecyclerView.ViewHolder { binding.accountHost.setText(Uri.parse(account.getUrl()).getHost()); Glide.with(itemView.getContext()) .load(new SingleSignOnUrl(account.getName(), account.getAvatarUrl(dpToPx(binding.accountItemAvatar.getContext(), R.dimen.avatar_size)))) - .error(R.drawable.ic_person_grey600_24dp) + .placeholder(R.drawable.ic_baseline_account_circle_24) + .error(R.drawable.ic_baseline_account_circle_24) .apply(RequestOptions.circleCropTransform()) .into(binding.accountItemAvatar); itemView.setOnClickListener((v) -> onAccountClick.accept(account)); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedboards/ArchivedBoardsActvitiy.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedboards/ArchivedBoardsActvitiy.java index 1febd4950..f0146a379 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedboards/ArchivedBoardsActvitiy.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedboards/ArchivedBoardsActvitiy.java @@ -53,7 +53,7 @@ public class ArchivedBoardsActvitiy extends BrandedActivity implements DeleteBoa setSupportActionBar(binding.toolbar); viewModel = new ViewModelProvider(this).get(MainViewModel.class); - viewModel.setCurrentAccount(account, account.getServerDeckVersionAsObject().isSupported(this)); + viewModel.setCurrentAccount(account); syncManager = new SyncManager(this); adapter = new ArchivedBoardsAdapter(viewModel.isCurrentAccountIsSupportedVersion(), getSupportFragmentManager(), (board) -> syncManager.dearchiveBoard(board)); @@ -67,8 +67,8 @@ public class ArchivedBoardsActvitiy extends BrandedActivity implements DeleteBoa } @Override - public void applyBrand(int mainColor, int textColor) { - applyBrandToPrimaryToolbar(mainColor, textColor, binding.toolbar); + public void applyBrand(int mainColor) { + // Nothing to do... } @NonNull diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedcards/ArchivedCardsActvitiy.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedcards/ArchivedCardsActvitiy.java index 00500ae97..ed2ee7097 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedcards/ArchivedCardsActvitiy.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedcards/ArchivedCardsActvitiy.java @@ -65,8 +65,8 @@ public class ArchivedCardsActvitiy extends BrandedActivity { } @Override - public void applyBrand(int mainColor, int textColor) { - applyBrandToPrimaryToolbar(mainColor, textColor, binding.toolbar); + public void applyBrand(int mainColor) { + // Nothing to do... } @NonNull 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 1283695e0..e5d0a482b 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 @@ -15,10 +15,11 @@ import it.niedermann.nextcloud.deck.databinding.DialogTextColorInputBinding; import it.niedermann.nextcloud.deck.model.full.FullBoard; import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; import it.niedermann.nextcloud.deck.ui.MainViewModel; -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.ui.branding.BrandingUtil.applyBrandToEditText; + public class EditBoardDialogFragment extends BrandedDialogFragment { private DialogTextColorInputBinding binding; @@ -95,7 +96,7 @@ public class EditBoardDialogFragment extends BrandedDialogFragment { } @Override - public void applyBrand(int mainColor, int textColor) { - BrandedActivity.applyBrandToEditText(mainColor, textColor, binding.input); + public void applyBrand(int mainColor) { + applyBrandToEditText(mainColor, binding.input); } }
\ No newline at end of file diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/accesscontrol/AccessControlAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/accesscontrol/AccessControlAdapter.java index 4ab3ac80b..e5a50d9f4 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/accesscontrol/AccessControlAdapter.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/accesscontrol/AccessControlAdapter.java @@ -17,7 +17,6 @@ import java.util.LinkedList; import java.util.List; import java.util.NoSuchElementException; -import it.niedermann.nextcloud.deck.Application; import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.ItemAccessControlBinding; import it.niedermann.nextcloud.deck.databinding.ItemAccessControlOwnerBinding; @@ -25,10 +24,10 @@ import it.niedermann.nextcloud.deck.model.AccessControl; import it.niedermann.nextcloud.deck.model.Account; import it.niedermann.nextcloud.deck.model.enums.DBStatus; import it.niedermann.nextcloud.deck.ui.branding.Branded; -import it.niedermann.nextcloud.deck.ui.branding.BrandedActivity; import it.niedermann.nextcloud.deck.util.ViewUtil; -import static it.niedermann.nextcloud.deck.ui.branding.BrandedActivity.getSecondaryForegroundColorDependingOnTheme; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.getSecondaryForegroundColorDependingOnTheme; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.isBrandingEnabled; public class AccessControlAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements Branded { @@ -122,7 +121,7 @@ public class AccessControlAdapter extends RecyclerView.Adapter<RecyclerView.View accessControlChangedListener.updateAccessControl(ac); }); - if (Application.isBrandingEnabled(context)) { + if (isBrandingEnabled(context)) { if (hasManagePermission) { brandSwitch(context, acHolder.binding.permissionEdit, mainColor); brandSwitch(context, acHolder.binding.permissionManage, mainColor); @@ -159,9 +158,9 @@ public class AccessControlAdapter extends RecyclerView.Adapter<RecyclerView.View } @Override - public void applyBrand(int mainColor, int textColor) { - if (Application.isBrandingEnabled(context)) { - this.mainColor = BrandedActivity.getSecondaryForegroundColorDependingOnTheme(context, mainColor); + public void applyBrand(int mainColor) { + if (isBrandingEnabled(context)) { + this.mainColor = getSecondaryForegroundColorDependingOnTheme(context, mainColor); notifyDataSetChanged(); } } 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 9b170aacd..33c0fe5b1 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 @@ -25,7 +25,6 @@ import it.niedermann.nextcloud.deck.model.full.FullBoard; import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.WrappedLiveData; import it.niedermann.nextcloud.deck.ui.MainViewModel; -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.branding.BrandedSnackbar; @@ -34,6 +33,7 @@ import it.niedermann.nextcloud.deck.ui.exception.ExceptionDialogFragment; import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.LiveDataHelper.observeOnce; import static it.niedermann.nextcloud.deck.ui.board.accesscontrol.AccessControlAdapter.HEADER_ITEM_LOCAL_ID; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.applyBrandToEditText; public class AccessControlDialogFragment extends BrandedDialogFragment implements AccessControlChangedListener, OnItemClickListener { @@ -135,9 +135,9 @@ public class AccessControlDialogFragment extends BrandedDialogFragment implement } @Override - public void applyBrand(int mainColor, int textColor) { - BrandedActivity.applyBrandToEditText(mainColor, textColor, binding.people); - this.adapter.applyBrand(mainColor, textColor); + public void applyBrand(int mainColor) { + applyBrandToEditText(mainColor, binding.people); + this.adapter.applyBrand(mainColor); } public static DialogFragment newInstance(long boardLocalId) { diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/managelabels/EditLabelDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/managelabels/EditLabelDialogFragment.java index 7570510fd..d460d1590 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/managelabels/EditLabelDialogFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/managelabels/EditLabelDialogFragment.java @@ -11,10 +11,11 @@ import androidx.fragment.app.DialogFragment; import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.DialogTextColorInputBinding; import it.niedermann.nextcloud.deck.model.Label; -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.ui.branding.BrandingUtil.applyBrandToEditText; + public class EditLabelDialogFragment extends BrandedDialogFragment { private DialogTextColorInputBinding binding; @@ -83,7 +84,7 @@ public class EditLabelDialogFragment extends BrandedDialogFragment { } @Override - public void applyBrand(int mainColor, int textColor) { - BrandedActivity.applyBrandToEditText(mainColor, textColor, binding.input); + public void applyBrand(int mainColor) { + applyBrandToEditText(mainColor, binding.input); } }
\ No newline at end of file diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/managelabels/ManageLabelsAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/managelabels/ManageLabelsAdapter.java index 34c06530c..d8bb57a11 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/managelabels/ManageLabelsAdapter.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/managelabels/ManageLabelsAdapter.java @@ -11,12 +11,13 @@ import java.util.LinkedList; import java.util.List; import java.util.NoSuchElementException; -import it.niedermann.nextcloud.deck.Application; import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.ItemManageLabelBinding; import it.niedermann.nextcloud.deck.model.Label; import it.niedermann.nextcloud.deck.ui.branding.Branded; -import it.niedermann.nextcloud.deck.ui.branding.BrandedActivity; + +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.getSecondaryForegroundColorDependingOnTheme; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.isBrandingEnabled; public class ManageLabelsAdapter extends RecyclerView.Adapter<ManageLabelsViewHolder> implements Branded { @@ -74,9 +75,9 @@ public class ManageLabelsAdapter extends RecyclerView.Adapter<ManageLabelsViewHo } @Override - public void applyBrand(int mainColor, int textColor) { - if (Application.isBrandingEnabled(context)) { - this.mainColor = BrandedActivity.getSecondaryForegroundColorDependingOnTheme(context, mainColor); + public void applyBrand(int mainColor) { + if (isBrandingEnabled(context)) { + this.mainColor = getSecondaryForegroundColorDependingOnTheme(context, mainColor); notifyDataSetChanged(); } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/managelabels/ManageLabelsDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/managelabels/ManageLabelsDialogFragment.java index d6727f4b0..3391c7a99 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/managelabels/ManageLabelsDialogFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/managelabels/ManageLabelsDialogFragment.java @@ -20,12 +20,13 @@ import it.niedermann.nextcloud.deck.model.Label; import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.WrappedLiveData; import it.niedermann.nextcloud.deck.ui.MainViewModel; -import it.niedermann.nextcloud.deck.ui.branding.BrandedActivity; import it.niedermann.nextcloud.deck.ui.branding.BrandedAlertDialogBuilder; import it.niedermann.nextcloud.deck.ui.branding.BrandedDeleteAlertDialogBuilder; import it.niedermann.nextcloud.deck.ui.branding.BrandedDialogFragment; import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.LiveDataHelper.observeOnce; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.applyBrandToEditText; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.applyBrandToFAB; public class ManageLabelsDialogFragment extends BrandedDialogFragment implements ManageLabelListener, EditLabelListener { @@ -108,9 +109,9 @@ public class ManageLabelsDialogFragment extends BrandedDialogFragment implements } @Override - public void applyBrand(int mainColor, int textColor) { - BrandedActivity.applyBrandToFAB(mainColor, textColor, binding.fab); - BrandedActivity.applyBrandToEditText(mainColor, textColor, binding.addLabelTitle); + public void applyBrand(int mainColor) { + applyBrandToFAB(mainColor, binding.fab); + applyBrandToEditText(mainColor, binding.addLabelTitle); } public static DialogFragment newInstance(long boardLocalId) { 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 index 15ffb8528..99ad9c074 100644 --- 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 @@ -5,5 +5,5 @@ import androidx.annotation.UiThread; public interface Branded { @UiThread - void applyBrand(@ColorInt int mainColor, @ColorInt int textColor); + void applyBrand(@ColorInt int mainColor); }
\ 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 index 6278ac1f5..3420e888b 100644 --- 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 @@ -1,158 +1,41 @@ package it.niedermann.nextcloud.deck.ui.branding; -import android.content.Context; -import android.content.res.ColorStateList; -import android.graphics.Color; -import android.graphics.PorterDuff; -import android.graphics.drawable.Drawable; -import android.os.Bundle; +import android.util.TypedValue; import android.view.Menu; -import android.view.View; -import android.view.Window; -import android.widget.EditText; 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 it.niedermann.nextcloud.deck.R; -import it.niedermann.nextcloud.deck.util.ColorUtil; -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; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.isBrandingEnabled; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.readBrandMainColor; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.tintMenuIcon; public abstract class BrandedActivity extends AppCompatActivity implements Branded { - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - if (Application.isBrandingEnabled(this)) { - @ColorInt final int mainColor = Application.readBrandMainColor(this); - @ColorInt final int textColor = Application.readBrandTextColor(this); - setTheme(ColorUtil.isColorDark(textColor) ? R.style.AppThemeLightBrand : R.style.AppTheme); - applyBrandToStatusbar(getWindow(), mainColor, textColor); - } else { - setTheme(R.style.AppTheme); - } - } + @ColorInt + protected int colorAccent; @Override protected void onStart() { super.onStart(); - if (Application.isBrandingEnabled(this)) { - @ColorInt final int mainColor = Application.readBrandMainColor(this); - @ColorInt final int textColor = Application.readBrandTextColor(this); - applyBrand(mainColor, textColor); + final TypedValue typedValue = new TypedValue(); + getTheme().resolveAttribute(R.attr.colorAccent, typedValue, true); + colorAccent = typedValue.data; + + if (isBrandingEnabled(this)) { + @ColorInt final int mainColor = readBrandMainColor(this); + applyBrand(mainColor); } } - // TODO maybe this can be handled in R.style.AppThemLightBrand @Override public boolean onCreateOptionsMenu(Menu menu) { - @ColorInt final int textColor = Application.readBrandTextColor(this); for (int i = 0; i < menu.size(); i++) { - Drawable drawable = menu.getItem(i).getIcon(); - if (drawable != null) { - drawable = DrawableCompat.wrap(drawable); - DrawableCompat.setTint(drawable, textColor); - menu.getItem(i).setIcon(drawable); - } + tintMenuIcon(menu.getItem(i), colorAccent); } return super.onCreateOptionsMenu(menu); } - - public static void applyBrandToStatusbar(@NonNull Window window, @ColorInt int mainColor, @ColorInt int textColor) { - if (SDK_INT >= LOLLIPOP) { // Set status bar color - 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); - } - } - } - } - - public 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 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) { - @ColorInt final int finalMainColor = getSecondaryForegroundColorDependingOnTheme(editText.getContext(), mainColor); - DrawableCompat.setTintList(editText.getBackground(), new ColorStateList( - new int[][]{ - new int[]{android.R.attr.state_active}, - new int[]{android.R.attr.state_activated}, - new int[]{android.R.attr.state_focused}, - new int[]{android.R.attr.state_pressed}, - new int[]{} - }, - new int[]{ - finalMainColor, - finalMainColor, - finalMainColor, - finalMainColor, - editText.getContext().getResources().getColor(R.color.fg_secondary) - } - )); - } - - /** - * Since we may collide with dark theme in this area, we have to make sure that the color is visible depending on the background - */ - @ColorInt - public static int - getSecondaryForegroundColorDependingOnTheme(@NonNull Context context, @ColorInt int mainColor) { - final 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 index d502772b3..cfeffe7dc 100644 --- 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 @@ -11,7 +11,8 @@ import androidx.appcompat.app.AlertDialog; import org.jetbrains.annotations.NotNull; -import it.niedermann.nextcloud.deck.Application; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.getSecondaryForegroundColorDependingOnTheme; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.readBrandMainColor; public class BrandedAlertDialogBuilder extends AlertDialog.Builder implements Branded { @@ -27,23 +28,22 @@ public class BrandedAlertDialogBuilder extends AlertDialog.Builder implements Br this.dialog = super.create(); @NonNull Context context = getContext(); - @ColorInt final int mainColor = Application.readBrandMainColor(context); - @ColorInt final int textColor = Application.readBrandTextColor(context); - applyBrand(mainColor, textColor); - dialog.setOnShowListener(dialog -> applyBrand(mainColor, textColor)); + @ColorInt final int mainColor = readBrandMainColor(context); + applyBrand(mainColor); + dialog.setOnShowListener(dialog -> applyBrand(mainColor)); return dialog; } @CallSuper @Override - public void applyBrand(int mainColor, int textColor) { + public void applyBrand(int mainColor) { 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.getSecondaryForegroundColorDependingOnTheme(button.getContext(), mainColor)); + button.setTextColor(getSecondaryForegroundColorDependingOnTheme(button.getContext(), mainColor)); } } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedDatePickerDialog.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedDatePickerDialog.java index b56ad3669..5bef66f2c 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedDatePickerDialog.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedDatePickerDialog.java @@ -10,37 +10,41 @@ import android.view.ViewGroup; import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; import com.wdullaer.materialdatetimepicker.date.DatePickerDialog; import java.util.Calendar; -import it.niedermann.nextcloud.deck.Application; +import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.util.ColorUtil; +import static it.niedermann.nextcloud.deck.DeckApplication.isDarkTheme; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.getSecondaryForegroundColorDependingOnTheme; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.isBrandingEnabled; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.readBrandMainColor; + public class BrandedDatePickerDialog extends DatePickerDialog implements Branded { @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @Nullable Context context = getContext(); if (context != null) { - setThemeDark(Application.getAppTheme(context)); - if (Application.isBrandingEnabled(context)) { - @ColorInt final int mainColor = Application.readBrandMainColor(context); - @ColorInt final int textColor = Application.readBrandTextColor(context); - applyBrand(mainColor, textColor); + setThemeDark(isDarkTheme(context)); + if (isBrandingEnabled(context)) { + applyBrand(readBrandMainColor(context)); } } return super.onCreateView(inflater, container, savedInstanceState); } @Override - public void applyBrand(int mainColor, int textColor) { - @ColorInt final int buttonTextColor = BrandedActivity.getSecondaryForegroundColorDependingOnTheme(requireContext(), mainColor); + public void applyBrand(int mainColor) { + @ColorInt final int buttonTextColor = getSecondaryForegroundColorDependingOnTheme(requireContext(), mainColor); setOkColor(buttonTextColor); setCancelColor(buttonTextColor); // Text in picker title is always white - setAccentColor(ColorUtil.contrastRatioIsSufficient(Color.WHITE, mainColor) ? mainColor : textColor); + setAccentColor(ColorUtil.contrastRatioIsSufficientBigAreas(Color.WHITE, mainColor) ? mainColor : ContextCompat.getColor(requireContext(), R.color.accent)); } /** 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 index 29cac691f..ec3cef553 100644 --- 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 @@ -16,8 +16,8 @@ public class BrandedDeleteAlertDialogBuilder extends BrandedAlertDialogBuilder { @CallSuper @Override - public void applyBrand(int mainColor, int textColor) { - super.applyBrand(mainColor, textColor); + public void applyBrand(int mainColor) { + super.applyBrand(mainColor); 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 index 75eb90b12..adf3844e9 100644 --- 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 @@ -2,11 +2,11 @@ package it.niedermann.nextcloud.deck.ui.branding; import android.content.Context; -import androidx.annotation.ColorInt; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; -import it.niedermann.nextcloud.deck.Application; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.isBrandingEnabled; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.readBrandMainColor; public abstract class BrandedDialogFragment extends DialogFragment implements Branded { @@ -16,10 +16,8 @@ public abstract class BrandedDialogFragment extends DialogFragment implements Br @Nullable Context context = getContext(); if (context != null) { - if (Application.isBrandingEnabled(context)) { - @ColorInt final int mainColor = Application.readBrandMainColor(context); - @ColorInt final int textColor = Application.readBrandTextColor(context); - applyBrand(mainColor, textColor); + if (isBrandingEnabled(context)) { + applyBrand(readBrandMainColor(context)); } } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedFragment.java index 0854b547b..fe202f48c 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedFragment.java @@ -2,11 +2,11 @@ package it.niedermann.nextcloud.deck.ui.branding; import android.content.Context; -import androidx.annotation.ColorInt; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; -import it.niedermann.nextcloud.deck.Application; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.isBrandingEnabled; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.readBrandMainColor; public abstract class BrandedFragment extends Fragment implements Branded { @@ -15,10 +15,8 @@ public abstract class BrandedFragment extends Fragment implements Branded { super.onStart(); @Nullable Context context = getContext(); - if (context != null && Application.isBrandingEnabled(context)) { - @ColorInt final int mainColor = Application.readBrandMainColor(context); - @ColorInt final int textColor = Application.readBrandTextColor(context); - applyBrand(mainColor, textColor); + if (context != null && isBrandingEnabled(context)) { + applyBrand(readBrandMainColor(context)); } } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedPreferenceCategory.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedPreferenceCategory.java index dd7f0a037..e01c523c6 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedPreferenceCategory.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedPreferenceCategory.java @@ -10,10 +10,9 @@ import androidx.annotation.Nullable; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceViewHolder; -import it.niedermann.nextcloud.deck.Application; - -import static it.niedermann.nextcloud.deck.Application.readBrandMainColor; -import static it.niedermann.nextcloud.deck.ui.branding.BrandedActivity.getSecondaryForegroundColorDependingOnTheme; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.getSecondaryForegroundColorDependingOnTheme; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.isBrandingEnabled; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.readBrandMainColor; public class BrandedPreferenceCategory extends PreferenceCategory { @@ -21,7 +20,7 @@ public class BrandedPreferenceCategory extends PreferenceCategory { public void onBindViewHolder(PreferenceViewHolder holder) { super.onBindViewHolder(holder); - if (Application.isBrandingEnabled(getContext())) { + if (isBrandingEnabled(getContext())) { final View v = holder.itemView.findViewById(android.R.id.title); @Nullable final Context context = getContext(); if (context != null && v instanceof TextView) { diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedSnackbar.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedSnackbar.java index b28b00ac0..20e6f8dc8 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedSnackbar.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedSnackbar.java @@ -3,24 +3,31 @@ package it.niedermann.nextcloud.deck.ui.branding; import android.graphics.Color; import android.view.View; +import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.StringRes; +import androidx.core.content.ContextCompat; import com.google.android.material.snackbar.BaseTransientBottomBar; import com.google.android.material.snackbar.Snackbar; -import it.niedermann.nextcloud.deck.Application; +import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.util.ColorUtil; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.isBrandingEnabled; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.readBrandMainColor; + public class BrandedSnackbar { @NonNull public static Snackbar make( @NonNull View view, @NonNull CharSequence text, @BaseTransientBottomBar.Duration int duration) { final Snackbar snackbar = Snackbar.make(view, text, duration); - if (Application.isBrandingEnabled(view.getContext())) { - int color = Application.readBrandMainColor(view.getContext()); + if (isBrandingEnabled(view.getContext())) { + @ColorInt final int color = readBrandMainColor(view.getContext()); snackbar.setActionTextColor(ColorUtil.isColorDark(color) ? Color.WHITE : color); + } else { + snackbar.setActionTextColor(ContextCompat.getColor(view.getContext(), R.color.primary)); } return snackbar; } 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 index a0b2c222e..463800a0a 100644 --- 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 @@ -13,21 +13,16 @@ import androidx.core.graphics.drawable.DrawableCompat; import androidx.preference.PreferenceViewHolder; import androidx.preference.SwitchPreference; -import it.niedermann.nextcloud.deck.Application; 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.getSecondaryForegroundColorDependingOnTheme; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.getSecondaryForegroundColorDependingOnTheme; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.isBrandingEnabled; public class BrandedSwitchPreference extends SwitchPreference implements Branded { @ColorInt private Integer mainColor = null; - @ColorInt - private Integer textColor = null; - @Nullable private Switch switchView; @@ -51,26 +46,25 @@ public class BrandedSwitchPreference extends SwitchPreference implements Branded public void onBindViewHolder(PreferenceViewHolder holder) { super.onBindViewHolder(holder); - if (Application.isBrandingEnabled(getContext()) && holder.itemView instanceof ViewGroup) { + if (isBrandingEnabled(getContext()) && holder.itemView instanceof ViewGroup) { switchView = findSwitchWidget(holder.itemView); - if (mainColor != null && textColor != null) { + if (mainColor != null) { applyBrand(); } } } @Override - public void applyBrand(@ColorInt int mainColor, @ColorInt int textColor) { + public void applyBrand(@ColorInt int mainColor) { this.mainColor = mainColor; - this.textColor = textColor; // onBindViewHolder is called after applyBrand, therefore we have to store the given values and apply them later. - if (Application.isBrandingEnabled(getContext())) { + if (isBrandingEnabled(getContext())) { applyBrand(); } } private void applyBrand() { - if (switchView != null && SDK_INT >= JELLY_BEAN) { + if (switchView != null) { final int finalMainColor = getSecondaryForegroundColorDependingOnTheme(getContext(), mainColor); // int trackColor = Color.argb(77, Color.red(finalMainColor), Color.green(finalMainColor), Color.blue(finalMainColor)); DrawableCompat.setTintList(switchView.getThumbDrawable(), new ColorStateList( diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedTimePickerDialog.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedTimePickerDialog.java index cd67d7820..a1963aa18 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedTimePickerDialog.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandedTimePickerDialog.java @@ -10,37 +10,41 @@ import android.view.ViewGroup; import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; import com.wdullaer.materialdatetimepicker.time.TimePickerDialog; import java.util.Calendar; -import it.niedermann.nextcloud.deck.Application; +import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.util.ColorUtil; +import static it.niedermann.nextcloud.deck.DeckApplication.isDarkTheme; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.getSecondaryForegroundColorDependingOnTheme; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.isBrandingEnabled; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.readBrandMainColor; + public class BrandedTimePickerDialog extends TimePickerDialog implements Branded { @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @Nullable Context context = getContext(); if (context != null) { - setThemeDark(Application.getAppTheme(context)); - if (Application.isBrandingEnabled(context)) { - @ColorInt final int mainColor = Application.readBrandMainColor(context); - @ColorInt final int textColor = Application.readBrandTextColor(context); - applyBrand(mainColor, textColor); + setThemeDark(isDarkTheme(context)); + if (isBrandingEnabled(context)) { + applyBrand(readBrandMainColor(context)); } } return super.onCreateView(inflater, container, savedInstanceState); } @Override - public void applyBrand(int mainColor, int textColor) { - @ColorInt final int buttonTextColor = BrandedActivity.getSecondaryForegroundColorDependingOnTheme(requireContext(), mainColor); + public void applyBrand(int mainColor) { + @ColorInt final int buttonTextColor = getSecondaryForegroundColorDependingOnTheme(requireContext(), mainColor); setOkColor(buttonTextColor); setCancelColor(buttonTextColor); // Text in picker title is always white - setAccentColor(ColorUtil.contrastRatioIsSufficient(Color.WHITE, mainColor) ? mainColor : textColor); + setAccentColor(ColorUtil.contrastRatioIsSufficientBigAreas(Color.WHITE, mainColor) ? mainColor : ContextCompat.getColor(requireContext(), R.color.accent)); } /** diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandingUtil.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandingUtil.java new file mode 100644 index 000000000..02ad6b309 --- /dev/null +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/branding/BrandingUtil.java @@ -0,0 +1,128 @@ +package it.niedermann.nextcloud.deck.ui.branding; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.ColorStateList; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.view.MenuItem; +import android.widget.EditText; + +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.core.graphics.drawable.DrawableCompat; +import androidx.preference.PreferenceManager; + +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.google.android.material.tabs.TabLayout; + +import it.niedermann.nextcloud.deck.DeckLog; +import it.niedermann.nextcloud.deck.R; + +import static it.niedermann.nextcloud.deck.DeckApplication.isDarkTheme; +import static it.niedermann.nextcloud.deck.util.ColorUtil.contrastRatioIsSufficient; +import static it.niedermann.nextcloud.deck.util.ColorUtil.contrastRatioIsSufficientBigAreas; +import static it.niedermann.nextcloud.deck.util.ColorUtil.getContrastRatio; +import static it.niedermann.nextcloud.deck.util.ColorUtil.getForegroundColorForBackgroundColor; + +public abstract class BrandingUtil { + + private BrandingUtil() { + // Util class + } + + public static boolean isBrandingEnabled(@NonNull Context context) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + return prefs.getBoolean(context.getString(R.string.pref_key_branding), true); + } + + @ColorInt + public static int readBrandMainColor(@NonNull Context context) { + if (isBrandingEnabled(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.defaultBrand)); + } else { + return context.getResources().getColor(R.color.defaultBrand); + } + } + + public static void saveBrandColors(@NonNull Context context, @ColorInt int mainColor) { + if (isBrandingEnabled(context) && context instanceof BrandedActivity) { + final BrandedActivity activity = (BrandedActivity) context; + activity.applyBrand(mainColor); + } + SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit(); + DeckLog.log("--- Write: shared_preference_theme_main" + " | " + mainColor); + editor.putInt(context.getString(R.string.shared_preference_theme_main), mainColor); + editor.apply(); + } + + public static void clearBrandColors(@NonNull Context context) { + if (isBrandingEnabled(context) && context instanceof BrandedActivity) { + final BrandedActivity activity = (BrandedActivity) context; + activity.applyBrand(ContextCompat.getColor(context, R.color.defaultBrand)); + } + SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit(); + DeckLog.log("--- Write: Remove: shared_preference_theme_main" + " | "); + editor.remove(context.getString(R.string.shared_preference_theme_main)); + editor.apply(); + } + + /** + * Since we may collide with dark theme in this area, we have to make sure that the color is visible depending on the background + */ + @ColorInt + public static int getSecondaryForegroundColorDependingOnTheme(@NonNull Context context, @ColorInt int mainColor) { + if (contrastRatioIsSufficient(mainColor, ContextCompat.getColor(context, R.color.primary))) { + return mainColor; + } + DeckLog.verbose("Contrast ratio between brand color " + String.format("#%06X", (0xFFFFFF & mainColor)) + " and primary theme background is too low. Falling back to WHITE/BLACK as brand color."); + return isDarkTheme(context) ? Color.WHITE : Color.BLACK; + } + + public static void applyBrandToFAB(@ColorInt int mainColor, @NonNull FloatingActionButton fab) { + final boolean contrastRatioIsSufficient = contrastRatioIsSufficientBigAreas(mainColor, ContextCompat.getColor(fab.getContext(), R.color.primary)); + fab.setSupportBackgroundTintList(ColorStateList.valueOf(contrastRatioIsSufficient + ? mainColor + : ContextCompat.getColor(fab.getContext(), R.color.accent))); + fab.setColorFilter(contrastRatioIsSufficient ? getForegroundColorForBackgroundColor(mainColor) : mainColor); + } + + public static void applyBrandToPrimaryTabLayout(@ColorInt int mainColor, @NonNull TabLayout tabLayout) { + @ColorInt int finalMainColor = getSecondaryForegroundColorDependingOnTheme(tabLayout.getContext(), mainColor); + tabLayout.setBackgroundColor(ContextCompat.getColor(tabLayout.getContext(), R.color.primary)); + final boolean contrastRatioIsSufficient = getContrastRatio(mainColor, ContextCompat.getColor(tabLayout.getContext(), R.color.primary)) > 1.7d; + tabLayout.setSelectedTabIndicatorColor(contrastRatioIsSufficient ? mainColor : finalMainColor); + } + + public static void applyBrandToEditText(@ColorInt int mainColor, @NonNull EditText editText) { + @ColorInt final int finalMainColor = getSecondaryForegroundColorDependingOnTheme(editText.getContext(), mainColor); + DrawableCompat.setTintList(editText.getBackground(), new ColorStateList( + new int[][]{ + new int[]{android.R.attr.state_active}, + new int[]{android.R.attr.state_activated}, + new int[]{android.R.attr.state_focused}, + new int[]{android.R.attr.state_pressed}, + new int[]{} + }, + new int[]{ + finalMainColor, + finalMainColor, + finalMainColor, + finalMainColor, + editText.getContext().getResources().getColor(R.color.fg_secondary) + } + )); + } + + public static void tintMenuIcon(@NonNull MenuItem menuItem, @ColorInt int color) { + Drawable drawable = menuItem.getIcon(); + if (drawable != null) { + drawable = DrawableCompat.wrap(drawable); + DrawableCompat.setTint(drawable, color); + menuItem.setIcon(drawable); + } + } +} 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 b618c16a9..986a66cad 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 @@ -44,13 +44,13 @@ import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.LiveDataHelper; import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.WrappedLiveData; import it.niedermann.nextcloud.deck.ui.branding.Branded; -import it.niedermann.nextcloud.deck.ui.branding.BrandedActivity; import it.niedermann.nextcloud.deck.ui.branding.BrandedAlertDialogBuilder; import it.niedermann.nextcloud.deck.ui.exception.ExceptionDialogFragment; import it.niedermann.nextcloud.deck.util.DateUtil; import it.niedermann.nextcloud.deck.util.ViewUtil; import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.LiveDataHelper.observeOnce; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.getSecondaryForegroundColorDependingOnTheme; import static it.niedermann.nextcloud.deck.util.MimeTypeUtil.TEXT_PLAIN; public class CardAdapter extends RecyclerView.Adapter<ItemCardViewHolder> implements DragAndDropAdapter<FullCard>, Branded { @@ -346,8 +346,8 @@ public class CardAdapter extends RecyclerView.Adapter<ItemCardViewHolder> implem } @Override - public void applyBrand(int mainColor, int textColor) { - this.mainColor = BrandedActivity.getSecondaryForegroundColorDependingOnTheme(context, mainColor); + public void applyBrand(int mainColor) { + this.mainColor = getSecondaryForegroundColorDependingOnTheme(context, mainColor); notifyDataSetChanged(); } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/EditActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/EditActivity.java index c039b2952..0710b7d7c 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/EditActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/EditActivity.java @@ -2,7 +2,7 @@ package it.niedermann.nextcloud.deck.ui.card; import android.content.Context; import android.content.Intent; -import android.graphics.Color; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.text.Editable; import android.text.InputFilter; @@ -15,11 +15,13 @@ import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; +import androidx.core.graphics.drawable.DrawableCompat; import androidx.lifecycle.ViewModelProvider; import com.google.android.material.tabs.TabLayout; import com.google.android.material.tabs.TabLayoutMediator; +import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.ActivityEditBinding; import it.niedermann.nextcloud.deck.model.Account; @@ -31,6 +33,8 @@ import it.niedermann.nextcloud.deck.util.CardUtil; import static android.graphics.Color.parseColor; import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.LiveDataHelper.observeOnce; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.applyBrandToPrimaryTabLayout; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.isBrandingEnabled; public class EditActivity extends BrandedActivity { private static final String BUNDLE_KEY_ACCOUNT = "account"; @@ -87,9 +91,9 @@ public class EditActivity extends BrandedActivity { @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); + applyBrand(colorAccent); setIntent(intent); loadDataFromIntent(); - applyBrand(parseColor(viewModel.getAccount().getColor()), parseColor(viewModel.getAccount().getTextColor())); } private void loadDataFromIntent() { @@ -117,6 +121,7 @@ public class EditActivity extends BrandedActivity { final long boardId = args.getLong(BUNDLE_KEY_BOARD_ID); observeOnce(syncManager.getFullBoardById(account.getId(), boardId), EditActivity.this, (fullBoard -> { + applyBrand(parseColor('#' + fullBoard.getBoard().getColor())); viewModel.setCanEdit(fullBoard.getBoard().isPermissionEdit()); invalidateOptionsMenu(); if (viewModel.isCreateMode()) { @@ -290,12 +295,16 @@ public class EditActivity extends BrandedActivity { } @Override - public void applyBrand(int mainColor, int textColor) { - applyBrandToPrimaryToolbar(mainColor, textColor, binding.toolbar); - applyBrandToPrimaryTabLayout(mainColor, textColor, binding.tabLayout); - final int highlightColor = Color.argb(77, Color.red(textColor), Color.green(textColor), Color.blue(textColor)); - binding.title.setHighlightColor(highlightColor); - binding.title.setTextColor(textColor); + public void applyBrand(int mainColor) { + if(isBrandingEnabled(this)) { + final Drawable navigationIcon = binding.toolbar.getNavigationIcon(); + if (navigationIcon == null) { + DeckLog.error("Excpected navigationIcon to be present."); + } else { + DrawableCompat.setTint(binding.toolbar.getNavigationIcon(), colorAccent); + } + applyBrandToPrimaryTabLayout(mainColor, binding.tabLayout); + } } @NonNull 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 3ecee8583..a72ed8ef2 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 @@ -35,8 +35,6 @@ import it.niedermann.nextcloud.deck.util.DateUtil; import it.niedermann.nextcloud.deck.util.MimeTypeUtil; import static androidx.recyclerview.widget.RecyclerView.NO_ID; -import static it.niedermann.nextcloud.deck.Application.readBrandMainColor; -import static it.niedermann.nextcloud.deck.ui.branding.BrandedActivity.getSecondaryForegroundColorDependingOnTheme; import static it.niedermann.nextcloud.deck.util.ClipboardUtil.copyToClipboard; @SuppressWarnings("WeakerAccess") @@ -73,7 +71,6 @@ public class CardAttachmentAdapter extends RecyclerView.Adapter<AttachmentViewHo this.attachmentClickedListener = attachmentClickedListener; this.account = account; this.cardLocalId = cardLocalId == null ? NO_ID : cardLocalId; - this.mainColor = getSecondaryForegroundColorDependingOnTheme(context, readBrandMainColor(context)); setHasStableIds(true); } 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 dff12272e..c291c5bdf 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 @@ -44,7 +44,7 @@ import it.niedermann.nextcloud.deck.ui.card.EditCardViewModel; import it.niedermann.nextcloud.deck.ui.exception.ExceptionDialogFragment; import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.LiveDataHelper.observeOnce; -import static it.niedermann.nextcloud.deck.ui.branding.BrandedActivity.applyBrandToFAB; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.applyBrandToFAB; 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; import static it.niedermann.nextcloud.deck.util.AttachmentUtil.copyContentUriToTempFile; @@ -275,7 +275,7 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme } @Override - public void applyBrand(int mainColor, int textColor) { - applyBrandToFAB(mainColor, textColor, binding.fab); + public void applyBrand(int mainColor) { + applyBrandToFAB(mainColor, binding.fab); } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CardCommentsAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CardCommentsAdapter.java index 5e9324a3c..169a37c79 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CardCommentsAdapter.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/comments/CardCommentsAdapter.java @@ -16,8 +16,8 @@ import it.niedermann.nextcloud.deck.databinding.ItemCommentBinding; import it.niedermann.nextcloud.deck.model.Account; import it.niedermann.nextcloud.deck.model.ocs.comment.full.FullDeckComment; -import static it.niedermann.nextcloud.deck.Application.readBrandMainColor; -import static it.niedermann.nextcloud.deck.ui.branding.BrandedActivity.getSecondaryForegroundColorDependingOnTheme; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.getSecondaryForegroundColorDependingOnTheme; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.readBrandMainColor; public class CardCommentsAdapter extends RecyclerView.Adapter<ItemCommentViewHolder> { 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 f43ccb5a0..692f8eb8f 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 @@ -16,10 +16,11 @@ 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; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.applyBrandToEditText; + public class CardCommentsEditDialogFragment extends BrandedDialogFragment { private static final String BUNDLE_KEY_COMMENT_ID = "commentId"; private static final String BUNDLE_KEY_COMMENT_MESSAGE = "commentMessage"; @@ -78,8 +79,8 @@ public class CardCommentsEditDialogFragment extends BrandedDialogFragment { } @Override - public void applyBrand(int mainColor, int textColor) { - BrandedActivity.applyBrandToEditText(mainColor, textColor, binding.input); + public void applyBrand(int mainColor) { + applyBrandToEditText(mainColor, 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 302173544..e261c37a2 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 @@ -29,8 +29,8 @@ import it.niedermann.nextcloud.deck.ui.card.EditCardViewModel; 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.branding.BrandingUtil.applyBrandToEditText; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.applyBrandToFAB; import static it.niedermann.nextcloud.deck.util.ViewUtil.setupMentions; public class CardCommentsFragment extends BrandedFragment implements CommentEditedListener, CommentDeletedListener, CommentSelectAsReplyListener { @@ -142,9 +142,9 @@ public class CardCommentsFragment extends BrandedFragment implements CommentEdit } @Override - public void applyBrand(int mainColor, int textColor) { - applyBrandToEditText(mainColor, textColor, binding.message); - applyBrandToFAB(mainColor, textColor, binding.fab); + public void applyBrand(int mainColor) { + applyBrandToEditText(mainColor, binding.message); + applyBrandToFAB(mainColor, binding.fab); } @Override 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 a2a01b618..3182fffa2 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 @@ -58,7 +58,7 @@ import it.niedermann.nextcloud.deck.util.ViewUtil; import static android.text.format.DateFormat.getDateFormat; 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.branding.BrandingUtil.applyBrandToEditText; import static it.niedermann.nextcloud.deck.util.DimensionUtil.dpToPx; public class CardDetailsFragment extends BrandedFragment implements OnDateSetListener, OnTimeSetListener { @@ -136,12 +136,12 @@ public class CardDetailsFragment extends BrandedFragment implements OnDateSetLis } @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); + public void applyBrand(int mainColor) { + applyBrandToEditText(mainColor, binding.labels); + applyBrandToEditText(mainColor, binding.dueDateDate); + applyBrandToEditText(mainColor, binding.dueDateTime); + applyBrandToEditText(mainColor, binding.people); + applyBrandToEditText(mainColor, binding.description); } private void setupDescription() { diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/ExceptionActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/ExceptionActivity.java index 3ba3eb59f..9eef878c3 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/ExceptionActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/ExceptionActivity.java @@ -11,6 +11,7 @@ import androidx.appcompat.app.AppCompatActivity; import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.ActivityExceptionBinding; +import it.niedermann.nextcloud.deck.ui.exception.tips.TipsAdapter; import it.niedermann.nextcloud.deck.util.ExceptionUtil; import static it.niedermann.nextcloud.deck.util.ClipboardUtil.copyToClipboard; @@ -41,6 +42,11 @@ public class ExceptionActivity extends AppCompatActivity { binding.stacktrace.setText(debugInfo); + final TipsAdapter adapter = new TipsAdapter(this::startActivity); + binding.tips.setAdapter(adapter); + binding.tips.setNestedScrollingEnabled(false); + adapter.setThrowable(this, null, throwable); + binding.copy.setOnClickListener((v) -> copyToClipboard(this, getString(R.string.simple_exception), "```\n" + debugInfo + "\n```")); binding.close.setOnClickListener((v) -> finish()); } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/ExceptionDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/ExceptionDialogFragment.java index 9ab9b70c8..6c0d0ba79 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/ExceptionDialogFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/ExceptionDialogFragment.java @@ -2,8 +2,6 @@ package it.niedermann.nextcloud.deck.ui.exception; import android.app.Dialog; import android.content.Context; -import android.content.Intent; -import android.net.Uri; import android.os.Bundle; import android.view.View; @@ -13,27 +11,13 @@ import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatDialogFragment; import androidx.fragment.app.DialogFragment; -import com.nextcloud.android.sso.exceptions.NextcloudApiNotRespondingException; -import com.nextcloud.android.sso.exceptions.NextcloudFilesAppNotSupportedException; -import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException; -import com.nextcloud.android.sso.exceptions.TokenMismatchException; - -import org.json.JSONException; - -import java.net.ConnectException; -import java.net.SocketTimeoutException; - -import it.niedermann.nextcloud.deck.BuildConfig; import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.DialogExceptionBinding; -import it.niedermann.nextcloud.deck.exceptions.DeckException; -import it.niedermann.nextcloud.deck.exceptions.UploadAttachmentFailedException; import it.niedermann.nextcloud.deck.model.Account; import it.niedermann.nextcloud.deck.ui.exception.tips.TipsAdapter; import it.niedermann.nextcloud.deck.util.ExceptionUtil; -import static android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS; import static it.niedermann.nextcloud.deck.util.ClipboardUtil.copyToClipboard; public class ExceptionDialogFragment extends AppCompatDialogFragment { @@ -75,69 +59,7 @@ public class ExceptionDialogFragment extends AppCompatDialogFragment { DeckLog.logError(throwable); - if (throwable instanceof TokenMismatchException) { - adapter.add(R.string.error_dialog_tip_token_mismatch_retry); - adapter.add(R.string.error_dialog_tip_token_mismatch_clear_storage); - Intent intent = new Intent(ACTION_APPLICATION_DETAILS_SETTINGS) - .setData(Uri.parse("package:" + BuildConfig.APPLICATION_ID)) - .putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_open_deck_info); - adapter.add(R.string.error_dialog_tip_clear_storage, intent); - } else if (throwable instanceof NextcloudFilesAppNotSupportedException) { - adapter.add(R.string.error_dialog_tip_files_outdated); - } else if (throwable instanceof NextcloudApiNotRespondingException) { - adapter.add(R.string.error_dialog_tip_files_force_stop); - adapter.add(R.string.error_dialog_tip_files_delete_storage); - } else if (throwable instanceof SocketTimeoutException || throwable instanceof ConnectException) { - adapter.add(R.string.error_dialog_timeout_instance); - adapter.add(R.string.error_dialog_timeout_toggle, new Intent(android.provider.Settings.ACTION_WIFI_SETTINGS).putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_open_network)); - } else if (throwable instanceof JSONException || throwable instanceof NullPointerException) { - adapter.add(R.string.error_dialog_check_server); - } else if (throwable instanceof NextcloudHttpRequestFailedException) { - int statusCode = ((NextcloudHttpRequestFailedException) throwable).getStatusCode(); - switch (statusCode) { - case 302: - adapter.add(R.string.error_dialog_redirect); - break; - case 500: - if (account != null) { - adapter.add(R.string.error_dialog_check_server_logs, new Intent(Intent.ACTION_VIEW) - .putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_server_logs) - .setData(Uri.parse(account.getUrl() + getString(R.string.url_fragment_server_logs)))); - } else { - adapter.add(R.string.error_dialog_check_server_logs); - } - break; - case 503: - adapter.add(R.string.error_dialog_check_maintenance); - break; - case 507: - adapter.add(R.string.error_dialog_insufficient_storage); - break; - } - } else if (throwable instanceof UploadAttachmentFailedException) { - adapter.add(R.string.error_dialog_attachment_upload_failed); - } else if (throwable instanceof DeckException) { - switch (((DeckException) throwable).getHint()) { - case CAPABILITIES_VERSION_NOT_PARSABLE: - if (account != null) { - adapter.add(R.string.error_dialog_version_not_parsable, new Intent(Intent.ACTION_VIEW) - .putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_install) - .setData(Uri.parse(account.getUrl() + getString(R.string.url_fragment_install_deck)))); - } else { - adapter.add(R.string.error_dialog_version_not_parsable); - } - break; - case CAPABILITIES_NOT_PARSABLE: - default: - if (account != null) { - adapter.add(R.string.error_dialog_capabilities_not_parsable, new Intent(Intent.ACTION_VIEW) - .putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_server_logs) - .setData(Uri.parse(account.getUrl() + getString(R.string.url_fragment_server_logs)))); - } else { - adapter.add(R.string.error_dialog_capabilities_not_parsable); - } - } - } + adapter.setThrowable(requireContext(), account, throwable); return new AlertDialog.Builder(requireActivity()) .setView(binding.getRoot()) diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/tips/TipsAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/tips/TipsAdapter.java index 8ca1a4e09..fa4113b1e 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/tips/TipsAdapter.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/tips/TipsAdapter.java @@ -1,6 +1,11 @@ package it.niedermann.nextcloud.deck.ui.exception.tips; +import android.content.Context; import android.content.Intent; +import android.net.Uri; +import android.os.Build.VERSION; +import android.os.Build.VERSION_CODES; +import android.provider.Settings; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -11,10 +16,26 @@ import androidx.annotation.StringRes; import androidx.core.util.Consumer; import androidx.recyclerview.widget.RecyclerView; +import com.nextcloud.android.sso.exceptions.NextcloudApiNotRespondingException; +import com.nextcloud.android.sso.exceptions.NextcloudFilesAppNotSupportedException; +import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException; +import com.nextcloud.android.sso.exceptions.TokenMismatchException; + +import org.json.JSONException; + +import java.net.ConnectException; +import java.net.SocketTimeoutException; import java.util.LinkedList; import java.util.List; +import it.niedermann.nextcloud.deck.BuildConfig; import it.niedermann.nextcloud.deck.R; +import it.niedermann.nextcloud.deck.exceptions.DeckException; +import it.niedermann.nextcloud.deck.exceptions.UploadAttachmentFailedException; +import it.niedermann.nextcloud.deck.model.Account; + +import static android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS; +import static it.niedermann.nextcloud.deck.ui.exception.ExceptionDialogFragment.INTENT_EXTRA_BUTTON_TEXT; public class TipsAdapter extends RecyclerView.Adapter<TipsViewHolder> { @@ -44,6 +65,77 @@ public class TipsAdapter extends RecyclerView.Adapter<TipsViewHolder> { return tips.size(); } + public void setThrowable(@NonNull Context context, @Nullable Account account, @NonNull Throwable throwable) { + if (throwable instanceof TokenMismatchException) { + add(R.string.error_dialog_tip_token_mismatch_retry); + add(R.string.error_dialog_tip_token_mismatch_clear_storage); + Intent intent = new Intent(ACTION_APPLICATION_DETAILS_SETTINGS) + .setData(Uri.parse("package:" + BuildConfig.APPLICATION_ID)) + .putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_open_deck_info); + add(R.string.error_dialog_tip_clear_storage, intent); + } else if (throwable instanceof NextcloudFilesAppNotSupportedException) { + add(R.string.error_dialog_tip_files_outdated); + } else if (throwable instanceof NextcloudApiNotRespondingException) { + if (VERSION.SDK_INT >= VERSION_CODES.M) { + add(R.string.error_dialog_tip_disable_battery_optimizations, new Intent().setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS).putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_open_battery_settings)); + } else { + add(R.string.error_dialog_tip_disable_battery_optimizations); + } + add(R.string.error_dialog_tip_files_force_stop); + add(R.string.error_dialog_tip_files_delete_storage); + } else if (throwable instanceof SocketTimeoutException || throwable instanceof ConnectException) { + add(R.string.error_dialog_timeout_instance); + add(R.string.error_dialog_timeout_toggle, new Intent(Settings.ACTION_WIFI_SETTINGS).putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_open_network)); + } else if (throwable instanceof JSONException || throwable instanceof NullPointerException) { + add(R.string.error_dialog_check_server); + } else if (throwable instanceof NextcloudHttpRequestFailedException) { + int statusCode = ((NextcloudHttpRequestFailedException) throwable).getStatusCode(); + switch (statusCode) { + case 302: + add(R.string.error_dialog_redirect); + break; + case 500: + if (account != null) { + add(R.string.error_dialog_check_server_logs, new Intent(Intent.ACTION_VIEW) + .putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_server_logs) + .setData(Uri.parse(account.getUrl() + context.getString(R.string.url_fragment_server_logs)))); + } else { + add(R.string.error_dialog_check_server_logs); + } + break; + case 503: + add(R.string.error_dialog_check_maintenance); + break; + case 507: + add(R.string.error_dialog_insufficient_storage); + break; + } + } else if (throwable instanceof UploadAttachmentFailedException) { + add(R.string.error_dialog_attachment_upload_failed); + } else if (throwable instanceof DeckException) { + switch (((DeckException) throwable).getHint()) { + case CAPABILITIES_VERSION_NOT_PARSABLE: + if (account != null) { + add(R.string.error_dialog_version_not_parsable, new Intent(Intent.ACTION_VIEW) + .putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_install) + .setData(Uri.parse(account.getUrl() + context.getString(R.string.url_fragment_install_deck)))); + } else { + add(R.string.error_dialog_version_not_parsable); + } + break; + case CAPABILITIES_NOT_PARSABLE: + default: + if (account != null) { + add(R.string.error_dialog_capabilities_not_parsable, new Intent(Intent.ACTION_VIEW) + .putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_server_logs) + .setData(Uri.parse(account.getUrl() + context.getString(R.string.url_fragment_server_logs)))); + } else { + add(R.string.error_dialog_capabilities_not_parsable); + } + } + } + } + public void add(@StringRes int text) { add(text, null); } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterDialogFragment.java index 12dd38eac..aa6f59d04 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterDialogFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterDialogFragment.java @@ -23,10 +23,11 @@ import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.DialogFilterBinding; import it.niedermann.nextcloud.deck.model.enums.EDueType; import it.niedermann.nextcloud.deck.model.internal.FilterInformation; -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.ui.branding.BrandingUtil.getSecondaryForegroundColorDependingOnTheme; + public class FilterDialogFragment extends BrandedDialogFragment { private DialogFilterBinding binding; @@ -101,8 +102,8 @@ public class FilterDialogFragment extends BrandedDialogFragment { } @Override - public void applyBrand(int mainColor, int textColor) { - @ColorInt int finalMainColor = BrandedActivity.getSecondaryForegroundColorDependingOnTheme(requireContext(), mainColor); + public void applyBrand(int mainColor) { + @ColorInt int finalMainColor = getSecondaryForegroundColorDependingOnTheme(requireContext(), mainColor); binding.tabLayout.setSelectedTabIndicatorColor(finalMainColor); indicator.setColorFilter(finalMainColor, PorterDuff.Mode.SRC_ATOP); } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/manageaccounts/ManageAccountViewHolder.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/manageaccounts/ManageAccountViewHolder.java index 231e3f124..4b43cbed6 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/manageaccounts/ManageAccountViewHolder.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/manageaccounts/ManageAccountViewHolder.java @@ -34,7 +34,8 @@ public class ManageAccountViewHolder extends RecyclerView.ViewHolder { binding.accountHost.setText(Uri.parse(account.getUrl()).getHost()); Glide.with(itemView.getContext()) .load(new SingleSignOnUrl(account.getName(), account.getAvatarUrl(dpToPx(binding.accountItemAvatar.getContext(), R.dimen.avatar_size)))) - .error(R.drawable.ic_person_grey600_24dp) + .placeholder(R.drawable.ic_baseline_account_circle_24) + .error(R.drawable.ic_baseline_account_circle_24) .apply(RequestOptions.circleCropTransform()) .into(binding.accountItemAvatar); binding.currentAccountIndicator.setSelected(isCurrentAccount); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/manageaccounts/ManageAccountsActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/manageaccounts/ManageAccountsActivity.java index ed62e85cb..9d273cdcb 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/manageaccounts/ManageAccountsActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/manageaccounts/ManageAccountsActivity.java @@ -1,6 +1,5 @@ package it.niedermann.nextcloud.deck.ui.manageaccounts; -import android.graphics.Color; import android.os.Bundle; import android.util.Log; @@ -9,15 +8,15 @@ import androidx.appcompat.app.AppCompatActivity; import com.nextcloud.android.sso.helper.SingleAccountHelper; -import it.niedermann.nextcloud.deck.Application; import it.niedermann.nextcloud.deck.databinding.ActivityManageAccountsBinding; import it.niedermann.nextcloud.deck.model.Account; import it.niedermann.nextcloud.deck.persistence.sync.SyncManager; -import it.niedermann.nextcloud.deck.ui.branding.BrandedActivity; +import static it.niedermann.nextcloud.deck.DeckApplication.readCurrentAccountId; +import static it.niedermann.nextcloud.deck.DeckApplication.saveCurrentAccountId; import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.LiveDataHelper.observeOnce; -public class ManageAccountsActivity extends BrandedActivity { +public class ManageAccountsActivity extends AppCompatActivity { private static final String TAG = ManageAccountsActivity.class.getSimpleName(); @@ -39,8 +38,7 @@ public class ManageAccountsActivity extends BrandedActivity { adapter = new ManageAccountAdapter((account) -> { SingleAccountHelper.setCurrentAccount(getApplicationContext(), account.getName()); syncManager = new SyncManager(this); - Application.saveBrandColors(this, Color.parseColor(account.getColor()), Color.parseColor(account.getTextColor())); - Application.saveCurrentAccountId(this, account.getId()); + saveCurrentAccountId(this, account.getId()); }, (accountPair) -> { if (accountPair.first != null) { syncManager.deleteAccount(accountPair.first.getId()); @@ -50,8 +48,7 @@ public class ManageAccountsActivity extends BrandedActivity { Account newAccount = accountPair.second; if (newAccount != null) { SingleAccountHelper.setCurrentAccount(getApplicationContext(), newAccount.getName()); - Application.saveBrandColors(this, Color.parseColor(newAccount.getColor()), Color.parseColor(newAccount.getTextColor())); - Application.saveCurrentAccountId(this, newAccount.getId()); + saveCurrentAccountId(this, newAccount.getId()); syncManager = new SyncManager(this); } else { Log.i(TAG, "Got delete account request, but new account is null. Maybe last account has been deleted?"); @@ -59,7 +56,7 @@ public class ManageAccountsActivity extends BrandedActivity { }); binding.accounts.setAdapter(adapter); - observeOnce(syncManager.readAccount(Application.readCurrentAccountId(this)), this, (account -> { + observeOnce(syncManager.readAccount(readCurrentAccountId(this)), this, (account -> { adapter.setCurrentAccount(account); syncManager.readAccounts().observe(this, (localAccounts -> { if (localAccounts.size() == 0) { @@ -77,9 +74,4 @@ public class ManageAccountsActivity extends BrandedActivity { public void onBackPressed() { onSupportNavigateUp(); } - - @Override - public void applyBrand(int mainColor, int textColor) { - applyBrandToPrimaryToolbar(mainColor, textColor, binding.toolbar); - } } 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 index b2e9cb012..ab0cc4816 100644 --- 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 @@ -2,34 +2,51 @@ package it.niedermann.nextcloud.deck.ui.preparecreate; import android.content.ClipData; import android.content.Intent; +import android.content.res.ColorStateList; +import android.graphics.Color; import android.os.Bundle; import android.text.TextUtils; import android.widget.ArrayAdapter; +import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.content.ContextCompat; +import androidx.core.graphics.drawable.DrawableCompat; import androidx.lifecycle.LiveData; import androidx.lifecycle.Observer; 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.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.branding.Branded; import it.niedermann.nextcloud.deck.ui.card.EditActivity; import it.niedermann.nextcloud.deck.ui.exception.ExceptionDialogFragment; import it.niedermann.nextcloud.deck.ui.exception.ExceptionHandler; +import it.niedermann.nextcloud.deck.util.ColorUtil; import static android.graphics.Color.parseColor; import static androidx.lifecycle.Transformations.switchMap; - -public class PrepareCreateActivity extends BrandedActivity { +import static it.niedermann.nextcloud.deck.DeckApplication.isDarkTheme; +import static it.niedermann.nextcloud.deck.DeckApplication.readCurrentAccountId; +import static it.niedermann.nextcloud.deck.DeckApplication.readCurrentBoardId; +import static it.niedermann.nextcloud.deck.DeckApplication.readCurrentStackId; +import static it.niedermann.nextcloud.deck.DeckApplication.saveCurrentAccountId; +import static it.niedermann.nextcloud.deck.DeckApplication.saveCurrentBoardId; +import static it.niedermann.nextcloud.deck.DeckApplication.saveCurrentStackId; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.getSecondaryForegroundColorDependingOnTheme; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.isBrandingEnabled; +import static it.niedermann.nextcloud.deck.util.ColorUtil.contrastRatioIsSufficientBigAreas; + +public class PrepareCreateActivity extends AppCompatActivity implements Branded { private ActivityPrepareCreateBinding binding; @@ -59,10 +76,12 @@ public class PrepareCreateActivity extends BrandedActivity { for (Board board : boards) { if (board.getLocalId() == lastBoardId) { binding.boardSelect.setSelection(boardAdapter.getPosition(board)); + applyBrand(Color.parseColor('#' + board.getColor())); break; } } } else { + applyBrand(ContextCompat.getColor(this, R.color.defaultBrand)); binding.boardSelect.setEnabled(false); binding.submit.setEnabled(false); } @@ -97,7 +116,7 @@ public class PrepareCreateActivity extends BrandedActivity { Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(this)); - brandingEnabled = Application.isBrandingEnabled(this); + brandingEnabled = isBrandingEnabled(this); binding = ActivityPrepareCreateBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); @@ -127,9 +146,9 @@ public class PrepareCreateActivity extends BrandedActivity { 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); + lastAccountId = readCurrentAccountId(this); + lastBoardId = readCurrentBoardId(this, lastAccountId); + lastStackId = readCurrentStackId(this, lastAccountId, lastBoardId); accountAdapter.clear(); accountAdapter.addAll(accounts); @@ -144,12 +163,13 @@ public class PrepareCreateActivity extends BrandedActivity { }); binding.accountSelect.setOnItemSelectedListener((SelectedListener) (parent, view, position, id) -> { - applyTemporaryBrand(accountAdapter.getItem(position)); 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.boardSelect.setOnItemSelectedListener((SelectedListener) (parent, view, position, id) -> { + applyBrand(Color.parseColor('#' + ((Board) binding.boardSelect.getSelectedItem()).getColor())); + updateLiveDataSource(stacksLiveData, stacksObserver, syncManager.getStacksForBoard(binding.accountSelect.getSelectedItemId(), parent.getSelectedItemId())); + }); binding.cancel.setOnClickListener((v) -> finish()); binding.submit.setOnClickListener((v) -> onSubmit()); @@ -181,10 +201,10 @@ public class PrepareCreateActivity extends BrandedActivity { startActivity(EditActivity.createNewCardIntent(this, account, boardId, stackId, receivedClipData)); } - Application.saveCurrentAccountId(this, account.getId()); - Application.saveCurrentBoardId(this, account.getId(), boardId); - Application.saveCurrentStackId(this, account.getId(), boardId, stackId); - applyBrand(parseColor(account.getColor()), parseColor(account.getTextColor())); + saveCurrentAccountId(this, account.getId()); + saveCurrentBoardId(this, account.getId(), boardId); + saveCurrentStackId(this, account.getId(), boardId, stackId); + applyBrand(parseColor(account.getColor())); finish(); } else { @@ -213,21 +233,19 @@ public class PrepareCreateActivity extends BrandedActivity { return TextUtils.isEmpty(text) ? null : text.toString(); } - private void applyTemporaryBrand(@Nullable Account account) { + @Override + public void applyBrand(int mainColor) { try { - if (account != null && brandingEnabled) { - applyBrand(parseColor(account.getColor()), parseColor(account.getTextColor())); + if (brandingEnabled) { + @ColorInt final int finalMainColor = contrastRatioIsSufficientBigAreas(mainColor, ContextCompat.getColor(this, R.color.primary)) + ? mainColor + : isDarkTheme(this) ? Color.WHITE : Color.BLACK; + DrawableCompat.setTintList(binding.submit.getBackground(), ColorStateList.valueOf(finalMainColor)); + binding.submit.setTextColor(ColorUtil.getForegroundColorForBackgroundColor(finalMainColor)); + binding.cancel.setTextColor(getSecondaryForegroundColorDependingOnTheme(this, mainColor)); } } catch (Throwable t) { DeckLog.logError(t); } } - - @Override - public void applyBrand(int mainColor, int textColor) { - applyBrandToPrimaryToolbar(mainColor, textColor, binding.toolbar); - binding.submit.setBackgroundColor(mainColor); - binding.submit.setTextColor(textColor); - binding.cancel.setTextColor(getSecondaryForegroundColorDependingOnTheme(this, mainColor)); - } }
\ No newline at end of file diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/SettingsActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/SettingsActivity.java index 363e5b46e..6f5a9a7e8 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/SettingsActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/settings/SettingsActivity.java @@ -37,7 +37,7 @@ public class SettingsActivity extends BrandedActivity { } @Override - public void applyBrand(int mainColor, int textColor) { - applyBrandToPrimaryToolbar(mainColor, textColor, binding.toolbar); + public void applyBrand(int mainColor) { + // Nothing to do... } } 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 f531abbe1..ea8d90f22 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 @@ -4,19 +4,20 @@ import android.app.Activity; import android.content.Context; import android.os.Bundle; -import androidx.annotation.ColorInt; import androidx.annotation.Nullable; import androidx.preference.ListPreference; import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; -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; +import static it.niedermann.nextcloud.deck.DeckApplication.setAppTheme; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.readBrandMainColor; + public class SettingsFragment extends PreferenceFragmentCompat implements Branded { private BrandedSwitchPreference wifiOnlyPref; @@ -44,7 +45,7 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Brande themePref.setOnPreferenceChangeListener((Preference preference, Object newValue) -> { final Boolean darkTheme = (Boolean) newValue; DeckLog.log("darkTheme: " + darkTheme); - Application.setAppTheme(darkTheme); + setAppTheme(darkTheme); requireActivity().setResult(Activity.RESULT_OK); requireActivity().recreate(); return true; @@ -82,16 +83,14 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Brande super.onStart(); @Nullable Context context = getContext(); if (context != null) { - @ColorInt final int mainColor = Application.readBrandMainColor(context); - @ColorInt final int textColor = Application.readBrandTextColor(context); - applyBrand(mainColor, textColor); + applyBrand(readBrandMainColor(context)); } } @Override - public void applyBrand(int mainColor, int textColor) { - wifiOnlyPref.applyBrand(mainColor, textColor); - themePref.applyBrand(mainColor, textColor); - brandingPref.applyBrand(mainColor, textColor); + public void applyBrand(int mainColor) { + wifiOnlyPref.applyBrand(mainColor); + themePref.applyBrand(mainColor); + brandingPref.applyBrand(mainColor); } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/sharetarget/ShareProgressDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/sharetarget/ShareProgressDialogFragment.java index 12a06bb11..271b60489 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/sharetarget/ShareProgressDialogFragment.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/sharetarget/ShareProgressDialogFragment.java @@ -21,7 +21,7 @@ import it.niedermann.nextcloud.deck.ui.branding.BrandedDialogFragment; import it.niedermann.nextcloud.deck.ui.exception.ExceptionDialogFragment; import static android.graphics.PorterDuff.Mode; -import static it.niedermann.nextcloud.deck.ui.branding.BrandedActivity.getSecondaryForegroundColorDependingOnTheme; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.getSecondaryForegroundColorDependingOnTheme; import static it.niedermann.nextcloud.deck.util.ExceptionUtil.getDebugInfos; public class ShareProgressDialogFragment extends BrandedDialogFragment { @@ -114,7 +114,7 @@ public class ShareProgressDialogFragment extends BrandedDialogFragment { } @Override - public void applyBrand(int mainColor, int textColor) { + public void applyBrand(int mainColor) { binding.progress.getProgressDrawable().setColorFilter( getSecondaryForegroundColorDependingOnTheme(requireContext(), mainColor), Mode.SRC_IN); binding.errorReportButton.setTextColor(getSecondaryForegroundColorDependingOnTheme(requireContext(), mainColor)); 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 92272b99e..6bedd0a0f 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 @@ -17,11 +17,11 @@ import java.util.Objects; 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; +import static it.niedermann.nextcloud.deck.DeckApplication.NO_STACK_ID; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.applyBrandToEditText; public class EditStackDialogFragment extends BrandedDialogFragment { private static final String KEY_STACK_ID = "stack_id"; @@ -90,7 +90,7 @@ public class EditStackDialogFragment extends BrandedDialogFragment { } @Override - public void applyBrand(int mainColor, int textColor) { - BrandedActivity.applyBrandToEditText(mainColor, textColor, binding.input); + public void applyBrand(int mainColor) { + applyBrandToEditText(mainColor, 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 942310199..726a74184 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 @@ -138,9 +138,9 @@ public class StackFragment extends BrandedFragment implements DragAndDropTab<Car } @Override - public void applyBrand(int mainColor, int textColor) { + public void applyBrand(int mainColor) { if (this.adapter != null) { - this.adapter.applyBrand(mainColor, textColor); + this.adapter.applyBrand(mainColor); } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/view/OverlappingAvatars.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/view/OverlappingAvatars.java index 63be42465..501d33106 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/view/OverlappingAvatars.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/view/OverlappingAvatars.java @@ -48,7 +48,7 @@ public class OverlappingAvatars extends RelativeLayout { avatarSize = dpToPx(context, R.dimen.avatar_size_small) + avatarBorderSize * 2; overlapPx = dpToPx(context, R.dimen.avatar_size_small_overlapping); borderDrawable = getResources().getDrawable(R.drawable.avatar_border); - DrawableCompat.setTint(borderDrawable, getResources().getColor(R.color.avatars_overlapping_border_color)); + DrawableCompat.setTint(borderDrawable, getResources().getColor(R.color.bg_card)); } public void setAvatars(@NonNull Account account, @NonNull List<User> assignedUsers) { diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/singlecard/SelectCardForWidgetActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/singlecard/SelectCardForWidgetActivity.java index cda805450..8c1fbe1fa 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/singlecard/SelectCardForWidgetActivity.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/singlecard/SelectCardForWidgetActivity.java @@ -6,17 +6,22 @@ import android.os.Bundle; import android.view.Menu; import android.view.View; +import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.model.Board; import it.niedermann.nextcloud.deck.model.full.FullCard; import it.niedermann.nextcloud.deck.ui.MainActivity; +import it.niedermann.nextcloud.deck.ui.branding.BrandingUtil; import it.niedermann.nextcloud.deck.ui.card.SelectCardListener; +import static it.niedermann.nextcloud.deck.ui.branding.BrandingUtil.saveBrandColors; + public class SelectCardForWidgetActivity extends MainActivity implements SelectCardListener { private int appWidgetId; + @ColorInt private int originalBrandColor; @Override protected void onCreate(Bundle savedInstanceState) { @@ -35,6 +40,7 @@ public class SelectCardForWidgetActivity extends MainActivity implements SelectC if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) { finish(); } + originalBrandColor = BrandingUtil.readBrandMainColor(this); } @Override @@ -45,6 +51,7 @@ public class SelectCardForWidgetActivity extends MainActivity implements SelectC .putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); setResult(RESULT_OK, updateIntent); getApplicationContext().sendBroadcast(updateIntent); + saveBrandColors(this, originalBrandColor); finish(); } 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 4adf43b34..08354c5fb 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 @@ -109,7 +109,18 @@ public final class ColorUtil { return ret; } - private static double getContrastRatio(@ColorInt int colorOne, @ColorInt int colorTwo) { + public static boolean contrastRatioIsSufficientBigAreas(@ColorInt int colorOne, @ColorInt int colorTwo) { + ColorPair key = new ColorPair(colorOne, colorTwo); + Boolean ret = CONTRAST_RATIO_SUFFICIENT_CACHE.get(key); + if (ret == null) { + ret = getContrastRatio(colorOne, colorTwo) > 1.47d; + CONTRAST_RATIO_SUFFICIENT_CACHE.put(key, ret); + return ret; + } + return ret; + } + + public static double getContrastRatio(@ColorInt int colorOne, @ColorInt int colorTwo) { final double lum1 = getLuminanace(colorOne); final double lum2 = getLuminanace(colorTwo); final double brightest = Math.max(lum1, lum2); 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 1039b5c95..6abbde557 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 @@ -27,11 +27,12 @@ import com.bumptech.glide.request.transition.Transition; import java.util.Date; import java.util.List; -import it.niedermann.nextcloud.deck.Application; import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.model.Account; import it.niedermann.nextcloud.deck.model.ocs.comment.Mention; +import static it.niedermann.nextcloud.deck.DeckApplication.isDarkTheme; + public final class ViewUtil { private ViewUtil() { } @@ -53,7 +54,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.grey600; + int textColor = isDarkTheme(context) ? R.color.dark_fg_primary : R.color.grey600; if (diff == 1) { // due date: tomorrow |