From 60b4c5649adf4719acf897ef6df0f567ca56aba7 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Mon, 5 Sep 2016 14:33:44 -0300 Subject: [PATCH 1/8] Make blog post text clickable by making it only selectable in detail view --- .../res/layout/list_item_blog_comment.xml | 1 - .../res/layout/list_item_blog_post.xml | 4 ++-- .../android/blogs/BlogPostViewHolder.java | 18 +++++++++++------- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/briar-android/res/layout/list_item_blog_comment.xml b/briar-android/res/layout/list_item_blog_comment.xml index bdbe42842..1be478ab2 100644 --- a/briar-android/res/layout/list_item_blog_comment.xml +++ b/briar-android/res/layout/list_item_blog_comment.xml @@ -29,7 +29,6 @@ android:paddingLeft="@dimen/listitem_vertical_margin" android:paddingRight="@dimen/listitem_vertical_margin" android:textColor="@color/briar_text_secondary" - android:textIsSelectable="true" android:textSize="@dimen/text_size_small" tools:text="This is a comment that appears below a blog post. Usually, it is expected to be rather short. Not much longer than this one."/> diff --git a/briar-android/res/layout/list_item_blog_post.xml b/briar-android/res/layout/list_item_blog_post.xml index 8b136f2b7..d3cd14d48 100644 --- a/briar-android/res/layout/list_item_blog_post.xml +++ b/briar-android/res/layout/list_item_blog_post.xml @@ -6,7 +6,8 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" + android:foreground="?android:attr/selectableItemBackground"> diff --git a/briar-android/src/org/briarproject/android/blogs/BlogPostViewHolder.java b/briar-android/src/org/briarproject/android/blogs/BlogPostViewHolder.java index 9cc23d079..186792a11 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogPostViewHolder.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogPostViewHolder.java @@ -10,6 +10,7 @@ import android.support.v4.view.ViewCompat; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; +import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; @@ -81,14 +82,15 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder { void bindItem(final BlogPostItem item) { setTransitionName(item.getId()); - layout.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (listener != null) { + if (listener != null) { + layout.setClickable(true); + layout.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { listener.onBlogPostClick(item); } - } - }); + }); + } // author and date BlogPostHeader post = item.getPostHeader(); @@ -105,9 +107,10 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder { // post body body.setText(item.getBody()); + if (listener == null) body.setTextIsSelectable(true); // reblog button - reblogButton.setOnClickListener(new View.OnClickListener() { + reblogButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent i = new Intent(ctx, ReblogActivity.class); @@ -154,6 +157,7 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder { // TODO make author clickable #624 body.setText(c.getComment()); + if (listener == null) body.setTextIsSelectable(true); commentContainer.addView(v); } From 307e124ee84a3ec74c33d4c7ad7aef7ae4088e49 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Mon, 5 Sep 2016 20:21:11 -0300 Subject: [PATCH 2/8] Make the blog post pager usable for the feed and individual blogs --- .../layout/activity_fragment_container.xml | 12 +- .../res/layout/fragment_blog_post.xml | 7 +- .../res/layout/fragment_blog_post_pager.xml | 6 + .../android/ActivityComponent.java | 7 + .../android/NavDrawerActivity.java | 5 +- .../android/blogs/BasePostFragment.java | 99 +++++++ .../android/blogs/BasePostPagerFragment.java | 187 ++++++++++++ .../android/blogs/BlogActivity.java | 266 ++---------------- .../android/blogs/BlogFragment.java | 48 +++- .../android/blogs/BlogPostFragment.java | 90 +----- .../android/blogs/BlogPostPagerFragment.java | 66 +++++ .../android/blogs/FeedFragment.java | 7 +- .../android/blogs/FeedPostFragment.java | 85 ++++++ .../android/blogs/FeedPostPagerFragment.java | 65 +++++ 14 files changed, 618 insertions(+), 332 deletions(-) create mode 100644 briar-android/res/layout/fragment_blog_post_pager.xml create mode 100644 briar-android/src/org/briarproject/android/blogs/BasePostFragment.java create mode 100644 briar-android/src/org/briarproject/android/blogs/BasePostPagerFragment.java create mode 100644 briar-android/src/org/briarproject/android/blogs/BlogPostPagerFragment.java create mode 100644 briar-android/src/org/briarproject/android/blogs/FeedPostFragment.java create mode 100644 briar-android/src/org/briarproject/android/blogs/FeedPostPagerFragment.java diff --git a/briar-android/res/layout/activity_fragment_container.xml b/briar-android/res/layout/activity_fragment_container.xml index e6c20760f..8bf59ee5a 100644 --- a/briar-android/res/layout/activity_fragment_container.xml +++ b/briar-android/res/layout/activity_fragment_container.xml @@ -3,4 +3,14 @@ android:id="@+id/fragmentContainer" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="match_parent"/> \ No newline at end of file + android:layout_height="match_parent"> + + + + \ No newline at end of file diff --git a/briar-android/res/layout/fragment_blog_post.xml b/briar-android/res/layout/fragment_blog_post.xml index 7a0df0d0b..bc1b87c2a 100644 --- a/briar-android/res/layout/fragment_blog_post.xml +++ b/briar-android/res/layout/fragment_blog_post.xml @@ -6,7 +6,12 @@ + android:layout_height="wrap_content" + android:descendantFocusability="beforeDescendants" + android:focusable="true" + android:focusableInTouchMode="true"> + + \ No newline at end of file diff --git a/briar-android/src/org/briarproject/android/ActivityComponent.java b/briar-android/src/org/briarproject/android/ActivityComponent.java index 2a0d82c4b..baee29d41 100644 --- a/briar-android/src/org/briarproject/android/ActivityComponent.java +++ b/briar-android/src/org/briarproject/android/ActivityComponent.java @@ -6,8 +6,11 @@ import org.briarproject.android.blogs.BlogActivity; import org.briarproject.android.blogs.BlogFragment; import org.briarproject.android.blogs.BlogListFragment; import org.briarproject.android.blogs.BlogPostFragment; +import org.briarproject.android.blogs.BlogPostPagerFragment; import org.briarproject.android.blogs.CreateBlogActivity; +import org.briarproject.android.blogs.FeedPostFragment; import org.briarproject.android.blogs.FeedFragment; +import org.briarproject.android.blogs.FeedPostPagerFragment; import org.briarproject.android.blogs.ReblogActivity; import org.briarproject.android.blogs.ReblogFragment; import org.briarproject.android.blogs.RssFeedImportActivity; @@ -92,6 +95,10 @@ public interface ActivityComponent { void inject(BlogFragment fragment); void inject(BlogPostFragment fragment); + void inject(FeedPostFragment fragment); + + void inject(BlogPostPagerFragment fragment); + void inject(FeedPostPagerFragment fragment); void inject(ReblogFragment fragment); diff --git a/briar-android/src/org/briarproject/android/NavDrawerActivity.java b/briar-android/src/org/briarproject/android/NavDrawerActivity.java index 6381bc9cd..d4bacf55a 100644 --- a/briar-android/src/org/briarproject/android/NavDrawerActivity.java +++ b/briar-android/src/org/briarproject/android/NavDrawerActivity.java @@ -74,7 +74,9 @@ public class NavDrawerActivity extends BriarFragmentActivity implements super.onNewIntent(intent); exitIfStartupFailed(intent); checkAuthorHandle(intent); - clearBackStack(); + // FIXME why was the stack cleared here? + // This prevents state from being restored properly +// clearBackStack(); if (intent.getBooleanExtra(INTENT_FORUMS, false)) { startFragment(ForumListFragment.newInstance()); } @@ -248,7 +250,6 @@ public class NavDrawerActivity extends BriarFragmentActivity implements @Override public void hideLoadingScreen() { drawerLayout.setDrawerLockMode(LOCK_MODE_UNLOCKED); - CustomAnimations.animateHeight(toolbar, true, 250); progressViewGroup.setVisibility(INVISIBLE); } diff --git a/briar-android/src/org/briarproject/android/blogs/BasePostFragment.java b/briar-android/src/org/briarproject/android/blogs/BasePostFragment.java new file mode 100644 index 000000000..e340a3fcb --- /dev/null +++ b/briar-android/src/org/briarproject/android/blogs/BasePostFragment.java @@ -0,0 +1,99 @@ +package org.briarproject.android.blogs; + +import android.os.Bundle; +import android.support.annotation.CallSuper; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; + +import org.briarproject.R; +import org.briarproject.android.fragment.BaseFragment; +import org.briarproject.api.db.DbException; + +import java.util.logging.Logger; + +import static org.briarproject.android.util.AndroidUtils.MIN_RESOLUTION; + +public abstract class BasePostFragment extends BaseFragment { + + private final Logger LOG = + Logger.getLogger(BasePostFragment.class.getName()); + + private View view; + private BlogPostViewHolder ui; + private BlogPostItem post; + private Runnable refresher; + + @CallSuper + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + setHasOptionsMenu(true); + + view = inflater.inflate(R.layout.fragment_blog_post, container, + false); + ui = new BlogPostViewHolder(view); + return view; + } + + @CallSuper + @Override + public void onStart() { + super.onStart(); + startPeriodicUpdate(); + } + + @Override + public void onStop() { + super.onStop(); + stopPeriodicUpdate(); + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + getActivity().onBackPressed(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + protected void onBlogPostLoaded(BlogPostItem post) { + listener.hideLoadingScreen(); + this.post = post; + ui.bindItem(post); + } + + protected void onBlogPostLoadException(DbException exception) { + // TODO: Decide how to handle errors in the UI + finish(); + } + + private void startPeriodicUpdate() { + refresher = new Runnable() { + @Override + public void run() { + if (ui == null) return; + LOG.info("Updating Content..."); + + ui.updateDate(post.getTimestamp()); + view.postDelayed(refresher, MIN_RESOLUTION); + } + }; + LOG.info("Adding Handler Callback"); + view.postDelayed(refresher, MIN_RESOLUTION); + } + + private void stopPeriodicUpdate() { + if (refresher != null && ui != null) { + LOG.info("Removing Handler Callback"); + view.removeCallbacks(refresher); + } + } + +} diff --git a/briar-android/src/org/briarproject/android/blogs/BasePostPagerFragment.java b/briar-android/src/org/briarproject/android/blogs/BasePostPagerFragment.java new file mode 100644 index 000000000..b24f6be3a --- /dev/null +++ b/briar-android/src/org/briarproject/android/blogs/BasePostPagerFragment.java @@ -0,0 +1,187 @@ +package org.briarproject.android.blogs; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.annotation.UiThread; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentStatePagerAdapter; +import android.support.v4.view.ViewPager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import org.briarproject.R; +import org.briarproject.android.blogs.BaseController.OnBlogPostAddedListener; +import org.briarproject.android.controller.handler.UiResultExceptionHandler; +import org.briarproject.android.fragment.BaseFragment; +import org.briarproject.api.blogs.BlogPostHeader; +import org.briarproject.api.db.DbException; +import org.briarproject.api.sync.MessageId; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static org.briarproject.android.blogs.BasePostPagerFragment.BlogPostPagerAdapter.INVALID_POSITION; +import static org.briarproject.android.blogs.BlogActivity.POST_ID; + +abstract class BasePostPagerFragment extends BaseFragment + implements OnBlogPostAddedListener { + + private ViewPager pager; + private BlogPostPagerAdapter postPagerAdapter; + private MessageId postId; + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle state) { + + Bundle args; + if (state == null) args = getArguments(); + else args = state; + byte[] p = args.getByteArray(POST_ID); + if (p == null) + throw new IllegalStateException("No post ID in args"); + postId = new MessageId(p); + + View v = inflater.inflate(R.layout.fragment_blog_post_pager, container, + false); + pager = (ViewPager) v.findViewById(R.id.pager); + postPagerAdapter = new BlogPostPagerAdapter(getChildFragmentManager()); + listener.showLoadingScreen(false, R.string.progress_title_please_wait); + + return v; + } + + @Override + public void onStart() { + super.onStart(); + if (postId == null) { + MessageId selected = getSelectedPost(); + if (selected != null) loadBlogPosts(selected); + } else { + loadBlogPosts(postId); + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + MessageId selected = getSelectedPost(); + if (selected != null) + outState.putByteArray(POST_ID, selected.getBytes()); + } + + @Override + public void onBlogPostAdded(BlogPostHeader header, boolean local) { + loadBlogPost(header); + } + + abstract void loadBlogPosts(final MessageId select); + + abstract BaseController getController(); + + protected void onBlogPostsLoaded(MessageId select, + Collection posts) { + + postId = null; + postPagerAdapter.setPosts(posts); + selectPost(select); + } + + protected void onBlogPostsLoadedException(DbException exception) { + // TODO: Decide how to handle errors in the UI + finish(); + } + + private void loadBlogPost(BlogPostHeader header) { + getController().loadBlogPost(header, + new UiResultExceptionHandler( + getActivity()) { + @Override + public void onResultUi(BlogPostItem post) { + addPost(post); + } + + @Override + public void onExceptionUi(DbException exception) { + // TODO: Decide how to handle errors in the UI + finish(); + } + }); + } + + @Nullable + private MessageId getSelectedPost() { + if (postPagerAdapter.getCount() == 0) return null; + int position = pager.getCurrentItem(); + return postPagerAdapter.getPost(position).getId(); + } + + private void selectPost(MessageId m) { + int pos = postPagerAdapter.getPostPosition(m); + if (pos != INVALID_POSITION) { + pager.setAdapter(postPagerAdapter); + pager.setCurrentItem(pos); + } + } + + protected void addPost(BlogPostItem post) { + MessageId selected = getSelectedPost(); + postPagerAdapter.addPost(post); + if (selected != null) selectPost(selected); + } + + @UiThread + static class BlogPostPagerAdapter extends FragmentStatePagerAdapter { + + static final int INVALID_POSITION = -1; + private final List posts = new ArrayList<>(); + + private BlogPostPagerAdapter(FragmentManager fm) { + super(fm); + } + + @Override + public int getCount() { + return posts.size(); + } + + @Override + public Fragment getItem(int position) { + BlogPostItem post = posts.get(position); + return FeedPostFragment.newInstance(post.getGroupId(), post.getId()); + } + + private BlogPostItem getPost(int position) { + return posts.get(position); + } + + private void setPosts(Collection posts) { + this.posts.clear(); + this.posts.addAll(posts); + Collections.sort(this.posts); + notifyDataSetChanged(); + } + + private void addPost(BlogPostItem post) { + posts.add(post); + Collections.sort(posts); + notifyDataSetChanged(); + } + + private int getPostPosition(MessageId m) { + int count = getCount(); + for (int i = 0; i < count; i++) { + if (getPost(i).getId().equals(m)) { + return i; + } + } + return INVALID_POSITION; + } + } + +} diff --git a/briar-android/src/org/briarproject/android/blogs/BlogActivity.java b/briar-android/src/org/briarproject/android/blogs/BlogActivity.java index 249d0ff7c..34ba66f98 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogActivity.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogActivity.java @@ -2,13 +2,6 @@ package org.briarproject.android.blogs; import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentStatePagerAdapter; -import android.support.v4.view.ViewPager; -import android.view.ViewGroup; import android.widget.ProgressBar; import org.briarproject.R; @@ -16,42 +9,25 @@ import org.briarproject.android.ActivityComponent; import org.briarproject.android.BriarActivity; import org.briarproject.android.blogs.BaseController.OnBlogPostAddedListener; import org.briarproject.android.blogs.BlogPostAdapter.OnBlogPostClickListener; -import org.briarproject.android.controller.handler.UiResultExceptionHandler; import org.briarproject.android.fragment.BaseFragment.BaseFragmentListener; import org.briarproject.api.blogs.BlogPostHeader; -import org.briarproject.api.db.DbException; import org.briarproject.api.sync.GroupId; -import org.briarproject.api.sync.MessageId; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; import javax.inject.Inject; -import static android.view.View.GONE; +import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; public class BlogActivity extends BriarActivity implements - OnBlogPostAddedListener, - OnBlogPostClickListener, BaseFragmentListener { + OnBlogPostAddedListener, OnBlogPostClickListener, BaseFragmentListener { static final int REQUEST_WRITE_POST = 1; static final int REQUEST_SHARE = 2; - public static final String BLOG_NAME = "briar.BLOG_NAME"; + static final String BLOG_NAME = "briar.BLOG_NAME"; static final String IS_NEW_BLOG = "briar.IS_NEW_BLOG"; + static final String POST_ID = "briar.POST_ID"; - public static final String POST_ID = "briar.POST_ID"; - - private GroupId groupId; private ProgressBar progressBar; - private ViewPager pager; - private BlogPagerAdapter blogPagerAdapter; - private BlogPostPagerAdapter postPagerAdapter; - private String blogName; - private boolean isNew; - private MessageId savedPostId; @Inject BlogController blogController; @@ -64,63 +40,30 @@ public class BlogActivity extends BriarActivity implements Intent i = getIntent(); byte[] b = i.getByteArrayExtra(GROUP_ID); if (b == null) throw new IllegalStateException("No group ID in intent"); - groupId = new GroupId(b); + GroupId groupId = new GroupId(b); blogController.setGroupId(groupId); // Name of the blog - blogName = i.getStringExtra(BLOG_NAME); + String blogName = i.getStringExtra(BLOG_NAME); if (blogName != null) setTitle(blogName); // Was this blog just created? - isNew = i.getBooleanExtra(IS_NEW_BLOG, false); + boolean isNew = i.getBooleanExtra(IS_NEW_BLOG, false); - setContentView(R.layout.activity_blog); - - pager = (ViewPager) findViewById(R.id.pager); + setContentView(R.layout.activity_fragment_container); progressBar = (ProgressBar) findViewById(R.id.progressBar); - blogPagerAdapter = new BlogPagerAdapter(getSupportFragmentManager()); - postPagerAdapter = new BlogPostPagerAdapter( - getSupportFragmentManager()); - - if (state == null || state.getByteArray(POST_ID) == null) { - // The blog fragment has its own progress bar - hideLoadingScreen(); - pager.setAdapter(blogPagerAdapter); - savedPostId = null; - } else { - // Adapter will be set in selectPostInPostPager() - savedPostId = new MessageId(state.getByteArray(POST_ID)); + if (state == null) { + BlogFragment f = BlogFragment.newInstance(groupId, blogName, isNew); + getSupportFragmentManager().beginTransaction() + .replace(R.id.fragmentContainer, f, f.getUniqueTag()) + .commit(); } } @Override public void onResume() { super.onResume(); - if (savedPostId == null) { - MessageId selected = getSelectedPostInPostPager(); - if (selected != null) loadBlogPosts(selected); - } else { - loadBlogPosts(savedPostId); - } - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - MessageId selected = getSelectedPostInPostPager(); - if (selected != null) - outState.putByteArray(POST_ID, selected.getBytes()); - } - - @Override - public void onBackPressed() { - if (pager.getAdapter() == postPagerAdapter) { - pager.setAdapter(blogPagerAdapter); - savedPostId = null; - } else { - super.onBackPressed(); - } } @Override @@ -128,6 +71,21 @@ public class BlogActivity extends BriarActivity implements component.inject(this); } + @Override + public void onBlogPostAdded(BlogPostHeader header, boolean local) { + // all our fragments are implementing and registering that hook, + // so we don't need to do that ourselves + } + + @Override + public void onBlogPostClick(BlogPostItem post) { + BlogPostPagerFragment f = BlogPostPagerFragment.newInstance(post.getId()); + getSupportFragmentManager().beginTransaction() + .replace(R.id.fragmentContainer, f, f.getUniqueTag()) + .addToBackStack(f.getUniqueTag()) + .commit(); + } + @Override public void showLoadingScreen(boolean isBlocking, int stringId) { progressBar.setVisibility(VISIBLE); @@ -135,176 +93,10 @@ public class BlogActivity extends BriarActivity implements @Override public void hideLoadingScreen() { - progressBar.setVisibility(GONE); + progressBar.setVisibility(INVISIBLE); } @Override public void onFragmentCreated(String tag) { - } - - @Override - public void onBlogPostClick(BlogPostItem post) { - loadBlogPosts(post.getId()); - } - - private void loadBlogPosts(final MessageId select) { - blogController.loadBlogPosts( - new UiResultExceptionHandler, DbException>( - this) { - @Override - public void onResultUi(Collection posts) { - hideLoadingScreen(); - savedPostId = null; - postPagerAdapter.setPosts(posts); - selectPostInPostPager(select); - } - - @Override - public void onExceptionUi(DbException exception) { - // TODO: Decide how to handle errors in the UI - finish(); - } - }); - } - - @Override - public void onBlogPostAdded(BlogPostHeader header, boolean local) { - if (pager.getAdapter() == postPagerAdapter) { - loadBlogPost(header); - } else { - BlogFragment f = blogPagerAdapter.getFragment(); - if (f != null && f.isVisible()) f.onBlogPostAdded(header, local); - } - } - - private void loadBlogPost(BlogPostHeader header) { - blogController.loadBlogPost(header, - new UiResultExceptionHandler(this) { - @Override - public void onResultUi(BlogPostItem post) { - addPostToPostPager(post); - } - - @Override - public void onExceptionUi(DbException exception) { - // TODO: Decide how to handle errors in the UI - finish(); - } - }); - } - - @Nullable - private MessageId getSelectedPostInPostPager() { - if (pager.getAdapter() != postPagerAdapter) return null; - if (postPagerAdapter.getCount() == 0) return null; - int position = pager.getCurrentItem(); - return postPagerAdapter.getPost(position).getId(); - } - - private void selectPostInPostPager(MessageId m) { - int count = postPagerAdapter.getCount(); - for (int i = 0; i < count; i++) { - if (postPagerAdapter.getPost(i).getId().equals(m)) { - pager.setAdapter(postPagerAdapter); - pager.setCurrentItem(i); - return; - } - } - } - - private void addPostToPostPager(BlogPostItem post) { - MessageId selected = getSelectedPostInPostPager(); - postPagerAdapter.addPost(post); - if (selected != null) selectPostInPostPager(selected); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, - Intent data) { - super.onActivityResult(requestCode, resultCode, data); - - // The BlogPostAddedEvent arrives when the controller is not listening, - // so we need to manually reload the blog posts :( - if (requestCode == REQUEST_WRITE_POST && resultCode == RESULT_OK) { - if (pager.getAdapter() == postPagerAdapter) { - MessageId selected = getSelectedPostInPostPager(); - if (selected != null) loadBlogPosts(selected); - } else { - BlogFragment f = blogPagerAdapter.getFragment(); - if (f != null && f.isVisible()) f.loadBlogPosts(true); - } - } - } - - @UiThread - private class BlogPagerAdapter extends FragmentStatePagerAdapter { - - private BlogFragment fragment = null; - - private BlogPagerAdapter(FragmentManager fm) { - super(fm); - } - - @Override - public int getCount() { - return 1; - } - - @Override - public Fragment getItem(int position) { - return BlogFragment.newInstance(groupId, blogName, isNew); - } - - @Override - public Object instantiateItem(ViewGroup container, int position) { - // save a reference to the single fragment here for later - fragment = - (BlogFragment) super.instantiateItem(container, position); - return fragment; - } - - private BlogFragment getFragment() { - return fragment; - } - } - - @UiThread - private static class BlogPostPagerAdapter - extends FragmentStatePagerAdapter { - - private final List posts = new ArrayList<>(); - - private BlogPostPagerAdapter(FragmentManager fm) { - super(fm); - } - - @Override - public int getCount() { - return posts.size(); - } - - @Override - public Fragment getItem(int position) { - return BlogPostFragment.newInstance(posts.get(position).getId()); - } - - private BlogPostItem getPost(int position) { - return posts.get(position); - } - - private void setPosts(Collection posts) { - this.posts.clear(); - this.posts.addAll(posts); - Collections.sort(this.posts); - notifyDataSetChanged(); - } - - private void addPost(BlogPostItem post) { - posts.add(post); - Collections.sort(posts); - notifyDataSetChanged(); - } - } - } diff --git a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java index b3b87a113..0d9a0fe98 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java @@ -5,8 +5,8 @@ import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.design.widget.Snackbar; -import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityOptionsCompat; +import android.support.v4.content.ContextCompat; import android.support.v7.app.AlertDialog; import android.support.v7.widget.LinearLayoutManager; import android.view.LayoutInflater; @@ -59,6 +59,7 @@ public class BlogFragment extends BaseFragment implements private BlogPostAdapter adapter; private BriarRecyclerView list; private MenuItem writeButton, deleteButton; + private boolean isMyBlog = false, canDeleteBlog = false; static BlogFragment newInstance(GroupId groupId, String name, boolean isNew) { @@ -114,7 +115,7 @@ public class BlogFragment extends BaseFragment implements @Override public void injectFragment(ActivityComponent component) { component.inject(this); - blogController.setGroupId(groupId); + blogController.setOnBlogPostAddedListener(this); } @Override @@ -141,7 +142,9 @@ public class BlogFragment extends BaseFragment implements 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.setVisible(true); super.onCreateOptionsMenu(menu, inflater); } @@ -161,8 +164,8 @@ public class BlogFragment extends BaseFragment implements new Intent(getActivity(), WriteBlogPostActivity.class); i.putExtra(GROUP_ID, groupId.getBytes()); i.putExtra(BLOG_NAME, blogName); - ActivityCompat.startActivityForResult(getActivity(), i, - REQUEST_WRITE_POST, options.toBundle()); + startActivityForResult(i, REQUEST_WRITE_POST, + options.toBundle()); return true; case R.id.action_blog_share: Intent i2 = new Intent(getActivity(), ShareBlogActivity.class); @@ -190,9 +193,10 @@ public class BlogFragment extends BaseFragment implements super.onActivityResult(request, result, data); if (request == REQUEST_WRITE_POST && result == RESULT_OK) { - displaySnackbar(R.string.blogs_blog_post_created); + displaySnackbar(R.string.blogs_blog_post_created, true); + loadBlogPosts(true); } else if (request == REQUEST_SHARE && result == RESULT_OK) { - displaySnackbar(R.string.blogs_sharing_snackbar); + displaySnackbar(R.string.blogs_sharing_snackbar, true); } } @@ -211,9 +215,9 @@ public class BlogFragment extends BaseFragment implements adapter.add(post); if (local) { list.scrollToPosition(0); - displaySnackbar(R.string.blogs_blog_post_created); + displaySnackbar(R.string.blogs_blog_post_created, false); } else { - displaySnackbar(R.string.blogs_blog_post_received); + displaySnackbar(R.string.blogs_blog_post_received, true); } } @@ -243,13 +247,13 @@ public class BlogFragment extends BaseFragment implements @Override public void onExceptionUi(DbException exception) { // TODO: Decide how to handle errors in the UI - getActivity().finish(); + finish(); } }); } private void checkIfThisIsMyBlog() { - blogController.canDeleteBlog( + blogController.isMyBlog( new UiResultExceptionHandler( getActivity()) { @Override @@ -262,7 +266,7 @@ public class BlogFragment extends BaseFragment implements @Override public void onExceptionUi(DbException exception) { // TODO: Decide how to handle errors in the UI - getActivity().finish(); + finish(); } }); } @@ -281,25 +285,39 @@ public class BlogFragment extends BaseFragment implements @Override public void onExceptionUi(DbException exception) { // TODO: Decide how to handle errors in the UI - getActivity().finish(); + finish(); } }); } private void showWriteButton() { + isMyBlog = true; if (writeButton != null) writeButton.setVisible(true); } private void showDeleteButton() { + canDeleteBlog = true; if (deleteButton != null) deleteButton.setVisible(true); } - private void displaySnackbar(int stringId) { + private void displaySnackbar(int stringId, boolean scroll) { Snackbar snackbar = - Snackbar.make(list, stringId, Snackbar.LENGTH_SHORT); + Snackbar.make(list, stringId, Snackbar.LENGTH_LONG); snackbar.getView().setBackgroundResource(R.color.briar_primary); + if (scroll) { + View.OnClickListener onClick = new View.OnClickListener() { + @Override + public void onClick(View v) { + list.smoothScrollToPosition(0); + } + }; + snackbar.setActionTextColor(ContextCompat + .getColor(getContext(), + R.color.briar_button_positive)); + snackbar.setAction(R.string.blogs_blog_post_scroll_to, onClick); + } snackbar.show(); } @@ -335,7 +353,7 @@ public class BlogFragment extends BaseFragment implements @Override public void onExceptionUi(DbException exception) { // TODO: Decide how to handle errors in the UI - getActivity().finish(); + finish(); } }); } diff --git a/briar-android/src/org/briarproject/android/blogs/BlogPostFragment.java b/briar-android/src/org/briarproject/android/blogs/BlogPostFragment.java index 926ce7f37..b70a36062 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogPostFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogPostFragment.java @@ -3,35 +3,23 @@ package org.briarproject.android.blogs; import android.os.Bundle; import android.support.annotation.Nullable; import android.view.LayoutInflater; -import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import org.briarproject.R; import org.briarproject.android.ActivityComponent; import org.briarproject.android.controller.handler.UiResultExceptionHandler; -import org.briarproject.android.fragment.BaseFragment; import org.briarproject.api.db.DbException; import org.briarproject.api.sync.MessageId; -import java.util.logging.Logger; - import javax.inject.Inject; -import static org.briarproject.android.util.AndroidUtils.MIN_RESOLUTION; +import static org.briarproject.android.blogs.BlogActivity.POST_ID; -public class BlogPostFragment extends BaseFragment { +public class BlogPostFragment extends BasePostFragment { public final static String TAG = BlogPostFragment.class.getName(); - private static final Logger LOG = Logger.getLogger(TAG); - private static final String BLOG_POST_ID = "briar.BLOG_POST_ID"; - - private View view; private MessageId postId; - private BlogPostViewHolder ui; - private BlogPostItem post; - private Runnable refresher; @Inject BlogController blogController; @@ -40,7 +28,7 @@ public class BlogPostFragment extends BaseFragment { BlogPostFragment f = new BlogPostFragment(); Bundle bundle = new Bundle(); - bundle.putByteArray(BLOG_POST_ID, postId.getBytes()); + bundle.putByteArray(POST_ID, postId.getBytes()); f.setArguments(bundle); return f; @@ -50,16 +38,18 @@ public class BlogPostFragment extends BaseFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - setHasOptionsMenu(true); - byte[] b = getArguments().getByteArray(BLOG_POST_ID); - if (b == null) throw new IllegalStateException("No post ID in args"); - postId = new MessageId(b); + Bundle args = getArguments(); + byte[] p = args.getByteArray(POST_ID); + if (p == null) throw new IllegalStateException("No post ID in args"); + postId = new MessageId(p); - view = inflater.inflate(R.layout.fragment_blog_post, container, - false); - ui = new BlogPostViewHolder(view); - return view; + return super.onCreateView(inflater, container, savedInstanceState); + } + + @Override + public String getUniqueTag() { + return TAG; } @Override @@ -75,62 +65,12 @@ public class BlogPostFragment extends BaseFragment { getActivity()) { @Override public void onResultUi(BlogPostItem post) { - listener.hideLoadingScreen(); - BlogPostFragment.this.post = post; - ui.bindItem(post); - startPeriodicUpdate(); + onBlogPostLoaded(post); } - @Override public void onExceptionUi(DbException exception) { - // TODO: Decide how to handle errors in the UI - finish(); + onBlogPostLoadException(exception); } }); } - - @Override - public void onStop() { - super.onStop(); - stopPeriodicUpdate(); - } - - @Override - public boolean onOptionsItemSelected(final MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - getActivity().onBackPressed(); - return true; - default: - return super.onOptionsItemSelected(item); - } - } - - @Override - public String getUniqueTag() { - return TAG; - } - - private void startPeriodicUpdate() { - refresher = new Runnable() { - @Override - public void run() { - if (ui == null) return; - LOG.info("Updating Content..."); - - ui.updateDate(post.getTimestamp()); - view.postDelayed(refresher, MIN_RESOLUTION); - } - }; - LOG.info("Adding Handler Callback"); - view.postDelayed(refresher, MIN_RESOLUTION); - } - - private void stopPeriodicUpdate() { - if (refresher != null && ui != null) { - LOG.info("Removing Handler Callback"); - view.removeCallbacks(refresher); - } - } - } diff --git a/briar-android/src/org/briarproject/android/blogs/BlogPostPagerFragment.java b/briar-android/src/org/briarproject/android/blogs/BlogPostPagerFragment.java new file mode 100644 index 000000000..54e646f9c --- /dev/null +++ b/briar-android/src/org/briarproject/android/blogs/BlogPostPagerFragment.java @@ -0,0 +1,66 @@ +package org.briarproject.android.blogs; + +import android.os.Bundle; + +import org.briarproject.android.ActivityComponent; +import org.briarproject.android.controller.handler.UiResultExceptionHandler; +import org.briarproject.api.db.DbException; +import org.briarproject.api.sync.MessageId; + +import java.util.Collection; + +import javax.inject.Inject; + +import static org.briarproject.android.blogs.BlogActivity.POST_ID; + + +public class BlogPostPagerFragment extends BasePostPagerFragment { + + public final static String TAG = BlogPostPagerFragment.class.getName(); + + @Inject + BlogController blogController; + + static BlogPostPagerFragment newInstance(MessageId postId) { + BlogPostPagerFragment f = new BlogPostPagerFragment(); + + Bundle args = new Bundle(); + args.putByteArray(POST_ID, postId.getBytes()); + f.setArguments(args); + + return f; + } + + @Override + public void injectFragment(ActivityComponent component) { + component.inject(this); + blogController.setOnBlogPostAddedListener(this); + } + + @Override + public String getUniqueTag() { + return TAG; + } + + @Override + BaseController getController() { + return blogController; + } + + void loadBlogPosts(final MessageId select) { + blogController.loadBlogPosts( + new UiResultExceptionHandler, DbException>( + getActivity()) { + @Override + public void onResultUi(Collection posts) { + onBlogPostsLoaded(select, posts); + } + + @Override + public void onExceptionUi(DbException exception) { + onBlogPostsLoadedException(exception); + } + }); + } + +} diff --git a/briar-android/src/org/briarproject/android/blogs/FeedFragment.java b/briar-android/src/org/briarproject/android/blogs/FeedFragment.java index 9e6f57748..dbdd11127 100644 --- a/briar-android/src/org/briarproject/android/blogs/FeedFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/FeedFragment.java @@ -195,7 +195,12 @@ public class FeedFragment extends BaseFragment implements @Override public void onBlogPostClick(BlogPostItem post) { - // TODO Open detail view of post + FeedPostPagerFragment f = FeedPostPagerFragment + .newInstance(post.getId()); + getActivity().getSupportFragmentManager().beginTransaction() + .replace(R.id.content_fragment, f, f.getUniqueTag()) + .addToBackStack(f.getUniqueTag()) + .commit(); } @Override diff --git a/briar-android/src/org/briarproject/android/blogs/FeedPostFragment.java b/briar-android/src/org/briarproject/android/blogs/FeedPostFragment.java new file mode 100644 index 000000000..5b4841cd4 --- /dev/null +++ b/briar-android/src/org/briarproject/android/blogs/FeedPostFragment.java @@ -0,0 +1,85 @@ +package org.briarproject.android.blogs; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import org.briarproject.android.ActivityComponent; +import org.briarproject.android.controller.handler.UiResultExceptionHandler; +import org.briarproject.api.db.DbException; +import org.briarproject.api.sync.GroupId; +import org.briarproject.api.sync.MessageId; + +import javax.inject.Inject; + +import static org.briarproject.android.BriarActivity.GROUP_ID; +import static org.briarproject.android.blogs.BlogActivity.POST_ID; + +public class FeedPostFragment extends BasePostFragment { + + public final static String TAG = FeedPostFragment.class.getName(); + + private MessageId postId; + private GroupId blogId; + + @Inject + FeedController feedController; + + 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; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + Bundle args = getArguments(); + byte[] b = args.getByteArray(GROUP_ID); + if (b == null) throw new IllegalStateException("No group ID in args"); + blogId = new GroupId(b); + + byte[] p = args.getByteArray(POST_ID); + if (p == null) throw new IllegalStateException("No post ID in args"); + postId = new MessageId(p); + + return super.onCreateView(inflater, container, savedInstanceState); + } + + @Override + public void injectFragment(ActivityComponent component) { + component.inject(this); + } + + @Override + public void onStart() { + super.onStart(); + feedController.loadBlogPost(blogId, postId, + new UiResultExceptionHandler( + getActivity()) { + @Override + public void onResultUi(BlogPostItem post) { + onBlogPostLoaded(post); + } + @Override + public void onExceptionUi(DbException exception) { + onBlogPostLoadException(exception); + } + }); + } + + @Override + public String getUniqueTag() { + return TAG; + } + +} diff --git a/briar-android/src/org/briarproject/android/blogs/FeedPostPagerFragment.java b/briar-android/src/org/briarproject/android/blogs/FeedPostPagerFragment.java new file mode 100644 index 000000000..db30ac1f3 --- /dev/null +++ b/briar-android/src/org/briarproject/android/blogs/FeedPostPagerFragment.java @@ -0,0 +1,65 @@ +package org.briarproject.android.blogs; + +import android.os.Bundle; + +import org.briarproject.android.ActivityComponent; +import org.briarproject.android.controller.handler.UiResultExceptionHandler; +import org.briarproject.api.db.DbException; +import org.briarproject.api.sync.MessageId; + +import java.util.Collection; + +import javax.inject.Inject; + +import static org.briarproject.android.blogs.BlogActivity.POST_ID; + +public class FeedPostPagerFragment extends BasePostPagerFragment { + + public final static String TAG = FeedPostPagerFragment.class.getName(); + + @Inject + FeedController feedController; + + static FeedPostPagerFragment newInstance(MessageId postId) { + FeedPostPagerFragment f = new FeedPostPagerFragment(); + + Bundle args = new Bundle(); + args.putByteArray(POST_ID, postId.getBytes()); + f.setArguments(args); + + return f; + } + + @Override + public void injectFragment(ActivityComponent component) { + component.inject(this); + feedController.setOnBlogPostAddedListener(this); + } + + @Override + public String getUniqueTag() { + return TAG; + } + + @Override + BaseController getController() { + return feedController; + } + + void loadBlogPosts(final MessageId select) { + feedController.loadBlogPosts( + new UiResultExceptionHandler, DbException>( + getActivity()) { + @Override + public void onResultUi(Collection posts) { + onBlogPostsLoaded(select, posts); + } + + @Override + public void onExceptionUi(DbException exception) { + onBlogPostsLoadedException(exception); + } + }); + } + +} From 73bc86df4a82f92c1ef8f45769747834fe638f01 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 6 Sep 2016 12:52:44 -0300 Subject: [PATCH 3/8] show only a teaser for blog posts in lists --- briar-android/res/values/strings.xml | 1 + .../android/blogs/BlogPostViewHolder.java | 34 +++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index ba764c356..4bbf13c15 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -211,6 +211,7 @@ This blog is empty This blog is currently empty.\n\nEither the author hasn\'t written anything yet, or the person who shared this blog with you needs to come online, so posts can be synchronized. NEW + read more Write Blog Post Add a title (optional) Type your blog post here diff --git a/briar-android/src/org/briarproject/android/blogs/BlogPostViewHolder.java b/briar-android/src/org/briarproject/android/blogs/BlogPostViewHolder.java index 186792a11..e9a99449e 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogPostViewHolder.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogPostViewHolder.java @@ -6,8 +6,13 @@ import android.content.Intent; import android.support.annotation.UiThread; import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityOptionsCompat; +import android.support.v4.content.ContextCompat; import android.support.v4.view.ViewCompat; import android.support.v7.widget.RecyclerView; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.style.ForegroundColorSpan; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; @@ -33,6 +38,8 @@ import static org.briarproject.api.blogs.MessageType.POST; @UiThread class BlogPostViewHolder extends RecyclerView.ViewHolder { + private static final int TEASER_LENGTH = 240; + private final Context ctx; private final ViewGroup layout; private final AuthorView reblogger; @@ -106,8 +113,15 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder { } // post body - body.setText(item.getBody()); - if (listener == null) body.setTextIsSelectable(true); + CharSequence bodyText = item.getBody(); + if (listener == null) { + body.setTextIsSelectable(true); + } else { + body.setTextIsSelectable(false); + if (item.getBody().length() > TEASER_LENGTH) + bodyText = getTeaser(item.getBody()); + } + body.setText(bodyText); // reblog button reblogButton.setOnClickListener(new OnClickListener() { @@ -162,4 +176,20 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder { commentContainer.addView(v); } } + + private SpannableStringBuilder getTeaser(String body) { + SpannableStringBuilder builder = + new SpannableStringBuilder(body.substring(0, TEASER_LENGTH)); + builder.append("… "); + + Spannable readMore = + new SpannableString(ctx.getString(R.string.read_more) + "…"); + ForegroundColorSpan fg = new ForegroundColorSpan( + ContextCompat.getColor(ctx, R.color.briar_text_link)); + readMore.setSpan(fg, 0, readMore.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + builder.append(readMore); + + return builder; + } } From cb647409169995b82a29ff9b404719a4c02cfa6f Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 6 Sep 2016 14:09:17 -0300 Subject: [PATCH 4/8] Set blog title when opening blog Fixes #634 --- .../android/blogs/BlogController.java | 4 +- .../android/blogs/BlogControllerImpl.java | 31 +++++--------- .../android/blogs/BlogFragment.java | 40 ++++++++----------- .../{BlogListItem.java => BlogItem.java} | 12 ++++-- .../android/blogs/BlogListAdapter.java | 26 ++++++------ 5 files changed, 49 insertions(+), 64 deletions(-) rename briar-android/src/org/briarproject/android/blogs/{BlogListItem.java => BlogItem.java} (82%) diff --git a/briar-android/src/org/briarproject/android/blogs/BlogController.java b/briar-android/src/org/briarproject/android/blogs/BlogController.java index 768d29c14..4d5c35cbc 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogController.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogController.java @@ -21,9 +21,7 @@ public interface BlogController extends BaseController { void loadBlogPost(MessageId m, ResultExceptionHandler handler); - void isMyBlog(ResultExceptionHandler handler); - - void canDeleteBlog(ResultExceptionHandler handler); + void loadBlog(ResultExceptionHandler handler); void deleteBlog(ResultExceptionHandler handler); diff --git a/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java b/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java index d70779e34..55615009f 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java @@ -3,6 +3,7 @@ package org.briarproject.android.blogs; import org.briarproject.android.controller.ActivityLifecycleController; import org.briarproject.android.controller.handler.ResultExceptionHandler; import org.briarproject.api.blogs.Blog; +import org.briarproject.api.blogs.BlogPostHeader; import org.briarproject.api.db.DbException; import org.briarproject.api.event.BlogPostAddedEvent; import org.briarproject.api.event.Event; @@ -13,6 +14,7 @@ import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; import java.util.Collection; +import java.util.Collections; import java.util.logging.Logger; import javax.inject.Inject; @@ -102,8 +104,8 @@ public class BlogControllerImpl extends BaseControllerImpl } @Override - public void isMyBlog( - final ResultExceptionHandler handler) { + public void loadBlog( + final ResultExceptionHandler handler) { if (groupId == null) throw new IllegalStateException(); runOnDbThread(new Runnable() { @Override @@ -111,7 +113,12 @@ public class BlogControllerImpl extends BaseControllerImpl try { LocalAuthor a = identityManager.getLocalAuthor(); Blog b = blogManager.getBlog(groupId); - handler.onResult(b.getAuthor().getId().equals(a.getId())); + boolean ours = a.getId().equals(b.getAuthor().getId()); + boolean removable = blogManager.canBeRemoved(groupId); + BlogItem blog = new BlogItem(b, + Collections.emptyList(), + ours, removable); + handler.onResult(blog); } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); @@ -122,24 +129,6 @@ public class BlogControllerImpl extends BaseControllerImpl } - @Override - public void canDeleteBlog( - final ResultExceptionHandler handler) { - if (groupId == null) throw new IllegalStateException(); - runOnDbThread(new Runnable() { - @Override - public void run() { - try { - handler.onResult(blogManager.canBeRemoved(groupId)); - } catch (DbException e) { - if (LOG.isLoggable(WARNING)) - LOG.log(WARNING, e.toString(), e); - handler.onException(e); - } - } - }); - } - @Override public void deleteBlog( final ResultExceptionHandler handler) { diff --git a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java index 0d9a0fe98..5c175517d 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java @@ -28,6 +28,7 @@ import org.briarproject.android.sharing.SharingStatusBlogActivity; import org.briarproject.android.util.BriarRecyclerView; import org.briarproject.api.blogs.BlogPostHeader; import org.briarproject.api.db.DbException; +import org.briarproject.api.identity.Author; import org.briarproject.api.sync.GroupId; import java.util.Collection; @@ -121,8 +122,7 @@ public class BlogFragment extends BaseFragment implements @Override public void onStart() { super.onStart(); - checkIfThisIsMyBlog(); - checkIfBlogCanBeDeleted(); + loadBlog(); } @Override @@ -252,15 +252,17 @@ public class BlogFragment extends BaseFragment implements }); } - private void checkIfThisIsMyBlog() { - blogController.isMyBlog( - new UiResultExceptionHandler( + private void loadBlog() { + blogController.loadBlog( + new UiResultExceptionHandler( getActivity()) { @Override - public void onResultUi(Boolean isMyBlog) { - if (isMyBlog) { + public void onResultUi(BlogItem blog) { + setToolbarTitle(blog.getBlog().getAuthor()); + if (blog.isOurs()) showWriteButton(); - } + if (blog.canBeRemoved()) + showDeleteButton(); } @Override @@ -271,23 +273,13 @@ public class BlogFragment extends BaseFragment implements }); } - private void checkIfBlogCanBeDeleted() { - blogController.canDeleteBlog( - new UiResultExceptionHandler( - getActivity()) { - @Override - public void onResultUi(Boolean canBeDeleted) { - if (canBeDeleted) { - showDeleteButton(); - } - } + private void setToolbarTitle(Author a) { + String title = getString(R.string.blogs_personal_blog, a.getName()); + getActivity().setTitle(title); - @Override - public void onExceptionUi(DbException exception) { - // TODO: Decide how to handle errors in the UI - finish(); - } - }); + // safe title in intent, so it can be restored automatically + Intent intent = getActivity().getIntent(); + intent.putExtra(BLOG_NAME, title); } private void showWriteButton() { diff --git a/briar-android/src/org/briarproject/android/blogs/BlogListItem.java b/briar-android/src/org/briarproject/android/blogs/BlogItem.java similarity index 82% rename from briar-android/src/org/briarproject/android/blogs/BlogListItem.java rename to briar-android/src/org/briarproject/android/blogs/BlogItem.java index 35c9f532b..536d05f24 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogListItem.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogItem.java @@ -5,15 +5,16 @@ import org.briarproject.api.blogs.BlogPostHeader; import java.util.Collection; -class BlogListItem { +class BlogItem { private final Blog blog; private final int postCount; private final long timestamp; private final int unread; - private final boolean ours; + private final boolean ours, removable; - BlogListItem(Blog blog, Collection headers, boolean ours) { + BlogItem(Blog blog, Collection headers, boolean ours, + boolean removable) { this.blog = blog; if (headers.isEmpty()) { postCount = 0; @@ -35,6 +36,7 @@ class BlogListItem { this.unread = unread; } this.ours = ours; + this.removable = removable; } Blog getBlog() { @@ -64,4 +66,8 @@ class BlogListItem { boolean isOurs() { return ours; } + + boolean canBeRemoved() { + return removable; + } } diff --git a/briar-android/src/org/briarproject/android/blogs/BlogListAdapter.java b/briar-android/src/org/briarproject/android/blogs/BlogListAdapter.java index 37f7dd301..b3e55f848 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogListAdapter.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogListAdapter.java @@ -29,11 +29,11 @@ import static org.briarproject.android.blogs.BlogActivity.BLOG_NAME; class BlogListAdapter extends RecyclerView.Adapter { - private SortedList blogs = new SortedList<>( - BlogListItem.class, new SortedList.Callback() { + private SortedList blogs = new SortedList<>( + BlogItem.class, new SortedList.Callback() { @Override - public int compare(BlogListItem a, BlogListItem b) { + public int compare(BlogItem a, BlogItem b) { if (a == b) return 0; // The blog with the newest message comes first long aTime = a.getTimestamp(), bTime = b.getTimestamp(); @@ -66,14 +66,14 @@ class BlogListAdapter extends } @Override - public boolean areContentsTheSame(BlogListItem a, BlogListItem b) { + public boolean areContentsTheSame(BlogItem a, BlogItem b) { return a.getBlog().equals(b.getBlog()) && a.getTimestamp() == b.getTimestamp() && a.getUnreadCount() == b.getUnreadCount(); } @Override - public boolean areItemsTheSame(BlogListItem a, BlogListItem b) { + public boolean areItemsTheSame(BlogItem a, BlogItem b) { return a.getBlog().equals(b.getBlog()); } }); @@ -93,7 +93,7 @@ class BlogListAdapter extends @Override public void onBindViewHolder(BlogViewHolder ui, int position) { - final BlogListItem item = getItem(position); + final BlogItem item = getItem(position); // Avatar ui.avatar.setText(item.getName().substring(0, 1)); @@ -145,14 +145,14 @@ class BlogListAdapter extends return blogs.size(); } - public BlogListItem getItem(int position) { + public BlogItem getItem(int position) { return blogs.get(position); } @Nullable - public BlogListItem getItem(GroupId g) { + public BlogItem getItem(GroupId g) { for (int i = 0; i < blogs.size(); i++) { - BlogListItem item = blogs.get(i); + BlogItem item = blogs.get(i); if (item.getBlog().getGroup().getId().equals(g)) { return item; } @@ -160,17 +160,17 @@ class BlogListAdapter extends return null; } - public void addAll(Collection items) { + public void addAll(Collection items) { blogs.addAll(items); } - void updateItem(BlogListItem item) { - BlogListItem oldItem = getItem(item.getBlog().getGroup().getId()); + void updateItem(BlogItem item) { + BlogItem oldItem = getItem(item.getBlog().getGroup().getId()); int position = blogs.indexOf(oldItem); blogs.updateItemAt(position, item); } - public void remove(BlogListItem item) { + public void remove(BlogItem item) { blogs.remove(item); } From 0a0e1b4280377d002c8d4a22beb9f9c6f21b3587 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 6 Sep 2016 14:24:01 -0300 Subject: [PATCH 5/8] Always replace current blog activity when new one opened Fixes #635 --- briar-android/src/org/briarproject/android/util/AuthorView.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/briar-android/src/org/briarproject/android/util/AuthorView.java b/briar-android/src/org/briarproject/android/util/AuthorView.java index 6920ebbf1..45ab5d347 100644 --- a/briar-android/src/org/briarproject/android/util/AuthorView.java +++ b/briar-android/src/org/briarproject/android/util/AuthorView.java @@ -26,6 +26,7 @@ import de.hdodenhof.circleimageview.CircleImageView; import im.delight.android.identicons.IdenticonDrawable; import static android.content.Context.LAYOUT_INFLATER_SERVICE; +import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; import static android.graphics.Typeface.BOLD; import static android.graphics.Typeface.NORMAL; import static android.support.v4.app.ActivityOptionsCompat.makeCustomAnimation; @@ -106,6 +107,7 @@ public class AuthorView extends RelativeLayout { public void onClick(View v) { Intent i = new Intent(getContext(), BlogActivity.class); i.putExtra(GROUP_ID, groupId.getBytes()); + i.setFlags(FLAG_ACTIVITY_CLEAR_TOP); ActivityOptionsCompat options = makeCustomAnimation(getContext(), android.R.anim.slide_in_left, From ac325d44232169e2e75db4ab687d514e0b2dc063 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 6 Sep 2016 14:52:27 -0300 Subject: [PATCH 6/8] remove unused resources --- briar-android/res/drawable/ic_chat.xml | 10 ---- .../drawable/ic_expand_more_black_24dp.xml | 9 ---- briar-android/res/layout/activity_blog.xml | 21 --------- briar-android/res/layout/dropdown_author.xml | 28 ----------- briar-android/res/layout/fragment_blogs.xml | 46 ------------------- .../res/layout/fragment_blogs_my.xml | 7 --- briar-android/res/menu/blogs_my_actions.xml | 12 ----- briar-android/res/values/color.xml | 1 - briar-android/res/values/dimens.xml | 1 - briar-android/res/values/strings.xml | 5 -- 10 files changed, 140 deletions(-) delete mode 100644 briar-android/res/drawable/ic_chat.xml delete mode 100644 briar-android/res/drawable/ic_expand_more_black_24dp.xml delete mode 100644 briar-android/res/layout/activity_blog.xml delete mode 100644 briar-android/res/layout/dropdown_author.xml delete mode 100644 briar-android/res/layout/fragment_blogs.xml delete mode 100644 briar-android/res/layout/fragment_blogs_my.xml delete mode 100644 briar-android/res/menu/blogs_my_actions.xml diff --git a/briar-android/res/drawable/ic_chat.xml b/briar-android/res/drawable/ic_chat.xml deleted file mode 100644 index 04f9fdcdf..000000000 --- a/briar-android/res/drawable/ic_chat.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/briar-android/res/drawable/ic_expand_more_black_24dp.xml b/briar-android/res/drawable/ic_expand_more_black_24dp.xml deleted file mode 100644 index 8d57dbc10..000000000 --- a/briar-android/res/drawable/ic_expand_more_black_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/briar-android/res/layout/activity_blog.xml b/briar-android/res/layout/activity_blog.xml deleted file mode 100644 index 3ff8d409e..000000000 --- a/briar-android/res/layout/activity_blog.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/briar-android/res/layout/dropdown_author.xml b/briar-android/res/layout/dropdown_author.xml deleted file mode 100644 index 1af9c5965..000000000 --- a/briar-android/res/layout/dropdown_author.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/briar-android/res/layout/fragment_blogs.xml b/briar-android/res/layout/fragment_blogs.xml deleted file mode 100644 index 2e618a9b1..000000000 --- a/briar-android/res/layout/fragment_blogs.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/briar-android/res/layout/fragment_blogs_my.xml b/briar-android/res/layout/fragment_blogs_my.xml deleted file mode 100644 index 288adfaa3..000000000 --- a/briar-android/res/layout/fragment_blogs_my.xml +++ /dev/null @@ -1,7 +0,0 @@ - - diff --git a/briar-android/res/menu/blogs_my_actions.xml b/briar-android/res/menu/blogs_my_actions.xml deleted file mode 100644 index 9a3ce5b49..000000000 --- a/briar-android/res/menu/blogs_my_actions.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/briar-android/res/values/color.xml b/briar-android/res/values/color.xml index e7cb49b15..0ac3140ee 100644 --- a/briar-android/res/values/color.xml +++ b/briar-android/res/values/color.xml @@ -35,7 +35,6 @@ #FFFFFF #61000000 - @color/briar_blue_dark #cfd2d4 #ffffff \ No newline at end of file diff --git a/briar-android/res/values/dimens.xml b/briar-android/res/values/dimens.xml index 9f62ff094..c8e7eca7d 100644 --- a/briar-android/res/values/dimens.xml +++ b/briar-android/res/values/dimens.xml @@ -27,7 +27,6 @@ 53dp 2dp 40dp - 32dp 48dp 2dp 30sp diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index 4bbf13c15..8ba94a5da 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -199,14 +199,11 @@ Nobody - Feed - My Blogs Create Blog Add new Blog Blog title (cannot be changed later) A short description of your new blog Potential readers may or may not subscribe to your blog based on the content of the description. - You don\'t have any blogs.\n\nWhy don\'t you create one now by clicking the plus in the top right screen corner? Blog created This blog is empty This blog is currently empty.\n\nEither the author hasn\'t written anything yet, or the person who shared this blog with you needs to come online, so posts can be synchronized. @@ -232,7 +229,6 @@ Blog List Available Blogs - Drafts Share Blog @@ -313,7 +309,6 @@ Anonymous - New identity\u2026 New Identity Create Identity Identity created From ccc49df08ea7d0e52a22682ef8876983a4d0cac3 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 7 Sep 2016 13:57:51 -0300 Subject: [PATCH 7/8] Address review issues --- .../res/layout/fragment_blog_post.xml | 7 ++++ .../res/layout/fragment_blog_post_pager.xml | 20 ++++++++++-- briar-android/res/values/strings.xml | 1 + .../android/blogs/BaseControllerImpl.java | 3 ++ .../android/blogs/BasePostFragment.java | 12 ++++++- .../android/blogs/BasePostPagerFragment.java | 32 +++++++------------ .../android/blogs/BlogActivity.java | 16 +--------- .../android/blogs/BlogControllerImpl.java | 7 ---- .../android/blogs/BlogPostFragment.java | 2 +- .../android/blogs/BlogPostPagerFragment.java | 24 ++++++++++---- .../android/blogs/BlogPostViewHolder.java | 29 +++-------------- .../android/blogs/FeedPostFragment.java | 2 +- .../android/blogs/FeedPostPagerFragment.java | 24 ++++++++++---- .../android/blogs/ReblogActivity.java | 2 +- .../android/blogs/ReblogFragment.java | 2 +- .../android/util/AndroidUtils.java | 27 ++++++++++++++++ 16 files changed, 122 insertions(+), 88 deletions(-) diff --git a/briar-android/res/layout/fragment_blog_post.xml b/briar-android/res/layout/fragment_blog_post.xml index bc1b87c2a..18ec1f417 100644 --- a/briar-android/res/layout/fragment_blog_post.xml +++ b/briar-android/res/layout/fragment_blog_post.xml @@ -20,6 +20,13 @@ android:layout_width="wrap_content" android:layout_height="wrap_content"/> + + diff --git a/briar-android/res/layout/fragment_blog_post_pager.xml b/briar-android/res/layout/fragment_blog_post_pager.xml index fe1c2568a..626dcaf26 100644 --- a/briar-android/res/layout/fragment_blog_post_pager.xml +++ b/briar-android/res/layout/fragment_blog_post_pager.xml @@ -1,6 +1,20 @@ - \ No newline at end of file + android:layout_height="match_parent"> + + + + + + \ No newline at end of file diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index 8ba94a5da..e86654509 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -73,6 +73,7 @@ Offline Send No data + It seems that you are new here and have no contacts yet.\n\nTap the + icon at the top and follow the instructions to add some friends to your list.\n\nPlease remember: You can only add new contacts face-to-face to prevent anyone from impersonating you or reading your messages in the future. diff --git a/briar-android/src/org/briarproject/android/blogs/BaseControllerImpl.java b/briar-android/src/org/briarproject/android/blogs/BaseControllerImpl.java index ab513217a..3c4f1bc21 100644 --- a/briar-android/src/org/briarproject/android/blogs/BaseControllerImpl.java +++ b/briar-android/src/org/briarproject/android/blogs/BaseControllerImpl.java @@ -59,6 +59,9 @@ abstract class BaseControllerImpl extends DbControllerImpl @Override @CallSuper public void onStart() { + if (listener == null) + throw new IllegalStateException( + "OnBlogPostAddedListener needs to be attached"); eventBus.addListener(this); } diff --git a/briar-android/src/org/briarproject/android/blogs/BasePostFragment.java b/briar-android/src/org/briarproject/android/blogs/BasePostFragment.java index e340a3fcb..06153e422 100644 --- a/briar-android/src/org/briarproject/android/blogs/BasePostFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/BasePostFragment.java @@ -3,10 +3,12 @@ package org.briarproject.android.blogs; import android.os.Bundle; import android.support.annotation.CallSuper; import android.support.annotation.Nullable; +import android.support.annotation.UiThread; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.widget.ProgressBar; import org.briarproject.R; import org.briarproject.android.fragment.BaseFragment; @@ -14,6 +16,8 @@ import org.briarproject.api.db.DbException; import java.util.logging.Logger; +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; import static org.briarproject.android.util.AndroidUtils.MIN_RESOLUTION; public abstract class BasePostFragment extends BaseFragment { @@ -22,6 +26,7 @@ public abstract class BasePostFragment extends BaseFragment { Logger.getLogger(BasePostFragment.class.getName()); private View view; + private ProgressBar progressBar; private BlogPostViewHolder ui; private BlogPostItem post; private Runnable refresher; @@ -35,6 +40,8 @@ public abstract class BasePostFragment extends BaseFragment { view = inflater.inflate(R.layout.fragment_blog_post, container, false); + progressBar = (ProgressBar) view.findViewById(R.id.progressBar); + progressBar.setVisibility(VISIBLE); ui = new BlogPostViewHolder(view); return view; } @@ -46,6 +53,7 @@ public abstract class BasePostFragment extends BaseFragment { startPeriodicUpdate(); } + @CallSuper @Override public void onStop() { super.onStop(); @@ -63,12 +71,14 @@ public abstract class BasePostFragment extends BaseFragment { } } + @UiThread protected void onBlogPostLoaded(BlogPostItem post) { - listener.hideLoadingScreen(); + progressBar.setVisibility(INVISIBLE); this.post = post; ui.bindItem(post); } + @UiThread protected void onBlogPostLoadException(DbException exception) { // TODO: Decide how to handle errors in the UI finish(); diff --git a/briar-android/src/org/briarproject/android/blogs/BasePostPagerFragment.java b/briar-android/src/org/briarproject/android/blogs/BasePostPagerFragment.java index b24f6be3a..e27c1470f 100644 --- a/briar-android/src/org/briarproject/android/blogs/BasePostPagerFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/BasePostPagerFragment.java @@ -10,10 +10,10 @@ import android.support.v4.view.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ProgressBar; import org.briarproject.R; import org.briarproject.android.blogs.BaseController.OnBlogPostAddedListener; -import org.briarproject.android.controller.handler.UiResultExceptionHandler; import org.briarproject.android.fragment.BaseFragment; import org.briarproject.api.blogs.BlogPostHeader; import org.briarproject.api.db.DbException; @@ -24,13 +24,17 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; import static org.briarproject.android.blogs.BasePostPagerFragment.BlogPostPagerAdapter.INVALID_POSITION; -import static org.briarproject.android.blogs.BlogActivity.POST_ID; abstract class BasePostPagerFragment extends BaseFragment implements OnBlogPostAddedListener { + static final String POST_ID = "briar.POST_ID"; + private ViewPager pager; + private ProgressBar progressBar; private BlogPostPagerAdapter postPagerAdapter; private MessageId postId; @@ -49,9 +53,11 @@ abstract class BasePostPagerFragment extends BaseFragment View v = inflater.inflate(R.layout.fragment_blog_post_pager, container, false); + progressBar = (ProgressBar) v.findViewById(R.id.progressBar); + progressBar.setVisibility(VISIBLE); + pager = (ViewPager) v.findViewById(R.id.pager); postPagerAdapter = new BlogPostPagerAdapter(getChildFragmentManager()); - listener.showLoadingScreen(false, R.string.progress_title_please_wait); return v; } @@ -82,7 +88,7 @@ abstract class BasePostPagerFragment extends BaseFragment abstract void loadBlogPosts(final MessageId select); - abstract BaseController getController(); + abstract void loadBlogPost(BlogPostHeader header); protected void onBlogPostsLoaded(MessageId select, Collection posts) { @@ -97,23 +103,6 @@ abstract class BasePostPagerFragment extends BaseFragment finish(); } - private void loadBlogPost(BlogPostHeader header) { - getController().loadBlogPost(header, - new UiResultExceptionHandler( - getActivity()) { - @Override - public void onResultUi(BlogPostItem post) { - addPost(post); - } - - @Override - public void onExceptionUi(DbException exception) { - // TODO: Decide how to handle errors in the UI - finish(); - } - }); - } - @Nullable private MessageId getSelectedPost() { if (postPagerAdapter.getCount() == 0) return null; @@ -124,6 +113,7 @@ abstract class BasePostPagerFragment extends BaseFragment private void selectPost(MessageId m) { int pos = postPagerAdapter.getPostPosition(m); if (pos != INVALID_POSITION) { + progressBar.setVisibility(INVISIBLE); pager.setAdapter(postPagerAdapter); pager.setCurrentItem(pos); } diff --git a/briar-android/src/org/briarproject/android/blogs/BlogActivity.java b/briar-android/src/org/briarproject/android/blogs/BlogActivity.java index 34ba66f98..bb7a5cc8d 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogActivity.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogActivity.java @@ -7,10 +7,8 @@ import android.widget.ProgressBar; import org.briarproject.R; import org.briarproject.android.ActivityComponent; import org.briarproject.android.BriarActivity; -import org.briarproject.android.blogs.BaseController.OnBlogPostAddedListener; import org.briarproject.android.blogs.BlogPostAdapter.OnBlogPostClickListener; import org.briarproject.android.fragment.BaseFragment.BaseFragmentListener; -import org.briarproject.api.blogs.BlogPostHeader; import org.briarproject.api.sync.GroupId; import javax.inject.Inject; @@ -19,13 +17,12 @@ import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; public class BlogActivity extends BriarActivity implements - OnBlogPostAddedListener, OnBlogPostClickListener, BaseFragmentListener { + OnBlogPostClickListener, BaseFragmentListener { static final int REQUEST_WRITE_POST = 1; static final int REQUEST_SHARE = 2; static final String BLOG_NAME = "briar.BLOG_NAME"; static final String IS_NEW_BLOG = "briar.IS_NEW_BLOG"; - static final String POST_ID = "briar.POST_ID"; private ProgressBar progressBar; @@ -61,22 +58,11 @@ public class BlogActivity extends BriarActivity implements } } - @Override - public void onResume() { - super.onResume(); - } - @Override public void injectActivity(ActivityComponent component) { component.inject(this); } - @Override - public void onBlogPostAdded(BlogPostHeader header, boolean local) { - // all our fragments are implementing and registering that hook, - // so we don't need to do that ourselves - } - @Override public void onBlogPostClick(BlogPostItem post) { BlogPostPagerFragment f = BlogPostPagerFragment.newInstance(post.getId()); diff --git a/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java b/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java index 55615009f..ad7b7597d 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java @@ -35,13 +35,6 @@ public class BlogControllerImpl extends BaseControllerImpl @Override public void onActivityCreate() { - if (activity instanceof OnBlogPostAddedListener) { - listener = (OnBlogPostAddedListener) activity; - } else { - throw new IllegalStateException( - "An activity that injects the BlogController must " + - "implement the OnBlogPostAddedListener"); - } } @Override diff --git a/briar-android/src/org/briarproject/android/blogs/BlogPostFragment.java b/briar-android/src/org/briarproject/android/blogs/BlogPostFragment.java index b70a36062..39c1bf3a5 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogPostFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogPostFragment.java @@ -13,7 +13,7 @@ import org.briarproject.api.sync.MessageId; import javax.inject.Inject; -import static org.briarproject.android.blogs.BlogActivity.POST_ID; +import static org.briarproject.android.blogs.BasePostPagerFragment.POST_ID; public class BlogPostFragment extends BasePostFragment { diff --git a/briar-android/src/org/briarproject/android/blogs/BlogPostPagerFragment.java b/briar-android/src/org/briarproject/android/blogs/BlogPostPagerFragment.java index 54e646f9c..3a68030a1 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogPostPagerFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogPostPagerFragment.java @@ -4,6 +4,7 @@ import android.os.Bundle; import org.briarproject.android.ActivityComponent; import org.briarproject.android.controller.handler.UiResultExceptionHandler; +import org.briarproject.api.blogs.BlogPostHeader; import org.briarproject.api.db.DbException; import org.briarproject.api.sync.MessageId; @@ -11,8 +12,6 @@ import java.util.Collection; import javax.inject.Inject; -import static org.briarproject.android.blogs.BlogActivity.POST_ID; - public class BlogPostPagerFragment extends BasePostPagerFragment { @@ -42,10 +41,6 @@ public class BlogPostPagerFragment extends BasePostPagerFragment { return TAG; } - @Override - BaseController getController() { - return blogController; - } void loadBlogPosts(final MessageId select) { blogController.loadBlogPosts( @@ -63,4 +58,21 @@ public class BlogPostPagerFragment extends BasePostPagerFragment { }); } + void loadBlogPost(BlogPostHeader header) { + blogController.loadBlogPost(header, + new UiResultExceptionHandler( + getActivity()) { + @Override + public void onResultUi(BlogPostItem post) { + addPost(post); + } + + @Override + public void onExceptionUi(DbException exception) { + // TODO: Decide how to handle errors in the UI + finish(); + } + }); + } + } diff --git a/briar-android/src/org/briarproject/android/blogs/BlogPostViewHolder.java b/briar-android/src/org/briarproject/android/blogs/BlogPostViewHolder.java index e9a99449e..13a1b3f17 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogPostViewHolder.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogPostViewHolder.java @@ -6,13 +6,8 @@ import android.content.Intent; import android.support.annotation.UiThread; import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityOptionsCompat; -import android.support.v4.content.ContextCompat; import android.support.v4.view.ViewCompat; import android.support.v7.widget.RecyclerView; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.SpannableStringBuilder; -import android.text.style.ForegroundColorSpan; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; @@ -32,14 +27,14 @@ import static android.support.v4.app.ActivityOptionsCompat.makeSceneTransitionAn import static android.view.View.GONE; import static android.view.View.VISIBLE; import static org.briarproject.android.BriarActivity.GROUP_ID; -import static org.briarproject.android.blogs.BlogActivity.POST_ID; +import static org.briarproject.android.blogs.BasePostPagerFragment.POST_ID; +import static org.briarproject.android.util.AndroidUtils.TEASER_LENGTH; +import static org.briarproject.android.util.AndroidUtils.getTeaser; import static org.briarproject.api.blogs.MessageType.POST; @UiThread class BlogPostViewHolder extends RecyclerView.ViewHolder { - private static final int TEASER_LENGTH = 240; - private final Context ctx; private final ViewGroup layout; private final AuthorView reblogger; @@ -119,7 +114,7 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder { } else { body.setTextIsSelectable(false); if (item.getBody().length() > TEASER_LENGTH) - bodyText = getTeaser(item.getBody()); + bodyText = getTeaser(ctx, item.getBody()); } body.setText(bodyText); @@ -176,20 +171,4 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder { commentContainer.addView(v); } } - - private SpannableStringBuilder getTeaser(String body) { - SpannableStringBuilder builder = - new SpannableStringBuilder(body.substring(0, TEASER_LENGTH)); - builder.append("… "); - - Spannable readMore = - new SpannableString(ctx.getString(R.string.read_more) + "…"); - ForegroundColorSpan fg = new ForegroundColorSpan( - ContextCompat.getColor(ctx, R.color.briar_text_link)); - readMore.setSpan(fg, 0, readMore.length(), - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - builder.append(readMore); - - return builder; - } } diff --git a/briar-android/src/org/briarproject/android/blogs/FeedPostFragment.java b/briar-android/src/org/briarproject/android/blogs/FeedPostFragment.java index 5b4841cd4..807bcd6e3 100644 --- a/briar-android/src/org/briarproject/android/blogs/FeedPostFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/FeedPostFragment.java @@ -15,7 +15,7 @@ import org.briarproject.api.sync.MessageId; import javax.inject.Inject; import static org.briarproject.android.BriarActivity.GROUP_ID; -import static org.briarproject.android.blogs.BlogActivity.POST_ID; +import static org.briarproject.android.blogs.BasePostPagerFragment.POST_ID; public class FeedPostFragment extends BasePostFragment { diff --git a/briar-android/src/org/briarproject/android/blogs/FeedPostPagerFragment.java b/briar-android/src/org/briarproject/android/blogs/FeedPostPagerFragment.java index db30ac1f3..df2c4e33e 100644 --- a/briar-android/src/org/briarproject/android/blogs/FeedPostPagerFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/FeedPostPagerFragment.java @@ -4,6 +4,7 @@ import android.os.Bundle; import org.briarproject.android.ActivityComponent; import org.briarproject.android.controller.handler.UiResultExceptionHandler; +import org.briarproject.api.blogs.BlogPostHeader; import org.briarproject.api.db.DbException; import org.briarproject.api.sync.MessageId; @@ -11,8 +12,6 @@ import java.util.Collection; import javax.inject.Inject; -import static org.briarproject.android.blogs.BlogActivity.POST_ID; - public class FeedPostPagerFragment extends BasePostPagerFragment { public final static String TAG = FeedPostPagerFragment.class.getName(); @@ -41,10 +40,6 @@ public class FeedPostPagerFragment extends BasePostPagerFragment { return TAG; } - @Override - BaseController getController() { - return feedController; - } void loadBlogPosts(final MessageId select) { feedController.loadBlogPosts( @@ -62,4 +57,21 @@ public class FeedPostPagerFragment extends BasePostPagerFragment { }); } + void loadBlogPost(BlogPostHeader header) { + feedController.loadBlogPost(header, + new UiResultExceptionHandler( + getActivity()) { + @Override + public void onResultUi(BlogPostItem post) { + addPost(post); + } + + @Override + public void onExceptionUi(DbException exception) { + // TODO: Decide how to handle errors in the UI + finish(); + } + }); + } + } diff --git a/briar-android/src/org/briarproject/android/blogs/ReblogActivity.java b/briar-android/src/org/briarproject/android/blogs/ReblogActivity.java index 923d520a6..6b4afb89b 100644 --- a/briar-android/src/org/briarproject/android/blogs/ReblogActivity.java +++ b/briar-android/src/org/briarproject/android/blogs/ReblogActivity.java @@ -15,7 +15,7 @@ import org.briarproject.android.fragment.BaseFragment.BaseFragmentListener; import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; -import static org.briarproject.android.blogs.BlogActivity.POST_ID; +import static org.briarproject.android.blogs.BasePostPagerFragment.POST_ID; public class ReblogActivity extends BriarActivity implements BaseFragmentListener { diff --git a/briar-android/src/org/briarproject/android/blogs/ReblogFragment.java b/briar-android/src/org/briarproject/android/blogs/ReblogFragment.java index 1fee6c647..87ac61380 100644 --- a/briar-android/src/org/briarproject/android/blogs/ReblogFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/ReblogFragment.java @@ -27,7 +27,7 @@ import static android.view.View.GONE; import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static org.briarproject.android.BriarActivity.GROUP_ID; -import static org.briarproject.android.blogs.BlogActivity.POST_ID; +import static org.briarproject.android.blogs.BasePostPagerFragment.POST_ID; public class ReblogFragment extends BaseFragment { diff --git a/briar-android/src/org/briarproject/android/util/AndroidUtils.java b/briar-android/src/org/briarproject/android/util/AndroidUtils.java index 610e480e5..66593d0f8 100644 --- a/briar-android/src/org/briarproject/android/util/AndroidUtils.java +++ b/briar-android/src/org/briarproject/android/util/AndroidUtils.java @@ -6,7 +6,12 @@ import android.content.Context; import android.os.Build; import android.provider.Settings; import android.support.design.widget.TextInputLayout; +import android.support.v4.content.ContextCompat; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; import android.text.format.DateUtils; +import android.text.style.ForegroundColorSpan; import org.briarproject.R; import org.briarproject.util.IoUtils; @@ -31,6 +36,7 @@ import static android.text.format.DateUtils.WEEK_IN_MILLIS; public class AndroidUtils { public static final long MIN_RESOLUTION = MINUTE_IN_MILLIS; + public static final int TEASER_LENGTH = 240; // Fake Bluetooth address returned by BluetoothAdapter on API 23 and later private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00"; @@ -115,4 +121,25 @@ public class AndroidUtils { MIN_RESOLUTION, flags).toString(); } + public static SpannableStringBuilder getTeaser(Context ctx, String body) { + if (body.length() < TEASER_LENGTH) + throw new IllegalArgumentException( + "String is shorter than TEASER_LENGTH"); + + SpannableStringBuilder builder = + new SpannableStringBuilder(body.substring(0, TEASER_LENGTH)); + String ellipsis = ctx.getString(R.string.ellipsis); + builder.append(ellipsis).append(" "); + + Spannable readMore = new SpannableString( + ctx.getString(R.string.read_more) + ellipsis); + ForegroundColorSpan fg = new ForegroundColorSpan( + ContextCompat.getColor(ctx, R.color.briar_text_link)); + readMore.setSpan(fg, 0, readMore.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + builder.append(readMore); + + return builder; + } + } From 7c5945de01c17accfa84af688e3b6c7cbbd084c2 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 7 Sep 2016 16:50:43 -0300 Subject: [PATCH 8/8] Check if activity is still alive before returning results to it --- .../org/briarproject/android/Destroyable.java | 2 +- .../android/blogs/BlogFragment.java | 9 ++++----- .../android/blogs/BlogPostFragment.java | 2 +- .../android/blogs/BlogPostPagerFragment.java | 4 ++-- .../android/blogs/FeedFragment.java | 4 ++-- .../android/blogs/FeedPostFragment.java | 2 +- .../android/blogs/FeedPostPagerFragment.java | 4 ++-- .../android/blogs/ReblogFragment.java | 4 ++-- .../handler/UiResultExceptionHandler.java | 19 +++++++++++-------- .../controller/handler/UiResultHandler.java | 14 ++++++++------ .../android/fragment/BaseFragment.java | 3 ++- 11 files changed, 36 insertions(+), 31 deletions(-) diff --git a/briar-android/src/org/briarproject/android/Destroyable.java b/briar-android/src/org/briarproject/android/Destroyable.java index a9a9ef8ce..17c7dc850 100644 --- a/briar-android/src/org/briarproject/android/Destroyable.java +++ b/briar-android/src/org/briarproject/android/Destroyable.java @@ -2,7 +2,7 @@ package org.briarproject.android; import android.support.annotation.UiThread; -interface Destroyable { +public interface Destroyable { @UiThread boolean hasBeenDestroyed(); diff --git a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java index 5c175517d..4ff2695e3 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java @@ -209,7 +209,7 @@ public class BlogFragment extends BaseFragment implements public void onBlogPostAdded(BlogPostHeader header, final boolean local) { blogController.loadBlogPost(header, new UiResultExceptionHandler( - getActivity()) { + listener) { @Override public void onResultUi(BlogPostItem post) { adapter.add(post); @@ -233,7 +233,7 @@ public class BlogFragment extends BaseFragment implements void loadBlogPosts(final boolean reload) { blogController.loadBlogPosts( new UiResultExceptionHandler, DbException>( - getActivity()) { + listener) { @Override public void onResultUi(Collection posts) { if (posts.size() > 0) { @@ -254,8 +254,7 @@ public class BlogFragment extends BaseFragment implements private void loadBlog() { blogController.loadBlog( - new UiResultExceptionHandler( - getActivity()) { + new UiResultExceptionHandler(listener) { @Override public void onResultUi(BlogItem blog) { setToolbarTitle(blog.getBlog().getAuthor()); @@ -333,7 +332,7 @@ public class BlogFragment extends BaseFragment implements private void deleteBlog() { blogController.deleteBlog( - new UiResultExceptionHandler(getActivity()) { + new UiResultExceptionHandler(listener) { @Override public void onResultUi(Void result) { Toast.makeText(getActivity(), diff --git a/briar-android/src/org/briarproject/android/blogs/BlogPostFragment.java b/briar-android/src/org/briarproject/android/blogs/BlogPostFragment.java index 39c1bf3a5..ac7b4d504 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogPostFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogPostFragment.java @@ -62,7 +62,7 @@ public class BlogPostFragment extends BasePostFragment { super.onStart(); blogController.loadBlogPost(postId, new UiResultExceptionHandler( - getActivity()) { + listener) { @Override public void onResultUi(BlogPostItem post) { onBlogPostLoaded(post); diff --git a/briar-android/src/org/briarproject/android/blogs/BlogPostPagerFragment.java b/briar-android/src/org/briarproject/android/blogs/BlogPostPagerFragment.java index 3a68030a1..f0a534b84 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogPostPagerFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogPostPagerFragment.java @@ -45,7 +45,7 @@ public class BlogPostPagerFragment extends BasePostPagerFragment { void loadBlogPosts(final MessageId select) { blogController.loadBlogPosts( new UiResultExceptionHandler, DbException>( - getActivity()) { + listener) { @Override public void onResultUi(Collection posts) { onBlogPostsLoaded(select, posts); @@ -61,7 +61,7 @@ public class BlogPostPagerFragment extends BasePostPagerFragment { void loadBlogPost(BlogPostHeader header) { blogController.loadBlogPost(header, new UiResultExceptionHandler( - getActivity()) { + listener) { @Override public void onResultUi(BlogPostItem post) { addPost(post); diff --git a/briar-android/src/org/briarproject/android/blogs/FeedFragment.java b/briar-android/src/org/briarproject/android/blogs/FeedFragment.java index dbdd11127..41791e962 100644 --- a/briar-android/src/org/briarproject/android/blogs/FeedFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/FeedFragment.java @@ -108,7 +108,7 @@ public class FeedFragment extends BaseFragment implements }); feedController.loadBlogPosts( new UiResultExceptionHandler, DbException>( - getActivity()) { + listener) { @Override public void onResultUi(Collection posts) { if (posts.isEmpty()) { @@ -175,7 +175,7 @@ public class FeedFragment extends BaseFragment implements public void onBlogPostAdded(BlogPostHeader header, final boolean local) { feedController.loadBlogPost(header, new UiResultExceptionHandler( - getActivity()) { + listener) { @Override public void onResultUi(BlogPostItem post) { adapter.add(post); diff --git a/briar-android/src/org/briarproject/android/blogs/FeedPostFragment.java b/briar-android/src/org/briarproject/android/blogs/FeedPostFragment.java index 807bcd6e3..442a85ef9 100644 --- a/briar-android/src/org/briarproject/android/blogs/FeedPostFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/FeedPostFragment.java @@ -65,7 +65,7 @@ public class FeedPostFragment extends BasePostFragment { super.onStart(); feedController.loadBlogPost(blogId, postId, new UiResultExceptionHandler( - getActivity()) { + listener) { @Override public void onResultUi(BlogPostItem post) { onBlogPostLoaded(post); diff --git a/briar-android/src/org/briarproject/android/blogs/FeedPostPagerFragment.java b/briar-android/src/org/briarproject/android/blogs/FeedPostPagerFragment.java index df2c4e33e..ab9444104 100644 --- a/briar-android/src/org/briarproject/android/blogs/FeedPostPagerFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/FeedPostPagerFragment.java @@ -44,7 +44,7 @@ public class FeedPostPagerFragment extends BasePostPagerFragment { void loadBlogPosts(final MessageId select) { feedController.loadBlogPosts( new UiResultExceptionHandler, DbException>( - getActivity()) { + listener) { @Override public void onResultUi(Collection posts) { onBlogPostsLoaded(select, posts); @@ -60,7 +60,7 @@ public class FeedPostPagerFragment extends BasePostPagerFragment { void loadBlogPost(BlogPostHeader header) { feedController.loadBlogPost(header, new UiResultExceptionHandler( - getActivity()) { + listener) { @Override public void onResultUi(BlogPostItem post) { addPost(post); diff --git a/briar-android/src/org/briarproject/android/blogs/ReblogFragment.java b/briar-android/src/org/briarproject/android/blogs/ReblogFragment.java index 87ac61380..305273ba8 100644 --- a/briar-android/src/org/briarproject/android/blogs/ReblogFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/ReblogFragment.java @@ -106,7 +106,7 @@ public class ReblogFragment extends BaseFragment { // TODO: Load blog post when fragment is created. #631 feedController.loadBlogPost(blogId, postId, new UiResultExceptionHandler( - getActivity()) { + listener) { @Override public void onResultUi(BlogPostItem result) { item = result; @@ -148,7 +148,7 @@ public class ReblogFragment extends BaseFragment { private void send() { String comment = getComment(); feedController.repeatPost(item, comment, - new UiResultExceptionHandler(getActivity()) { + new UiResultExceptionHandler(listener) { @Override public void onResultUi(Void result) { // do nothing, this fragment is gone already diff --git a/briar-android/src/org/briarproject/android/controller/handler/UiResultExceptionHandler.java b/briar-android/src/org/briarproject/android/controller/handler/UiResultExceptionHandler.java index ba2eab195..1f9cab093 100644 --- a/briar-android/src/org/briarproject/android/controller/handler/UiResultExceptionHandler.java +++ b/briar-android/src/org/briarproject/android/controller/handler/UiResultExceptionHandler.java @@ -1,33 +1,36 @@ package org.briarproject.android.controller.handler; -import android.app.Activity; import android.support.annotation.UiThread; +import org.briarproject.android.fragment.BaseFragment.BaseFragmentListener; + public abstract class UiResultExceptionHandler implements ResultExceptionHandler { - private final Activity activity; + private final BaseFragmentListener listener; - public UiResultExceptionHandler(Activity activity) { - this.activity = activity; + protected UiResultExceptionHandler(BaseFragmentListener listener) { + this.listener = listener; } @Override public void onResult(final R result) { - activity.runOnUiThread(new Runnable() { + listener.runOnUiThread(new Runnable() { @Override public void run() { - onResultUi(result); + if (!listener.hasBeenDestroyed()) + onResultUi(result); } }); } @Override public void onException(final E exception) { - activity.runOnUiThread(new Runnable() { + listener.runOnUiThread(new Runnable() { @Override public void run() { - onExceptionUi(exception); + if (!listener.hasBeenDestroyed()) + onExceptionUi(exception); } }); } diff --git a/briar-android/src/org/briarproject/android/controller/handler/UiResultHandler.java b/briar-android/src/org/briarproject/android/controller/handler/UiResultHandler.java index 0616b82a2..03c68d7ac 100644 --- a/briar-android/src/org/briarproject/android/controller/handler/UiResultHandler.java +++ b/briar-android/src/org/briarproject/android/controller/handler/UiResultHandler.java @@ -1,22 +1,24 @@ package org.briarproject.android.controller.handler; -import android.app.Activity; import android.support.annotation.UiThread; +import org.briarproject.android.fragment.BaseFragment.BaseFragmentListener; + public abstract class UiResultHandler implements ResultHandler { - private final Activity activity; + private final BaseFragmentListener listener; - public UiResultHandler(Activity activity) { - this.activity = activity; + protected UiResultHandler(BaseFragmentListener listener) { + this.listener = listener; } @Override public void onResult(final R result) { - activity.runOnUiThread(new Runnable() { + listener.runOnUiThread(new Runnable() { @Override public void run() { - onResultUi(result); + if (!listener.hasBeenDestroyed()) + onResultUi(result); } }); } diff --git a/briar-android/src/org/briarproject/android/fragment/BaseFragment.java b/briar-android/src/org/briarproject/android/fragment/BaseFragment.java index c19bcf1ee..d6f4ed363 100644 --- a/briar-android/src/org/briarproject/android/fragment/BaseFragment.java +++ b/briar-android/src/org/briarproject/android/fragment/BaseFragment.java @@ -7,6 +7,7 @@ import android.support.annotation.UiThread; import android.support.v4.app.Fragment; import org.briarproject.android.ActivityComponent; +import org.briarproject.android.Destroyable; public abstract class BaseFragment extends Fragment { @@ -45,7 +46,7 @@ public abstract class BaseFragment extends Fragment { getActivity().supportFinishAfterTransition(); } - public interface BaseFragmentListener { + public interface BaseFragmentListener extends Destroyable { @UiThread void showLoadingScreen(boolean isBlocking, int stringId);