From ec7897901127b11f70596b2af013633780d7f5db Mon Sep 17 00:00:00 2001 From: Jannis Mattheis Date: Fri, 2 Nov 2018 14:04:48 +0100 Subject: [PATCH] Add state holder for message activity --- .../messages/provider/ApplicationHolder.java | 54 ++++++++++++ .../messages/provider/MessageFacade.java | 71 +++++++++++++++ .../provider/MessageImageCombiner.java | 37 ++++++++ .../messages/provider/MessageRequester.java | 52 +++++++++++ .../messages/provider/MessageState.java | 16 ++++ .../messages/provider/MessageStateHolder.java | 88 +++++++++++++++++++ .../messages/provider/MessageWithImage.java | 8 ++ 7 files changed, 326 insertions(+) create mode 100644 app/src/main/java/com/github/gotify/messages/provider/ApplicationHolder.java create mode 100644 app/src/main/java/com/github/gotify/messages/provider/MessageFacade.java create mode 100644 app/src/main/java/com/github/gotify/messages/provider/MessageImageCombiner.java create mode 100644 app/src/main/java/com/github/gotify/messages/provider/MessageRequester.java create mode 100644 app/src/main/java/com/github/gotify/messages/provider/MessageState.java create mode 100644 app/src/main/java/com/github/gotify/messages/provider/MessageStateHolder.java create mode 100644 app/src/main/java/com/github/gotify/messages/provider/MessageWithImage.java diff --git a/app/src/main/java/com/github/gotify/messages/provider/ApplicationHolder.java b/app/src/main/java/com/github/gotify/messages/provider/ApplicationHolder.java new file mode 100644 index 0000000..697292a --- /dev/null +++ b/app/src/main/java/com/github/gotify/messages/provider/ApplicationHolder.java @@ -0,0 +1,54 @@ +package com.github.gotify.messages.provider; + +import android.app.Activity; + +import com.github.gotify.Utils; +import com.github.gotify.api.Api; +import com.github.gotify.client.ApiClient; +import com.github.gotify.client.ApiException; +import com.github.gotify.client.api.TokenApi; +import com.github.gotify.client.model.Application; + +import java.util.Collections; +import java.util.List; + +public class ApplicationHolder { + private List state; + private Runnable onUpdate; + private Activity activity; + private ApiClient client; + + public ApplicationHolder(Activity activity, ApiClient client) { + this.activity = activity; + this.client = client; + } + + public void requestIfMissing() { + if (state == null) { + request(); + } + } + + public void request() { + TokenApi tokenApi = new TokenApi(client); + Api.withLogging(tokenApi::getAppsAsync) + .handleInUIThread(activity, this::onReceiveApps, this::onFailedApps); + } + + private void onReceiveApps(List apps) { + state = apps; + onUpdate.run(); + } + + private void onFailedApps(ApiException e) { + Utils.showSnackBar(activity, "Could not request applications, see logs."); + } + + public List get() { + return state == null ? Collections.emptyList() : state; + } + + public void onUpdate(Runnable runnable) { + this.onUpdate = runnable; + } +} diff --git a/app/src/main/java/com/github/gotify/messages/provider/MessageFacade.java b/app/src/main/java/com/github/gotify/messages/provider/MessageFacade.java new file mode 100644 index 0000000..30873d3 --- /dev/null +++ b/app/src/main/java/com/github/gotify/messages/provider/MessageFacade.java @@ -0,0 +1,71 @@ +package com.github.gotify.messages.provider; + +import com.github.gotify.client.api.MessageApi; +import com.github.gotify.client.model.Message; +import com.github.gotify.client.model.PagedMessages; + +import java.util.List; + +public class MessageFacade { + private final ApplicationHolder applicationHolder; + private final MessageRequester requester; + private final MessageStateHolder state; + private final MessageImageCombiner combiner; + + public MessageFacade(MessageApi api, ApplicationHolder applicationHolder) { + this.applicationHolder = applicationHolder; + this.requester = new MessageRequester(api); + this.combiner = new MessageImageCombiner(); + this.state = new MessageStateHolder(); + } + + public List get(Integer appId) { + return combiner.combine(state.state(appId).messages, applicationHolder.get()); + } + + public void addMessages(List messages) { + for (Message message : messages) { + state.newMessage(message); + } + } + + public List loadMore(Integer appId) { + MessageState state = this.state.state(appId); + if (state.hasNext || !state.loaded) { + PagedMessages pagedMessages = requester.loadMore(state); + this.state.newMessages(appId, pagedMessages); + } + return get(appId); + } + + public List getOrLoadMore(Integer appId) { + MessageState state = this.state.state(appId); + if (state.loaded) { + return get(appId); + } + return loadMore(appId); + } + + public void clear() { + this.state.clear(); + } + + public int getLastReceivedMessage() { + return state.getLastReceivedMessage(); + } + + public void delete(Message message) { + this.requester.asyncRemoveMessage(message); + this.state.removeMessage(message); + } + + public boolean deleteAll(Integer appId) { + boolean success = this.requester.deleteAll(appId); + this.state.deleteAll(appId); + return success; + } + + public boolean canLoadMore(Integer appId) { + return state.state(appId).hasNext; + } +} diff --git a/app/src/main/java/com/github/gotify/messages/provider/MessageImageCombiner.java b/app/src/main/java/com/github/gotify/messages/provider/MessageImageCombiner.java new file mode 100644 index 0000000..b6fa9f7 --- /dev/null +++ b/app/src/main/java/com/github/gotify/messages/provider/MessageImageCombiner.java @@ -0,0 +1,37 @@ +package com.github.gotify.messages.provider; + +import com.github.gotify.client.model.Application; +import com.github.gotify.client.model.Message; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +class MessageImageCombiner { + + List combine(List messages, List applications) { + Map appIdToImage = appIdToImage(applications); + + List result = new ArrayList<>(); + + for (Message message : messages) { + MessageWithImage messageWithImage = new MessageWithImage(); + + messageWithImage.message = message; + messageWithImage.image = appIdToImage.get(message.getAppid()); + + result.add(messageWithImage); + } + + return result; + } + + private Map appIdToImage(List applications) { + Map map = new HashMap<>(); + for (Application app : applications) { + map.put(app.getId(), app.getImage()); + } + return map; + } +} diff --git a/app/src/main/java/com/github/gotify/messages/provider/MessageRequester.java b/app/src/main/java/com/github/gotify/messages/provider/MessageRequester.java new file mode 100644 index 0000000..db8e840 --- /dev/null +++ b/app/src/main/java/com/github/gotify/messages/provider/MessageRequester.java @@ -0,0 +1,52 @@ +package com.github.gotify.messages.provider; + +import com.github.gotify.api.Api; +import com.github.gotify.client.ApiException; +import com.github.gotify.client.api.MessageApi; +import com.github.gotify.client.model.Message; +import com.github.gotify.client.model.PagedMessages; +import com.github.gotify.log.Log; + +class MessageRequester { + private static final Integer LIMIT = 100; + private MessageApi messageApi; + + MessageRequester(MessageApi messageApi) { + this.messageApi = messageApi; + } + + PagedMessages loadMore(MessageState state) { + try { + Log.i("Loading more messages for " + state.appId); + if (MessageState.ALL_MESSAGES == state.appId) { + return messageApi.getMessages(LIMIT, state.nextSince); + } else { + return messageApi.getAppMessages(state.appId, LIMIT, state.nextSince); + } + } catch (ApiException apiException) { + Log.e("failed requesting messages", apiException); + return null; + } + } + + void asyncRemoveMessage(Message message) { + Log.i("Removing message with id " + message.getId()); + Api.withLogging((cb) -> messageApi.deleteMessageAsync(message.getId(), cb)) + .handle((a) -> {}, (e) -> {}); + } + + boolean deleteAll(Integer appId) { + try { + Log.i("Deleting all messages for " + appId); + if (MessageState.ALL_MESSAGES == appId) { + messageApi.deleteMessages(); + } else { + messageApi.deleteAppMessages(appId); + } + return true; + } catch (ApiException e) { + Log.e("Could not delete messages", e); + return false; + } + } +} diff --git a/app/src/main/java/com/github/gotify/messages/provider/MessageState.java b/app/src/main/java/com/github/gotify/messages/provider/MessageState.java new file mode 100644 index 0000000..607d5ae --- /dev/null +++ b/app/src/main/java/com/github/gotify/messages/provider/MessageState.java @@ -0,0 +1,16 @@ +package com.github.gotify.messages.provider; + +import com.github.gotify.client.model.Message; + +import java.util.ArrayList; +import java.util.List; + +public class MessageState { + public static final int ALL_MESSAGES = -1; + + int appId; + boolean loaded; + boolean hasNext; + int nextSince = 0; + List messages = new ArrayList<>(); +} diff --git a/app/src/main/java/com/github/gotify/messages/provider/MessageStateHolder.java b/app/src/main/java/com/github/gotify/messages/provider/MessageStateHolder.java new file mode 100644 index 0000000..348761d --- /dev/null +++ b/app/src/main/java/com/github/gotify/messages/provider/MessageStateHolder.java @@ -0,0 +1,88 @@ +package com.github.gotify.messages.provider; + +import com.github.gotify.client.model.Message; +import com.github.gotify.client.model.PagedMessages; + +import java.util.HashMap; +import java.util.Map; + +class MessageStateHolder { + private int lastReceivedMessage = -1; + private Map states = new HashMap<>(); + + synchronized void clear() { + states = new HashMap<>(); + } + + synchronized void newMessages(Integer appId, PagedMessages pagedMessages) { + MessageState state = state(appId); + + if (!state.loaded && pagedMessages.getMessages().size() > 0) { + lastReceivedMessage = + Math.max(pagedMessages.getMessages().get(0).getId(), lastReceivedMessage); + } + + state.loaded = true; + state.messages.addAll(pagedMessages.getMessages()); + state.hasNext = pagedMessages.getPaging().getNext() != null; + state.nextSince = pagedMessages.getPaging().getSince(); + state.appId = appId; + states.put(appId, state); + } + + synchronized void newMessage(Message message) { + MessageState allMessages = state(MessageState.ALL_MESSAGES); + MessageState appMessages = state(message.getAppid()); + + if (allMessages.loaded) { + allMessages.messages.add(0, message); + } + + if (appMessages.loaded) { + appMessages.messages.add(0, message); + } + + lastReceivedMessage = message.getId(); + } + + synchronized MessageState state(Integer appId) { + MessageState state = states.get(appId); + if (state == null) { + return emptyState(appId); + } + return state; + } + + void deleteAll(Integer appId) { + clear(); + MessageState state = state(appId); + state.loaded = true; + states.put(appId, state); + } + + private MessageState emptyState(Integer appId) { + MessageState emptyState = new MessageState(); + emptyState.loaded = false; + emptyState.hasNext = false; + emptyState.nextSince = 0; + emptyState.appId = appId; + return emptyState; + } + + synchronized int getLastReceivedMessage() { + return lastReceivedMessage; + } + + void removeMessage(Message message) { + MessageState allMessages = state(MessageState.ALL_MESSAGES); + MessageState appMessages = state(message.getAppid()); + + if (allMessages.loaded) { + allMessages.messages.remove(message); + } + + if (appMessages.loaded) { + appMessages.messages.remove(message); + } + } +} diff --git a/app/src/main/java/com/github/gotify/messages/provider/MessageWithImage.java b/app/src/main/java/com/github/gotify/messages/provider/MessageWithImage.java new file mode 100644 index 0000000..6a7ef47 --- /dev/null +++ b/app/src/main/java/com/github/gotify/messages/provider/MessageWithImage.java @@ -0,0 +1,8 @@ +package com.github.gotify.messages.provider; + +import com.github.gotify.client.model.Message; + +public class MessageWithImage { + public Message message; + public String image; +}