diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/RequestCodes.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/RequestCodes.java index 58ab2ef0c..cb0133788 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/RequestCodes.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/RequestCodes.java @@ -6,7 +6,6 @@ public interface RequestCodes { int REQUEST_INTRODUCTION = 2; int REQUEST_GROUP_INVITE = 3; int REQUEST_SHARE_FORUM = 4; - int REQUEST_WRITE_BLOG_POST = 5; int REQUEST_SHARE_BLOG = 6; int REQUEST_RINGTONE = 7; int REQUEST_PERMISSION_CAMERA_LOCATION = 8; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BaseViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BaseViewModel.java index 5902f1746..1dd159ea1 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BaseViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BaseViewModel.java @@ -176,10 +176,22 @@ abstract class BaseViewModel extends DbViewModel implements EventListener { return result == null ? null : result.getItems(); } + /** + * Call this after {@link ListUpdate#getPostAddedWasLocal()} was processed. + * This prevents it from getting processed again. + */ + @UiThread + void resetLocalUpdate() { + LiveResult value = blogPosts.getValue(); + if (value == null) return; + ListUpdate result = value.getResultOrNull(); + result.postAddedWasLocal = null; + } + static class ListUpdate { @Nullable - private final Boolean postAddedWasLocal; + private Boolean postAddedWasLocal; private final List items; ListUpdate(@Nullable Boolean postAddedWasLocal, diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogActivity.java index be7b9b9ba..ae8da2f67 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogActivity.java @@ -6,9 +6,11 @@ import android.os.Bundle; 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.R; import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.BriarActivity; +import org.briarproject.briar.android.fragment.BaseFragment; import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener; import org.briarproject.briar.android.sharing.BlogSharingStatusActivity; @@ -19,6 +21,7 @@ import androidx.appcompat.widget.Toolbar; import androidx.lifecycle.ViewModelProvider; import static java.util.Objects.requireNonNull; +import static org.briarproject.briar.android.blog.BlogPostFragment.POST_ID; @MethodsNotNullByDefault @ParametersNotNullByDefault @@ -45,7 +48,10 @@ public class BlogActivity extends BriarActivity Intent i = getIntent(); GroupId groupId = new GroupId(requireNonNull(i.getByteArrayExtra(GROUP_ID))); - viewModel.setGroupId(groupId); + // Get post info from intent + @Nullable byte[] postId = i.getByteArrayExtra(POST_ID); + + viewModel.setGroupId(groupId, postId == null); setContentView(R.layout.activity_fragment_container_toolbar); Toolbar toolbar = setUpCustomToolbar(false); @@ -66,7 +72,14 @@ public class BlogActivity extends BriarActivity ); if (state == null) { - showInitialFragment(BlogFragment.newInstance(groupId)); + if (postId == null) { + showInitialFragment(BlogFragment.newInstance(groupId)); + } else { + MessageId messageId = new MessageId(postId); + BaseFragment f = + BlogPostFragment.newInstance(groupId, messageId); + showInitialFragment(f); + } } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogFragment.java index f43b209fd..451790de0 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogFragment.java @@ -38,7 +38,6 @@ import static android.widget.Toast.LENGTH_SHORT; import static com.google.android.material.snackbar.Snackbar.LENGTH_LONG; import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_SHARE_BLOG; -import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_WRITE_BLOG_POST; @UiThread @MethodsNotNullByDefault @@ -134,7 +133,7 @@ public class BlogFragment extends BaseFragment 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); + startActivity(i); return true; } else if (itemId == R.id.action_blog_share) { Intent i = new Intent(getActivity(), ShareBlogActivity.class); @@ -160,10 +159,7 @@ public class BlogFragment extends BaseFragment public void onActivityResult(int request, int result, @Nullable Intent data) { super.onActivityResult(request, result, data); - - if (request == REQUEST_WRITE_BLOG_POST && result == RESULT_OK) { - displaySnackbar(R.string.blogs_blog_post_created, true); - } else if (request == REQUEST_SHARE_BLOG && result == RESULT_OK) { + if (request == REQUEST_SHARE_BLOG && result == RESULT_OK) { displaySnackbar(R.string.blogs_sharing_snackbar, false); } } @@ -184,6 +180,7 @@ public class BlogFragment extends BaseFragment displaySnackbar(R.string.blogs_blog_post_received, true); } + viewModel.resetLocalUpdate(); list.showData(); }); } @@ -191,7 +188,7 @@ public class BlogFragment extends BaseFragment @Override public void onBlogPostClick(BlogPostItem post) { BlogPostFragment f = - BlogPostFragment.newInstance(groupId, post.getId(), false); + BlogPostFragment.newInstance(groupId, post.getId()); showNextFragment(f); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogPostFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogPostFragment.java index 605597e59..b7790571e 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogPostFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogPostFragment.java @@ -44,7 +44,6 @@ public class BlogPostFragment extends BaseFragment private static final Logger LOG = getLogger(TAG); static final String POST_ID = "briar.POST_ID"; - static final String IS_FEED = "briar.IS_FEED"; protected BlogViewModel viewModel; private final Handler handler = new Handler(Looper.getMainLooper()); @@ -57,13 +56,11 @@ public class BlogPostFragment extends BaseFragment @Inject ViewModelProvider.Factory viewModelFactory; - static BlogPostFragment newInstance(GroupId blogId, MessageId postId, - boolean isFeed) { + static BlogPostFragment newInstance(GroupId blogId, MessageId postId) { BlogPostFragment f = new BlogPostFragment(); Bundle bundle = new Bundle(); bundle.putByteArray(GROUP_ID, blogId.getBytes()); bundle.putByteArray(POST_ID, postId.getBytes()); - bundle.putBoolean(IS_FEED, isFeed); f.setArguments(bundle); return f; } @@ -85,13 +82,12 @@ public class BlogPostFragment extends BaseFragment new GroupId(requireNonNull(args.getByteArray(GROUP_ID))); MessageId postId = new MessageId(requireNonNull(args.getByteArray(POST_ID))); - boolean isFeed = args.getBoolean(IS_FEED); 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, isFeed); + ui = new BlogPostViewHolder(view, true, this, false); LifecycleOwner owner = getViewLifecycleOwner(); viewModel.loadBlogPost(groupId, postId).observe(owner, result -> result.onError(this::handleException) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogPostViewHolder.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogPostViewHolder.java index 5f1648e6a..5da03b132 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogPostViewHolder.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogPostViewHolder.java @@ -16,8 +16,6 @@ import org.briarproject.briar.android.view.AuthorView; import org.briarproject.briar.api.blog.BlogCommentHeader; import org.briarproject.briar.api.blog.BlogPostHeader; -import javax.annotation.Nullable; - import androidx.annotation.UiThread; import androidx.core.view.ViewCompat; import androidx.recyclerview.widget.RecyclerView; @@ -81,15 +79,15 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder { return "blogPost" + id.hashCode(); } - void bindItem(@Nullable BlogPostItem item) { - if (item == null) return; - + void bindItem(BlogPostItem item) { setTransitionName(item.getId()); if (!fullText) { layout.setClickable(true); layout.setOnClickListener(v -> listener.onBlogPostClick(item)); } + boolean isReblog = item instanceof BlogCommentItem; + // author and date BlogPostHeader post = item.getPostHeader(); author.setAuthor(post.getAuthor(), post.getAuthorInfo()); @@ -97,7 +95,7 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder { author.setPersona( item.isRssFeed() ? AuthorView.RSS_FEED : AuthorView.NORMAL); // TODO make author clickable more often #624 - if (authorClickable) { + if (authorClickable && !isReblog) { author.setAuthorClickable(v -> listener.onAuthorClick(item)); } else { author.setAuthorNotClickable(); @@ -126,19 +124,21 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder { // comments commentContainer.removeAllViews(); - if (item instanceof BlogCommentItem) { - onBindComment((BlogCommentItem) item); + if (isReblog) { + onBindComment((BlogCommentItem) item, authorClickable); } else { reblogger.setVisibility(GONE); } } - private void onBindComment(BlogCommentItem item) { + private void onBindComment(BlogCommentItem item, boolean authorClickable) { // reblogger reblogger.setAuthor(item.getAuthor(), item.getAuthorInfo()); reblogger.setDate(item.getTimestamp()); - if (!fullText) { + if (authorClickable) { reblogger.setAuthorClickable(v -> listener.onAuthorClick(item)); + } else { + reblogger.setAuthorNotClickable(); } reblogger.setVisibility(VISIBLE); reblogger.setPersona(REBLOGGER); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogViewModel.java index d3cd53c79..f21876e40 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogViewModel.java @@ -111,11 +111,11 @@ class BlogViewModel extends BaseViewModel { * Set this before calling any other methods. */ @UiThread - public void setGroupId(GroupId groupId) { + public void setGroupId(GroupId groupId, boolean loadAllPosts) { if (this.groupId == groupId) return; // configuration change this.groupId = groupId; loadBlog(groupId); - loadBlogPosts(groupId); + if (loadAllPosts) loadBlogPosts(groupId); loadSharingContacts(groupId); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/FeedFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/FeedFragment.java index bf7ce988c..4e55eb795 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/FeedFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/FeedFragment.java @@ -11,6 +11,7 @@ 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.briar.R; import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.blog.BaseViewModel.ListUpdate; @@ -29,6 +30,7 @@ import androidx.recyclerview.widget.LinearLayoutManager; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; import static com.google.android.material.snackbar.Snackbar.LENGTH_LONG; import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID; +import static org.briarproject.briar.android.blog.BlogPostFragment.POST_ID; @MethodsNotNullByDefault @ParametersNotNullByDefault @@ -108,6 +110,7 @@ public class FeedFragment extends BaseFragment } else if (wasLocal != null) { showSnackBar(R.string.blogs_blog_post_received); } + viewModel.resetLocalUpdate(); list.showData(); }); } @@ -145,16 +148,14 @@ public class FeedFragment extends BaseFragment @Override public void onBlogPostClick(BlogPostItem post) { - BaseFragment f = BlogPostFragment - .newInstance(post.getGroupId(), post.getId(), true); - showNextFragment(f); + Intent i = getBlogActivityIntent(post.getGroupId()); + i.putExtra(POST_ID, post.getId().getBytes()); + requireContext().startActivity(i); } @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); + Intent i = getBlogActivityIntent(post.getGroupId()); requireContext().startActivity(i); } @@ -169,6 +170,13 @@ public class FeedFragment extends BaseFragment return TAG; } + private Intent getBlogActivityIntent(GroupId groupId) { + Intent i = new Intent(requireContext(), BlogActivity.class); + i.putExtra(GROUP_ID, groupId.getBytes()); + i.setFlags(FLAG_ACTIVITY_CLEAR_TOP); + return i; + } + private void showSnackBar(int stringRes) { int firstVisible = layoutManager.findFirstCompletelyVisibleItemPosition(); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/view/AuthorView.java b/briar-android/src/main/java/org/briarproject/briar/android/view/AuthorView.java index 6cd18ed85..389215b3a 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/view/AuthorView.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/view/AuthorView.java @@ -135,9 +135,10 @@ public class AuthorView extends ConstraintLayout { } public void setAuthorNotClickable() { - setClickable(false); - setBackgroundResource(0); setOnClickListener(null); + setClickable(false); + setFocusable(false); + setBackgroundResource(0); } /** diff --git a/briar-android/src/main/res/layout/list_item_blog_post.xml b/briar-android/src/main/res/layout/list_item_blog_post.xml index fa53019cf..d86e5ab5e 100644 --- a/briar-android/src/main/res/layout/list_item_blog_post.xml +++ b/briar-android/src/main/res/layout/list_item_blog_post.xml @@ -16,27 +16,18 @@ android:id="@+id/rebloggerView" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginStart="@dimen/listitem_vertical_margin" - android:layout_marginLeft="@dimen/listitem_vertical_margin" - android:layout_marginTop="@dimen/listitem_vertical_margin" - android:layout_marginEnd="@dimen/listitem_vertical_margin" - android:layout_marginRight="@dimen/listitem_vertical_margin" - android:layout_marginBottom="@dimen/listitem_horizontal_margin" + android:padding="@dimen/listitem_vertical_margin" app:layout_constraintEnd_toStartOf="@+id/commentView" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" - app:persona="reblogger" /> + app:persona="reblogger" + tools:visibility="visible" />