mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Migrate BlogController to BlogViewModel
This commit is contained in:
@@ -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<List<BlogPostItem>, DbException> handler);
|
||||
|
||||
void loadBlogPost(BlogPostHeader header,
|
||||
ResultExceptionHandler<BlogPostItem, DbException> handler);
|
||||
|
||||
void loadBlogPost(GroupId g, MessageId m,
|
||||
ResultExceptionHandler<BlogPostItem, DbException> handler);
|
||||
|
||||
void repeatPost(BlogPostItem item, @Nullable String comment,
|
||||
ExceptionHandler<DbException> handler);
|
||||
|
||||
@NotNullByDefault
|
||||
interface BlogListener {
|
||||
|
||||
@UiThread
|
||||
void onBlogPostAdded(BlogPostHeader header, boolean local);
|
||||
|
||||
@UiThread
|
||||
void onBlogRemoved();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<MessageId, String> textCache = new ConcurrentHashMap<>();
|
||||
private final Map<MessageId, BlogPostHeader> 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<List<BlogPostItem>, DbException> handler) {
|
||||
runOnDbThread(() -> {
|
||||
try {
|
||||
List<BlogPostItem> items = loadItems(groupId);
|
||||
handler.onResult(items);
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
handler.onException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
List<BlogPostItem> loadItems(GroupId groupId) throws DbException {
|
||||
long start = now();
|
||||
Collection<BlogPostHeader> headers =
|
||||
blogManager.getPostHeaders(groupId);
|
||||
logDuration(LOG, "Loading headers", start);
|
||||
List<BlogPostItem> 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<BlogPostItem, DbException> 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<BlogPostItem, DbException> 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<DbException> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<LiveResult<List<BlogPostItem>>> blogPosts =
|
||||
private final MutableLiveData<LiveResult<List<BlogPostItem>>> blogPosts =
|
||||
new MutableLiveData<>();
|
||||
|
||||
// TODO do we still need those caches?
|
||||
private final Map<MessageId, String> textCache = new ConcurrentHashMap<>();
|
||||
private final Map<MessageId, BlogPostHeader> 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<BlogPostItem> 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<List<BlogPostItem>> 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<BlogPostItem> 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<LiveResult<List<BlogPostItem>>> getAllBlogPosts() {
|
||||
LiveData<LiveResult<List<BlogPostItem>>> getBlogPosts() {
|
||||
return blogPosts;
|
||||
}
|
||||
|
||||
LiveData<LiveResult<List<BlogPostItem>>> getBlogPosts(GroupId g) {
|
||||
return Transformations.map(blogPosts, result -> {
|
||||
List<BlogPostItem> allPosts = result.getResultOrNull();
|
||||
if (allPosts == null) return result;
|
||||
List<BlogPostItem> groupPosts = new ArrayList<>();
|
||||
for (BlogPostItem item : allPosts) {
|
||||
if (item.getGroupId().equals(g)) groupPosts.add(item);
|
||||
}
|
||||
return new LiveResult<>(groupPosts);
|
||||
});
|
||||
}
|
||||
|
||||
LiveData<LiveResult<BlogPostItem>> getBlogPost(MessageId m) {
|
||||
return Transformations.map(blogPosts, result -> {
|
||||
List<BlogPostItem> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<List<BlogPostItem>, DbException> handler);
|
||||
|
||||
void loadBlogPost(MessageId m,
|
||||
ResultExceptionHandler<BlogPostItem, DbException> handler);
|
||||
|
||||
void loadBlog(ResultExceptionHandler<BlogItem, DbException> handler);
|
||||
|
||||
void deleteBlog(ResultExceptionHandler<Void, DbException> handler);
|
||||
|
||||
void loadSharingContacts(
|
||||
ResultExceptionHandler<Collection<ContactId>, DbException> handler);
|
||||
|
||||
interface BlogSharingListener extends BlogListener {
|
||||
@UiThread
|
||||
void onBlogInvitationAccepted(ContactId c);
|
||||
|
||||
@UiThread
|
||||
void onBlogLeft(ContactId c);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<List<BlogPostItem>, DbException> handler) {
|
||||
if (groupId == null) throw new IllegalStateException();
|
||||
loadBlogPosts(groupId, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadBlogPost(MessageId m,
|
||||
ResultExceptionHandler<BlogPostItem, DbException> handler) {
|
||||
if (groupId == null) throw new IllegalStateException();
|
||||
loadBlogPost(groupId, m, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadBlog(
|
||||
ResultExceptionHandler<BlogItem, DbException> 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<Void, DbException> 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
|
||||
|
||||
@@ -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<BlogPostItem, DbException>(
|
||||
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<BlogPostItem> 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<List<BlogPostItem>,
|
||||
DbException>(this) {
|
||||
@Override
|
||||
public void onResultUi(List<BlogPostItem> 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<BlogItem, DbException>(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<Void, DbException>(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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<BlogPostItem, DbException>(
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<BlogItem> blog = new MutableLiveData<>();
|
||||
private final MutableLiveData<Boolean> 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<LiveResult<BlogPostItem>> loadBlogPost(MessageId m) {
|
||||
return loadBlogPost(groupId, m);
|
||||
}
|
||||
|
||||
LiveData<BlogItem> getBlog() {
|
||||
return blog;
|
||||
}
|
||||
|
||||
LiveData<Boolean> getBlogRemoved() {
|
||||
return blogRemoved;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Blog> 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<BlogPostItem> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user