mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 02:39:05 +01:00
Compare commits
1 Commits
beta-1.5.1
...
1866-blog-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b4f38e81ea |
@@ -53,13 +53,9 @@ abstract class BaseViewModel extends DbViewModel implements EventListener {
|
||||
protected final AndroidNotificationManager notificationManager;
|
||||
protected final BlogManager blogManager;
|
||||
|
||||
protected final MutableLiveData<LiveResult<List<BlogPostItem>>> blogPosts =
|
||||
protected final MutableLiveData<LiveResult<ListUpdate>> blogPosts =
|
||||
new MutableLiveData<>();
|
||||
|
||||
// UI thread
|
||||
@Nullable
|
||||
private Boolean postAddedWasLocal = null;
|
||||
|
||||
BaseViewModel(Application application,
|
||||
@DatabaseExecutor Executor dbExecutor,
|
||||
LifecycleManager lifecycleManager,
|
||||
@@ -147,11 +143,10 @@ abstract class BaseViewModel extends DbViewModel implements EventListener {
|
||||
|
||||
@UiThread
|
||||
private void onBlogPostItemAdded(BlogPostItem item, boolean local) {
|
||||
List<BlogPostItem> items = addListItem(blogPosts, item);
|
||||
List<BlogPostItem> items = addListItem(getBlogPostItems(), item);
|
||||
if (items != null) {
|
||||
Collections.sort(items);
|
||||
postAddedWasLocal = local;
|
||||
blogPosts.setValue(new LiveResult<>(items));
|
||||
blogPosts.setValue(new LiveResult<>(new ListUpdate(local, items)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,17 +163,37 @@ abstract class BaseViewModel extends DbViewModel implements EventListener {
|
||||
});
|
||||
}
|
||||
|
||||
LiveData<LiveResult<List<BlogPostItem>>> getBlogPosts() {
|
||||
LiveData<LiveResult<ListUpdate>> getBlogPosts() {
|
||||
return blogPosts;
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@Nullable
|
||||
Boolean getPostAddedWasLocalAndReset() {
|
||||
if (postAddedWasLocal == null) return null;
|
||||
boolean wasLocal = postAddedWasLocal;
|
||||
postAddedWasLocal = null;
|
||||
return wasLocal;
|
||||
protected List<BlogPostItem> getBlogPostItems() {
|
||||
LiveResult<ListUpdate> value = blogPosts.getValue();
|
||||
if (value == null) return null;
|
||||
ListUpdate result = value.getResultOrNull();
|
||||
return result == null ? null : result.getItems();
|
||||
}
|
||||
|
||||
static class ListUpdate {
|
||||
|
||||
@Nullable
|
||||
private final Boolean postAddedWasLocal;
|
||||
private final List<BlogPostItem> items;
|
||||
|
||||
ListUpdate(@Nullable Boolean postAddedWasLocal,
|
||||
List<BlogPostItem> items) {
|
||||
this.postAddedWasLocal = postAddedWasLocal;
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Boolean getPostAddedWasLocal() {
|
||||
return postAddedWasLocal;
|
||||
}
|
||||
|
||||
public List<BlogPostItem> getItems() {
|
||||
return items;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||
import org.briarproject.briar.android.blog.BaseViewModel.ListUpdate;
|
||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||
import org.briarproject.briar.android.sharing.BlogSharingStatusActivity;
|
||||
import org.briarproject.briar.android.sharing.ShareBlogActivity;
|
||||
@@ -22,8 +23,6 @@ import org.briarproject.briar.android.util.BriarSnackbarBuilder;
|
||||
import org.briarproject.briar.android.view.BriarRecyclerView;
|
||||
import org.briarproject.briar.android.widget.LinkDialogFragment;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -174,9 +173,9 @@ public class BlogFragment extends BaseFragment
|
||||
return TAG;
|
||||
}
|
||||
|
||||
private void onBlogPostsLoaded(List<BlogPostItem> items) {
|
||||
adapter.submitList(items, () -> {
|
||||
Boolean wasLocal = viewModel.getPostAddedWasLocalAndReset();
|
||||
private void onBlogPostsLoaded(ListUpdate update) {
|
||||
adapter.submitList(update.getItems(), () -> {
|
||||
Boolean wasLocal = update.getPostAddedWasLocal();
|
||||
if (wasLocal != null && wasLocal) {
|
||||
list.scrollToPosition(0);
|
||||
displaySnackbar(R.string.blogs_blog_post_created,
|
||||
|
||||
@@ -145,7 +145,8 @@ class BlogViewModel extends BaseViewModel {
|
||||
}
|
||||
|
||||
private void loadBlogPosts(GroupId groupId) {
|
||||
loadList(txn -> loadBlogPosts(txn, groupId), blogPosts::setValue);
|
||||
loadList(txn -> new ListUpdate(null, loadBlogPosts(txn, groupId)),
|
||||
blogPosts::setValue);
|
||||
}
|
||||
|
||||
private void loadSharingContacts(GroupId groupId) {
|
||||
|
||||
@@ -13,14 +13,13 @@ import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||
import org.briarproject.briar.android.blog.BaseViewModel.ListUpdate;
|
||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||
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.Blog;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -101,10 +100,9 @@ public class FeedFragment extends BaseFragment
|
||||
list.stopPeriodicUpdate();
|
||||
}
|
||||
|
||||
private void onBlogPostsLoaded(List<BlogPostItem> items) {
|
||||
if (items.isEmpty()) list.showData();
|
||||
else adapter.submitList(items, () -> {
|
||||
Boolean wasLocal = viewModel.getPostAddedWasLocalAndReset();
|
||||
private void onBlogPostsLoaded(ListUpdate update) {
|
||||
adapter.submitList(update.getItems(), () -> {
|
||||
Boolean wasLocal = update.getPostAddedWasLocal();
|
||||
if (wasLocal != null && wasLocal) {
|
||||
showSnackBar(R.string.blogs_blog_post_created);
|
||||
} else if (wasLocal != null) {
|
||||
|
||||
@@ -13,7 +13,6 @@ import org.briarproject.bramble.api.identity.IdentityManager;
|
||||
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.event.GroupAddedEvent;
|
||||
import org.briarproject.bramble.api.sync.event.GroupRemovedEvent;
|
||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||
import org.briarproject.briar.android.viewmodel.LiveResult;
|
||||
@@ -34,10 +33,8 @@ import androidx.annotation.UiThread;
|
||||
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;
|
||||
import static org.briarproject.briar.api.blog.BlogManager.CLIENT_ID;
|
||||
|
||||
@@ -70,15 +67,8 @@ class FeedViewModel extends BaseViewModel {
|
||||
BlogPostAddedEvent b = (BlogPostAddedEvent) e;
|
||||
LOG.info("Blog post added");
|
||||
onBlogPostAdded(b.getHeader(), b.isLocal());
|
||||
} else if (e instanceof GroupAddedEvent) {
|
||||
GroupAddedEvent g = (GroupAddedEvent) e;
|
||||
if (g.getGroup().getClientId().equals(CLIENT_ID)) {
|
||||
LOG.info("Blog added");
|
||||
// TODO how can this even happen?
|
||||
// added RSS feeds should trigger BlogPostAddedEvent, no?
|
||||
onBlogAdded(g.getGroup().getId());
|
||||
}
|
||||
} else if (e instanceof GroupRemovedEvent) {
|
||||
}
|
||||
if (e instanceof GroupRemovedEvent) {
|
||||
GroupRemovedEvent g = (GroupRemovedEvent) e;
|
||||
if (g.getGroup().getClientId().equals(CLIENT_ID)) {
|
||||
LOG.info("Blog removed");
|
||||
@@ -119,7 +109,7 @@ class FeedViewModel extends BaseViewModel {
|
||||
}
|
||||
|
||||
@DatabaseExecutor
|
||||
private List<BlogPostItem> loadAllBlogPosts(Transaction txn)
|
||||
private ListUpdate loadAllBlogPosts(Transaction txn)
|
||||
throws DbException {
|
||||
long start = now();
|
||||
List<BlogPostItem> posts = new ArrayList<>();
|
||||
@@ -128,29 +118,17 @@ class FeedViewModel extends BaseViewModel {
|
||||
}
|
||||
Collections.sort(posts);
|
||||
logDuration(LOG, "Loading all posts", start);
|
||||
return posts;
|
||||
}
|
||||
|
||||
private void onBlogAdded(GroupId g) {
|
||||
runOnDbThread(true, txn -> {
|
||||
List<BlogPostItem> posts = loadBlogPosts(txn, g);
|
||||
txn.attach(() -> onBlogPostItemsAdded(posts));
|
||||
}, e -> logException(LOG, WARNING, e));
|
||||
return new ListUpdate(null, posts);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void onBlogPostItemsAdded(List<BlogPostItem> posts) {
|
||||
List<BlogPostItem> items = addListItems(blogPosts, posts);
|
||||
private void onBlogRemoved(GroupId g) {
|
||||
List<BlogPostItem> items = removeListItems(getBlogPostItems(),
|
||||
item -> item.getGroupId().equals(g)
|
||||
);
|
||||
if (items != null) {
|
||||
Collections.sort(items);
|
||||
blogPosts.setValue(new LiveResult<>(items));
|
||||
blogPosts.setValue(new LiveResult<>(new ListUpdate(null, items)));
|
||||
}
|
||||
}
|
||||
|
||||
private void onBlogRemoved(GroupId g) {
|
||||
removeAndUpdateListItems(blogPosts, item ->
|
||||
item.getGroupId().equals(g)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ public class ContactsViewModel extends DbViewModel implements EventListener {
|
||||
@UiThread
|
||||
private void updateItem(ContactId c,
|
||||
Function<ContactListItem, ContactListItem> replacer, boolean sort) {
|
||||
List<ContactListItem> list = updateListItems(contactListItems,
|
||||
List<ContactListItem> list = updateListItems(getList(contactListItems),
|
||||
itemToTest -> itemToTest.getContact().getId().equals(c),
|
||||
replacer);
|
||||
if (list == null) return;
|
||||
@@ -161,10 +161,8 @@ public class ContactsViewModel extends DbViewModel implements EventListener {
|
||||
|
||||
@UiThread
|
||||
private void removeItem(ContactId c) {
|
||||
List<ContactListItem> list = removeListItems(contactListItems,
|
||||
removeAndUpdateListItems(contactListItems,
|
||||
itemToTest -> itemToTest.getContact().getId().equals(c));
|
||||
if (list == null) return;
|
||||
contactListItems.setValue(new LiveResult<>(list));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ class ForumListViewModel extends DbViewModel implements EventListener {
|
||||
|
||||
@UiThread
|
||||
private void onForumPostReceived(GroupId g, ForumPostHeader header) {
|
||||
List<ForumListItem> list = updateListItems(forumItems,
|
||||
List<ForumListItem> list = updateListItems(getList(forumItems),
|
||||
itemToTest -> itemToTest.getForum().getId().equals(g),
|
||||
itemToUpdate -> new ForumListItem(itemToUpdate, header));
|
||||
if (list == null) return;
|
||||
|
||||
@@ -2,7 +2,6 @@ package org.briarproject.briar.android.privategroup.list;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactManager;
|
||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
@@ -173,7 +172,7 @@ class GroupListViewModel extends DbViewModel implements EventListener {
|
||||
@UiThread
|
||||
private void onGroupMessageAdded(GroupMessageHeader header) {
|
||||
GroupId g = header.getGroupId();
|
||||
List<GroupItem> list = updateListItems(groupItems,
|
||||
List<GroupItem> list = updateListItems(getList(groupItems),
|
||||
itemToTest -> itemToTest.getId().equals(g),
|
||||
itemToUpdate -> new GroupItem(itemToUpdate, header));
|
||||
if (list == null) return;
|
||||
@@ -184,7 +183,7 @@ class GroupListViewModel extends DbViewModel implements EventListener {
|
||||
|
||||
@UiThread
|
||||
private void onGroupDissolved(GroupId groupId) {
|
||||
List<GroupItem> list = updateListItems(groupItems,
|
||||
List<GroupItem> list = updateListItems(getList(groupItems),
|
||||
itemToTest -> itemToTest.getId().equals(groupId),
|
||||
itemToUpdate -> new GroupItem(itemToUpdate, true));
|
||||
if (list == null) return;
|
||||
|
||||
@@ -120,9 +120,11 @@ public abstract class DbViewModel extends AndroidViewModel {
|
||||
* This method ensures that those operations can be processed on the
|
||||
* UiThread in the correct order so that the removed message will not be
|
||||
* re-added when the re-load completes.
|
||||
*
|
||||
* TODO: Rename this method and update javadoc, as it's not restricted to
|
||||
* lists
|
||||
*/
|
||||
protected <T extends List<?>> void loadList(
|
||||
DbCallable<T, DbException> task,
|
||||
protected <T> void loadList(DbCallable<T, DbException> task,
|
||||
UiConsumer<LiveResult<T>> uiConsumer) {
|
||||
dbExecutor.execute(() -> {
|
||||
try {
|
||||
@@ -149,63 +151,46 @@ public abstract class DbViewModel extends AndroidViewModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of the list available in the given LiveData
|
||||
* and adds the given item to the copy.
|
||||
* Creates a copy of the given list and adds the given item to the copy.
|
||||
*
|
||||
* @return a copy of the list in the LiveData with item added or null when
|
||||
* <ul>
|
||||
* <li> LiveData does not have a value
|
||||
* <li> LiveResult in the LiveData has an error
|
||||
* </ul>
|
||||
* @return an updated copy of the list, or null if the list is null
|
||||
*/
|
||||
@Nullable
|
||||
protected <T> List<T> addListItem(LiveData<LiveResult<List<T>>> liveData,
|
||||
T item) {
|
||||
List<T> items = getListCopy(liveData);
|
||||
if (items == null) return null;
|
||||
items.add(item);
|
||||
return items;
|
||||
protected <T> List<T> addListItem(@Nullable List<T> list, T item) {
|
||||
if (list == null) return null;
|
||||
List<T> copy = new ArrayList<>(list);
|
||||
copy.add(item);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of the list available in the given LiveData
|
||||
* and adds the given items to the copy.
|
||||
* Creates a copy of the given list and adds the given items to the copy.
|
||||
*
|
||||
* @return a copy of the list in the LiveData with items added or null when
|
||||
* <ul>
|
||||
* <li> LiveData does not have a value
|
||||
* <li> LiveResult in the LiveData has an error
|
||||
* </ul>
|
||||
* @return an updated copy of the list, or null if the list is null
|
||||
*/
|
||||
@Nullable
|
||||
protected <T> List<T> addListItems(LiveData<LiveResult<List<T>>> liveData,
|
||||
protected <T> List<T> addListItems(@Nullable List<T> list,
|
||||
Collection<T> items) {
|
||||
List<T> copiedItems = getListCopy(liveData);
|
||||
if (copiedItems == null) return null;
|
||||
copiedItems.addAll(items);
|
||||
return copiedItems;
|
||||
if (list == null) return null;
|
||||
List<T> copy = new ArrayList<>(list);
|
||||
copy.addAll(items);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of the list available in the given LiveData
|
||||
* and replaces items where the given test function returns true.
|
||||
* Creates a copy of the given list, replacing items where the given test
|
||||
* function returns true.
|
||||
*
|
||||
* @return a copy of the list in the LiveData with item(s) replaced
|
||||
* or null when the
|
||||
* <ul>
|
||||
* <li> LiveData does not have a value
|
||||
* <li> LiveResult in the LiveData has an error
|
||||
* <li> test function did return false for all items in the list
|
||||
* </ul>
|
||||
* @return an updated copy of the list, or null if either the list is null
|
||||
* or the test function returns false for all items
|
||||
*/
|
||||
@Nullable
|
||||
protected <T> List<T> updateListItems(
|
||||
LiveData<LiveResult<List<T>>> liveData, Function<T, Boolean> test,
|
||||
Function<T, T> replacer) {
|
||||
List<T> items = getListCopy(liveData);
|
||||
if (items == null) return null;
|
||||
protected <T> List<T> updateListItems(@Nullable List<T> list,
|
||||
Function<T, Boolean> test, Function<T, T> replacer) {
|
||||
if (list == null) return null;
|
||||
List<T> copy = new ArrayList<>(list);
|
||||
|
||||
ListIterator<T> iterator = items.listIterator();
|
||||
ListIterator<T> iterator = copy.listIterator();
|
||||
boolean changed = false;
|
||||
while (iterator.hasNext()) {
|
||||
T item = iterator.next();
|
||||
@@ -214,28 +199,23 @@ public abstract class DbViewModel extends AndroidViewModel {
|
||||
iterator.set(replacer.apply(item));
|
||||
}
|
||||
}
|
||||
return changed ? items : null;
|
||||
return changed ? copy : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of the list available in the given LiveData
|
||||
* and removes the items from it where the given test function returns true.
|
||||
* Creates a copy of the given list, removing items from it where the given
|
||||
* test function returns true.
|
||||
*
|
||||
* @return a copy of the list in the LiveData with item(s) removed
|
||||
* or null when the
|
||||
* <ul>
|
||||
* <li> LiveData does not have a value
|
||||
* <li> LiveResult in the LiveData has an error
|
||||
* <li> test function did return false for all items in the list
|
||||
* </ul>
|
||||
* @return an updated copy of the list, or null if either the list is null
|
||||
* or the test function returns false for all items
|
||||
*/
|
||||
@Nullable
|
||||
protected <T> List<T> removeListItems(
|
||||
LiveData<LiveResult<List<T>>> liveData, Function<T, Boolean> test) {
|
||||
List<T> items = getListCopy(liveData);
|
||||
if (items == null) return null;
|
||||
protected <T> List<T> removeListItems(@Nullable List<T> list,
|
||||
Function<T, Boolean> test) {
|
||||
if (list == null) return null;
|
||||
List<T> copy = new ArrayList<>(list);
|
||||
|
||||
ListIterator<T> iterator = items.listIterator();
|
||||
ListIterator<T> iterator = copy.listIterator();
|
||||
boolean changed = false;
|
||||
while (iterator.hasNext()) {
|
||||
T item = iterator.next();
|
||||
@@ -244,7 +224,7 @@ public abstract class DbViewModel extends AndroidViewModel {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
return changed ? items : null;
|
||||
return changed ? copy : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -255,29 +235,26 @@ public abstract class DbViewModel extends AndroidViewModel {
|
||||
* <ul>
|
||||
* <li> LiveData does not have a value
|
||||
* <li> LiveResult in the LiveData has an error
|
||||
* <li> test function did return false for all items in the list
|
||||
* <li> test function returned false for all items in the list
|
||||
* </ul>
|
||||
*/
|
||||
@UiThread
|
||||
protected <T> void removeAndUpdateListItems(
|
||||
MutableLiveData<LiveResult<List<T>>> liveData,
|
||||
Function<T, Boolean> test) {
|
||||
List<T> list = removeListItems(liveData, test);
|
||||
if (list != null) liveData.setValue(new LiveResult<>(list));
|
||||
List<T> copy = removeListItems(getList(liveData), test);
|
||||
if (copy != null) liveData.setValue(new LiveResult<>(copy));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a copy of the list of items from the given LiveData
|
||||
* or null if it is not available.
|
||||
* The list copy can be safely mutated.
|
||||
* Returns the list of items from the given LiveData, or null if no list is
|
||||
* available.
|
||||
*/
|
||||
@Nullable
|
||||
private <T> List<T> getListCopy(LiveData<LiveResult<List<T>>> liveData) {
|
||||
protected <T> List<T> getList(LiveData<LiveResult<List<T>>> liveData) {
|
||||
LiveResult<List<T>> value = liveData.getValue();
|
||||
if (value == null) return null;
|
||||
List<T> list = value.getResultOrNull();
|
||||
if (list == null) return null;
|
||||
return new ArrayList<>(list);
|
||||
return value.getResultOrNull();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user