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

github.com/stefan-niedermann/nextcloud-deck.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Niedermann <info@niedermann.it>2020-11-25 21:49:12 +0300
committerStefan Niedermann <info@niedermann.it>2020-11-25 21:49:12 +0300
commit8110ebb0724c7e414223be651e9dcf6a95bcde4b (patch)
treed7bee0e0538f309aaebcd3a77bafbca8e98157a1 /app/src/main/java/it/niedermann
parent5411d277ee02a00d8c393967880ad1d1bbe70fc4 (diff)
parentd4f8c50e0b8609481aa43614a2715477724087b1 (diff)
Merge branch 'master' into webview-markdown
Diffstat (limited to 'app/src/main/java/it/niedermann')
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/api/DeckAPI.java5
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/api/IResponseCallback.java6
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/api/JsonToEntityParser.java66
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/exceptions/DeckException.java3
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/exceptions/TraceableException.java2
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/model/Account.java9
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/model/Board.java6
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/model/interfaces/AbstractRemoteEntity.java11
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/model/interfaces/IRemoteEntity.java8
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/SyncManager.java48
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/ServerAdapter.java4
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DeckDatabase.java22
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/util/WrappedLiveData.java6
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/DataPropagationHelper.java119
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/SyncHelper.java44
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/BoardDataProvider.java24
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/CardDataProvider.java13
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/StackDataProvider.java4
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/MainActivity.java18
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedboards/ArchivedBoardViewHolder.java37
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/board/BoardAdapter.java2
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/board/EditBoardDialogFragment.java6
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/board/EditBoardListener.java4
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/board/managelabels/EditLabelDialogFragment.java2
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/BoardAdapter.java2
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/view/ColorChooser.java38
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/stack/StackWidgetConfigurationActivity.java3
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/util/DrawerMenuUtil.java50
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/util/ProjectUtil.java4
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/util/ViewUtil.java10
30 files changed, 378 insertions, 198 deletions
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/api/DeckAPI.java b/app/src/main/java/it/niedermann/nextcloud/deck/api/DeckAPI.java
index a303a8a33..1f0148b91 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/api/DeckAPI.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/api/DeckAPI.java
@@ -1,6 +1,8 @@
package it.niedermann.nextcloud.deck.api;
+import com.nextcloud.android.sso.api.ParsedResponse;
+
import java.util.List;
import io.reactivex.Observable;
@@ -33,6 +35,7 @@ import retrofit2.http.Query;
public interface DeckAPI {
String MODIFIED_SINCE_HEADER = "If-Modified-Since";
+ String IF_NONE_MATCH = "If-None-Match";
// ### BOARDS
@POST("boards")
@@ -51,7 +54,7 @@ public interface DeckAPI {
Observable<FullBoard> restoreBoard(@Path("id") long id);
@GET("boards")
- Observable<List<FullBoard>> getBoards(@Query ("details") boolean verbose, @Header(MODIFIED_SINCE_HEADER) String lastSync );
+ Observable<ParsedResponse<List<FullBoard>>> getBoards(@Query ("details") boolean verbose, @Header(MODIFIED_SINCE_HEADER) String lastSync, @Header(IF_NONE_MATCH) String eTag);
// ### Stacks
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/api/IResponseCallback.java b/app/src/main/java/it/niedermann/nextcloud/deck/api/IResponseCallback.java
index 0e523c318..be3eaeb22 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/api/IResponseCallback.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/api/IResponseCallback.java
@@ -24,12 +24,18 @@ public abstract class IResponseCallback<T> {
DeckLog.logError(throwable);
}
+ @CallSuper
+ public void onError(Throwable throwable, T locallyCreatedEntity) {
+ onError(throwable);
+ }
+
public static <T> IResponseCallback<T> getDefaultResponseCallback(Account account) {
return new IResponseCallback<T>(account) {
@Override
public void onResponse(T response) {
// Do Nothing
}
+
};
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/api/JsonToEntityParser.java b/app/src/main/java/it/niedermann/nextcloud/deck/api/JsonToEntityParser.java
index 8601cab41..e759f27d4 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/api/JsonToEntityParser.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/api/JsonToEntityParser.java
@@ -284,6 +284,7 @@ public class JsonToEntityParser {
makeTraceableIfFails(() -> {
board.setTitle(getNullAsEmptyString(e.get("title")));
board.setColor(getNullAsEmptyString(e.get("color")));
+ board.setEtag(getNullAsNull(e.get("ETag")));
board.setArchived(e.get("archived").getAsBoolean());
board.setLastModified(getTimestampFromLong(e.get("lastModified")));
@@ -396,6 +397,7 @@ public class JsonToEntityParser {
card.setDescription(getNullAsEmptyString(e.get("description")));
card.setStackId(e.get("stackId").getAsLong());
card.setType(getNullAsEmptyString(e.get("type")));
+ card.setEtag(getNullAsNull(e.get("ETag")));
card.setLastModified(getTimestampFromLong(e.get("lastModified")));
card.setCreatedAt(getTimestampFromLong(e.get("createdAt")));
card.setDeletedAt(getTimestampFromLong(e.get("deletedAt")));
@@ -456,6 +458,7 @@ public class JsonToEntityParser {
a.setId(e.get("id").getAsLong());
a.setCardId(e.get("cardId").getAsLong());
a.setType(e.get("type").getAsString());
+ a.setEtag(getNullAsNull(e.get("ETag")));
a.setData(e.get("data").getAsString());
a.setLastModified(getTimestampFromLong(e.get("lastModified")));
a.setCreatedAt(getTimestampFromLong(e.get("createdAt")));
@@ -571,33 +574,6 @@ public class JsonToEntityParser {
return Color.GRAY;
}
- protected static List<Activity> parseActivity(JsonObject e) {
- DeckLog.verbose(e.toString());
- List<Activity> activityList = new ArrayList<>();
-
- makeTraceableIfFails(() -> {
- if (e.has("ocs")) {
- JsonObject ocs = e.getAsJsonObject("ocs");
- if (ocs.has("data")) {
- JsonArray data = ocs.getAsJsonArray("data");
- for (JsonElement activityJson : data) {
- Activity activity = new Activity();
- JsonObject activityObject = activityJson.getAsJsonObject();
-
- activity.setId(activityObject.get("activity_id").getAsLong());
- activity.setType(ActivityType.findByPath(getNullAsEmptyString(activityObject.get("icon"))).getId());
- activity.setSubject(getNullAsEmptyString(activityObject.get("subject")));
- activity.setCardId(activityObject.get("object_id").getAsLong());
- activity.setLastModified(getTimestampFromString(activityObject.get("datetime")));
-
- activityList.add(activity);
- }
- }
- }
- }, e);
- return activityList;
- }
-
protected static FullStack parseStack(JsonObject e) {
DeckLog.verbose(e.toString());
FullStack fullStack = new FullStack();
@@ -607,6 +583,7 @@ public class JsonToEntityParser {
stack.setTitle(getNullAsEmptyString(e.get("title")));
stack.setBoardId(e.get("boardId").getAsLong());
stack.setId(e.get("id").getAsLong());
+ stack.setEtag(getNullAsNull(e.get("ETag")));
stack.setLastModified(getTimestampFromLong(e.get("lastModified")));
stack.setDeletedAt(getTimestampFromLong(e.get("deletedAt")));
if (e.has("order") && !e.get("order").isJsonNull()) {
@@ -627,6 +604,34 @@ public class JsonToEntityParser {
return fullStack;
}
+ protected static List<Activity> parseActivity(JsonObject e) {
+ DeckLog.verbose(e.toString());
+ List<Activity> activityList = new ArrayList<>();
+
+ makeTraceableIfFails(() -> {
+ if (e.has("ocs")) {
+ JsonObject ocs = e.getAsJsonObject("ocs");
+ if (ocs.has("data")) {
+ JsonArray data = ocs.getAsJsonArray("data");
+ for (JsonElement activityJson : data) {
+ Activity activity = new Activity();
+ JsonObject activityObject = activityJson.getAsJsonObject();
+
+ activity.setId(activityObject.get("activity_id").getAsLong());
+ activity.setType(ActivityType.findByPath(getNullAsEmptyString(activityObject.get("icon"))).getId());
+ activity.setSubject(getNullAsEmptyString(activityObject.get("subject")));
+ activity.setCardId(activityObject.get("object_id").getAsLong());
+ activity.setEtag(getNullAsNull(e.get("ETag")));
+ activity.setLastModified(getTimestampFromString(activityObject.get("datetime")));
+
+ activityList.add(activity);
+ }
+ }
+ }
+ }, e);
+ return activityList;
+ }
+
protected static Label parseLabel(JsonObject e) {
DeckLog.verbose(e.toString());
Label label = new Label();
@@ -635,13 +640,18 @@ public class JsonToEntityParser {
//todo: last modified!
// label.setLastModified(get);
label.setTitle(getNullAsEmptyString(e.get("title")));
+ label.setEtag(getNullAsNull(e.get("ETag")));
label.setColor(getColorAsInt(e, "color"));
}, e);
return label;
}
private static String getNullAsEmptyString(JsonElement jsonElement) {
- return jsonElement.isJsonNull() ? "" : jsonElement.getAsString();
+ return jsonElement == null || jsonElement.isJsonNull() ? "" : jsonElement.getAsString();
+ }
+
+ private static String getNullAsNull(JsonElement jsonElement) {
+ return jsonElement == null || jsonElement.isJsonNull() ? null : jsonElement.getAsString();
}
private static Instant getTimestampFromString(JsonElement jsonElement) {
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/exceptions/DeckException.java b/app/src/main/java/it/niedermann/nextcloud/deck/exceptions/DeckException.java
index d9d8c5dde..0512f8a60 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/exceptions/DeckException.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/exceptions/DeckException.java
@@ -5,7 +5,8 @@ public class DeckException extends IllegalArgumentException {
public enum Hint {
CAPABILITIES_NOT_PARSABLE,
CAPABILITIES_VERSION_NOT_PARSABLE,
- UNKNOWN_ACCOUNT_USER_ID
+ UNKNOWN_ACCOUNT_USER_ID,
+ DEPENDENCY_NOT_SYNCED_YET
}
private Hint hint;
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/exceptions/TraceableException.java b/app/src/main/java/it/niedermann/nextcloud/deck/exceptions/TraceableException.java
index 7acfb60bd..8d436477d 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/exceptions/TraceableException.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/exceptions/TraceableException.java
@@ -11,6 +11,8 @@ public class TraceableException extends RuntimeException {
public static void makeTraceableIfFails(Runnable runnable, Object... args) {
try {
runnable.run();
+ } catch (TraceableException t) {
+ throw t;
} catch (Throwable t) {
final StringBuilder message = new StringBuilder("Sorry, a wild error appeared!\n\n" +
"⚠️ If you want to tell us about the following issue, " +
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/model/Account.java b/app/src/main/java/it/niedermann/nextcloud/deck/model/Account.java
index 1c189d162..8abcbced7 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/model/Account.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/model/Account.java
@@ -54,6 +54,7 @@ public class Account implements Serializable {
private boolean maintenanceEnabled = false;
private String etag;
+ private String boardsEtag;
@Ignore
public Account(Long id, @NonNull String name, @NonNull String userName, @NonNull String url) {
@@ -190,6 +191,14 @@ public class Account implements Serializable {
this.etag = etag;
}
+ public String getBoardsEtag() {
+ return boardsEtag;
+ }
+
+ public void setBoardsEtag(String boardsEtag) {
+ this.boardsEtag = boardsEtag;
+ }
+
/**
* A cache buster parameter is added for duplicate account names on different hosts which shall be fetched from the same {@link SingleSignOnAccount} (e. g. {@link AccountSwitcherDialog})
*
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/model/Board.java b/app/src/main/java/it/niedermann/nextcloud/deck/model/Board.java
index f88594e7f..27dcd1df8 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/model/Board.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/model/Board.java
@@ -37,8 +37,8 @@ public class Board extends AbstractRemoteEntity implements Serializable {
}
@Ignore
- public Board(String title, String color) {
- this.title = title;
+ public Board(String title, @ColorInt int color) {
+ setTitle(title);
setColor(color);
}
@@ -98,7 +98,7 @@ public class Board extends AbstractRemoteEntity implements Serializable {
}
}
- public void setColor(Integer color) {
+ public void setColor(@ColorInt Integer color) {
this.color = color;
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/model/interfaces/AbstractRemoteEntity.java b/app/src/main/java/it/niedermann/nextcloud/deck/model/interfaces/AbstractRemoteEntity.java
index 54cd0fc31..2f7771383 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/model/interfaces/AbstractRemoteEntity.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/model/interfaces/AbstractRemoteEntity.java
@@ -39,6 +39,8 @@ public abstract class AbstractRemoteEntity implements IRemoteEntity {
protected Instant lastModified;
protected Instant lastModifiedLocal;
+ protected String etag;
+
public AbstractRemoteEntity() {
}
@@ -137,6 +139,15 @@ public abstract class AbstractRemoteEntity implements IRemoteEntity {
this.status = status.getId();
}
+ @Override
+ public String getEtag() {
+ return etag;
+ }
+
+ @Override
+ public void setEtag(String etag) {
+ this.etag = etag;
+ }
@Override
public boolean equals(Object o) {
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/model/interfaces/IRemoteEntity.java b/app/src/main/java/it/niedermann/nextcloud/deck/model/interfaces/IRemoteEntity.java
index f50bf0b90..f197c0d30 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/model/interfaces/IRemoteEntity.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/model/interfaces/IRemoteEntity.java
@@ -68,6 +68,14 @@ public interface IRemoteEntity {
getEntity().setStatusEnum(status);
}
+ default String getEtag() {
+ return getEntity().getEtag();
+ }
+
+ default void setEtag(String etag) {
+ getEntity().setEtag(etag);
+ }
+
default <T> List<T> copyList(List<T> listToCopy) {
if (listToCopy == null) {
return null;
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 0a7f213ef..c86f65340 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
@@ -527,8 +527,8 @@ public class SyncManager {
}
@AnyThread
- public LiveData<FullBoard> createBoard(long accountId, @NonNull Board board) {
- MutableLiveData<FullBoard> liveData = new MutableLiveData<>();
+ public WrappedLiveData<FullBoard> createBoard(long accountId, @NonNull Board board) {
+ WrappedLiveData<FullBoard> liveData = new WrappedLiveData<>();
doAsync(() -> {
Account account = dataBaseAdapter.getAccountByIdDirectly(accountId);
User owner = dataBaseAdapter.getUserByUidDirectly(accountId, account.getUserName());
@@ -547,6 +547,12 @@ public class SyncManager {
public void onResponse(FullBoard response) {
liveData.postValue(response);
}
+
+ @SuppressLint("MissingSuperCall")
+ @Override
+ public void onError(Throwable throwable, FullBoard entity) {
+ liveData.postError(throwable, entity);
+ }
});
}
});
@@ -907,7 +913,18 @@ public class SyncManager {
stack.setBoardId(board.getLocalId());
fullStack.setStack(stack);
fullStack.setAccountId(accountId);
- new DataPropagationHelper(serverAdapter, dataBaseAdapter).createEntity(new StackDataProvider(null, board), fullStack, getCallbackToLiveDataConverter(account, liveData));
+ new DataPropagationHelper(serverAdapter, dataBaseAdapter).createEntity(new StackDataProvider(null, board), fullStack, new IResponseCallback<FullStack>(account) {
+ @Override
+ public void onResponse(FullStack response) {
+ liveData.postValue(response);
+ }
+
+ @SuppressLint("MissingSuperCall")
+ @Override
+ public void onError(Throwable throwable, FullStack entity) {
+ liveData.postError(throwable, entity);
+ }
+ });
});
return liveData;
}
@@ -1036,8 +1053,8 @@ public class SyncManager {
// }
@AnyThread
- public LiveData<FullCard> createFullCard(long accountId, long localBoardId, long localStackId, @NonNull FullCard card) {
- MutableLiveData<FullCard> liveData = new MutableLiveData<>();
+ public WrappedLiveData<FullCard> createFullCard(long accountId, long localBoardId, long localStackId, @NonNull FullCard card) {
+ WrappedLiveData<FullCard> liveData = new WrappedLiveData<>();
doAsync(() -> {
Account account = dataBaseAdapter.getAccountByIdDirectly(accountId);
User owner = dataBaseAdapter.getUserByUidDirectly(accountId, account.getUserName());
@@ -1074,11 +1091,28 @@ public class SyncManager {
}
}
- liveData.postValue(card);
+
if (serverAdapter.hasInternetConnection()) {
new SyncHelper(serverAdapter, dataBaseAdapter, null)
- .setResponseCallback(IResponseCallback.getDefaultResponseCallback(account))
+ .setResponseCallback(new IResponseCallback<Boolean>(account) {
+ @Override
+ public void onResponse(Boolean response) {
+ liveData.postValue(card);
+ }
+
+ @SuppressLint("MissingSuperCall")
+ @Override
+ public void onError(Throwable throwable) {
+ if (throwable.getClass() == DeckException.class && ((DeckException)throwable).getHint().equals(DeckException.Hint.DEPENDENCY_NOT_SYNCED_YET)) {
+ liveData.postValue(card);
+ } else {
+ liveData.postError(throwable);
+ }
+ }
+ })
.doUpSyncFor(new CardDataProvider(null, board, stack));
+ } else {
+ liveData.postValue(card);
}
});
return liveData;
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/ServerAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/ServerAdapter.java
index a0b9fd8aa..bff8ddfdb 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/ServerAdapter.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/ServerAdapter.java
@@ -125,9 +125,9 @@ public class ServerAdapter {
// return lastSyncHeader;
}
- public void getBoards(IResponseCallback<List<FullBoard>> responseCallback) {
+ public void getBoards(IResponseCallback<ParsedResponse<List<FullBoard>>> responseCallback) {
RequestHelper.request(provider, () ->
- provider.getDeckAPI().getBoards(true, getLastSyncDateFormatted(responseCallback.getAccount().getId())),
+ provider.getDeckAPI().getBoards(true, getLastSyncDateFormatted(responseCallback.getAccount().getId()), responseCallback.getAccount().getBoardsEtag()),
responseCallback);
}
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 0ac0f786b..a491946ed 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
@@ -97,7 +97,7 @@ import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao.widgets.Sta
UserInBoard.class,
},
exportSchema = false,
- version = 22
+ version = 23
)
@TypeConverters({DateTypeConverter.class})
public abstract class DeckDatabase extends RoomDatabase {
@@ -375,6 +375,25 @@ public abstract class DeckDatabase extends RoomDatabase {
}
};
+ private static final Migration MIGRATION_22_23 = new Migration(22, 23) {
+ @Override
+ public void migrate(SupportSQLiteDatabase database) {
+ // https://github.com/stefan-niedermann/nextcloud-deck/issues/359
+ database.execSQL("ALTER TABLE `Account` ADD `boardsEtag` TEXT");
+ database.execSQL("ALTER TABLE `Board` ADD `etag` TEXT");
+ database.execSQL("ALTER TABLE `Stack` ADD `etag` TEXT");
+ database.execSQL("ALTER TABLE `Card` ADD `etag` TEXT");
+ database.execSQL("ALTER TABLE `Label` ADD `etag` TEXT");
+ database.execSQL("ALTER TABLE `AccessControl` ADD `etag` TEXT");
+ database.execSQL("ALTER TABLE `Attachment` ADD `etag` TEXT");
+ database.execSQL("ALTER TABLE `User` ADD `etag` TEXT");
+ database.execSQL("ALTER TABLE `DeckComment` ADD `etag` TEXT");
+ database.execSQL("ALTER TABLE `Activity` ADD `etag` TEXT");
+ database.execSQL("ALTER TABLE `OcsProject` ADD `etag` TEXT");
+ database.execSQL("ALTER TABLE `OcsProjectResource` ADD `etag` TEXT");
+ }
+ };
+
public static final RoomDatabase.Callback ON_CREATE_CALLBACK = new RoomDatabase.Callback() {
@Override
public void onCreate(@NonNull SupportSQLiteDatabase db) {
@@ -434,6 +453,7 @@ public abstract class DeckDatabase extends RoomDatabase {
lastSyncPref.apply();
}
})
+ .addMigrations(MIGRATION_22_23)
.fallbackToDestructiveMigration()
.addCallback(ON_CREATE_CALLBACK)
.build();
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/util/WrappedLiveData.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/util/WrappedLiveData.java
index 038fcbad8..003bceb26 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/util/WrappedLiveData.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/util/WrappedLiveData.java
@@ -1,5 +1,6 @@
package it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.MutableLiveData;
@@ -28,10 +29,13 @@ public class WrappedLiveData<T> extends MutableLiveData<T> {
}
public void postError(@Nullable Throwable error) {
+ postError(error, null);
+ }
+ public void postError(@Nullable Throwable error, @NonNull T locallyCreatedEntity) {
if (error == null) {
DeckLog.warn("Given error is null");
}
setError(error);
- postValue(null);
+ postValue(locallyCreatedEntity);
}
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/DataPropagationHelper.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/DataPropagationHelper.java
index 9590f5abd..782b6d951 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/DataPropagationHelper.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/DataPropagationHelper.java
@@ -34,27 +34,31 @@ public class DataPropagationHelper {
entity.setLocalId(newID);
boolean connected = serverAdapter.hasInternetConnection();
if (connected) {
- provider.createOnServer(serverAdapter, dataBaseAdapter, accountId, new IResponseCallback<T>(new Account(accountId)) {
- @Override
- public void onResponse(T response) {
- new Thread(() -> {
- response.setAccountId(accountId);
- response.setLocalId(newID);
- if (actionOnResponse!= null) {
- actionOnResponse.onResponse(entity, response);
- }
- response.setStatus(DBStatus.UP_TO_DATE.getId());
- provider.updateInDB(dataBaseAdapter, accountId, response, false);
- callback.onResponse(response);
- }).start();
- }
+ try {
+ provider.createOnServer(serverAdapter, dataBaseAdapter, accountId, new IResponseCallback<T>(new Account(accountId)) {
+ @Override
+ public void onResponse(T response) {
+ new Thread(() -> {
+ response.setAccountId(accountId);
+ response.setLocalId(newID);
+ if (actionOnResponse != null) {
+ actionOnResponse.onResponse(entity, response);
+ }
+ response.setStatus(DBStatus.UP_TO_DATE.getId());
+ provider.updateInDB(dataBaseAdapter, accountId, response, false);
+ callback.onResponse(response);
+ }).start();
+ }
- @Override
- public void onError(Throwable throwable) {
- super.onError(throwable);
- new Thread(() -> callback.onError(throwable)).start();
- }
- }, entity);
+ @Override
+ public void onError(Throwable throwable) {
+ super.onError(throwable);
+ new Thread(() -> callback.onError(throwable, entity)).start();
+ }
+ }, entity);
+ } catch (Throwable t) {
+ callback.onError(t, entity);
+ }
} else {
callback.onResponse(entity);
}
@@ -71,24 +75,28 @@ public class DataPropagationHelper {
}
boolean connected = serverAdapter.hasInternetConnection();
if (entity.getId() != null && connected) {
- provider.updateOnServer(serverAdapter, dataBaseAdapter, accountId, new IResponseCallback<T>(new Account(accountId)) {
- @Override
- public void onResponse(T response) {
- new Thread(() -> {
- entity.setStatus(DBStatus.UP_TO_DATE.getId());
- provider.updateInDB(dataBaseAdapter, accountId, entity, false);
- callback.onResponse(entity);
- }).start();
- }
+ try {
+ provider.updateOnServer(serverAdapter, dataBaseAdapter, accountId, new IResponseCallback<T>(new Account(accountId)) {
+ @Override
+ public void onResponse(T response) {
+ new Thread(() -> {
+ entity.setStatus(DBStatus.UP_TO_DATE.getId());
+ provider.updateInDB(dataBaseAdapter, accountId, entity, false);
+ callback.onResponse(entity);
+ }).start();
+ }
- @Override
- public void onError(Throwable throwable) {
- super.onError(throwable);
- new Thread(() -> {
- callback.onError(throwable);
- }).start();
- }
- }, entity);
+ @Override
+ public void onError(Throwable throwable) {
+ super.onError(throwable);
+ new Thread(() -> {
+ callback.onError(throwable, entity);
+ }).start();
+ }
+ }, entity);
+ } catch (Throwable t) {
+ callback.onError(t, entity);
+ }
} else {
callback.onResponse(entity);
}
@@ -98,23 +106,28 @@ public class DataPropagationHelper {
provider.deleteInDB(dataBaseAdapter, accountId, entity);
boolean connected = serverAdapter.hasInternetConnection();
if (entity.getId() != null && connected) {
- provider.deleteOnServer(serverAdapter, accountId, new IResponseCallback<Void>(new Account(accountId)) {
- @Override
- public void onResponse(Void response) {
- new Thread(() -> {
- provider.deletePhysicallyInDB(dataBaseAdapter, accountId, entity);
- callback.onResponse(null);
- }).start();
- }
+ try {
+ provider.deleteOnServer(serverAdapter, accountId, new IResponseCallback<Void>(new Account(accountId)) {
+ @Override
+ public void onResponse(Void response) {
+ new Thread(() -> {
+ provider.deletePhysicallyInDB(dataBaseAdapter, accountId, entity);
+ callback.onResponse(null);
+ }).start();
+ }
+
+ @Override
+ public void onError(Throwable throwable) {
+ super.onError(throwable);
+ new Thread(() -> {
+ callback.onError(throwable);
+ }).start();
+ }
+ }, entity, dataBaseAdapter);
+ } catch (Throwable t) {
+ callback.onError(t);
+ }
- @Override
- public void onError(Throwable throwable) {
- super.onError(throwable);
- new Thread(() -> {
- callback.onError(throwable);
- }).start();
- }
- }, entity, dataBaseAdapter);
} else {
callback.onResponse(null);
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/SyncHelper.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/SyncHelper.java
index 032c3594a..17c0de2cf 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/SyncHelper.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/SyncHelper.java
@@ -1,5 +1,11 @@
package it.niedermann.nextcloud.deck.persistence.sync.helpers;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException;
+
+import java.net.HttpURLConnection;
import java.time.Instant;
import java.util.List;
import java.util.concurrent.CountDownLatch;
@@ -29,7 +35,7 @@ public class SyncHelper {
}
// Sync Server -> App
- public <T extends IRemoteEntity> void doSyncFor(final AbstractSyncDataProvider<T> provider) {
+ public <T extends IRemoteEntity> void doSyncFor(@NonNull final AbstractSyncDataProvider<T> provider) {
provider.registerChildInParent(provider);
provider.getAllFromServer(serverAdapter, dataBaseAdapter, accountId, new IResponseCallback<List<T>>(account) {
@Override
@@ -50,12 +56,13 @@ public class SyncHelper {
} else {
//TODO: how to handle deletes? what about archived?
if (existingEntity.getStatus() != DBStatus.UP_TO_DATE.getId()) {
- DeckLog.log("Conflicting changes on entity: " + existingEntity);
+ DeckLog.warn("Conflicting changes on entity: " + existingEntity);
// TODO: what to do?
} else {
-// if (existingEntity.getLastModified().getTime() == entityFromServer.getLastModified().getTime()) {
-// continue; // TODO: is this is ok for sure? -> isn`t! NPE
-// }
+ if (entityFromServer.getEtag() != null && entityFromServer.getEtag().equals(existingEntity.getEtag())) {
+ DeckLog.log("[" + provider.getClass().getSimpleName() + "] ETags do match! skipping " + existingEntity.getClass().getSimpleName() + " with localId: " + existingEntity.getLocalId());
+ continue;
+ }
provider.updateInDB(dataBaseAdapter, accountId, applyUpdatesFromRemote(provider, existingEntity, entityFromServer, accountId), false);
}
}
@@ -73,20 +80,29 @@ public class SyncHelper {
@Override
public void onError(Throwable throwable) {
+ super.onError(throwable);
+ if (throwable.getClass() == NextcloudHttpRequestFailedException.class) {
+ NextcloudHttpRequestFailedException requestFailedException = (NextcloudHttpRequestFailedException) throwable;
+ if (HttpURLConnection.HTTP_NOT_MODIFIED == requestFailedException.getStatusCode()){
+ DeckLog.log("[" + provider.getClass().getSimpleName() + "] ETags do match! skipping this one.");
+ // well, etags say we're fine here. no need to go deeper.
+ provider.childDone(provider, responseCallback, false);
+ return;
+ }
+ }
provider.onError(throwable, responseCallback);
- DeckLog.logError(throwable);
responseCallback.onError(throwable);
}
}, lastSync);
}
// Sync App -> Server
- public <T extends IRemoteEntity> void doUpSyncFor(AbstractSyncDataProvider<T> provider) {
+ public <T extends IRemoteEntity> void doUpSyncFor(@NonNull AbstractSyncDataProvider<T> provider) {
doUpSyncFor(provider, null);
}
- public <T extends IRemoteEntity> void doUpSyncFor(AbstractSyncDataProvider<T> provider, CountDownLatch countDownLatch) {
- List<T> allFromDB = provider.getAllChangedFromDB(dataBaseAdapter, accountId, lastSync);
+ public <T extends IRemoteEntity> void doUpSyncFor(@NonNull AbstractSyncDataProvider<T> provider, @Nullable CountDownLatch countDownLatch) {
+ final List<T> allFromDB = provider.getAllChangedFromDB(dataBaseAdapter, accountId, lastSync);
if (allFromDB != null && !allFromDB.isEmpty()) {
for (T entity : allFromDB) {
if (entity.getId() != null) {
@@ -110,7 +126,7 @@ public class SyncHelper {
}
}
- private <T extends IRemoteEntity> IResponseCallback<Void> getDeleteCallback(AbstractSyncDataProvider<T> provider, T entity) {
+ private <T extends IRemoteEntity> IResponseCallback<Void> getDeleteCallback(@NonNull AbstractSyncDataProvider<T> provider, T entity) {
return new IResponseCallback<Void>(account) {
@Override
public void onResponse(Void response) {
@@ -126,7 +142,7 @@ public class SyncHelper {
};
}
- private <T extends IRemoteEntity> IResponseCallback<T> getUpdateCallback(AbstractSyncDataProvider<T> provider, T entity, CountDownLatch countDownLatch) {
+ private <T extends IRemoteEntity> IResponseCallback<T> getUpdateCallback(@NonNull AbstractSyncDataProvider<T> provider, @NonNull T entity, @Nullable CountDownLatch countDownLatch) {
return new IResponseCallback<T>(account) {
@Override
public void onResponse(T response) {
@@ -152,13 +168,13 @@ public class SyncHelper {
};
}
- public void fixRelations(IRelationshipProvider relationshipProvider) {
+ public void fixRelations(@NonNull IRelationshipProvider relationshipProvider) {
// this is OK, since the delete only affects records with status UP_TO_DATE
relationshipProvider.deleteAllExisting(dataBaseAdapter, accountId);
relationshipProvider.insertAllNecessary(dataBaseAdapter, accountId);
}
- private <T extends IRemoteEntity> T applyUpdatesFromRemote(AbstractSyncDataProvider<T> provider, T localEntity, T remoteEntity, Long accountId) {
+ private <T extends IRemoteEntity> T applyUpdatesFromRemote(@NonNull AbstractSyncDataProvider<T> provider, @NonNull T localEntity, @NonNull T remoteEntity, @NonNull Long accountId) {
if (!accountId.equals(localEntity.getAccountId())) {
throw new IllegalArgumentException("IDs of Accounts are not matching! WTF are you doin?!");
}
@@ -167,7 +183,7 @@ public class SyncHelper {
return remoteEntity;
}
- public SyncHelper setResponseCallback(IResponseCallback<Boolean> callback) {
+ public SyncHelper setResponseCallback(@NonNull IResponseCallback<Boolean> callback) {
this.responseCallback = callback;
this.account = responseCallback.getAccount();
accountId = account.getId();
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/BoardDataProvider.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/BoardDataProvider.java
index 5b458471f..f5e071adb 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/BoardDataProvider.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/BoardDataProvider.java
@@ -1,5 +1,9 @@
package it.niedermann.nextcloud.deck.persistence.sync.helpers.providers;
+import android.annotation.SuppressLint;
+
+import com.nextcloud.android.sso.api.ParsedResponse;
+
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
@@ -26,8 +30,24 @@ public class BoardDataProvider extends AbstractSyncDataProvider<FullBoard> {
}
@Override
- public void getAllFromServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<List<FullBoard>> responder, Instant lastSync) {
- serverAdapter.getBoards(responder);
+ public void getAllFromServer(ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, long accountId, IResponseCallback<List<FullBoard>> responder, Instant lastSync) {
+ serverAdapter.getBoards(new IResponseCallback<ParsedResponse<List<FullBoard>>>(responder.getAccount()) {
+ @Override
+ public void onResponse(ParsedResponse<List<FullBoard>> response) {
+ String etag = response.getHeaders().get("ETag");
+ if (etag != null && !etag.equals(account.getBoardsEtag())) {
+ account.setBoardsEtag(etag);
+ dataBaseAdapter.updateAccount(account);
+ }
+ responder.onResponse(response.getResponse());
+ }
+
+ @SuppressLint("MissingSuperCall")
+ @Override
+ public void onError(Throwable throwable) {
+ responder.onError(throwable);
+ }
+ });
}
@Override
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/CardDataProvider.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/CardDataProvider.java
index 15b8b2b74..0ceac2cd8 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/CardDataProvider.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/CardDataProvider.java
@@ -1,5 +1,7 @@
package it.niedermann.nextcloud.deck.persistence.sync.helpers.providers;
+import android.annotation.SuppressLint;
+
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
@@ -7,6 +9,7 @@ import java.util.List;
import it.niedermann.nextcloud.deck.DeckLog;
import it.niedermann.nextcloud.deck.api.IResponseCallback;
+import it.niedermann.nextcloud.deck.exceptions.DeckException;
import it.niedermann.nextcloud.deck.exceptions.OfflineException;
import it.niedermann.nextcloud.deck.model.Account;
import it.niedermann.nextcloud.deck.model.Attachment;
@@ -54,6 +57,7 @@ public class CardDataProvider extends AbstractSyncDataProvider<FullCard> {
}
}
+ @SuppressLint("MissingSuperCall")
@Override
public void onError(Throwable throwable) {
responder.onError(throwable);
@@ -149,10 +153,14 @@ public class CardDataProvider extends AbstractSyncDataProvider<FullCard> {
@Override
public void createOnServer(ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, long accountId, IResponseCallback<FullCard> responder, FullCard entity) {
+ if (stack.getId() == null) {
+ responder.onError(new DeckException(DeckException.Hint.DEPENDENCY_NOT_SYNCED_YET, "Stack \"" +
+ stack.getStack().getTitle() + "\" for Card \"" + entity.getCard().getTitle() +
+ "\" is not synced yet. Perform a full sync (pull to refresh) as soon as you are online again."));
+ return;
+ }
entity.getCard().setStackId(stack.getId());
-// if (board != null && stack != null && board.getId() != null && stack.getId() != null) {
serverAdapter.createCard(board.getId(), stack.getId(), entity.getCard(), responder);
-// } else DeckLog.error("Skipped card creation due to missing remote ID");
}
@Override
@@ -323,6 +331,7 @@ public class CardDataProvider extends AbstractSyncDataProvider<FullCard> {
// do not delete, it's still there and was just moved!
}
+ @SuppressLint("MissingSuperCall")
@Override
public void onError(Throwable throwable) {
if (!(throwable instanceof OfflineException)) {
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/StackDataProvider.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/StackDataProvider.java
index 6a8e1f227..93761d616 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/StackDataProvider.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/StackDataProvider.java
@@ -7,6 +7,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;
import it.niedermann.nextcloud.deck.api.IResponseCallback;
+import it.niedermann.nextcloud.deck.exceptions.DeckException;
import it.niedermann.nextcloud.deck.model.Board;
import it.niedermann.nextcloud.deck.model.Card;
import it.niedermann.nextcloud.deck.model.full.FullBoard;
@@ -74,6 +75,9 @@ public class StackDataProvider extends AbstractSyncDataProvider<FullStack> {
@Override
public void createOnServer(ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, long accountId, IResponseCallback<FullStack> responder, FullStack entity) {
+ if (board.getId() == null) {
+ throw new DeckException(DeckException.Hint.DEPENDENCY_NOT_SYNCED_YET, "Board for this stack is not synced yet. Perform a full sync (pull to referesh) as soon as you are online again.");
+ }
entity.getStack().setBoardId(board.getId());
serverAdapter.createStack(board.getBoard(), entity.getStack(), responder);
}
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 91c08ffad..5056985fa 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
@@ -470,21 +470,23 @@ public class MainActivity extends BrandedActivity implements DeleteStackListener
}
@Override
- public void onCreateBoard(String title, String color) {
+ public void onCreateBoard(String title, @ColorInt int color) {
if (boardsLiveData == null || boardsLiveDataObserver == null) {
throw new IllegalStateException("Cannot create board when noone observe boards yet. boardsLiveData or observer is null.");
}
boardsLiveData.removeObserver(boardsLiveDataObserver);
- final Board boardToCreate = new Board(title, color.startsWith("#") ? color.substring(1) : color);
+ final Board boardToCreate = new Board(title, color);
boardToCreate.setPermissionEdit(true);
boardToCreate.setPermissionManage(true);
- observeOnce(syncManager.createBoard(mainViewModel.getCurrentAccount().getId(), boardToCreate), this, createdBoard -> {
- if (createdBoard == null) {
- BrandedSnackbar.make(binding.coordinatorLayout, "Open Deck in web interface first!", Snackbar.LENGTH_LONG)
- // TODO implement action!
- // .setAction(R.string.simple_open, v -> ExceptionDialogFragment.newInstance(throwable).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()))
+
+ final WrappedLiveData<FullBoard> createLiveData = syncManager.createBoard(mainViewModel.getCurrentAccount().getId(), boardToCreate);
+ observeOnce(createLiveData, this, (createdBoard) -> {
+ if (createLiveData.hasError()) {
+ BrandedSnackbar.make(binding.coordinatorLayout, R.string.synchronization_failed, Snackbar.LENGTH_LONG)
+ .setAction(R.string.simple_more, v -> ExceptionDialogFragment.newInstance(createLiveData.getError(), mainViewModel.getCurrentAccount()).show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()))
.show();
- } else {
+ }
+ if (createdBoard != null && !createLiveData.hasError()) {
boardsList.add(createdBoard.getBoard());
setCurrentBoard(createdBoard.getBoard());
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedboards/ArchivedBoardViewHolder.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedboards/ArchivedBoardViewHolder.java
index 67b2c00be..30f1e5d49 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedboards/ArchivedBoardViewHolder.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/archivedboards/ArchivedBoardViewHolder.java
@@ -6,6 +6,7 @@ import android.view.MenuItem;
import android.view.View;
import androidx.appcompat.widget.PopupMenu;
+import androidx.core.content.ContextCompat;
import androidx.core.util.Consumer;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -30,14 +31,13 @@ public class ArchivedBoardViewHolder extends RecyclerView.ViewHolder {
void bind(boolean isSupportedVersion, Board board, FragmentManager fragmentManager, Consumer<Board> dearchiveBoardListener) {
final Context context = itemView.getContext();
- binding.boardIcon.setImageDrawable(ViewUtil.getTintedImageView(binding.boardIcon.getContext(), R.drawable.circle_grey600_36dp, String.format("#%06X", (0xFFFFFF & board.getColor()))));
+ binding.boardIcon.setImageDrawable(ViewUtil.getTintedImageView(binding.boardIcon.getContext(), R.drawable.circle_grey600_36dp, board.getColor()));
binding.boardMenu.setVisibility(View.GONE);
binding.boardTitle.setText(board.getTitle());
if (isSupportedVersion) {
if (board.isPermissionManage()) {
binding.boardMenu.setVisibility(View.VISIBLE);
- binding.boardMenu.setImageDrawable(ViewUtil.getTintedImageView(context, R.drawable.ic_menu, R.color.grey600));
-
+ binding.boardMenu.setImageDrawable(ViewUtil.getTintedImageView(context, R.drawable.ic_menu, ContextCompat.getColor(context, R.color.grey600)));
binding.boardMenu.setOnClickListener((v) -> {
PopupMenu popup = new PopupMenu(context, binding.boardMenu);
popup.getMenuInflater().inflate(R.menu.archived_board_menu, popup.getMenu());
@@ -47,28 +47,27 @@ public class ArchivedBoardViewHolder extends RecyclerView.ViewHolder {
}
popup.setOnMenuItemClickListener((MenuItem item) -> {
final String editBoard = context.getString(R.string.edit_board);
- switch (item.getItemId()) {
- case SHARE_BOARD_ID:
- AccessControlDialogFragment.newInstance(board.getLocalId()).show(fragmentManager, AccessControlDialogFragment.class.getSimpleName());
- return true;
- case R.id.edit_board:
- EditBoardDialogFragment.newInstance(board.getLocalId()).show(fragmentManager, editBoard);
- return true;
- case R.id.dearchive_board:
- dearchiveBoardListener.accept(board);
- return true;
- case R.id.delete_board:
- DeleteBoardDialogFragment.newInstance(board).show(fragmentManager, DeleteBoardDialogFragment.class.getSimpleName());
- return true;
- default:
- return false;
+ int itemId = item.getItemId();
+ if (itemId == SHARE_BOARD_ID) {
+ AccessControlDialogFragment.newInstance(board.getLocalId()).show(fragmentManager, AccessControlDialogFragment.class.getSimpleName());
+ return true;
+ } else if (itemId == R.id.edit_board) {
+ EditBoardDialogFragment.newInstance(board.getLocalId()).show(fragmentManager, editBoard);
+ return true;
+ } else if (itemId == R.id.dearchive_board) {
+ dearchiveBoardListener.accept(board);
+ return true;
+ } else if (itemId == R.id.delete_board) {
+ DeleteBoardDialogFragment.newInstance(board).show(fragmentManager, DeleteBoardDialogFragment.class.getSimpleName());
+ return true;
}
+ return false;
});
popup.show();
});
} else if (board.isPermissionShare()) {
binding.boardMenu.setVisibility(View.VISIBLE);
- binding.boardMenu.setImageDrawable(ViewUtil.getTintedImageView(context, R.drawable.ic_share_grey600_18dp, R.color.grey600));
+ binding.boardMenu.setImageDrawable(ViewUtil.getTintedImageView(context, R.drawable.ic_share_grey600_18dp, ContextCompat.getColor(context, R.color.grey600)));
binding.boardMenu.setOnClickListener((v) -> AccessControlDialogFragment.newInstance(board.getLocalId()).show(fragmentManager, AccessControlDialogFragment.class.getSimpleName()));
}
binding.boardMenu.setVisibility(View.VISIBLE);
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/BoardAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/BoardAdapter.java
index 5975e0306..c9501ffa9 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/BoardAdapter.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/BoardAdapter.java
@@ -37,7 +37,7 @@ public class BoardAdapter extends ArrayAdapter<Board> {
TextView boardName = convertView.findViewById(R.id.boardName);
if (board != null) {
boardName.setText(board.getTitle());
- boardName.setCompoundDrawables(ViewUtil.getTintedImageView(context, R.drawable.circle_grey600_36dp, String.format("#%06X", (0xFFFFFF & board.getColor()))), null, null, null);
+ boardName.setCompoundDrawables(ViewUtil.getTintedImageView(context, R.drawable.circle_grey600_36dp, board.getColor()), null, null, null);
} else {
DeckLog.logError(new IllegalArgumentException("board at position " + position + "is null"));
}
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 e197727d5..1ee23abfa 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
@@ -56,7 +56,7 @@ public class EditBoardDialogFragment extends BrandedDialogFragment {
dialogBuilder.setPositiveButton(R.string.simple_save, (dialog, which) -> {
this.fullBoard.board.setColor(binding.colorChooser.getSelectedColor());
this.fullBoard.board.setTitle(binding.input.getText().toString());
- editBoardListener.onUpdateBoard(fullBoard);
+ this.editBoardListener.onUpdateBoard(fullBoard);
});
final MainViewModel viewModel = new ViewModelProvider(requireActivity()).get(MainViewModel.class);
new SyncManager(requireActivity()).getFullBoardById(viewModel.getCurrentAccount().getId(), args.getLong(KEY_BOARD_ID)).observe(EditBoardDialogFragment.this, (FullBoard fb) -> {
@@ -65,13 +65,13 @@ public class EditBoardDialogFragment extends BrandedDialogFragment {
String title = this.fullBoard.getBoard().getTitle();
binding.input.setText(title);
binding.input.setSelection(title.length());
- binding.colorChooser.selectColor(String.format("#%06X", (0xFFFFFF & fullBoard.getBoard().getColor())));
+ binding.colorChooser.selectColor(fullBoard.getBoard().getColor());
}
});
} else {
dialogBuilder.setTitle(R.string.add_board);
dialogBuilder.setPositiveButton(R.string.simple_add, (dialog, which) -> editBoardListener.onCreateBoard(binding.input.getText().toString(), binding.colorChooser.getSelectedColor()));
- binding.colorChooser.selectColor(String.format("#%06X", 0xFFFFFF & ContextCompat.getColor(requireContext(), R.color.board_default_color)));
+ binding.colorChooser.selectColor(ContextCompat.getColor(requireContext(), R.color.board_default_color));
}
return dialogBuilder
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/EditBoardListener.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/EditBoardListener.java
index ee9ba9b9d..9d8fcdbde 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/EditBoardListener.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/board/EditBoardListener.java
@@ -1,11 +1,13 @@
package it.niedermann.nextcloud.deck.ui.board;
+import androidx.annotation.ColorInt;
+
import it.niedermann.nextcloud.deck.model.full.FullBoard;
public interface EditBoardListener {
void onUpdateBoard(FullBoard fullBoard);
- default void onCreateBoard(String title, String color) {
+ default void onCreateBoard(String title, @ColorInt int color) {
// Creating board is not necessary
}
} \ No newline at end of file
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 a0fb4cadd..2dacfe6ac 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
@@ -65,7 +65,7 @@ public class EditLabelDialogFragment extends BrandedDialogFragment {
String title = this.label.getTitle();
binding.input.setText(title);
binding.input.setSelection(title.length());
- binding.colorChooser.selectColor(String.format("#%06X", (0xFFFFFF & this.label.getColor())));
+ binding.colorChooser.selectColor(this.label.getColor());
return dialogBuilder
.setView(binding.getRoot())
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/BoardAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/BoardAdapter.java
index 558a22db4..c27fa04ee 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/BoardAdapter.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/preparecreate/BoardAdapter.java
@@ -37,7 +37,7 @@ public class BoardAdapter extends AbstractAdapter<Board> {
final Board item = getItem(position);
if (item != null) {
binding.boardTitle.setText(item.getTitle());
- binding.avatar.setImageDrawable(ViewUtil.getTintedImageView(binding.avatar.getContext(), R.drawable.circle_grey600_36dp, String.format("#%06X", (0xFFFFFF & item.getColor()))));
+ binding.avatar.setImageDrawable(ViewUtil.getTintedImageView(binding.avatar.getContext(), R.drawable.circle_grey600_36dp, item.getColor()));
} else {
DeckLog.logError(new IllegalArgumentException("No item for position " + position));
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/view/ColorChooser.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/view/ColorChooser.java
index c82f47c9c..0dd431ff9 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/view/ColorChooser.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/view/ColorChooser.java
@@ -2,6 +2,7 @@ package it.niedermann.nextcloud.deck.ui.view;
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.Color;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
@@ -9,11 +10,15 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
+import androidx.annotation.ColorInt;
import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
import com.google.android.flexbox.FlexboxLayout;
import com.skydoves.colorpickerview.listeners.ColorEnvelopeListener;
+import java.util.Arrays;
+
import it.niedermann.android.util.DimensionUtil;
import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.databinding.WidgetColorChooserBinding;
@@ -24,10 +29,12 @@ public class ColorChooser extends LinearLayout {
private final WidgetColorChooserBinding binding;
private final Context context;
- private final String[] colors;
+ private final int[] colors;
- private String selectedColor;
- private String previouslySelectedColor;
+ @ColorInt
+ private int selectedColor;
+ @ColorInt
+ private int previouslySelectedColor;
@Nullable
private ImageView previouslySelectedImageView;
@@ -42,14 +49,15 @@ public class ColorChooser extends LinearLayout {
params.setMargins(0, DimensionUtil.INSTANCE.dpToPx(context, R.dimen.spacer_1x), 0, 0);
params.setFlexBasisPercent(.15f);
- TypedArray a = context.obtainStyledAttributes(attrs,
- R.styleable.ColorChooser, 0, 0);
- colors = getResources().getStringArray(a.getResourceId(R.styleable.ColorChooser_colors, 0));
+ final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ColorChooser, 0, 0);
+ colors = Arrays.stream(getResources().getStringArray(a.getResourceId(R.styleable.ColorChooser_colors, 0)))
+ .mapToInt(Color::parseColor)
+ .toArray();
a.recycle();
binding = WidgetColorChooserBinding.inflate(LayoutInflater.from(context), this, true);
- for (final String color : colors) {
- ImageView image = new ImageView(getContext());
+ for (final int color : colors) {
+ final ImageView image = new ImageView(getContext());
image.setLayoutParams(params);
image.setOnClickListener((imageView) -> {
if (previouslySelectedImageView != null) { // null when first selection
@@ -59,7 +67,7 @@ public class ColorChooser extends LinearLayout {
selectedColor = color;
this.previouslySelectedColor = color;
this.previouslySelectedImageView = image;
- binding.customColorChooser.setImageDrawable(ViewUtil.getTintedImageView(this.context, R.drawable.circle_alpha_colorize_36dp, R.color.board_default_custom_color));
+ binding.customColorChooser.setImageDrawable(ViewUtil.getTintedImageView(this.context, R.drawable.circle_alpha_colorize_36dp, ContextCompat.getColor(context, R.color.board_default_custom_color)));
binding.customColorPicker.setVisibility(View.GONE);
binding.brightnessSlide.setVisibility(View.GONE);
});
@@ -82,19 +90,20 @@ public class ColorChooser extends LinearLayout {
previouslySelectedImageView.setImageDrawable(ViewUtil.getTintedImageView(this.context, R.drawable.circle_grey600_36dp, previouslySelectedColor));
previouslySelectedImageView = null;
}
- String customColor = "#" + envelope.getHexCode().substring(2);
+ @ColorInt
+ final int customColor = envelope.getColor();
selectedColor = customColor;
previouslySelectedColor = customColor;
binding.customColorChooser.setImageDrawable(ViewUtil.getTintedImageView(context, R.drawable.circle_alpha_colorize_36dp, selectedColor));
});
}
- public void selectColor(String newColor) {
+ public void selectColor(@ColorInt int newColor) {
boolean newColorIsCustomColor = true;
selectedColor = newColor;
for (int i = 0; i < colors.length; i++) {
- if (colors[i].equals(newColor)) {
- binding.customColorChooser.setImageDrawable(ViewUtil.getTintedImageView(this.context, R.drawable.circle_alpha_colorize_36dp, R.color.board_default_custom_color));
+ if (colors[i] == newColor) {
+ binding.customColorChooser.setImageDrawable(ViewUtil.getTintedImageView(this.context, R.drawable.circle_alpha_colorize_36dp, ContextCompat.getColor(context, R.color.board_default_custom_color)));
binding.colorPicker.getChildAt(i).performClick();
newColorIsCustomColor = false;
break;
@@ -105,7 +114,8 @@ public class ColorChooser extends LinearLayout {
}
}
- public String getSelectedColor() {
+ @ColorInt
+ public int getSelectedColor() {
return this.selectedColor;
}
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/stack/StackWidgetConfigurationActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/stack/StackWidgetConfigurationActivity.java
index 6b86b50ba..771feabc2 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/stack/StackWidgetConfigurationActivity.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/widget/stack/StackWidgetConfigurationActivity.java
@@ -7,6 +7,7 @@ import android.os.Bundle;
import androidx.appcompat.app.ActionBar;
import it.niedermann.nextcloud.deck.DeckLog;
+import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.model.Account;
import it.niedermann.nextcloud.deck.ui.PickStackActivity;
@@ -18,7 +19,7 @@ public class StackWidgetConfigurationActivity extends PickStackActivity {
super.onCreate(savedInstanceState);
final ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
- actionBar.setTitle("Add stack widget");
+ actionBar.setTitle(R.string.add_stack_widget);
}
setResult(RESULT_CANCELED);
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/util/DrawerMenuUtil.java b/app/src/main/java/it/niedermann/nextcloud/deck/util/DrawerMenuUtil.java
index 1f6490bf2..1a88bec97 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/util/DrawerMenuUtil.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/util/DrawerMenuUtil.java
@@ -7,6 +7,7 @@ import android.view.SubMenu;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatImageButton;
import androidx.appcompat.widget.PopupMenu;
+import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentActivity;
import java.util.List;
@@ -38,12 +39,12 @@ public class DrawerMenuUtil {
SubMenu boardsMenu = menu.addSubMenu(R.string.simple_boards);
int index = 0;
for (Board board : boards) {
- MenuItem m = boardsMenu.add(Menu.NONE, index++, Menu.NONE, board.getTitle()).setIcon(ViewUtil.getTintedImageView(context, R.drawable.circle_grey600_36dp, String.format("#%06X", (0xFFFFFF & board.getColor()))));
+ MenuItem m = boardsMenu.add(Menu.NONE, index++, Menu.NONE, board.getTitle()).setIcon(ViewUtil.getTintedImageView(context, R.drawable.circle_grey600_36dp, board.getColor()));
if (currentServerVersionIsSupported) {
if (board.isPermissionManage()) {
AppCompatImageButton contextMenu = new AppCompatImageButton(context);
contextMenu.setBackgroundDrawable(null);
- contextMenu.setImageDrawable(ViewUtil.getTintedImageView(context, R.drawable.ic_menu, R.color.grey600));
+ contextMenu.setImageDrawable(ViewUtil.getTintedImageView(context, R.drawable.ic_menu, ContextCompat.getColor(context, R.color.grey600)));
contextMenu.setOnClickListener((v) -> {
PopupMenu popup = new PopupMenu(context, contextMenu);
popup.getMenuInflater().inflate(R.menu.navigation_context_menu, popup.getMenu());
@@ -53,28 +54,27 @@ public class DrawerMenuUtil {
}
popup.setOnMenuItemClickListener((MenuItem item) -> {
final String editBoard = context.getString(R.string.edit_board);
- switch (item.getItemId()) {
- case SHARE_BOARD_ID:
- AccessControlDialogFragment.newInstance(board.getLocalId()).show(context.getSupportFragmentManager(), AccessControlDialogFragment.class.getSimpleName());
- return true;
- case R.id.edit_board:
- EditBoardDialogFragment.newInstance(board.getLocalId()).show(context.getSupportFragmentManager(), editBoard);
- return true;
- case R.id.manage_labels:
- ManageLabelsDialogFragment.newInstance(board.getLocalId()).show(context.getSupportFragmentManager(), editBoard);
- return true;
- case R.id.clone_board:
- context.onClone(board);
- return true;
- case R.id.archive_board:
- context.onArchive(board);
- return true;
- case R.id.delete_board:
- DeleteBoardDialogFragment.newInstance(board).show(context.getSupportFragmentManager(), DeleteBoardDialogFragment.class.getCanonicalName());
- return true;
- default:
- return false;
+ int itemId = item.getItemId();
+ if (itemId == SHARE_BOARD_ID) {
+ AccessControlDialogFragment.newInstance(board.getLocalId()).show(context.getSupportFragmentManager(), AccessControlDialogFragment.class.getSimpleName());
+ return true;
+ } else if (itemId == R.id.edit_board) {
+ EditBoardDialogFragment.newInstance(board.getLocalId()).show(context.getSupportFragmentManager(), editBoard);
+ return true;
+ } else if (itemId == R.id.manage_labels) {
+ ManageLabelsDialogFragment.newInstance(board.getLocalId()).show(context.getSupportFragmentManager(), editBoard);
+ return true;
+ } else if (itemId == R.id.clone_board) {
+ context.onClone(board);
+ return true;
+ } else if (itemId == R.id.archive_board) {
+ context.onArchive(board);
+ return true;
+ } else if (itemId == R.id.delete_board) {
+ DeleteBoardDialogFragment.newInstance(board).show(context.getSupportFragmentManager(), DeleteBoardDialogFragment.class.getCanonicalName());
+ return true;
}
+ return false;
});
popup.show();
});
@@ -82,7 +82,7 @@ public class DrawerMenuUtil {
} else if (board.isPermissionShare()) {
AppCompatImageButton contextMenu = new AppCompatImageButton(context);
contextMenu.setBackgroundDrawable(null);
- contextMenu.setImageDrawable(ViewUtil.getTintedImageView(context, R.drawable.ic_share_grey600_18dp, R.color.grey600));
+ contextMenu.setImageDrawable(ViewUtil.getTintedImageView(context, R.drawable.ic_share_grey600_18dp, ContextCompat.getColor(context, R.color.grey600)));
contextMenu.setOnClickListener((v) -> AccessControlDialogFragment.newInstance(board.getLocalId()).show(context.getSupportFragmentManager(), AccessControlDialogFragment.class.getSimpleName()));
m.setActionView(contextMenu);
}
@@ -90,7 +90,7 @@ public class DrawerMenuUtil {
}
if (hasArchivedBoards) {
- boardsMenu.add(Menu.NONE, MENU_ID_ARCHIVED_BOARDS, Menu.NONE, R.string.archived_boards).setIcon(ViewUtil.getTintedImageView(context, R.drawable.ic_archive_white_24dp, R.color.grey600));
+ boardsMenu.add(Menu.NONE, MENU_ID_ARCHIVED_BOARDS, Menu.NONE, R.string.archived_boards).setIcon(ViewUtil.getTintedImageView(context, R.drawable.ic_archive_white_24dp, ContextCompat.getColor(context, R.color.grey600)));
}
if (currentServerVersionIsSupported) {
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/util/ProjectUtil.java b/app/src/main/java/it/niedermann/nextcloud/deck/util/ProjectUtil.java
index f43f7d824..58c465290 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/util/ProjectUtil.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/util/ProjectUtil.java
@@ -33,7 +33,7 @@ public class ProjectUtil {
/**
* extracts the values of board- and card-ID from url.
- * Depending on what kind of url it gets, it will return a long[] of lenght 1 or 2:
+ * Depending on what kind of url it gets, it will return a long[] of length 1 or 2:
* If the url contains both values, you'll get 2, if it contains only the board, you'll get 1.
* <p>
* The order is fixed here: [boardId, cardId]
@@ -50,7 +50,7 @@ public class ProjectUtil {
throw new IllegalArgumentException("trimmed url is empty");
}
// extract important part
- String[] splitByPrefix = url.split(".*index\\.php/apps/deck(/#)?/board/");
+ String[] splitByPrefix = url.split(".*(index\\.php/)?apps/deck(/#)?/board/");
// split into board- and card part
if (splitByPrefix.length < 2) {
throw new IllegalArgumentException("This URL doesn't seem to be an URL containing the boardId: \"" + url + "\"");
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 ffc06e33d..7319f7793 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
@@ -3,7 +3,6 @@ package it.niedermann.nextcloud.deck.util;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
-import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.text.Spannable;
@@ -12,6 +11,7 @@ import android.text.style.ImageSpan;
import android.widget.ImageView;
import android.widget.TextView;
+import androidx.annotation.ColorInt;
import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
@@ -81,18 +81,14 @@ public final class ViewUtil {
TextViewCompat.setCompoundDrawableTintList(cardDueDate, ColorStateList.valueOf(ContextCompat.getColor(context, textColor)));
}
- public static Drawable getTintedImageView(@NonNull Context context, @DrawableRes int imageId, @NonNull String color) {
+ public static Drawable getTintedImageView(@NonNull Context context, @DrawableRes int imageId, @ColorInt int color) {
final Drawable drawable = ContextCompat.getDrawable(context, imageId);
assert drawable != null;
final Drawable wrapped = DrawableCompat.wrap(drawable).mutate();
- DrawableCompat.setTint(wrapped, Color.parseColor(color));
+ DrawableCompat.setTint(wrapped, color);
return drawable;
}
- public static Drawable getTintedImageView(@NonNull Context context, @DrawableRes int imageId, int colorId) {
- return getTintedImageView(context, imageId, context.getResources().getString(colorId));
- }
-
/**
* Replaces all mentions in the textView with an avatar and the display name
*