mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-22 07:39:53 +01:00
Clean up after migrating blog controllers to view model
This commit is contained in:
@@ -13,7 +13,6 @@ import org.briarproject.briar.android.blog.BlogActivity;
|
|||||||
import org.briarproject.briar.android.blog.BlogFragment;
|
import org.briarproject.briar.android.blog.BlogFragment;
|
||||||
import org.briarproject.briar.android.blog.BlogPostFragment;
|
import org.briarproject.briar.android.blog.BlogPostFragment;
|
||||||
import org.briarproject.briar.android.blog.FeedFragment;
|
import org.briarproject.briar.android.blog.FeedFragment;
|
||||||
import org.briarproject.briar.android.blog.FeedPostFragment;
|
|
||||||
import org.briarproject.briar.android.blog.ReblogActivity;
|
import org.briarproject.briar.android.blog.ReblogActivity;
|
||||||
import org.briarproject.briar.android.blog.ReblogFragment;
|
import org.briarproject.briar.android.blog.ReblogFragment;
|
||||||
import org.briarproject.briar.android.blog.RssFeedImportActivity;
|
import org.briarproject.briar.android.blog.RssFeedImportActivity;
|
||||||
@@ -150,8 +149,6 @@ public interface ActivityComponent {
|
|||||||
|
|
||||||
void inject(BlogPostFragment fragment);
|
void inject(BlogPostFragment fragment);
|
||||||
|
|
||||||
void inject(FeedPostFragment fragment);
|
|
||||||
|
|
||||||
void inject(ReblogFragment fragment);
|
void inject(ReblogFragment fragment);
|
||||||
|
|
||||||
void inject(ReblogActivity activity);
|
void inject(ReblogActivity activity);
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
package org.briarproject.briar.android.blog;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
|
||||||
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.lifecycle.LifecycleManager;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
|
||||||
import org.briarproject.briar.android.controller.DbControllerImpl;
|
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
|
||||||
import org.briarproject.briar.api.blog.BlogManager;
|
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
|
||||||
@ParametersNotNullByDefault
|
|
||||||
abstract class BaseControllerImpl extends DbControllerImpl
|
|
||||||
implements EventListener {
|
|
||||||
|
|
||||||
protected final EventBus eventBus;
|
|
||||||
protected final AndroidNotificationManager notificationManager;
|
|
||||||
protected final IdentityManager identityManager;
|
|
||||||
protected final BlogManager blogManager;
|
|
||||||
|
|
||||||
BaseControllerImpl(@DatabaseExecutor Executor dbExecutor,
|
|
||||||
LifecycleManager lifecycleManager, EventBus eventBus,
|
|
||||||
AndroidNotificationManager notificationManager,
|
|
||||||
IdentityManager identityManager, BlogManager blogManager) {
|
|
||||||
super(dbExecutor, lifecycleManager);
|
|
||||||
this.eventBus = eventBus;
|
|
||||||
this.notificationManager = notificationManager;
|
|
||||||
this.identityManager = identityManager;
|
|
||||||
this.blogManager = blogManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
package org.briarproject.briar.android.blog;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.ProgressBar;
|
|
||||||
|
|
||||||
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.R;
|
|
||||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
|
||||||
import org.briarproject.briar.android.widget.LinkDialogFragment;
|
|
||||||
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import androidx.annotation.CallSuper;
|
|
||||||
import androidx.annotation.UiThread;
|
|
||||||
|
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
|
||||||
import static android.view.View.INVISIBLE;
|
|
||||||
import static android.view.View.VISIBLE;
|
|
||||||
import static java.util.logging.Logger.getLogger;
|
|
||||||
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
|
|
||||||
import static org.briarproject.briar.android.util.UiUtils.MIN_DATE_RESOLUTION;
|
|
||||||
|
|
||||||
@UiThread
|
|
||||||
@MethodsNotNullByDefault
|
|
||||||
@ParametersNotNullByDefault
|
|
||||||
abstract class BasePostFragment extends BaseFragment {
|
|
||||||
|
|
||||||
static final String POST_ID = "briar.POST_ID";
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
|
||||||
getLogger(BasePostFragment.class.getName());
|
|
||||||
|
|
||||||
private final Handler handler = new Handler(Looper.getMainLooper());
|
|
||||||
|
|
||||||
protected MessageId postId;
|
|
||||||
private ProgressBar progressBar;
|
|
||||||
private BlogPostViewHolder ui;
|
|
||||||
private BlogPostItem post;
|
|
||||||
private Runnable refresher;
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public View onCreateView(LayoutInflater inflater,
|
|
||||||
@Nullable ViewGroup container,
|
|
||||||
@Nullable Bundle savedInstanceState) {
|
|
||||||
// retrieve MessageId of blog post from arguments
|
|
||||||
byte[] p = requireArguments().getByteArray(POST_ID);
|
|
||||||
if (p == null) throw new IllegalStateException("No post ID in args");
|
|
||||||
postId = new MessageId(p);
|
|
||||||
|
|
||||||
View view = inflater.inflate(R.layout.fragment_blog_post, container,
|
|
||||||
false);
|
|
||||||
progressBar = view.findViewById(R.id.progressBar);
|
|
||||||
progressBar.setVisibility(VISIBLE);
|
|
||||||
ui = new BlogPostViewHolder(view, true, new OnBlogPostClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onBlogPostClick(BlogPostItem post) {
|
|
||||||
// We're already there
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAuthorClick(BlogPostItem post) {
|
|
||||||
if (getContext() == null) return;
|
|
||||||
Intent i = new Intent(getContext(), BlogActivity.class);
|
|
||||||
i.putExtra(GROUP_ID, post.getGroupId().getBytes());
|
|
||||||
i.setFlags(FLAG_ACTIVITY_CLEAR_TOP);
|
|
||||||
getContext().startActivity(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLinkClick(String url) {
|
|
||||||
LinkDialogFragment f = LinkDialogFragment.newInstance(url);
|
|
||||||
f.show(getParentFragmentManager(), f.getUniqueTag());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
startPeriodicUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
@Override
|
|
||||||
public void onStop() {
|
|
||||||
super.onStop();
|
|
||||||
stopPeriodicUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@UiThread
|
|
||||||
protected void onBlogPostLoaded(BlogPostItem post) {
|
|
||||||
progressBar.setVisibility(INVISIBLE);
|
|
||||||
this.post = post;
|
|
||||||
ui.bindItem(post);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startPeriodicUpdate() {
|
|
||||||
refresher = () -> {
|
|
||||||
LOG.info("Updating Content...");
|
|
||||||
ui.updateDate(post.getTimestamp());
|
|
||||||
handler.postDelayed(refresher, MIN_DATE_RESOLUTION);
|
|
||||||
};
|
|
||||||
LOG.info("Adding Handler Callback");
|
|
||||||
handler.postDelayed(refresher, MIN_DATE_RESOLUTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stopPeriodicUpdate() {
|
|
||||||
if (refresher != null) {
|
|
||||||
LOG.info("Removing Handler Callback");
|
|
||||||
handler.removeCallbacks(refresher);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,6 @@ import org.briarproject.bramble.api.db.DatabaseExecutor;
|
|||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.db.TransactionManager;
|
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.event.EventBus;
|
||||||
import org.briarproject.bramble.api.event.EventListener;
|
import org.briarproject.bramble.api.event.EventListener;
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
@@ -28,13 +27,10 @@ import org.briarproject.briar.util.HtmlUtils;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import androidx.annotation.UiThread;
|
import androidx.annotation.UiThread;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
@@ -48,27 +44,23 @@ import static org.briarproject.bramble.util.LogUtils.now;
|
|||||||
import static org.briarproject.briar.util.HtmlUtils.ARTICLE;
|
import static org.briarproject.briar.util.HtmlUtils.ARTICLE;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class BaseViewModel extends DbViewModel implements EventListener {
|
abstract class BaseViewModel extends DbViewModel implements EventListener {
|
||||||
|
|
||||||
private static final Logger LOG = getLogger(BaseViewModel.class.getName());
|
private static final Logger LOG = getLogger(BaseViewModel.class.getName());
|
||||||
|
|
||||||
protected final TransactionManager db;
|
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
|
protected final TransactionManager db;
|
||||||
protected final IdentityManager identityManager;
|
protected final IdentityManager identityManager;
|
||||||
protected final AndroidNotificationManager notificationManager;
|
protected final AndroidNotificationManager notificationManager;
|
||||||
protected final BlogManager blogManager;
|
protected final BlogManager blogManager;
|
||||||
|
|
||||||
private final MutableLiveData<LiveResult<List<BlogPostItem>>> blogPosts =
|
protected final MutableLiveData<LiveResult<List<BlogPostItem>>> blogPosts =
|
||||||
new MutableLiveData<>();
|
new MutableLiveData<>();
|
||||||
|
|
||||||
// TODO do we still need those caches?
|
// UI thread
|
||||||
private final Map<MessageId, String> textCache = new ConcurrentHashMap<>();
|
|
||||||
private final Map<MessageId, BlogPostHeader> headerCache =
|
|
||||||
new ConcurrentHashMap<>();
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Boolean postAddedWasLocal = null;
|
private Boolean postAddedWasLocal = null;
|
||||||
|
|
||||||
@Inject
|
|
||||||
BaseViewModel(Application application,
|
BaseViewModel(Application application,
|
||||||
@DatabaseExecutor Executor dbExecutor,
|
@DatabaseExecutor Executor dbExecutor,
|
||||||
LifecycleManager lifecycleManager,
|
LifecycleManager lifecycleManager,
|
||||||
@@ -84,7 +76,6 @@ public class BaseViewModel extends DbViewModel implements EventListener {
|
|||||||
this.identityManager = identityManager;
|
this.identityManager = identityManager;
|
||||||
this.notificationManager = notificationManager;
|
this.notificationManager = notificationManager;
|
||||||
this.blogManager = blogManager;
|
this.blogManager = blogManager;
|
||||||
|
|
||||||
eventBus.addListener(this);
|
eventBus.addListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,10 +85,6 @@ public class BaseViewModel extends DbViewModel implements EventListener {
|
|||||||
eventBus.removeListener(this);
|
eventBus.removeListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void eventOccurred(Event e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@DatabaseExecutor
|
@DatabaseExecutor
|
||||||
protected List<BlogPostItem> loadBlogPosts(Transaction txn, GroupId groupId)
|
protected List<BlogPostItem> loadBlogPosts(Transaction txn, GroupId groupId)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
@@ -108,7 +95,6 @@ public class BaseViewModel extends DbViewModel implements EventListener {
|
|||||||
List<BlogPostItem> items = new ArrayList<>(headers.size());
|
List<BlogPostItem> items = new ArrayList<>(headers.size());
|
||||||
start = now();
|
start = now();
|
||||||
for (BlogPostHeader h : headers) {
|
for (BlogPostHeader h : headers) {
|
||||||
headerCache.put(h.getId(), h);
|
|
||||||
BlogPostItem item = getItem(txn, h);
|
BlogPostItem item = getItem(txn, h);
|
||||||
items.add(item);
|
items.add(item);
|
||||||
}
|
}
|
||||||
@@ -135,12 +121,7 @@ public class BaseViewModel extends DbViewModel implements EventListener {
|
|||||||
@DatabaseExecutor
|
@DatabaseExecutor
|
||||||
private String getPostText(Transaction txn, MessageId m)
|
private String getPostText(Transaction txn, MessageId m)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
String text = textCache.get(m);
|
return HtmlUtils.clean(blogManager.getPostText(txn, m), ARTICLE);
|
||||||
if (text == null) {
|
|
||||||
text = HtmlUtils.clean(blogManager.getPostText(txn, m), ARTICLE);
|
|
||||||
textCache.put(m, text);
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LiveData<LiveResult<BlogPostItem>> loadBlogPost(GroupId g, MessageId m) {
|
LiveData<LiveResult<BlogPostItem>> loadBlogPost(GroupId g, MessageId m) {
|
||||||
@@ -149,7 +130,7 @@ public class BaseViewModel extends DbViewModel implements EventListener {
|
|||||||
runOnDbThread(() -> {
|
runOnDbThread(() -> {
|
||||||
try {
|
try {
|
||||||
long start = now();
|
long start = now();
|
||||||
BlogPostHeader header = getPostHeader(g, m);
|
BlogPostHeader header = blogManager.getPostHeader(g, m);
|
||||||
BlogPostItem item = db.transactionWithResult(true, txn ->
|
BlogPostItem item = db.transactionWithResult(true, txn ->
|
||||||
getItem(txn, header)
|
getItem(txn, header)
|
||||||
);
|
);
|
||||||
@@ -163,24 +144,7 @@ public class BaseViewModel extends DbViewModel implements EventListener {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@DatabaseExecutor
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@UiThread
|
|
||||||
protected void updateBlogPosts(LiveResult<List<BlogPostItem>> posts) {
|
|
||||||
blogPosts.setValue(posts);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onBlogPostAdded(BlogPostHeader header, boolean local) {
|
protected void onBlogPostAdded(BlogPostHeader header, boolean local) {
|
||||||
postAddedWasLocal = local;
|
|
||||||
runOnDbThread(() -> {
|
runOnDbThread(() -> {
|
||||||
try {
|
try {
|
||||||
db.transaction(true, txn -> {
|
db.transaction(true, txn -> {
|
||||||
@@ -189,6 +153,7 @@ public class BaseViewModel extends DbViewModel implements EventListener {
|
|||||||
List<BlogPostItem> items = addListItem(blogPosts, item);
|
List<BlogPostItem> items = addListItem(blogPosts, item);
|
||||||
if (items != null) {
|
if (items != null) {
|
||||||
Collections.sort(items);
|
Collections.sort(items);
|
||||||
|
postAddedWasLocal = local;
|
||||||
blogPosts.setValue(new LiveResult<>(items));
|
blogPosts.setValue(new LiveResult<>(items));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ import java.util.Collections;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
// This class is not thread-safe
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
|
|
||||||
|
@NotThreadSafe
|
||||||
class BlogCommentItem extends BlogPostItem {
|
class BlogCommentItem extends BlogPostItem {
|
||||||
|
|
||||||
private static final BlogCommentComparator COMPARATOR =
|
private static final BlogCommentComparator COMPARATOR =
|
||||||
|
|||||||
@@ -166,7 +166,6 @@ public class BlogFragment extends BaseFragment
|
|||||||
|
|
||||||
if (request == REQUEST_WRITE_BLOG_POST && result == RESULT_OK) {
|
if (request == REQUEST_WRITE_BLOG_POST && result == RESULT_OK) {
|
||||||
displaySnackbar(R.string.blogs_blog_post_created, true);
|
displaySnackbar(R.string.blogs_blog_post_created, true);
|
||||||
viewModel.loadBlogPosts(groupId);
|
|
||||||
} else if (request == REQUEST_SHARE_BLOG && result == RESULT_OK) {
|
} else if (request == REQUEST_SHARE_BLOG && result == RESULT_OK) {
|
||||||
displaySnackbar(R.string.blogs_sharing_snackbar, false);
|
displaySnackbar(R.string.blogs_sharing_snackbar, false);
|
||||||
}
|
}
|
||||||
@@ -194,7 +193,8 @@ public class BlogFragment extends BaseFragment
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBlogPostClick(BlogPostItem post) {
|
public void onBlogPostClick(BlogPostItem post) {
|
||||||
BlogPostFragment f = BlogPostFragment.newInstance(post.getId());
|
BlogPostFragment f =
|
||||||
|
BlogPostFragment.newInstance(groupId, post.getId());
|
||||||
showNextFragment(f);
|
showNextFragment(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ public interface BlogModule {
|
|||||||
@Binds
|
@Binds
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@ViewModelKey(FeedViewModel.class)
|
@ViewModelKey(FeedViewModel.class)
|
||||||
abstract ViewModel bindFeedViewModel(FeedViewModel feedViewModel);
|
ViewModel bindFeedViewModel(FeedViewModel feedViewModel);
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@ViewModelKey(BlogViewModel.class)
|
@ViewModelKey(BlogViewModel.class)
|
||||||
abstract ViewModel bindBlogViewModel(BlogViewModel blogViewModel);
|
ViewModel bindBlogViewModel(BlogViewModel blogViewModel);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +1,68 @@
|
|||||||
package org.briarproject.briar.android.blog;
|
package org.briarproject.briar.android.blog;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
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.MessageId;
|
||||||
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
|
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||||
|
import org.briarproject.briar.android.widget.LinkDialogFragment;
|
||||||
|
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import androidx.annotation.CallSuper;
|
||||||
import androidx.annotation.UiThread;
|
import androidx.annotation.UiThread;
|
||||||
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
|
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
||||||
|
import static android.view.View.INVISIBLE;
|
||||||
|
import static android.view.View.VISIBLE;
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.MIN_DATE_RESOLUTION;
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
public class BlogPostFragment extends BasePostFragment {
|
public class BlogPostFragment extends BaseFragment
|
||||||
|
implements OnBlogPostClickListener {
|
||||||
|
|
||||||
private static final String TAG = BlogPostFragment.class.getName();
|
private static final String TAG = BlogPostFragment.class.getName();
|
||||||
|
private static final Logger LOG = getLogger(TAG);
|
||||||
|
|
||||||
|
static final String POST_ID = "briar.POST_ID";
|
||||||
|
|
||||||
|
protected BlogViewModel viewModel;
|
||||||
|
private final Handler handler = new Handler(Looper.getMainLooper());
|
||||||
|
|
||||||
|
private ProgressBar progressBar;
|
||||||
|
private BlogPostViewHolder ui;
|
||||||
|
private BlogPostItem post;
|
||||||
|
private Runnable refresher;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ViewModelProvider.Factory viewModelFactory;
|
ViewModelProvider.Factory viewModelFactory;
|
||||||
|
|
||||||
private BlogViewModel viewModel;
|
static BlogPostFragment newInstance(GroupId blogId, MessageId postId) {
|
||||||
|
|
||||||
static BlogPostFragment newInstance(MessageId postId) {
|
|
||||||
BlogPostFragment f = new BlogPostFragment();
|
BlogPostFragment f = new BlogPostFragment();
|
||||||
|
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putByteArray(GROUP_ID, blogId.getBytes());
|
||||||
bundle.putByteArray(POST_ID, postId.getBytes());
|
bundle.putByteArray(POST_ID, postId.getBytes());
|
||||||
|
|
||||||
f.setArguments(bundle);
|
f.setArguments(bundle);
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
@@ -45,22 +74,89 @@ public class BlogPostFragment extends BasePostFragment {
|
|||||||
.get(BlogViewModel.class);
|
.get(BlogViewModel.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUniqueTag() {
|
|
||||||
return TAG;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater,
|
public View onCreateView(LayoutInflater inflater,
|
||||||
@Nullable ViewGroup container,
|
@Nullable ViewGroup container,
|
||||||
@Nullable Bundle savedInstanceState) {
|
@Nullable Bundle savedInstanceState) {
|
||||||
View v = super.onCreateView(inflater, container, savedInstanceState);
|
Bundle args = requireArguments();
|
||||||
viewModel.loadBlogPost(postId).observe(getViewLifecycleOwner(), res ->
|
GroupId groupId =
|
||||||
res.onError(this::handleException)
|
new GroupId(requireNonNull(args.getByteArray(GROUP_ID)));
|
||||||
|
MessageId postId = new MessageId(args.getByteArray(POST_ID));
|
||||||
|
|
||||||
|
View view = inflater.inflate(R.layout.fragment_blog_post, container,
|
||||||
|
false);
|
||||||
|
progressBar = view.findViewById(R.id.progressBar);
|
||||||
|
progressBar.setVisibility(VISIBLE);
|
||||||
|
ui = new BlogPostViewHolder(view, true, this);
|
||||||
|
LifecycleOwner owner = getViewLifecycleOwner();
|
||||||
|
viewModel.loadBlogPost(groupId, postId).observe(owner, result ->
|
||||||
|
result.onError(this::handleException)
|
||||||
.onSuccess(this::onBlogPostLoaded)
|
.onSuccess(this::onBlogPostLoaded)
|
||||||
);
|
);
|
||||||
return v;
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
startPeriodicUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
|
@Override
|
||||||
|
public void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
stopPeriodicUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
private void onBlogPostLoaded(BlogPostItem post) {
|
||||||
|
progressBar.setVisibility(INVISIBLE);
|
||||||
|
this.post = post;
|
||||||
|
ui.bindItem(post);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBlogPostClick(BlogPostItem post) {
|
||||||
|
// We're already there
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAuthorClick(BlogPostItem post) {
|
||||||
|
Intent i = new Intent(requireContext(), BlogActivity.class);
|
||||||
|
i.putExtra(GROUP_ID, post.getGroupId().getBytes());
|
||||||
|
i.setFlags(FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
getContext().startActivity(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLinkClick(String url) {
|
||||||
|
LinkDialogFragment f = LinkDialogFragment.newInstance(url);
|
||||||
|
f.show(getParentFragmentManager(), f.getUniqueTag());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startPeriodicUpdate() {
|
||||||
|
refresher = () -> {
|
||||||
|
LOG.info("Updating Content...");
|
||||||
|
ui.updateDate(post.getTimestamp());
|
||||||
|
handler.postDelayed(refresher, MIN_DATE_RESOLUTION);
|
||||||
|
};
|
||||||
|
LOG.info("Adding Handler Callback");
|
||||||
|
handler.postDelayed(refresher, MIN_DATE_RESOLUTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopPeriodicUpdate() {
|
||||||
|
if (refresher != null) {
|
||||||
|
LOG.info("Removing Handler Callback");
|
||||||
|
handler.removeCallbacks(refresher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUniqueTag() {
|
||||||
|
return TAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public class BlogPostItem implements Comparable<BlogPostItem> {
|
|||||||
private final BlogPostHeader header;
|
private final BlogPostHeader header;
|
||||||
@Nullable
|
@Nullable
|
||||||
protected String text;
|
protected String text;
|
||||||
private boolean read;
|
private final boolean read;
|
||||||
|
|
||||||
BlogPostItem(BlogPostHeader header, @Nullable String text) {
|
BlogPostItem(BlogPostHeader header, @Nullable String text) {
|
||||||
this.header = header;
|
this.header = header;
|
||||||
|
|||||||
@@ -25,11 +25,14 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||||||
import static android.view.View.GONE;
|
import static android.view.View.GONE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
|
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
|
||||||
import static org.briarproject.briar.android.blog.BasePostFragment.POST_ID;
|
import static org.briarproject.briar.android.blog.BlogPostFragment.POST_ID;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.TEASER_LENGTH;
|
import static org.briarproject.briar.android.util.UiUtils.TEASER_LENGTH;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.getSpanned;
|
import static org.briarproject.briar.android.util.UiUtils.getSpanned;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.getTeaser;
|
import static org.briarproject.briar.android.util.UiUtils.getTeaser;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.makeLinksClickable;
|
import static org.briarproject.briar.android.util.UiUtils.makeLinksClickable;
|
||||||
|
import static org.briarproject.briar.android.view.AuthorView.COMMENTER;
|
||||||
|
import static org.briarproject.briar.android.view.AuthorView.REBLOGGER;
|
||||||
|
import static org.briarproject.briar.android.view.AuthorView.RSS_FEED_REBLOGGED;
|
||||||
import static org.briarproject.briar.api.blog.MessageType.POST;
|
import static org.briarproject.briar.api.blog.MessageType.POST;
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
@@ -138,17 +141,16 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder {
|
|||||||
reblogger.setAuthorClickable(v -> listener.onAuthorClick(item));
|
reblogger.setAuthorClickable(v -> listener.onAuthorClick(item));
|
||||||
}
|
}
|
||||||
reblogger.setVisibility(VISIBLE);
|
reblogger.setVisibility(VISIBLE);
|
||||||
reblogger.setPersona(AuthorView.REBLOGGER);
|
reblogger.setPersona(REBLOGGER);
|
||||||
|
|
||||||
author.setPersona(item.getHeader().getRootPost().isRssFeed() ?
|
author.setPersona(item.getHeader().getRootPost().isRssFeed() ?
|
||||||
AuthorView.RSS_FEED_REBLOGGED :
|
RSS_FEED_REBLOGGED : COMMENTER);
|
||||||
AuthorView.COMMENTER);
|
|
||||||
|
|
||||||
// comments
|
// comments
|
||||||
|
// TODO use nested RecyclerView instead like we do for Image Attachments
|
||||||
for (BlogCommentHeader c : item.getComments()) {
|
for (BlogCommentHeader c : item.getComments()) {
|
||||||
View v = LayoutInflater.from(ctx)
|
View v = LayoutInflater.from(ctx).inflate(
|
||||||
.inflate(R.layout.list_item_blog_comment,
|
R.layout.list_item_blog_comment, commentContainer, false);
|
||||||
commentContainer, false);
|
|
||||||
|
|
||||||
AuthorView author = v.findViewById(R.id.authorView);
|
AuthorView author = v.findViewById(R.id.authorView);
|
||||||
TextView text = v.findViewById(R.id.textView);
|
TextView text = v.findViewById(R.id.textView);
|
||||||
|
|||||||
@@ -148,8 +148,8 @@ class BlogViewModel extends BaseViewModel {
|
|||||||
notificationManager.unblockNotification(groupId);
|
notificationManager.unblockNotification(groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadBlogPosts(GroupId groupId) {
|
private void loadBlogPosts(GroupId groupId) {
|
||||||
loadList(txn -> loadBlogPosts(txn, groupId), this::updateBlogPosts);
|
loadList(txn -> loadBlogPosts(txn, groupId), blogPosts::setValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadSharingContacts(GroupId groupId) {
|
private void loadSharingContacts(GroupId groupId) {
|
||||||
|
|||||||
@@ -62,9 +62,6 @@ public class FeedFragment extends BaseFragment
|
|||||||
component.inject(this);
|
component.inject(this);
|
||||||
viewModel = new ViewModelProvider(this, viewModelFactory)
|
viewModel = new ViewModelProvider(this, viewModelFactory)
|
||||||
.get(FeedViewModel.class);
|
.get(FeedViewModel.class);
|
||||||
// TODO ideally we only do this once when the ViewModel gets created
|
|
||||||
viewModel.loadPersonalBlog();
|
|
||||||
viewModel.loadAllBlogPosts();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -154,8 +151,8 @@ public class FeedFragment extends BaseFragment
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBlogPostClick(BlogPostItem post) {
|
public void onBlogPostClick(BlogPostItem post) {
|
||||||
FeedPostFragment f =
|
BaseFragment f =
|
||||||
FeedPostFragment.newInstance(post.getGroupId(), post.getId());
|
BlogPostFragment.newInstance(post.getGroupId(), post.getId());
|
||||||
showNextFragment(f);
|
showNextFragment(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
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.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.activity.ActivityComponent;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import androidx.annotation.UiThread;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
|
||||||
|
|
||||||
import static java.util.Objects.requireNonNull;
|
|
||||||
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
|
|
||||||
|
|
||||||
@UiThread
|
|
||||||
@MethodsNotNullByDefault
|
|
||||||
@ParametersNotNullByDefault
|
|
||||||
public class FeedPostFragment extends BasePostFragment {
|
|
||||||
|
|
||||||
private static final String TAG = FeedPostFragment.class.getName();
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
ViewModelProvider.Factory viewModelFactory;
|
|
||||||
|
|
||||||
private FeedViewModel viewModel;
|
|
||||||
|
|
||||||
static FeedPostFragment newInstance(GroupId blogId, MessageId postId) {
|
|
||||||
FeedPostFragment f = new FeedPostFragment();
|
|
||||||
Bundle bundle = new Bundle();
|
|
||||||
bundle.putByteArray(GROUP_ID, blogId.getBytes());
|
|
||||||
bundle.putByteArray(POST_ID, postId.getBytes());
|
|
||||||
f.setArguments(bundle);
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void injectFragment(ActivityComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
|
|
||||||
.get(FeedViewModel.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public View onCreateView(LayoutInflater inflater,
|
|
||||||
@Nullable ViewGroup container,
|
|
||||||
@Nullable Bundle savedInstanceState) {
|
|
||||||
Bundle args = requireArguments();
|
|
||||||
GroupId groupId =
|
|
||||||
new GroupId(requireNonNull(args.getByteArray(GROUP_ID)));
|
|
||||||
MessageId postId =
|
|
||||||
new MessageId(requireNonNull(args.getByteArray(POST_ID)));
|
|
||||||
viewModel.loadBlogPost(groupId, postId).observe(getViewLifecycleOwner(),
|
|
||||||
result -> result.onError(this::handleException)
|
|
||||||
.onSuccess(this::onBlogPostLoaded)
|
|
||||||
);
|
|
||||||
return super.onCreateView(inflater, container, savedInstanceState);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUniqueTag() {
|
|
||||||
return TAG;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -17,6 +17,7 @@ import org.briarproject.bramble.api.sync.GroupId;
|
|||||||
import org.briarproject.bramble.api.sync.event.GroupAddedEvent;
|
import org.briarproject.bramble.api.sync.event.GroupAddedEvent;
|
||||||
import org.briarproject.bramble.api.sync.event.GroupRemovedEvent;
|
import org.briarproject.bramble.api.sync.event.GroupRemovedEvent;
|
||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
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.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.blog.Blog;
|
import org.briarproject.briar.api.blog.Blog;
|
||||||
import org.briarproject.briar.api.blog.BlogManager;
|
import org.briarproject.briar.api.blog.BlogManager;
|
||||||
@@ -59,6 +60,8 @@ class FeedViewModel extends BaseViewModel {
|
|||||||
BlogManager blogManager) {
|
BlogManager blogManager) {
|
||||||
super(application, dbExecutor, lifecycleManager, db, androidExecutor,
|
super(application, dbExecutor, lifecycleManager, db, androidExecutor,
|
||||||
eventBus, identityManager, notificationManager, blogManager);
|
eventBus, identityManager, notificationManager, blogManager);
|
||||||
|
loadPersonalBlog();
|
||||||
|
loadAllBlogPosts();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -71,13 +74,15 @@ class FeedViewModel extends BaseViewModel {
|
|||||||
GroupAddedEvent g = (GroupAddedEvent) e;
|
GroupAddedEvent g = (GroupAddedEvent) e;
|
||||||
if (g.getGroup().getClientId().equals(CLIENT_ID)) {
|
if (g.getGroup().getClientId().equals(CLIENT_ID)) {
|
||||||
LOG.info("Blog added");
|
LOG.info("Blog added");
|
||||||
loadAllBlogPosts();
|
// TODO how can this even happen?
|
||||||
|
// added RSS feeds should trigger BlogPostAddedEvent, no?
|
||||||
|
onBlogAdded(g.getGroup().getId());
|
||||||
}
|
}
|
||||||
} else if (e instanceof GroupRemovedEvent) {
|
} else if (e instanceof GroupRemovedEvent) {
|
||||||
GroupRemovedEvent g = (GroupRemovedEvent) e;
|
GroupRemovedEvent g = (GroupRemovedEvent) e;
|
||||||
if (g.getGroup().getClientId().equals(CLIENT_ID)) {
|
if (g.getGroup().getClientId().equals(CLIENT_ID)) {
|
||||||
LOG.info("Blog removed");
|
LOG.info("Blog removed");
|
||||||
loadAllBlogPosts();
|
onBlogRemoved(g.getGroup().getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,7 +99,7 @@ class FeedViewModel extends BaseViewModel {
|
|||||||
notificationManager.unblockAllBlogPostNotifications();
|
notificationManager.unblockAllBlogPostNotifications();
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadPersonalBlog() {
|
private void loadPersonalBlog() {
|
||||||
runOnDbThread(() -> {
|
runOnDbThread(() -> {
|
||||||
try {
|
try {
|
||||||
long start = now();
|
long start = now();
|
||||||
@@ -112,8 +117,8 @@ class FeedViewModel extends BaseViewModel {
|
|||||||
return personalBlog;
|
return personalBlog;
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadAllBlogPosts() {
|
private void loadAllBlogPosts() {
|
||||||
loadList(this::loadAllBlogPosts, this::updateBlogPosts);
|
loadList(this::loadAllBlogPosts, blogPosts::setValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@DatabaseExecutor
|
@DatabaseExecutor
|
||||||
@@ -133,4 +138,30 @@ class FeedViewModel extends BaseViewModel {
|
|||||||
return posts;
|
return posts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onBlogAdded(GroupId g) {
|
||||||
|
runOnDbThread(() -> {
|
||||||
|
try {
|
||||||
|
db.transaction(true, txn -> {
|
||||||
|
List<BlogPostItem> posts = loadBlogPosts(txn, g);
|
||||||
|
txn.attach(() -> {
|
||||||
|
List<BlogPostItem> items =
|
||||||
|
addListItems(blogPosts, posts);
|
||||||
|
if (items != null) {
|
||||||
|
Collections.sort(items);
|
||||||
|
blogPosts.setValue(new LiveResult<>(items));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} catch (DbException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onBlogRemoved(GroupId g) {
|
||||||
|
removeAndUpdateListItems(blogPosts, item ->
|
||||||
|
item.getGroupId().equals(g)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import org.briarproject.briar.android.activity.ActivityComponent;
|
|||||||
import org.briarproject.briar.android.activity.BriarActivity;
|
import org.briarproject.briar.android.activity.BriarActivity;
|
||||||
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
|
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
|
||||||
|
|
||||||
import static org.briarproject.briar.android.blog.BasePostFragment.POST_ID;
|
import static org.briarproject.briar.android.blog.BlogPostFragment.POST_ID;
|
||||||
|
|
||||||
public class ReblogActivity extends BriarActivity implements
|
public class ReblogActivity extends BriarActivity implements
|
||||||
BaseFragmentListener {
|
BaseFragmentListener {
|
||||||
@@ -39,13 +39,11 @@ public class ReblogActivity extends BriarActivity implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
if (item.getItemId() == android.R.id.home) {
|
||||||
case android.R.id.home:
|
onBackPressed();
|
||||||
onBackPressed();
|
return true;
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import static android.view.View.INVISIBLE;
|
|||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
|
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
|
||||||
import static org.briarproject.briar.android.blog.BasePostFragment.POST_ID;
|
import static org.briarproject.briar.android.blog.BlogPostFragment.POST_ID;
|
||||||
import static org.briarproject.briar.api.blog.BlogConstants.MAX_BLOG_POST_TEXT_LENGTH;
|
import static org.briarproject.briar.api.blog.BlogConstants.MAX_BLOG_POST_TEXT_LENGTH;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@@ -45,7 +45,7 @@ public class ReblogFragment extends BaseFragment implements SendListener {
|
|||||||
@Inject
|
@Inject
|
||||||
ViewModelProvider.Factory viewModelFactory;
|
ViewModelProvider.Factory viewModelFactory;
|
||||||
|
|
||||||
private FeedViewModel viewModel;
|
private BlogViewModel viewModel;
|
||||||
private ViewHolder ui;
|
private ViewHolder ui;
|
||||||
private BlogPostItem item;
|
private BlogPostItem item;
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ public class ReblogFragment extends BaseFragment implements SendListener {
|
|||||||
public void injectFragment(ActivityComponent component) {
|
public void injectFragment(ActivityComponent component) {
|
||||||
component.inject(this);
|
component.inject(this);
|
||||||
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
|
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
|
||||||
.get(FeedViewModel.class);
|
.get(BlogViewModel.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -131,7 +131,7 @@ public class ReblogFragment extends BaseFragment implements SendListener {
|
|||||||
ui.input.setVisibility(VISIBLE);
|
ui.input.setVisibility(VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ViewHolder {
|
private class ViewHolder implements OnBlogPostClickListener {
|
||||||
|
|
||||||
private final ScrollView scrollView;
|
private final ScrollView scrollView;
|
||||||
private final ProgressBar progressBar;
|
private final ProgressBar progressBar;
|
||||||
@@ -142,24 +142,25 @@ public class ReblogFragment extends BaseFragment implements SendListener {
|
|||||||
scrollView = v.findViewById(R.id.scrollView);
|
scrollView = v.findViewById(R.id.scrollView);
|
||||||
progressBar = v.findViewById(R.id.progressBar);
|
progressBar = v.findViewById(R.id.progressBar);
|
||||||
post = new BlogPostViewHolder(v.findViewById(R.id.postLayout),
|
post = new BlogPostViewHolder(v.findViewById(R.id.postLayout),
|
||||||
true, new OnBlogPostClickListener() {
|
true, this);
|
||||||
@Override
|
|
||||||
public void onBlogPostClick(BlogPostItem post) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAuthorClick(BlogPostItem post) {
|
|
||||||
// probably don't want to allow author clicks here
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLinkClick(String url) {
|
|
||||||
LinkDialogFragment f = LinkDialogFragment.newInstance(url);
|
|
||||||
f.show(getParentFragmentManager(), f.getUniqueTag());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
input = v.findViewById(R.id.inputText);
|
input = v.findViewById(R.id.inputText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBlogPostClick(BlogPostItem post) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAuthorClick(BlogPostItem post) {
|
||||||
|
// probably don't want to allow author clicks here
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLinkClick(String url) {
|
||||||
|
LinkDialogFragment f = LinkDialogFragment.newInstance(url);
|
||||||
|
f.show(getParentFragmentManager(), f.getUniqueTag());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -156,11 +156,9 @@ class ForumListViewModel extends DbViewModel implements EventListener {
|
|||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void onGroupRemoved(GroupId groupId) {
|
private void onGroupRemoved(GroupId groupId) {
|
||||||
List<ForumListItem> list = removeListItems(forumItems, i ->
|
removeAndUpdateListItems(forumItems, i ->
|
||||||
i.getForum().getId().equals(groupId)
|
i.getForum().getId().equals(groupId)
|
||||||
);
|
);
|
||||||
if (list == null) return;
|
|
||||||
forumItems.setValue(new LiveResult<>(list));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadForumInvitations() {
|
void loadForumInvitations() {
|
||||||
|
|||||||
@@ -193,10 +193,7 @@ class GroupListViewModel extends DbViewModel implements EventListener {
|
|||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void onGroupRemoved(GroupId groupId) {
|
private void onGroupRemoved(GroupId groupId) {
|
||||||
List<GroupItem> list =
|
removeAndUpdateListItems(groupItems, i -> i.getId().equals(groupId));
|
||||||
removeListItems(groupItems, i -> i.getId().equals(groupId));
|
|
||||||
if (list == null) return;
|
|
||||||
groupItems.setValue(new LiveResult<>(list));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeGroup(GroupId g) {
|
void removeGroup(GroupId g) {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ListIterator;
|
import java.util.ListIterator;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
@@ -27,6 +28,7 @@ import androidx.arch.core.util.Function;
|
|||||||
import androidx.core.util.Consumer;
|
import androidx.core.util.Consumer;
|
||||||
import androidx.lifecycle.AndroidViewModel;
|
import androidx.lifecycle.AndroidViewModel;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
|
import androidx.lifecycle.MutableLiveData;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
@@ -153,13 +155,33 @@ public abstract class DbViewModel extends AndroidViewModel {
|
|||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
protected <T> List<T> addListItem(LiveData<LiveResult<List<T>>> liveData, T item) {
|
protected <T> List<T> addListItem(LiveData<LiveResult<List<T>>> liveData,
|
||||||
|
T item) {
|
||||||
List<T> items = getListCopy(liveData);
|
List<T> items = getListCopy(liveData);
|
||||||
if (items == null) return null;
|
if (items == null) return null;
|
||||||
items.add(item);
|
items.add(item);
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a copy of the list available in the given LiveData
|
||||||
|
* 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>
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
protected <T> List<T> addListItems(LiveData<LiveResult<List<T>>> liveData,
|
||||||
|
Collection<T> items) {
|
||||||
|
List<T> copiedItems = getListCopy(liveData);
|
||||||
|
if (copiedItems == null) return null;
|
||||||
|
copiedItems.addAll(items);
|
||||||
|
return copiedItems;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a copy of the list available in the given LiveData
|
* Creates a copy of the list available in the given LiveData
|
||||||
* and replaces items where the given test function returns true.
|
* and replaces items where the given test function returns true.
|
||||||
@@ -221,6 +243,25 @@ public abstract class DbViewModel extends AndroidViewModel {
|
|||||||
return changed ? items : null;
|
return changed ? items : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the given LiveData with a copy of its list
|
||||||
|
* with the items removed where the given test function returns true.
|
||||||
|
* <p>
|
||||||
|
* Nothing is updated, if 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>
|
||||||
|
*/
|
||||||
|
@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));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a copy of the list of items from the given LiveData
|
* Retrieves a copy of the list of items from the given LiveData
|
||||||
* or null if it is not available.
|
* or null if it is not available.
|
||||||
|
|||||||
Reference in New Issue
Block a user