diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BaseController.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BaseController.java deleted file mode 100644 index 2e6115ced..000000000 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BaseController.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.briarproject.briar.android.blog; - -import org.briarproject.bramble.api.db.DbException; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.android.controller.handler.ExceptionHandler; -import org.briarproject.briar.android.controller.handler.ResultExceptionHandler; -import org.briarproject.briar.api.blog.BlogPostHeader; - -import java.util.List; - -import javax.annotation.Nullable; - -import androidx.annotation.UiThread; - -@NotNullByDefault -interface BaseController { - - @UiThread - void onStart(); - - @UiThread - void onStop(); - - void loadBlogPosts(GroupId g, - ResultExceptionHandler, DbException> handler); - - void loadBlogPost(BlogPostHeader header, - ResultExceptionHandler handler); - - void loadBlogPost(GroupId g, MessageId m, - ResultExceptionHandler handler); - - void repeatPost(BlogPostItem item, @Nullable String comment, - ExceptionHandler handler); - - @NotNullByDefault - interface BlogListener { - - @UiThread - void onBlogPostAdded(BlogPostHeader header, boolean local); - - @UiThread - void onBlogRemoved(); - } - -} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BaseControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BaseControllerImpl.java index 13f5e5193..d95a5c395 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BaseControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BaseControllerImpl.java @@ -1,61 +1,28 @@ package org.briarproject.briar.android.blog; import org.briarproject.bramble.api.db.DatabaseExecutor; -import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventListener; import org.briarproject.bramble.api.identity.IdentityManager; -import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; -import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.briar.android.controller.DbControllerImpl; -import org.briarproject.briar.android.controller.handler.ExceptionHandler; -import org.briarproject.briar.android.controller.handler.ResultExceptionHandler; import org.briarproject.briar.api.android.AndroidNotificationManager; -import org.briarproject.briar.api.blog.Blog; -import org.briarproject.briar.api.blog.BlogCommentHeader; import org.briarproject.briar.api.blog.BlogManager; -import org.briarproject.briar.api.blog.BlogPostHeader; -import org.briarproject.briar.util.HtmlUtils; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; -import java.util.logging.Logger; - -import javax.annotation.Nullable; - -import androidx.annotation.CallSuper; - -import static java.util.logging.Level.WARNING; -import static org.briarproject.bramble.util.LogUtils.logDuration; -import static org.briarproject.bramble.util.LogUtils.logException; -import static org.briarproject.bramble.util.LogUtils.now; -import static org.briarproject.briar.util.HtmlUtils.ARTICLE; @MethodsNotNullByDefault @ParametersNotNullByDefault abstract class BaseControllerImpl extends DbControllerImpl - implements BaseController, EventListener { - - private static final Logger LOG = - Logger.getLogger(BaseControllerImpl.class.getName()); + implements EventListener { protected final EventBus eventBus; protected final AndroidNotificationManager notificationManager; protected final IdentityManager identityManager; protected final BlogManager blogManager; - private final Map textCache = new ConcurrentHashMap<>(); - private final Map headerCache = - new ConcurrentHashMap<>(); - BaseControllerImpl(@DatabaseExecutor Executor dbExecutor, LifecycleManager lifecycleManager, EventBus eventBus, AndroidNotificationManager notificationManager, @@ -67,144 +34,4 @@ abstract class BaseControllerImpl extends DbControllerImpl this.blogManager = blogManager; } - @Override - @CallSuper - public void onStart() { - eventBus.addListener(this); - } - - @Override - @CallSuper - public void onStop() { - eventBus.removeListener(this); - } - - @Override - public void loadBlogPosts(GroupId groupId, - ResultExceptionHandler, DbException> handler) { - runOnDbThread(() -> { - try { - List items = loadItems(groupId); - handler.onResult(items); - } catch (DbException e) { - logException(LOG, WARNING, e); - handler.onException(e); - } - }); - } - - List loadItems(GroupId groupId) throws DbException { - long start = now(); - Collection headers = - blogManager.getPostHeaders(groupId); - logDuration(LOG, "Loading headers", start); - List items = new ArrayList<>(headers.size()); - start = now(); - for (BlogPostHeader h : headers) { - headerCache.put(h.getId(), h); - BlogPostItem item = getItem(h); - items.add(item); - } - logDuration(LOG, "Loading bodies", start); - return items; - } - - @Override - public void loadBlogPost(BlogPostHeader header, - ResultExceptionHandler handler) { - - String text = textCache.get(header.getId()); - if (text != null) { - LOG.info("Loaded text from cache"); - handler.onResult(new BlogPostItem(header, text)); - return; - } - runOnDbThread(() -> { - try { - long start = now(); - BlogPostItem item = getItem(header); - logDuration(LOG, "Loading text", start); - handler.onResult(item); - } catch (DbException e) { - logException(LOG, WARNING, e); - handler.onException(e); - } - }); - } - - @Override - public void loadBlogPost(GroupId g, MessageId m, - ResultExceptionHandler handler) { - - BlogPostHeader header = headerCache.get(m); - if (header != null) { - LOG.info("Loaded header from cache"); - loadBlogPost(header, handler); - return; - } - runOnDbThread(() -> { - try { - long start = now(); - BlogPostHeader header1 = getPostHeader(g, m); - BlogPostItem item = getItem(header1); - logDuration(LOG, "Loading post", start); - handler.onResult(item); - } catch (DbException e) { - logException(LOG, WARNING, e); - handler.onException(e); - } - }); - } - - @Override - public void repeatPost(BlogPostItem item, @Nullable String comment, - ExceptionHandler handler) { - runOnDbThread(() -> { - try { - LocalAuthor a = identityManager.getLocalAuthor(); - Blog b = blogManager.getPersonalBlog(a); - BlogPostHeader h = item.getHeader(); - blogManager.addLocalComment(a, b.getId(), comment, h); - } catch (DbException e) { - logException(LOG, WARNING, e); - handler.onException(e); - } - }); - } - - private BlogPostHeader getPostHeader(GroupId g, MessageId m) - throws DbException { - BlogPostHeader header = headerCache.get(m); - if (header == null) { - header = blogManager.getPostHeader(g, m); - headerCache.put(m, header); - } - return header; - } - - @DatabaseExecutor - private BlogPostItem getItem(BlogPostHeader h) throws DbException { - String text; - if (h instanceof BlogCommentHeader) { - BlogCommentHeader c = (BlogCommentHeader) h; - BlogCommentItem item = new BlogCommentItem(c); - text = getPostText(item.getPostHeader().getId()); - item.setText(text); - return item; - } else { - text = getPostText(h.getId()); - return new BlogPostItem(h, text); - } - } - - @DatabaseExecutor - private String getPostText(MessageId m) throws DbException { - String text = textCache.get(m); - if (text == null) { - text = HtmlUtils.clean(blogManager.getPostText(m), ARTICLE); - textCache.put(m, text); - } - return text; - } - } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BaseViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BaseViewModel.java index 10e105b46..d6690c4c2 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BaseViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BaseViewModel.java @@ -4,7 +4,6 @@ import android.app.Application; import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DbException; -import org.briarproject.bramble.api.db.NoSuchMessageException; import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.TransactionManager; import org.briarproject.bramble.api.event.Event; @@ -19,6 +18,7 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.briar.android.viewmodel.DbViewModel; import org.briarproject.briar.android.viewmodel.LiveResult; +import org.briarproject.briar.api.android.AndroidNotificationManager; import org.briarproject.briar.api.blog.Blog; import org.briarproject.briar.api.blog.BlogCommentHeader; import org.briarproject.briar.api.blog.BlogManager; @@ -26,6 +26,7 @@ import org.briarproject.briar.api.blog.BlogPostHeader; import org.briarproject.briar.util.HtmlUtils; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -35,11 +36,10 @@ import java.util.logging.Logger; import javax.annotation.Nullable; import javax.inject.Inject; +import androidx.annotation.UiThread; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.Transformations; -import static java.util.Objects.requireNonNull; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.util.LogUtils.logDuration; @@ -50,20 +50,23 @@ import static org.briarproject.briar.util.HtmlUtils.ARTICLE; @NotNullByDefault public class BaseViewModel extends DbViewModel implements EventListener { - private static Logger LOG = getLogger(BaseViewModel.class.getName()); + private static final Logger LOG = getLogger(BaseViewModel.class.getName()); protected final TransactionManager db; private final EventBus eventBus; protected final IdentityManager identityManager; + protected final AndroidNotificationManager notificationManager; protected final BlogManager blogManager; - protected final MutableLiveData>> blogPosts = + private final MutableLiveData>> blogPosts = new MutableLiveData<>(); // TODO do we still need those caches? private final Map textCache = new ConcurrentHashMap<>(); private final Map headerCache = new ConcurrentHashMap<>(); + @Nullable + private Boolean postAddedWasLocal = null; @Inject BaseViewModel(Application application, @@ -73,11 +76,13 @@ public class BaseViewModel extends DbViewModel implements EventListener { AndroidExecutor androidExecutor, EventBus eventBus, IdentityManager identityManager, + AndroidNotificationManager notificationManager, BlogManager blogManager) { super(application, dbExecutor, lifecycleManager, db, androidExecutor); this.db = db; this.eventBus = eventBus; this.identityManager = identityManager; + this.notificationManager = notificationManager; this.blogManager = blogManager; eventBus.addListener(this); @@ -93,10 +98,6 @@ public class BaseViewModel extends DbViewModel implements EventListener { public void eventOccurred(Event e) { } - void loadItems(GroupId groupId) { - loadList(txn -> loadBlogPosts(txn, groupId), blogPosts::setValue); - } - @DatabaseExecutor protected List loadBlogPosts(Transaction txn, GroupId groupId) throws DbException { @@ -148,9 +149,9 @@ public class BaseViewModel extends DbViewModel implements EventListener { runOnDbThread(() -> { try { long start = now(); - BlogPostHeader header1 = getPostHeader(g, m); + BlogPostHeader header = getPostHeader(g, m); BlogPostItem item = db.transactionWithResult(true, txn -> - getItem(txn, header1) + getItem(txn, header) ); logDuration(LOG, "Loading post", start); result.postValue(new LiveResult<>(item)); @@ -173,6 +174,31 @@ public class BaseViewModel extends DbViewModel implements EventListener { return header; } + @UiThread + protected void updateBlogPosts(LiveResult> posts) { + blogPosts.setValue(posts); + } + + protected void onBlogPostAdded(BlogPostHeader header, boolean local) { + postAddedWasLocal = local; + runOnDbThread(() -> { + try { + db.transaction(true, txn -> { + BlogPostItem item = getItem(txn, header); + txn.attach(() -> { + List items = addListItem(blogPosts, item); + if (items != null) { + Collections.sort(items); + blogPosts.setValue(new LiveResult<>(items)); + } + }); + }); + } catch (DbException e) { + logException(LOG, WARNING, e); + } + }); + } + void repeatPost(BlogPostItem item, @Nullable String comment) { runOnDbThread(() -> { try { @@ -186,34 +212,17 @@ public class BaseViewModel extends DbViewModel implements EventListener { }); } - LiveData>> getAllBlogPosts() { + LiveData>> getBlogPosts() { return blogPosts; } - LiveData>> getBlogPosts(GroupId g) { - return Transformations.map(blogPosts, result -> { - List allPosts = result.getResultOrNull(); - if (allPosts == null) return result; - List groupPosts = new ArrayList<>(); - for (BlogPostItem item : allPosts) { - if (item.getGroupId().equals(g)) groupPosts.add(item); - } - return new LiveResult<>(groupPosts); - }); - } - - LiveData> getBlogPost(MessageId m) { - return Transformations.map(blogPosts, result -> { - List allPosts = result.getResultOrNull(); - if (allPosts == null) { - Exception e = requireNonNull(result.getException()); - return new LiveResult<>(e); - } - for (BlogPostItem item : allPosts) { - if (item.getId().equals(m)) return new LiveResult<>(item); - } - return new LiveResult<>(new NoSuchMessageException()); - }); + @UiThread + @Nullable + Boolean getPostAddedWasLocalAndReset() { + if (postAddedWasLocal == null) return null; + boolean wasLocal = postAddedWasLocal; + postAddedWasLocal = null; + return wasLocal; } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogActivity.java index 23a7ff252..bbe9b6961 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogActivity.java @@ -16,15 +16,27 @@ import javax.annotation.Nullable; import javax.inject.Inject; import androidx.appcompat.widget.Toolbar; +import androidx.lifecycle.ViewModelProvider; @MethodsNotNullByDefault @ParametersNotNullByDefault public class BlogActivity extends BriarActivity implements BaseFragmentListener { + @Inject + ViewModelProvider.Factory viewModelFactory; @Inject BlogController blogController; + private BlogViewModel viewModel; + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + viewModel = new ViewModelProvider(this, viewModelFactory) + .get(BlogViewModel.class); + } + @Override public void onCreate(@Nullable Bundle state) { super.onCreate(state); @@ -35,6 +47,7 @@ public class BlogActivity extends BriarActivity if (b == null) throw new IllegalStateException("No group ID in intent"); GroupId groupId = new GroupId(b); blogController.setGroupId(groupId); + viewModel.setGroupId(groupId); setContentView(R.layout.activity_fragment_container_toolbar); Toolbar toolbar = setUpCustomToolbar(false); @@ -54,9 +67,4 @@ public class BlogActivity extends BriarActivity } } - @Override - public void injectActivity(ActivityComponent component) { - component.inject(this); - } - } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogController.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogController.java index 7f4dba0b2..5ce9df167 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogController.java @@ -4,44 +4,16 @@ import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.briar.android.controller.handler.ResultExceptionHandler; import java.util.Collection; -import java.util.List; - -import androidx.annotation.UiThread; @NotNullByDefault -public interface BlogController extends BaseController { +public interface BlogController { void setGroupId(GroupId g); - @UiThread - void setBlogSharingListener(BlogSharingListener listener); - - @UiThread - void unsetBlogSharingListener(BlogSharingListener listener); - - void loadBlogPosts( - ResultExceptionHandler, DbException> handler); - - void loadBlogPost(MessageId m, - ResultExceptionHandler handler); - - void loadBlog(ResultExceptionHandler handler); - - void deleteBlog(ResultExceptionHandler handler); - void loadSharingContacts( ResultExceptionHandler, DbException> handler); - interface BlogSharingListener extends BlogListener { - @UiThread - void onBlogInvitationAccepted(ContactId c); - - @UiThread - void onBlogLeft(ContactId c); - } - } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogControllerImpl.java index 317a75134..10f59ab8b 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogControllerImpl.java @@ -10,38 +10,25 @@ import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventListener; import org.briarproject.bramble.api.identity.IdentityManager; -import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.bramble.api.sync.event.GroupRemovedEvent; import org.briarproject.briar.android.controller.ActivityLifecycleController; import org.briarproject.briar.android.controller.handler.ResultExceptionHandler; import org.briarproject.briar.api.android.AndroidNotificationManager; -import org.briarproject.briar.api.blog.Blog; -import org.briarproject.briar.api.blog.BlogInvitationResponse; import org.briarproject.briar.api.blog.BlogManager; import org.briarproject.briar.api.blog.BlogSharingManager; -import org.briarproject.briar.api.blog.event.BlogInvitationResponseReceivedEvent; -import org.briarproject.briar.api.blog.event.BlogPostAddedEvent; -import org.briarproject.briar.api.sharing.event.ContactLeftShareableEvent; import java.util.ArrayList; import java.util.Collection; -import java.util.List; import java.util.concurrent.Executor; import java.util.logging.Logger; import javax.inject.Inject; -import androidx.annotation.Nullable; - import static java.util.logging.Level.WARNING; -import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logException; -import static org.briarproject.bramble.util.LogUtils.now; @MethodsNotNullByDefault @ParametersNotNullByDefault @@ -53,10 +40,6 @@ class BlogControllerImpl extends BaseControllerImpl private final BlogSharingManager blogSharingManager; - // UI thread - @Nullable - private BlogSharingListener listener; - private volatile GroupId groupId = null; @Inject @@ -76,15 +59,10 @@ class BlogControllerImpl extends BaseControllerImpl @Override public void onActivityStart() { - super.onStart(); - notificationManager.blockNotification(groupId); - notificationManager.clearBlogPostNotification(groupId); } @Override public void onActivityStop() { - super.onStop(); - notificationManager.unblockNotification(groupId); } @Override @@ -96,99 +74,9 @@ class BlogControllerImpl extends BaseControllerImpl groupId = g; } - @Override - public void setBlogSharingListener(BlogSharingListener listener) { - this.listener = listener; - } - - @Override - public void unsetBlogSharingListener(BlogSharingListener listener) { - if (this.listener == listener) this.listener = null; - } - @Override public void eventOccurred(Event e) { - if (groupId == null || listener == null) - throw new IllegalStateException(); - if (e instanceof BlogPostAddedEvent) { - BlogPostAddedEvent b = (BlogPostAddedEvent) e; - if (b.getGroupId().equals(groupId)) { - LOG.info("Blog post added"); - listener.onBlogPostAdded(b.getHeader(), b.isLocal()); - } - } else if (e instanceof BlogInvitationResponseReceivedEvent) { - BlogInvitationResponseReceivedEvent b = - (BlogInvitationResponseReceivedEvent) e; - BlogInvitationResponse r = b.getMessageHeader(); - if (r.getShareableId().equals(groupId) && r.wasAccepted()) { - LOG.info("Blog invitation accepted"); - listener.onBlogInvitationAccepted(b.getContactId()); - } - } else if (e instanceof ContactLeftShareableEvent) { - ContactLeftShareableEvent s = (ContactLeftShareableEvent) e; - if (s.getGroupId().equals(groupId)) { - LOG.info("Blog left by contact"); - listener.onBlogLeft(s.getContactId()); - } - } else if (e instanceof GroupRemovedEvent) { - GroupRemovedEvent g = (GroupRemovedEvent) e; - if (g.getGroup().getId().equals(groupId)) { - LOG.info("Blog removed"); - listener.onBlogRemoved(); - } - } - } - @Override - public void loadBlogPosts( - ResultExceptionHandler, DbException> handler) { - if (groupId == null) throw new IllegalStateException(); - loadBlogPosts(groupId, handler); - } - - @Override - public void loadBlogPost(MessageId m, - ResultExceptionHandler handler) { - if (groupId == null) throw new IllegalStateException(); - loadBlogPost(groupId, m, handler); - } - - @Override - public void loadBlog( - ResultExceptionHandler handler) { - if (groupId == null) throw new IllegalStateException(); - runOnDbThread(() -> { - try { - long start = now(); - LocalAuthor a = identityManager.getLocalAuthor(); - Blog b = blogManager.getBlog(groupId); - boolean ours = a.getId().equals(b.getAuthor().getId()); - boolean removable = blogManager.canBeRemoved(b); - BlogItem blog = new BlogItem(b, ours, removable); - logDuration(LOG, "Loading blog", start); - handler.onResult(blog); - } catch (DbException e) { - logException(LOG, WARNING, e); - handler.onException(e); - } - }); - } - - @Override - public void deleteBlog(ResultExceptionHandler handler) { - if (groupId == null) throw new IllegalStateException(); - runOnDbThread(() -> { - try { - long start = now(); - Blog b = blogManager.getBlog(groupId); - blogManager.removeBlog(b); - logDuration(LOG, "Removing blog", start); - handler.onResult(null); - } catch (DbException e) { - logException(LOG, WARNING, e); - handler.onException(e); - } - }); } @Override diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogFragment.java index a6ead22c1..2ab3bfc12 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogFragment.java @@ -1,6 +1,5 @@ package org.briarproject.briar.android.blog; -import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.os.Parcelable; @@ -21,7 +20,6 @@ import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.briar.R; import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.BriarActivity; -import org.briarproject.briar.android.blog.BlogController.BlogSharingListener; import org.briarproject.briar.android.controller.SharingController; import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler; import org.briarproject.briar.android.fragment.BaseFragment; @@ -30,7 +28,6 @@ import org.briarproject.briar.android.sharing.ShareBlogActivity; import org.briarproject.briar.android.util.BriarSnackbarBuilder; import org.briarproject.briar.android.view.BriarRecyclerView; import org.briarproject.briar.android.widget.LinkDialogFragment; -import org.briarproject.briar.api.blog.BlogPostHeader; import java.util.Collection; import java.util.List; @@ -41,6 +38,7 @@ import androidx.annotation.Nullable; import androidx.annotation.UiThread; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; +import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView.LayoutManager; @@ -57,11 +55,12 @@ import static org.briarproject.briar.android.controller.SharingController.Sharin @MethodsNotNullByDefault @ParametersNotNullByDefault public class BlogFragment extends BaseFragment - implements BlogSharingListener, SharingListener, - OnBlogPostClickListener { + implements SharingListener, OnBlogPostClickListener { private final static String TAG = BlogFragment.class.getName(); + @Inject + ViewModelProvider.Factory viewModelFactory; @Inject BlogController blogController; @Inject @@ -70,11 +69,10 @@ public class BlogFragment extends BaseFragment private Parcelable layoutManagerState; private GroupId groupId; + private BlogViewModel viewModel; private final BlogPostAdapter adapter = new BlogPostAdapter(this); private LayoutManager layoutManager; private BriarRecyclerView list; - private MenuItem writeButton, deleteButton; - private boolean isMyBlog = false, canDeleteBlog = false; static BlogFragment newInstance(GroupId groupId) { BlogFragment f = new BlogFragment(); @@ -89,7 +87,8 @@ public class BlogFragment extends BaseFragment @Override public void injectFragment(ActivityComponent component) { component.inject(this); - blogController.setBlogSharingListener(this); + viewModel = new ViewModelProvider(requireActivity(), viewModelFactory) + .get(BlogViewModel.class); sharingController.setSharingListener(this); } @@ -112,6 +111,14 @@ public class BlogFragment extends BaseFragment list.showProgressBar(); list.setEmptyText(getString(R.string.blogs_other_blog_empty_state)); + viewModel.getBlogPosts().observe(getViewLifecycleOwner(), result -> + result.onError(this::handleException) + .onSuccess(this::onBlogPostsLoaded) + ); + viewModel.getBlogRemoved().observe(getViewLifecycleOwner(), removed -> { + if (removed) finish(); + }); + if (savedInstanceState != null) { layoutManagerState = savedInstanceState.getParcelable("layoutManager"); @@ -123,16 +130,17 @@ public class BlogFragment extends BaseFragment @Override public void onStart() { super.onStart(); + viewModel.blockNotifications(); + viewModel.clearBlogPostNotifications(); sharingController.onStart(); - loadBlog(); loadSharedContacts(); - loadBlogPosts(false); list.startPeriodicUpdate(); } @Override public void onStop() { super.onStop(); + viewModel.unblockNotifications(); sharingController.onStop(); list.stopPeriodicUpdate(); } @@ -140,7 +148,6 @@ public class BlogFragment extends BaseFragment @Override public void onDestroy() { super.onDestroy(); - blogController.unsetBlogSharingListener(this); sharingController.unsetSharingListener(this); } @@ -156,42 +163,43 @@ public class BlogFragment extends BaseFragment @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.blogs_blog_actions, menu); - writeButton = menu.findItem(R.id.action_write_blog_post); - if (isMyBlog) writeButton.setVisible(true); - deleteButton = menu.findItem(R.id.action_blog_delete); - if (canDeleteBlog) deleteButton.setEnabled(true); - + MenuItem writeButton = menu.findItem(R.id.action_write_blog_post); + MenuItem deleteButton = menu.findItem(R.id.action_blog_delete); + viewModel.getBlog().observe(getViewLifecycleOwner(), blog -> { + setToolbarTitle(blog.getBlog().getAuthor()); + if (blog.isOurs()) writeButton.setVisible(true); + if (blog.canBeRemoved()) deleteButton.setEnabled(true); + }); super.onCreateOptionsMenu(menu, inflater); } @Override public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.action_write_blog_post: - Intent i = new Intent(getActivity(), - WriteBlogPostActivity.class); - i.putExtra(GROUP_ID, groupId.getBytes()); - startActivityForResult(i, REQUEST_WRITE_BLOG_POST); - return true; - case R.id.action_blog_share: - Intent i2 = new Intent(getActivity(), ShareBlogActivity.class); - i2.setFlags(FLAG_ACTIVITY_CLEAR_TOP); - i2.putExtra(GROUP_ID, groupId.getBytes()); - startActivityForResult(i2, REQUEST_SHARE_BLOG); - return true; - case R.id.action_blog_sharing_status: - Intent i3 = new Intent(getActivity(), - BlogSharingStatusActivity.class); - i3.setFlags(FLAG_ACTIVITY_CLEAR_TOP); - i3.putExtra(GROUP_ID, groupId.getBytes()); - startActivity(i3); - return true; - case R.id.action_blog_delete: - showDeleteDialog(); - return true; - default: - return super.onOptionsItemSelected(item); + int itemId = item.getItemId(); + if (itemId == R.id.action_write_blog_post) { + Intent i = new Intent(getActivity(), + WriteBlogPostActivity.class); + i.putExtra(GROUP_ID, groupId.getBytes()); + startActivityForResult(i, REQUEST_WRITE_BLOG_POST); + return true; + } else if (itemId == R.id.action_blog_share) { + Intent i2 = new Intent(getActivity(), ShareBlogActivity.class); + i2.setFlags(FLAG_ACTIVITY_CLEAR_TOP); + i2.putExtra(GROUP_ID, groupId.getBytes()); + startActivityForResult(i2, REQUEST_SHARE_BLOG); + return true; + } else if (itemId == R.id.action_blog_sharing_status) { + Intent i3 = new Intent(getActivity(), + BlogSharingStatusActivity.class); + i3.setFlags(FLAG_ACTIVITY_CLEAR_TOP); + i3.putExtra(GROUP_ID, groupId.getBytes()); + startActivity(i3); + return true; + } else if (itemId == R.id.action_blog_delete) { + showDeleteDialog(); + return true; } + return super.onOptionsItemSelected(item); } @Override @@ -201,7 +209,7 @@ public class BlogFragment extends BaseFragment if (request == REQUEST_WRITE_BLOG_POST && result == RESULT_OK) { displaySnackbar(R.string.blogs_blog_post_created, true); - loadBlogPosts(true); + viewModel.loadBlogPosts(groupId); } else if (request == REQUEST_SHARE_BLOG && result == RESULT_OK) { displaySnackbar(R.string.blogs_sharing_snackbar, false); } @@ -212,30 +220,25 @@ public class BlogFragment extends BaseFragment return TAG; } - @Override - public void onBlogPostAdded(BlogPostHeader header, boolean local) { - blogController.loadBlogPost(header, - new UiResultExceptionHandler( - this) { - @Override - public void onResultUi(BlogPostItem post) { -// adapter.add(post); - if (local) { - list.scrollToPosition(0); - displaySnackbar(R.string.blogs_blog_post_created, - false); - } else { - displaySnackbar(R.string.blogs_blog_post_received, - true); - } - } - - @Override - public void onExceptionUi(DbException exception) { - handleException(exception); - } - } - ); + private void onBlogPostsLoaded(List items) { + adapter.submitList(items, () -> { + Boolean wasLocal = viewModel.getPostAddedWasLocalAndReset(); + if (wasLocal != null && wasLocal) { + list.scrollToPosition(0); + displaySnackbar(R.string.blogs_blog_post_created, + false); + } else if (wasLocal != null) { + displaySnackbar(R.string.blogs_blog_post_received, + true); + } + list.showData(); + if (layoutManagerState == null) { + list.scrollToPosition(0); + } else { + layoutManager.onRestoreInstanceState( + layoutManagerState); + } + }); } @Override @@ -262,53 +265,8 @@ public class BlogFragment extends BaseFragment f.show(getParentFragmentManager(), f.getUniqueTag()); } - private void loadBlogPosts(boolean reload) { - blogController.loadBlogPosts( - new UiResultExceptionHandler, - DbException>(this) { - @Override - public void onResultUi(List posts) { - if (posts.isEmpty()) { - list.showData(); - } else { - adapter.submitList(posts); - if (reload || layoutManagerState == null) { - list.scrollToPosition(0); - } else { - layoutManager.onRestoreInstanceState( - layoutManagerState); - } - } - } - - @Override - public void onExceptionUi(DbException exception) { - handleException(exception); - } - }); - } - - private void loadBlog() { - blogController.loadBlog( - new UiResultExceptionHandler(this) { - @Override - public void onResultUi(BlogItem blog) { - setToolbarTitle(blog.getBlog().getAuthor()); - if (blog.isOurs()) - showWriteButton(); - if (blog.canBeRemoved()) - enableDeleteButton(); - } - - @Override - public void onExceptionUi(DbException exception) { - handleException(exception); - } - }); - } - private void setToolbarTitle(Author a) { - getActivity().setTitle(a.getName()); + requireActivity().setTitle(a.getName()); } private void loadSharedContacts() { @@ -329,20 +287,6 @@ public class BlogFragment extends BaseFragment }); } - @Override - public void onBlogInvitationAccepted(ContactId c) { - sharingController.add(c); - setToolbarSubTitle(sharingController.getTotalCount(), - sharingController.getOnlineCount()); - } - - @Override - public void onBlogLeft(ContactId c) { - sharingController.remove(c); - setToolbarSubTitle(sharingController.getTotalCount(), - sharingController.getOnlineCount()); - } - @Override public void onSharingInfoUpdated(int total, int online) { setToolbarSubTitle(total, online); @@ -350,25 +294,13 @@ public class BlogFragment extends BaseFragment private void setToolbarSubTitle(int total, int online) { ActionBar actionBar = - ((BriarActivity) getActivity()).getSupportActionBar(); + ((BriarActivity) requireActivity()).getSupportActionBar(); if (actionBar != null) { actionBar.setSubtitle( getString(R.string.shared_with, total, online)); } } - private void showWriteButton() { - isMyBlog = true; - if (writeButton != null) - writeButton.setVisible(true); - } - - private void enableDeleteButton() { - canDeleteBlog = true; - if (deleteButton != null) - deleteButton.setEnabled(true); - } - private void displaySnackbar(int stringId, boolean scroll) { BriarSnackbarBuilder sb = new BriarSnackbarBuilder(); if (scroll) { @@ -379,38 +311,21 @@ public class BlogFragment extends BaseFragment } private void showDeleteDialog() { - DialogInterface.OnClickListener okListener = - (dialog, which) -> deleteBlog(); - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), + AlertDialog.Builder builder = new AlertDialog.Builder(requireContext(), R.style.BriarDialogTheme); builder.setTitle(getString(R.string.blogs_remove_blog)); builder.setMessage( getString(R.string.blogs_remove_blog_dialog_message)); builder.setPositiveButton(R.string.cancel, null); - builder.setNegativeButton(R.string.blogs_remove_blog_ok, okListener); + builder.setNegativeButton(R.string.blogs_remove_blog_ok, + (dialog, which) -> deleteBlog()); builder.show(); } private void deleteBlog() { - blogController.deleteBlog( - new UiResultExceptionHandler(this) { - @Override - public void onResultUi(Void result) { - Toast.makeText(getActivity(), - R.string.blogs_blog_removed, LENGTH_SHORT) - .show(); - finish(); - } - - @Override - public void onExceptionUi(DbException exception) { - handleException(exception); - } - }); - } - - @Override - public void onBlogRemoved() { + viewModel.deleteBlog(); + Toast.makeText(getActivity(), R.string.blogs_blog_removed, LENGTH_SHORT) + .show(); finish(); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogModule.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogModule.java index 9ab9ff681..a6cf55036 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogModule.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogModule.java @@ -21,6 +21,11 @@ public class BlogModule { @IntoMap @ViewModelKey(FeedViewModel.class) abstract ViewModel bindFeedViewModel(FeedViewModel feedViewModel); + + @Binds + @IntoMap + @ViewModelKey(BlogViewModel.class) + abstract ViewModel bindBlogViewModel(BlogViewModel blogViewModel); } @ActivityScope diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogPostFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogPostFragment.java index cb61b75de..7e201577c 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogPostFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogPostFragment.java @@ -1,30 +1,35 @@ package org.briarproject.briar.android.blog; import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; -import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.briar.android.activity.ActivityComponent; -import org.briarproject.briar.android.blog.BaseController.BlogListener; -import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler; -import org.briarproject.briar.api.blog.BlogPostHeader; +import javax.annotation.Nullable; import javax.inject.Inject; import androidx.annotation.UiThread; +import androidx.lifecycle.ViewModelProvider; @UiThread @MethodsNotNullByDefault @ParametersNotNullByDefault -public class BlogPostFragment extends BasePostFragment implements BlogListener { +public class BlogPostFragment extends BasePostFragment { private static final String TAG = BlogPostFragment.class.getName(); + @Inject + ViewModelProvider.Factory viewModelFactory; @Inject BlogController blogController; + private BlogViewModel viewModel; + static BlogPostFragment newInstance(MessageId postId) { BlogPostFragment f = new BlogPostFragment(); @@ -35,42 +40,29 @@ public class BlogPostFragment extends BasePostFragment implements BlogListener { return f; } + @Override + public void injectFragment(ActivityComponent component) { + component.inject(this); + viewModel = new ViewModelProvider(requireActivity(), viewModelFactory) + .get(BlogViewModel.class); + } + @Override public String getUniqueTag() { return TAG; } + @Nullable @Override - public void injectFragment(ActivityComponent component) { - component.inject(this); - } - - @Override - public void onStart() { - super.onStart(); - blogController.loadBlogPost(postId, - new UiResultExceptionHandler( - this) { - @Override - public void onResultUi(BlogPostItem post) { - onBlogPostLoaded(post); - } - - @Override - public void onExceptionUi(DbException exception) { - handleException(exception); - } - }); - } - - @Override - public void onBlogPostAdded(BlogPostHeader header, boolean local) { - // doesn't matter here - } - - @Override - public void onBlogRemoved() { - finish(); + public View onCreateView(LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View v = super.onCreateView(inflater, container, savedInstanceState); + viewModel.loadBlogPost(postId).observe(getViewLifecycleOwner(), res -> + res.onError(this::handleException) + .onSuccess(this::onBlogPostLoaded) + ); + return v; } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogViewModel.java new file mode 100644 index 000000000..0d8e6d5c0 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogViewModel.java @@ -0,0 +1,168 @@ +package org.briarproject.briar.android.blog; + +import android.app.Application; + +import org.briarproject.bramble.api.db.DatabaseExecutor; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.db.TransactionManager; +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.event.EventBus; +import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.identity.LocalAuthor; +import org.briarproject.bramble.api.lifecycle.LifecycleManager; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.sync.event.GroupRemovedEvent; +import org.briarproject.bramble.api.system.AndroidExecutor; +import org.briarproject.briar.android.viewmodel.LiveResult; +import org.briarproject.briar.api.android.AndroidNotificationManager; +import org.briarproject.briar.api.blog.Blog; +import org.briarproject.briar.api.blog.BlogInvitationResponse; +import org.briarproject.briar.api.blog.BlogManager; +import org.briarproject.briar.api.blog.event.BlogInvitationResponseReceivedEvent; +import org.briarproject.briar.api.blog.event.BlogPostAddedEvent; +import org.briarproject.briar.api.sharing.event.ContactLeftShareableEvent; + +import java.util.concurrent.Executor; +import java.util.logging.Logger; + +import javax.inject.Inject; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import static java.util.logging.Level.WARNING; +import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.util.LogUtils.logDuration; +import static org.briarproject.bramble.util.LogUtils.logException; +import static org.briarproject.bramble.util.LogUtils.now; + +@NotNullByDefault +class BlogViewModel extends BaseViewModel { + + private static final Logger LOG = getLogger(BlogViewModel.class.getName()); + + // implicitly non-null + private volatile GroupId groupId = null; + + private final MutableLiveData blog = new MutableLiveData<>(); + private final MutableLiveData blogRemoved = + new MutableLiveData<>(); + + @Inject + BlogViewModel(Application application, + @DatabaseExecutor Executor dbExecutor, + LifecycleManager lifecycleManager, + TransactionManager db, + AndroidExecutor androidExecutor, + EventBus eventBus, + IdentityManager identityManager, + AndroidNotificationManager notificationManager, + BlogManager blogManager) { + super(application, dbExecutor, lifecycleManager, db, androidExecutor, + eventBus, identityManager, notificationManager, blogManager); + } + + @Override + public void eventOccurred(Event e) { + if (e instanceof BlogPostAddedEvent) { + BlogPostAddedEvent b = (BlogPostAddedEvent) e; + if (b.getGroupId().equals(groupId)) { + LOG.info("Blog post added"); + onBlogPostAdded(b.getHeader(), b.isLocal()); + } + } else if (e instanceof BlogInvitationResponseReceivedEvent) { + BlogInvitationResponseReceivedEvent b = + (BlogInvitationResponseReceivedEvent) e; + BlogInvitationResponse r = b.getMessageHeader(); + if (r.getShareableId().equals(groupId) && r.wasAccepted()) { + LOG.info("Blog invitation accepted"); + // TODO +// onBlogInvitationAccepted(b.getContactId()); +// sharingController.add(c); + } + } else if (e instanceof ContactLeftShareableEvent) { + ContactLeftShareableEvent s = (ContactLeftShareableEvent) e; + if (s.getGroupId().equals(groupId)) { + LOG.info("Blog left by contact"); + // TODO +// onBlogLeft(s.getContactId()); +// sharingController.remove(c); + } + } else if (e instanceof GroupRemovedEvent) { + GroupRemovedEvent g = (GroupRemovedEvent) e; + if (g.getGroup().getId().equals(groupId)) { + LOG.info("Blog removed"); + blogRemoved.setValue(true); + } + } + } + + /** + * Set this before calling any other methods. + */ + public void setGroupId(GroupId groupId) { + this.groupId = groupId; + loadBlog(groupId); + loadBlogPosts(groupId); + } + + private void loadBlog(GroupId groupId) { + runOnDbThread(() -> { + try { + long start = now(); + LocalAuthor a = identityManager.getLocalAuthor(); + Blog b = blogManager.getBlog(groupId); + boolean ours = a.getId().equals(b.getAuthor().getId()); + boolean removable = blogManager.canBeRemoved(b); + blog.postValue(new BlogItem(b, ours, removable)); + logDuration(LOG, "Loading blog", start); + } catch (DbException e) { + logException(LOG, WARNING, e); + } + }); + } + + void blockNotifications() { + notificationManager.blockNotification(groupId); + } + + void clearBlogPostNotifications() { + notificationManager.clearBlogPostNotification(groupId); + } + + void unblockNotifications() { + notificationManager.unblockNotification(groupId); + } + + void loadBlogPosts(GroupId groupId) { + loadList(txn -> loadBlogPosts(txn, groupId), this::updateBlogPosts); + } + + void deleteBlog() { + runOnDbThread(() -> { + try { + long start = now(); + Blog b = blogManager.getBlog(groupId); + blogManager.removeBlog(b); + logDuration(LOG, "Removing blog", start); + } catch (DbException e) { + logException(LOG, WARNING, e); + } + }); + } + + LiveData> loadBlogPost(MessageId m) { + return loadBlogPost(groupId, m); + } + + LiveData getBlog() { + return blog; + } + + LiveData getBlogRemoved() { + return blogRemoved; + } + +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/FeedFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/FeedFragment.java index c876ca849..218d6dfcc 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/FeedFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/FeedFragment.java @@ -63,8 +63,7 @@ public class FeedFragment extends BaseFragment @Override public void injectFragment(ActivityComponent component) { component.inject(this); - // TODO don't use NavDrawerActivity scope here - viewModel = new ViewModelProvider(requireActivity(), viewModelFactory) + viewModel = new ViewModelProvider(this, viewModelFactory) .get(FeedViewModel.class); // TODO ideally we only do this once when the ViewModel gets created viewModel.loadPersonalBlog(); @@ -88,7 +87,7 @@ public class FeedFragment extends BaseFragment list.setEmptyText(R.string.blogs_feed_empty_state); list.setEmptyAction(R.string.blogs_feed_empty_state_action); - viewModel.getAllBlogPosts().observe(getViewLifecycleOwner(), result -> + viewModel.getBlogPosts().observe(getViewLifecycleOwner(), result -> result .onError(this::handleException) .onSuccess(this::onBlogPostsLoaded) @@ -135,6 +134,7 @@ public class FeedFragment extends BaseFragment } else if (wasLocal != null) { showSnackBar(R.string.blogs_blog_post_received); } + list.showData(); }); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/FeedViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/FeedViewModel.java index 6f5f44f44..3c18f5774 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/FeedViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/FeedViewModel.java @@ -17,11 +17,9 @@ import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.event.GroupAddedEvent; import org.briarproject.bramble.api.sync.event.GroupRemovedEvent; import org.briarproject.bramble.api.system.AndroidExecutor; -import org.briarproject.briar.android.viewmodel.LiveResult; import org.briarproject.briar.api.android.AndroidNotificationManager; import org.briarproject.briar.api.blog.Blog; import org.briarproject.briar.api.blog.BlogManager; -import org.briarproject.briar.api.blog.BlogPostHeader; import org.briarproject.briar.api.blog.event.BlogPostAddedEvent; import java.util.ArrayList; @@ -30,10 +28,8 @@ import java.util.List; import java.util.concurrent.Executor; import java.util.logging.Logger; -import javax.annotation.Nullable; import javax.inject.Inject; -import androidx.annotation.UiThread; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; @@ -49,11 +45,7 @@ class FeedViewModel extends BaseViewModel { private static final Logger LOG = getLogger(FeedViewModel.class.getName()); - protected final AndroidNotificationManager notificationManager; - private final MutableLiveData personalBlog = new MutableLiveData<>(); - @Nullable - private Boolean postAddedWasLocal = null; @Inject FeedViewModel(Application application, @@ -63,11 +55,10 @@ class FeedViewModel extends BaseViewModel { AndroidExecutor androidExecutor, EventBus eventBus, IdentityManager identityManager, - BlogManager blogManager, - AndroidNotificationManager notificationManager) { + AndroidNotificationManager notificationManager, + BlogManager blogManager) { super(application, dbExecutor, lifecycleManager, db, androidExecutor, - eventBus, identityManager, blogManager); - this.notificationManager = notificationManager; + eventBus, identityManager, notificationManager, blogManager); } @Override @@ -122,7 +113,7 @@ class FeedViewModel extends BaseViewModel { } void loadAllBlogPosts() { - loadList(this::loadAllBlogPosts, blogPosts::setValue); + loadList(this::loadAllBlogPosts, this::updateBlogPosts); } @DatabaseExecutor @@ -142,33 +133,4 @@ class FeedViewModel extends BaseViewModel { return posts; } - private void onBlogPostAdded(BlogPostHeader header, boolean local) { - postAddedWasLocal = local; - runOnDbThread(() -> { - try { - db.transaction(true, txn -> { - BlogPostItem item = getItem(txn, header); - txn.attach(() -> { - List items = addListItem(blogPosts, item); - if (items != null) { - Collections.sort(items); - blogPosts.setValue(new LiveResult<>(items)); - } - }); - }); - } catch (DbException e) { - logException(LOG, WARNING, e); - } - }); - } - - @UiThread - @Nullable - Boolean getPostAddedWasLocalAndReset() { - if (postAddedWasLocal == null) return null; - boolean wasLocal = postAddedWasLocal; - postAddedWasLocal = null; - return wasLocal; - } - }