mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-18 05:39:53 +01:00
Merge branch '637-effect-of-touching-a-post-is-inconsistent' into 'master'
Resolve Outstanding Blog Issues This MR has several commits which fix individual small issues. The biggest commit is a refactoring of the `BlogActivity`, so its `ViewPager` can be used also for the Blog feed. Closes #637 See merge request !309
This commit is contained in:
@@ -1,10 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:alpha="0.54"
|
|
||||||
android:viewportHeight="24.0"
|
|
||||||
android:viewportWidth="24.0">
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM6,9h12v2L6,11L6,9zM14,14L6,14v-2h8v2zM18,8L6,8L6,6h12v2z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24.0"
|
|
||||||
android:viewportHeight="24.0">
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -3,4 +3,14 @@
|
|||||||
android:id="@+id/fragmentContainer"
|
android:id="@+id/fragmentContainer"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"/>
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBar"
|
||||||
|
style="?android:attr/progressBarStyleLarge"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:visibility="invisible"/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center_vertical">
|
|
||||||
|
|
||||||
<de.hdodenhof.circleimageview.CircleImageView
|
|
||||||
android:id="@+id/avatarView"
|
|
||||||
style="@style/BriarAvatar"
|
|
||||||
android:layout_width="@dimen/dropdown_picture_size"
|
|
||||||
android:layout_height="@dimen/dropdown_picture_size"
|
|
||||||
android:layout_margin="@dimen/margin_small"
|
|
||||||
tools:src="@drawable/ic_launcher"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/nameView"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="@dimen/margin_small"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:textSize="@dimen/text_size_medium"
|
|
||||||
tools:text="This is a name of an author. It can be quite long."/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -6,7 +6,12 @@
|
|||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
|
android:descendantFocusability="beforeDescendants"
|
||||||
|
android:focusable="true"
|
||||||
|
android:focusableInTouchMode="true">
|
||||||
|
<!-- Above Focusability attributes prevent automatic scroll-down,
|
||||||
|
because body text is selectable -->
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/postLayout"
|
android:id="@+id/postLayout"
|
||||||
@@ -15,6 +20,13 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBar"
|
||||||
|
style="?android:attr/progressBarStyleLarge"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"/>
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<android.support.v4.view.ViewPager
|
<android.support.v4.view.ViewPager
|
||||||
android:id="@+id/pager"
|
android:id="@+id/pager"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"/>
|
||||||
tools:context=".android.blogs.BlogActivity"/>
|
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/progressBar"
|
android:id="@+id/progressBar"
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<android.support.design.widget.TabLayout
|
|
||||||
android:id="@+id/tabLayout"
|
|
||||||
style="@style/BriarTabLayout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<android.support.design.widget.TabItem
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/blogs_feed"/>
|
|
||||||
|
|
||||||
<android.support.design.widget.TabItem
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/blogs_my_blogs"/>
|
|
||||||
|
|
||||||
<android.support.design.widget.TabItem
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/blogs_blog_list"/>
|
|
||||||
|
|
||||||
<android.support.design.widget.TabItem
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/blogs_available_blogs"/>
|
|
||||||
|
|
||||||
<android.support.design.widget.TabItem
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/blogs_drafts"/>
|
|
||||||
|
|
||||||
</android.support.design.widget.TabLayout>
|
|
||||||
|
|
||||||
<android.support.v4.view.ViewPager
|
|
||||||
android:id="@+id/pager"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<org.briarproject.android.util.BriarRecyclerView
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
tools:listitem="@layout/list_item_blog"/>
|
|
||||||
@@ -29,7 +29,6 @@
|
|||||||
android:paddingLeft="@dimen/listitem_vertical_margin"
|
android:paddingLeft="@dimen/listitem_vertical_margin"
|
||||||
android:paddingRight="@dimen/listitem_vertical_margin"
|
android:paddingRight="@dimen/listitem_vertical_margin"
|
||||||
android:textColor="@color/briar_text_secondary"
|
android:textColor="@color/briar_text_secondary"
|
||||||
android:textIsSelectable="true"
|
|
||||||
android:textSize="@dimen/text_size_small"
|
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."/>
|
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."/>
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
|
android:foreground="?android:attr/selectableItemBackground">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -55,7 +56,6 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@+id/authorView"
|
android:layout_below="@+id/authorView"
|
||||||
android:textColor="@color/briar_text_secondary"
|
android:textColor="@color/briar_text_secondary"
|
||||||
android:textIsSelectable="true"
|
|
||||||
android:textSize="@dimen/text_size_medium"
|
android:textSize="@dimen/text_size_medium"
|
||||||
tools:text="This is a body text that shows the content of a blog post.\n\nThis one is not short, but it is also not too long."/>
|
tools:text="This is a body text that shows the content of a blog post.\n\nThis one is not short, but it is also not too long."/>
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<menu
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/action_create_blog"
|
|
||||||
android:icon="@drawable/ic_add_white"
|
|
||||||
android:title="@string/blogs_my_blogs_create"
|
|
||||||
app:showAsAction="ifRoom"/>
|
|
||||||
|
|
||||||
</menu>
|
|
||||||
@@ -35,7 +35,6 @@
|
|||||||
<color name="menu_background">#FFFFFF</color>
|
<color name="menu_background">#FFFFFF</color>
|
||||||
|
|
||||||
<color name="spinner_border">#61000000</color> <!-- 38% Black -->
|
<color name="spinner_border">#61000000</color> <!-- 38% Black -->
|
||||||
<color name="spinner_arrow">@color/briar_blue_dark</color>
|
|
||||||
<color name="forum_discussion_nested_line">#cfd2d4</color>
|
<color name="forum_discussion_nested_line">#cfd2d4</color>
|
||||||
<color name="forum_cell_highlight">#ffffff</color>
|
<color name="forum_cell_highlight">#ffffff</color>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -27,7 +27,6 @@
|
|||||||
<dimen name="listitem_picture_frame_size">53dp</dimen>
|
<dimen name="listitem_picture_frame_size">53dp</dimen>
|
||||||
<dimen name="listitem_picture_frame_offset">2dp</dimen>
|
<dimen name="listitem_picture_frame_offset">2dp</dimen>
|
||||||
<dimen name="listitem_selectable_picture_size">40dp</dimen>
|
<dimen name="listitem_selectable_picture_size">40dp</dimen>
|
||||||
<dimen name="dropdown_picture_size">32dp</dimen>
|
|
||||||
<dimen name="avatar_forum_size">48dp</dimen>
|
<dimen name="avatar_forum_size">48dp</dimen>
|
||||||
<dimen name="avatar_border_width">2dp</dimen>
|
<dimen name="avatar_border_width">2dp</dimen>
|
||||||
<dimen name="avatar_text_size">30sp</dimen>
|
<dimen name="avatar_text_size">30sp</dimen>
|
||||||
|
|||||||
@@ -73,6 +73,7 @@
|
|||||||
<string name="offline">Offline</string>
|
<string name="offline">Offline</string>
|
||||||
<string name="send">Send</string>
|
<string name="send">Send</string>
|
||||||
<string name="no_data">No data</string>
|
<string name="no_data">No data</string>
|
||||||
|
<string name="ellipsis">…</string>
|
||||||
|
|
||||||
<!-- Contacts and Private Conversations-->
|
<!-- Contacts and Private Conversations-->
|
||||||
<string name="no_contacts">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.</string>
|
<string name="no_contacts">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.</string>
|
||||||
@@ -199,18 +200,16 @@
|
|||||||
<string name="nobody">Nobody</string>
|
<string name="nobody">Nobody</string>
|
||||||
|
|
||||||
<!-- Blogs -->
|
<!-- Blogs -->
|
||||||
<string name="blogs_feed">Feed</string>
|
|
||||||
<string name="blogs_my_blogs">My Blogs</string>
|
|
||||||
<string name="blogs_my_blogs_create">Create Blog</string>
|
<string name="blogs_my_blogs_create">Create Blog</string>
|
||||||
<string name="blogs_my_blogs_label">Add new Blog</string>
|
<string name="blogs_my_blogs_label">Add new Blog</string>
|
||||||
<string name="blogs_my_blogs_create_hint_title">Blog title (cannot be changed later)</string>
|
<string name="blogs_my_blogs_create_hint_title">Blog title (cannot be changed later)</string>
|
||||||
<string name="blogs_my_blogs_create_hint_desc">A short description of your new blog</string>
|
<string name="blogs_my_blogs_create_hint_desc">A short description of your new blog</string>
|
||||||
<string name="blogs_my_blogs_create_hint_desc_explanation">Potential readers may or may not subscribe to your blog based on the content of the description.</string>
|
<string name="blogs_my_blogs_create_hint_desc_explanation">Potential readers may or may not subscribe to your blog based on the content of the description.</string>
|
||||||
<string name="blogs_my_blogs_empty_state">You don\'t have any blogs.\n\nWhy don\'t you create one now by clicking the plus in the top right screen corner?</string>
|
|
||||||
<string name="blogs_my_blogs_created">Blog created</string>
|
<string name="blogs_my_blogs_created">Blog created</string>
|
||||||
<string name="blogs_blog_is_empty">This blog is empty</string>
|
<string name="blogs_blog_is_empty">This blog is empty</string>
|
||||||
<string name="blogs_other_blog_empty_state">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.</string>
|
<string name="blogs_other_blog_empty_state">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.</string>
|
||||||
<string name="tag_new">NEW</string>
|
<string name="tag_new">NEW</string>
|
||||||
|
<string name="read_more">read more</string>
|
||||||
<string name="blogs_write_blog_post">Write Blog Post</string>
|
<string name="blogs_write_blog_post">Write Blog Post</string>
|
||||||
<string name="blogs_write_blog_post_title_hint">Add a title (optional)</string>
|
<string name="blogs_write_blog_post_title_hint">Add a title (optional)</string>
|
||||||
<string name="blogs_write_blog_post_body_hint">Type your blog post here</string>
|
<string name="blogs_write_blog_post_body_hint">Type your blog post here</string>
|
||||||
@@ -231,7 +230,6 @@
|
|||||||
|
|
||||||
<string name="blogs_blog_list">Blog List</string>
|
<string name="blogs_blog_list">Blog List</string>
|
||||||
<string name="blogs_available_blogs">Available Blogs</string>
|
<string name="blogs_available_blogs">Available Blogs</string>
|
||||||
<string name="blogs_drafts">Drafts</string>
|
|
||||||
|
|
||||||
<!-- Blog Sharing -->
|
<!-- Blog Sharing -->
|
||||||
<string name="blogs_sharing_share">Share Blog</string>
|
<string name="blogs_sharing_share">Share Blog</string>
|
||||||
@@ -312,7 +310,6 @@
|
|||||||
|
|
||||||
<!-- Multiple Identities -->
|
<!-- Multiple Identities -->
|
||||||
<string name="anonymous">Anonymous</string>
|
<string name="anonymous">Anonymous</string>
|
||||||
<string name="new_identity_item">New identity\u2026</string>
|
|
||||||
<string name="new_identity_title">New Identity</string>
|
<string name="new_identity_title">New Identity</string>
|
||||||
<string name="create_identity_button">Create Identity</string>
|
<string name="create_identity_button">Create Identity</string>
|
||||||
<string name="identity_created_toast">Identity created</string>
|
<string name="identity_created_toast">Identity created</string>
|
||||||
|
|||||||
@@ -6,8 +6,11 @@ import org.briarproject.android.blogs.BlogActivity;
|
|||||||
import org.briarproject.android.blogs.BlogFragment;
|
import org.briarproject.android.blogs.BlogFragment;
|
||||||
import org.briarproject.android.blogs.BlogListFragment;
|
import org.briarproject.android.blogs.BlogListFragment;
|
||||||
import org.briarproject.android.blogs.BlogPostFragment;
|
import org.briarproject.android.blogs.BlogPostFragment;
|
||||||
|
import org.briarproject.android.blogs.BlogPostPagerFragment;
|
||||||
import org.briarproject.android.blogs.CreateBlogActivity;
|
import org.briarproject.android.blogs.CreateBlogActivity;
|
||||||
|
import org.briarproject.android.blogs.FeedPostFragment;
|
||||||
import org.briarproject.android.blogs.FeedFragment;
|
import org.briarproject.android.blogs.FeedFragment;
|
||||||
|
import org.briarproject.android.blogs.FeedPostPagerFragment;
|
||||||
import org.briarproject.android.blogs.ReblogActivity;
|
import org.briarproject.android.blogs.ReblogActivity;
|
||||||
import org.briarproject.android.blogs.ReblogFragment;
|
import org.briarproject.android.blogs.ReblogFragment;
|
||||||
import org.briarproject.android.blogs.RssFeedImportActivity;
|
import org.briarproject.android.blogs.RssFeedImportActivity;
|
||||||
@@ -92,6 +95,10 @@ public interface ActivityComponent {
|
|||||||
void inject(BlogFragment fragment);
|
void inject(BlogFragment fragment);
|
||||||
|
|
||||||
void inject(BlogPostFragment fragment);
|
void inject(BlogPostFragment fragment);
|
||||||
|
void inject(FeedPostFragment fragment);
|
||||||
|
|
||||||
|
void inject(BlogPostPagerFragment fragment);
|
||||||
|
void inject(FeedPostPagerFragment fragment);
|
||||||
|
|
||||||
void inject(ReblogFragment fragment);
|
void inject(ReblogFragment fragment);
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package org.briarproject.android;
|
|||||||
|
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
|
|
||||||
interface Destroyable {
|
public interface Destroyable {
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
boolean hasBeenDestroyed();
|
boolean hasBeenDestroyed();
|
||||||
|
|||||||
@@ -74,7 +74,9 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
|
|||||||
super.onNewIntent(intent);
|
super.onNewIntent(intent);
|
||||||
exitIfStartupFailed(intent);
|
exitIfStartupFailed(intent);
|
||||||
checkAuthorHandle(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)) {
|
if (intent.getBooleanExtra(INTENT_FORUMS, false)) {
|
||||||
startFragment(ForumListFragment.newInstance());
|
startFragment(ForumListFragment.newInstance());
|
||||||
}
|
}
|
||||||
@@ -248,7 +250,6 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
|
|||||||
@Override
|
@Override
|
||||||
public void hideLoadingScreen() {
|
public void hideLoadingScreen() {
|
||||||
drawerLayout.setDrawerLockMode(LOCK_MODE_UNLOCKED);
|
drawerLayout.setDrawerLockMode(LOCK_MODE_UNLOCKED);
|
||||||
CustomAnimations.animateHeight(toolbar, true, 250);
|
|
||||||
progressViewGroup.setVisibility(INVISIBLE);
|
progressViewGroup.setVisibility(INVISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,9 @@ abstract class BaseControllerImpl extends DbControllerImpl
|
|||||||
@Override
|
@Override
|
||||||
@CallSuper
|
@CallSuper
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
|
if (listener == null)
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"OnBlogPostAddedListener needs to be attached");
|
||||||
eventBus.addListener(this);
|
eventBus.addListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
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;
|
||||||
|
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 {
|
||||||
|
|
||||||
|
private final Logger LOG =
|
||||||
|
Logger.getLogger(BasePostFragment.class.getName());
|
||||||
|
|
||||||
|
private View view;
|
||||||
|
private ProgressBar progressBar;
|
||||||
|
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);
|
||||||
|
progressBar = (ProgressBar) view.findViewById(R.id.progressBar);
|
||||||
|
progressBar.setVisibility(VISIBLE);
|
||||||
|
ui = new BlogPostViewHolder(view);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
startPeriodicUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
protected void onBlogPostLoaded(BlogPostItem post) {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
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 android.widget.ProgressBar;
|
||||||
|
|
||||||
|
import org.briarproject.R;
|
||||||
|
import org.briarproject.android.blogs.BaseController.OnBlogPostAddedListener;
|
||||||
|
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 android.view.View.INVISIBLE;
|
||||||
|
import static android.view.View.VISIBLE;
|
||||||
|
import static org.briarproject.android.blogs.BasePostPagerFragment.BlogPostPagerAdapter.INVALID_POSITION;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
@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);
|
||||||
|
progressBar = (ProgressBar) v.findViewById(R.id.progressBar);
|
||||||
|
progressBar.setVisibility(VISIBLE);
|
||||||
|
|
||||||
|
pager = (ViewPager) v.findViewById(R.id.pager);
|
||||||
|
postPagerAdapter = new BlogPostPagerAdapter(getChildFragmentManager());
|
||||||
|
|
||||||
|
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 void loadBlogPost(BlogPostHeader header);
|
||||||
|
|
||||||
|
protected void onBlogPostsLoaded(MessageId select,
|
||||||
|
Collection<BlogPostItem> posts) {
|
||||||
|
|
||||||
|
postId = null;
|
||||||
|
postPagerAdapter.setPosts(posts);
|
||||||
|
selectPost(select);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onBlogPostsLoadedException(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) {
|
||||||
|
progressBar.setVisibility(INVISIBLE);
|
||||||
|
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<BlogPostItem> 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<BlogPostItem> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,56 +2,29 @@ package org.briarproject.android.blogs;
|
|||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
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 android.widget.ProgressBar;
|
||||||
|
|
||||||
import org.briarproject.R;
|
import org.briarproject.R;
|
||||||
import org.briarproject.android.ActivityComponent;
|
import org.briarproject.android.ActivityComponent;
|
||||||
import org.briarproject.android.BriarActivity;
|
import org.briarproject.android.BriarActivity;
|
||||||
import org.briarproject.android.blogs.BaseController.OnBlogPostAddedListener;
|
|
||||||
import org.briarproject.android.blogs.BlogPostAdapter.OnBlogPostClickListener;
|
import org.briarproject.android.blogs.BlogPostAdapter.OnBlogPostClickListener;
|
||||||
import org.briarproject.android.controller.handler.UiResultExceptionHandler;
|
|
||||||
import org.briarproject.android.fragment.BaseFragment.BaseFragmentListener;
|
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.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 javax.inject.Inject;
|
||||||
|
|
||||||
import static android.view.View.GONE;
|
import static android.view.View.INVISIBLE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
|
|
||||||
public class BlogActivity extends BriarActivity implements
|
public class BlogActivity extends BriarActivity implements
|
||||||
OnBlogPostAddedListener,
|
|
||||||
OnBlogPostClickListener, BaseFragmentListener {
|
OnBlogPostClickListener, BaseFragmentListener {
|
||||||
|
|
||||||
static final int REQUEST_WRITE_POST = 1;
|
static final int REQUEST_WRITE_POST = 1;
|
||||||
static final int REQUEST_SHARE = 2;
|
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 IS_NEW_BLOG = "briar.IS_NEW_BLOG";
|
||||||
|
|
||||||
public static final String POST_ID = "briar.POST_ID";
|
|
||||||
|
|
||||||
private GroupId groupId;
|
|
||||||
private ProgressBar progressBar;
|
private ProgressBar progressBar;
|
||||||
private ViewPager pager;
|
|
||||||
private BlogPagerAdapter blogPagerAdapter;
|
|
||||||
private BlogPostPagerAdapter postPagerAdapter;
|
|
||||||
private String blogName;
|
|
||||||
private boolean isNew;
|
|
||||||
private MessageId savedPostId;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
BlogController blogController;
|
BlogController blogController;
|
||||||
@@ -64,62 +37,24 @@ public class BlogActivity extends BriarActivity implements
|
|||||||
Intent i = getIntent();
|
Intent i = getIntent();
|
||||||
byte[] b = i.getByteArrayExtra(GROUP_ID);
|
byte[] b = i.getByteArrayExtra(GROUP_ID);
|
||||||
if (b == null) throw new IllegalStateException("No group ID in intent");
|
if (b == null) throw new IllegalStateException("No group ID in intent");
|
||||||
groupId = new GroupId(b);
|
GroupId groupId = new GroupId(b);
|
||||||
blogController.setGroupId(groupId);
|
blogController.setGroupId(groupId);
|
||||||
|
|
||||||
// Name of the blog
|
// Name of the blog
|
||||||
blogName = i.getStringExtra(BLOG_NAME);
|
String blogName = i.getStringExtra(BLOG_NAME);
|
||||||
if (blogName != null) setTitle(blogName);
|
if (blogName != null) setTitle(blogName);
|
||||||
|
|
||||||
// Was this blog just created?
|
// 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);
|
setContentView(R.layout.activity_fragment_container);
|
||||||
|
|
||||||
pager = (ViewPager) findViewById(R.id.pager);
|
|
||||||
progressBar = (ProgressBar) findViewById(R.id.progressBar);
|
progressBar = (ProgressBar) findViewById(R.id.progressBar);
|
||||||
|
|
||||||
blogPagerAdapter = new BlogPagerAdapter(getSupportFragmentManager());
|
if (state == null) {
|
||||||
postPagerAdapter = new BlogPostPagerAdapter(
|
BlogFragment f = BlogFragment.newInstance(groupId, blogName, isNew);
|
||||||
getSupportFragmentManager());
|
getSupportFragmentManager().beginTransaction()
|
||||||
|
.replace(R.id.fragmentContainer, f, f.getUniqueTag())
|
||||||
if (state == null || state.getByteArray(POST_ID) == null) {
|
.commit();
|
||||||
// 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,6 +63,15 @@ public class BlogActivity extends BriarActivity implements
|
|||||||
component.inject(this);
|
component.inject(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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
|
@Override
|
||||||
public void showLoadingScreen(boolean isBlocking, int stringId) {
|
public void showLoadingScreen(boolean isBlocking, int stringId) {
|
||||||
progressBar.setVisibility(VISIBLE);
|
progressBar.setVisibility(VISIBLE);
|
||||||
@@ -135,176 +79,10 @@ public class BlogActivity extends BriarActivity implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void hideLoadingScreen() {
|
public void hideLoadingScreen() {
|
||||||
progressBar.setVisibility(GONE);
|
progressBar.setVisibility(INVISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFragmentCreated(String tag) {
|
public void onFragmentCreated(String tag) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBlogPostClick(BlogPostItem post) {
|
|
||||||
loadBlogPosts(post.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadBlogPosts(final MessageId select) {
|
|
||||||
blogController.loadBlogPosts(
|
|
||||||
new UiResultExceptionHandler<Collection<BlogPostItem>, DbException>(
|
|
||||||
this) {
|
|
||||||
@Override
|
|
||||||
public void onResultUi(Collection<BlogPostItem> 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<BlogPostItem, DbException>(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<BlogPostItem> 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<BlogPostItem> 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,9 +21,7 @@ public interface BlogController extends BaseController {
|
|||||||
void loadBlogPost(MessageId m,
|
void loadBlogPost(MessageId m,
|
||||||
ResultExceptionHandler<BlogPostItem, DbException> handler);
|
ResultExceptionHandler<BlogPostItem, DbException> handler);
|
||||||
|
|
||||||
void isMyBlog(ResultExceptionHandler<Boolean, DbException> handler);
|
void loadBlog(ResultExceptionHandler<BlogItem, DbException> handler);
|
||||||
|
|
||||||
void canDeleteBlog(ResultExceptionHandler<Boolean, DbException> handler);
|
|
||||||
|
|
||||||
void deleteBlog(ResultExceptionHandler<Void, DbException> handler);
|
void deleteBlog(ResultExceptionHandler<Void, DbException> handler);
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.android.blogs;
|
|||||||
import org.briarproject.android.controller.ActivityLifecycleController;
|
import org.briarproject.android.controller.ActivityLifecycleController;
|
||||||
import org.briarproject.android.controller.handler.ResultExceptionHandler;
|
import org.briarproject.android.controller.handler.ResultExceptionHandler;
|
||||||
import org.briarproject.api.blogs.Blog;
|
import org.briarproject.api.blogs.Blog;
|
||||||
|
import org.briarproject.api.blogs.BlogPostHeader;
|
||||||
import org.briarproject.api.db.DbException;
|
import org.briarproject.api.db.DbException;
|
||||||
import org.briarproject.api.event.BlogPostAddedEvent;
|
import org.briarproject.api.event.BlogPostAddedEvent;
|
||||||
import org.briarproject.api.event.Event;
|
import org.briarproject.api.event.Event;
|
||||||
@@ -13,6 +14,7 @@ import org.briarproject.api.sync.GroupId;
|
|||||||
import org.briarproject.api.sync.MessageId;
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -33,13 +35,6 @@ public class BlogControllerImpl extends BaseControllerImpl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityCreate() {
|
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
|
@Override
|
||||||
@@ -102,8 +97,8 @@ public class BlogControllerImpl extends BaseControllerImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void isMyBlog(
|
public void loadBlog(
|
||||||
final ResultExceptionHandler<Boolean, DbException> handler) {
|
final ResultExceptionHandler<BlogItem, DbException> handler) {
|
||||||
if (groupId == null) throw new IllegalStateException();
|
if (groupId == null) throw new IllegalStateException();
|
||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
@@ -111,7 +106,12 @@ public class BlogControllerImpl extends BaseControllerImpl
|
|||||||
try {
|
try {
|
||||||
LocalAuthor a = identityManager.getLocalAuthor();
|
LocalAuthor a = identityManager.getLocalAuthor();
|
||||||
Blog b = blogManager.getBlog(groupId);
|
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.<BlogPostHeader>emptyList(),
|
||||||
|
ours, removable);
|
||||||
|
handler.onResult(blog);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
@@ -122,24 +122,6 @@ public class BlogControllerImpl extends BaseControllerImpl
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void canDeleteBlog(
|
|
||||||
final ResultExceptionHandler<Boolean, DbException> 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
|
@Override
|
||||||
public void deleteBlog(
|
public void deleteBlog(
|
||||||
final ResultExceptionHandler<Void, DbException> handler) {
|
final ResultExceptionHandler<Void, DbException> handler) {
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import android.content.Intent;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.design.widget.Snackbar;
|
import android.support.design.widget.Snackbar;
|
||||||
import android.support.v4.app.ActivityCompat;
|
|
||||||
import android.support.v4.app.ActivityOptionsCompat;
|
import android.support.v4.app.ActivityOptionsCompat;
|
||||||
|
import android.support.v4.content.ContextCompat;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@@ -28,6 +28,7 @@ import org.briarproject.android.sharing.SharingStatusBlogActivity;
|
|||||||
import org.briarproject.android.util.BriarRecyclerView;
|
import org.briarproject.android.util.BriarRecyclerView;
|
||||||
import org.briarproject.api.blogs.BlogPostHeader;
|
import org.briarproject.api.blogs.BlogPostHeader;
|
||||||
import org.briarproject.api.db.DbException;
|
import org.briarproject.api.db.DbException;
|
||||||
|
import org.briarproject.api.identity.Author;
|
||||||
import org.briarproject.api.sync.GroupId;
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -59,6 +60,7 @@ public class BlogFragment extends BaseFragment implements
|
|||||||
private BlogPostAdapter adapter;
|
private BlogPostAdapter adapter;
|
||||||
private BriarRecyclerView list;
|
private BriarRecyclerView list;
|
||||||
private MenuItem writeButton, deleteButton;
|
private MenuItem writeButton, deleteButton;
|
||||||
|
private boolean isMyBlog = false, canDeleteBlog = false;
|
||||||
|
|
||||||
static BlogFragment newInstance(GroupId groupId, String name,
|
static BlogFragment newInstance(GroupId groupId, String name,
|
||||||
boolean isNew) {
|
boolean isNew) {
|
||||||
@@ -114,14 +116,13 @@ public class BlogFragment extends BaseFragment implements
|
|||||||
@Override
|
@Override
|
||||||
public void injectFragment(ActivityComponent component) {
|
public void injectFragment(ActivityComponent component) {
|
||||||
component.inject(this);
|
component.inject(this);
|
||||||
blogController.setGroupId(groupId);
|
blogController.setOnBlogPostAddedListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
checkIfThisIsMyBlog();
|
loadBlog();
|
||||||
checkIfBlogCanBeDeleted();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -141,7 +142,9 @@ public class BlogFragment extends BaseFragment implements
|
|||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
inflater.inflate(R.menu.blogs_blog_actions, menu);
|
inflater.inflate(R.menu.blogs_blog_actions, menu);
|
||||||
writeButton = menu.findItem(R.id.action_write_blog_post);
|
writeButton = menu.findItem(R.id.action_write_blog_post);
|
||||||
|
if (isMyBlog) writeButton.setVisible(true);
|
||||||
deleteButton = menu.findItem(R.id.action_blog_delete);
|
deleteButton = menu.findItem(R.id.action_blog_delete);
|
||||||
|
if (canDeleteBlog) deleteButton.setVisible(true);
|
||||||
|
|
||||||
super.onCreateOptionsMenu(menu, inflater);
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
}
|
}
|
||||||
@@ -161,8 +164,8 @@ public class BlogFragment extends BaseFragment implements
|
|||||||
new Intent(getActivity(), WriteBlogPostActivity.class);
|
new Intent(getActivity(), WriteBlogPostActivity.class);
|
||||||
i.putExtra(GROUP_ID, groupId.getBytes());
|
i.putExtra(GROUP_ID, groupId.getBytes());
|
||||||
i.putExtra(BLOG_NAME, blogName);
|
i.putExtra(BLOG_NAME, blogName);
|
||||||
ActivityCompat.startActivityForResult(getActivity(), i,
|
startActivityForResult(i, REQUEST_WRITE_POST,
|
||||||
REQUEST_WRITE_POST, options.toBundle());
|
options.toBundle());
|
||||||
return true;
|
return true;
|
||||||
case R.id.action_blog_share:
|
case R.id.action_blog_share:
|
||||||
Intent i2 = new Intent(getActivity(), ShareBlogActivity.class);
|
Intent i2 = new Intent(getActivity(), ShareBlogActivity.class);
|
||||||
@@ -190,9 +193,10 @@ public class BlogFragment extends BaseFragment implements
|
|||||||
super.onActivityResult(request, result, data);
|
super.onActivityResult(request, result, data);
|
||||||
|
|
||||||
if (request == REQUEST_WRITE_POST && result == RESULT_OK) {
|
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) {
|
} else if (request == REQUEST_SHARE && result == RESULT_OK) {
|
||||||
displaySnackbar(R.string.blogs_sharing_snackbar);
|
displaySnackbar(R.string.blogs_sharing_snackbar, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,15 +209,15 @@ public class BlogFragment extends BaseFragment implements
|
|||||||
public void onBlogPostAdded(BlogPostHeader header, final boolean local) {
|
public void onBlogPostAdded(BlogPostHeader header, final boolean local) {
|
||||||
blogController.loadBlogPost(header,
|
blogController.loadBlogPost(header,
|
||||||
new UiResultExceptionHandler<BlogPostItem, DbException>(
|
new UiResultExceptionHandler<BlogPostItem, DbException>(
|
||||||
getActivity()) {
|
listener) {
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(BlogPostItem post) {
|
public void onResultUi(BlogPostItem post) {
|
||||||
adapter.add(post);
|
adapter.add(post);
|
||||||
if (local) {
|
if (local) {
|
||||||
list.scrollToPosition(0);
|
list.scrollToPosition(0);
|
||||||
displaySnackbar(R.string.blogs_blog_post_created);
|
displaySnackbar(R.string.blogs_blog_post_created, false);
|
||||||
} else {
|
} else {
|
||||||
displaySnackbar(R.string.blogs_blog_post_received);
|
displaySnackbar(R.string.blogs_blog_post_received, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +233,7 @@ public class BlogFragment extends BaseFragment implements
|
|||||||
void loadBlogPosts(final boolean reload) {
|
void loadBlogPosts(final boolean reload) {
|
||||||
blogController.loadBlogPosts(
|
blogController.loadBlogPosts(
|
||||||
new UiResultExceptionHandler<Collection<BlogPostItem>, DbException>(
|
new UiResultExceptionHandler<Collection<BlogPostItem>, DbException>(
|
||||||
getActivity()) {
|
listener) {
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(Collection<BlogPostItem> posts) {
|
public void onResultUi(Collection<BlogPostItem> posts) {
|
||||||
if (posts.size() > 0) {
|
if (posts.size() > 0) {
|
||||||
@@ -243,63 +247,68 @@ public class BlogFragment extends BaseFragment implements
|
|||||||
@Override
|
@Override
|
||||||
public void onExceptionUi(DbException exception) {
|
public void onExceptionUi(DbException exception) {
|
||||||
// TODO: Decide how to handle errors in the UI
|
// TODO: Decide how to handle errors in the UI
|
||||||
getActivity().finish();
|
finish();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkIfThisIsMyBlog() {
|
private void loadBlog() {
|
||||||
blogController.canDeleteBlog(
|
blogController.loadBlog(
|
||||||
new UiResultExceptionHandler<Boolean, DbException>(
|
new UiResultExceptionHandler<BlogItem, DbException>(listener) {
|
||||||
getActivity()) {
|
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(Boolean isMyBlog) {
|
public void onResultUi(BlogItem blog) {
|
||||||
if (isMyBlog) {
|
setToolbarTitle(blog.getBlog().getAuthor());
|
||||||
|
if (blog.isOurs())
|
||||||
showWriteButton();
|
showWriteButton();
|
||||||
}
|
if (blog.canBeRemoved())
|
||||||
|
showDeleteButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onExceptionUi(DbException exception) {
|
public void onExceptionUi(DbException exception) {
|
||||||
// TODO: Decide how to handle errors in the UI
|
// TODO: Decide how to handle errors in the UI
|
||||||
getActivity().finish();
|
finish();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkIfBlogCanBeDeleted() {
|
private void setToolbarTitle(Author a) {
|
||||||
blogController.canDeleteBlog(
|
String title = getString(R.string.blogs_personal_blog, a.getName());
|
||||||
new UiResultExceptionHandler<Boolean, DbException>(
|
getActivity().setTitle(title);
|
||||||
getActivity()) {
|
|
||||||
@Override
|
|
||||||
public void onResultUi(Boolean canBeDeleted) {
|
|
||||||
if (canBeDeleted) {
|
|
||||||
showDeleteButton();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
// safe title in intent, so it can be restored automatically
|
||||||
public void onExceptionUi(DbException exception) {
|
Intent intent = getActivity().getIntent();
|
||||||
// TODO: Decide how to handle errors in the UI
|
intent.putExtra(BLOG_NAME, title);
|
||||||
getActivity().finish();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showWriteButton() {
|
private void showWriteButton() {
|
||||||
|
isMyBlog = true;
|
||||||
if (writeButton != null)
|
if (writeButton != null)
|
||||||
writeButton.setVisible(true);
|
writeButton.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showDeleteButton() {
|
private void showDeleteButton() {
|
||||||
|
canDeleteBlog = true;
|
||||||
if (deleteButton != null)
|
if (deleteButton != null)
|
||||||
deleteButton.setVisible(true);
|
deleteButton.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displaySnackbar(int stringId) {
|
private void displaySnackbar(int stringId, boolean scroll) {
|
||||||
Snackbar snackbar =
|
Snackbar snackbar =
|
||||||
Snackbar.make(list, stringId, Snackbar.LENGTH_SHORT);
|
Snackbar.make(list, stringId, Snackbar.LENGTH_LONG);
|
||||||
snackbar.getView().setBackgroundResource(R.color.briar_primary);
|
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();
|
snackbar.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,7 +332,7 @@ public class BlogFragment extends BaseFragment implements
|
|||||||
|
|
||||||
private void deleteBlog() {
|
private void deleteBlog() {
|
||||||
blogController.deleteBlog(
|
blogController.deleteBlog(
|
||||||
new UiResultExceptionHandler<Void, DbException>(getActivity()) {
|
new UiResultExceptionHandler<Void, DbException>(listener) {
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(Void result) {
|
public void onResultUi(Void result) {
|
||||||
Toast.makeText(getActivity(),
|
Toast.makeText(getActivity(),
|
||||||
@@ -335,7 +344,7 @@ public class BlogFragment extends BaseFragment implements
|
|||||||
@Override
|
@Override
|
||||||
public void onExceptionUi(DbException exception) {
|
public void onExceptionUi(DbException exception) {
|
||||||
// TODO: Decide how to handle errors in the UI
|
// TODO: Decide how to handle errors in the UI
|
||||||
getActivity().finish();
|
finish();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,15 +5,16 @@ import org.briarproject.api.blogs.BlogPostHeader;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
class BlogListItem {
|
class BlogItem {
|
||||||
|
|
||||||
private final Blog blog;
|
private final Blog blog;
|
||||||
private final int postCount;
|
private final int postCount;
|
||||||
private final long timestamp;
|
private final long timestamp;
|
||||||
private final int unread;
|
private final int unread;
|
||||||
private final boolean ours;
|
private final boolean ours, removable;
|
||||||
|
|
||||||
BlogListItem(Blog blog, Collection<BlogPostHeader> headers, boolean ours) {
|
BlogItem(Blog blog, Collection<BlogPostHeader> headers, boolean ours,
|
||||||
|
boolean removable) {
|
||||||
this.blog = blog;
|
this.blog = blog;
|
||||||
if (headers.isEmpty()) {
|
if (headers.isEmpty()) {
|
||||||
postCount = 0;
|
postCount = 0;
|
||||||
@@ -35,6 +36,7 @@ class BlogListItem {
|
|||||||
this.unread = unread;
|
this.unread = unread;
|
||||||
}
|
}
|
||||||
this.ours = ours;
|
this.ours = ours;
|
||||||
|
this.removable = removable;
|
||||||
}
|
}
|
||||||
|
|
||||||
Blog getBlog() {
|
Blog getBlog() {
|
||||||
@@ -64,4 +66,8 @@ class BlogListItem {
|
|||||||
boolean isOurs() {
|
boolean isOurs() {
|
||||||
return ours;
|
return ours;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean canBeRemoved() {
|
||||||
|
return removable;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -29,11 +29,11 @@ import static org.briarproject.android.blogs.BlogActivity.BLOG_NAME;
|
|||||||
class BlogListAdapter extends
|
class BlogListAdapter extends
|
||||||
RecyclerView.Adapter<BlogListAdapter.BlogViewHolder> {
|
RecyclerView.Adapter<BlogListAdapter.BlogViewHolder> {
|
||||||
|
|
||||||
private SortedList<BlogListItem> blogs = new SortedList<>(
|
private SortedList<BlogItem> blogs = new SortedList<>(
|
||||||
BlogListItem.class, new SortedList.Callback<BlogListItem>() {
|
BlogItem.class, new SortedList.Callback<BlogItem>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(BlogListItem a, BlogListItem b) {
|
public int compare(BlogItem a, BlogItem b) {
|
||||||
if (a == b) return 0;
|
if (a == b) return 0;
|
||||||
// The blog with the newest message comes first
|
// The blog with the newest message comes first
|
||||||
long aTime = a.getTimestamp(), bTime = b.getTimestamp();
|
long aTime = a.getTimestamp(), bTime = b.getTimestamp();
|
||||||
@@ -66,14 +66,14 @@ class BlogListAdapter extends
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean areContentsTheSame(BlogListItem a, BlogListItem b) {
|
public boolean areContentsTheSame(BlogItem a, BlogItem b) {
|
||||||
return a.getBlog().equals(b.getBlog()) &&
|
return a.getBlog().equals(b.getBlog()) &&
|
||||||
a.getTimestamp() == b.getTimestamp() &&
|
a.getTimestamp() == b.getTimestamp() &&
|
||||||
a.getUnreadCount() == b.getUnreadCount();
|
a.getUnreadCount() == b.getUnreadCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean areItemsTheSame(BlogListItem a, BlogListItem b) {
|
public boolean areItemsTheSame(BlogItem a, BlogItem b) {
|
||||||
return a.getBlog().equals(b.getBlog());
|
return a.getBlog().equals(b.getBlog());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -93,7 +93,7 @@ class BlogListAdapter extends
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(BlogViewHolder ui, int position) {
|
public void onBindViewHolder(BlogViewHolder ui, int position) {
|
||||||
final BlogListItem item = getItem(position);
|
final BlogItem item = getItem(position);
|
||||||
|
|
||||||
// Avatar
|
// Avatar
|
||||||
ui.avatar.setText(item.getName().substring(0, 1));
|
ui.avatar.setText(item.getName().substring(0, 1));
|
||||||
@@ -145,14 +145,14 @@ class BlogListAdapter extends
|
|||||||
return blogs.size();
|
return blogs.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlogListItem getItem(int position) {
|
public BlogItem getItem(int position) {
|
||||||
return blogs.get(position);
|
return blogs.get(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public BlogListItem getItem(GroupId g) {
|
public BlogItem getItem(GroupId g) {
|
||||||
for (int i = 0; i < blogs.size(); i++) {
|
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)) {
|
if (item.getBlog().getGroup().getId().equals(g)) {
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
@@ -160,17 +160,17 @@ class BlogListAdapter extends
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addAll(Collection<BlogListItem> items) {
|
public void addAll(Collection<BlogItem> items) {
|
||||||
blogs.addAll(items);
|
blogs.addAll(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateItem(BlogListItem item) {
|
void updateItem(BlogItem item) {
|
||||||
BlogListItem oldItem = getItem(item.getBlog().getGroup().getId());
|
BlogItem oldItem = getItem(item.getBlog().getGroup().getId());
|
||||||
int position = blogs.indexOf(oldItem);
|
int position = blogs.indexOf(oldItem);
|
||||||
blogs.updateItemAt(position, item);
|
blogs.updateItemAt(position, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(BlogListItem item) {
|
public void remove(BlogItem item) {
|
||||||
blogs.remove(item);
|
blogs.remove(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,35 +3,23 @@ package org.briarproject.android.blogs;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.briarproject.R;
|
|
||||||
import org.briarproject.android.ActivityComponent;
|
import org.briarproject.android.ActivityComponent;
|
||||||
import org.briarproject.android.controller.handler.UiResultExceptionHandler;
|
import org.briarproject.android.controller.handler.UiResultExceptionHandler;
|
||||||
import org.briarproject.android.fragment.BaseFragment;
|
|
||||||
import org.briarproject.api.db.DbException;
|
import org.briarproject.api.db.DbException;
|
||||||
import org.briarproject.api.sync.MessageId;
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static org.briarproject.android.util.AndroidUtils.MIN_RESOLUTION;
|
import static org.briarproject.android.blogs.BasePostPagerFragment.POST_ID;
|
||||||
|
|
||||||
public class BlogPostFragment extends BaseFragment {
|
public class BlogPostFragment extends BasePostFragment {
|
||||||
|
|
||||||
public final static String TAG = BlogPostFragment.class.getName();
|
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 MessageId postId;
|
||||||
private BlogPostViewHolder ui;
|
|
||||||
private BlogPostItem post;
|
|
||||||
private Runnable refresher;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
BlogController blogController;
|
BlogController blogController;
|
||||||
@@ -40,7 +28,7 @@ public class BlogPostFragment extends BaseFragment {
|
|||||||
BlogPostFragment f = new BlogPostFragment();
|
BlogPostFragment f = new BlogPostFragment();
|
||||||
|
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putByteArray(BLOG_POST_ID, postId.getBytes());
|
bundle.putByteArray(POST_ID, postId.getBytes());
|
||||||
|
|
||||||
f.setArguments(bundle);
|
f.setArguments(bundle);
|
||||||
return f;
|
return f;
|
||||||
@@ -50,16 +38,18 @@ public class BlogPostFragment extends BaseFragment {
|
|||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
setHasOptionsMenu(true);
|
|
||||||
|
|
||||||
byte[] b = getArguments().getByteArray(BLOG_POST_ID);
|
Bundle args = getArguments();
|
||||||
if (b == null) throw new IllegalStateException("No post ID in args");
|
byte[] p = args.getByteArray(POST_ID);
|
||||||
postId = new MessageId(b);
|
if (p == null) throw new IllegalStateException("No post ID in args");
|
||||||
|
postId = new MessageId(p);
|
||||||
|
|
||||||
view = inflater.inflate(R.layout.fragment_blog_post, container,
|
return super.onCreateView(inflater, container, savedInstanceState);
|
||||||
false);
|
}
|
||||||
ui = new BlogPostViewHolder(view);
|
|
||||||
return view;
|
@Override
|
||||||
|
public String getUniqueTag() {
|
||||||
|
return TAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -72,65 +62,15 @@ public class BlogPostFragment extends BaseFragment {
|
|||||||
super.onStart();
|
super.onStart();
|
||||||
blogController.loadBlogPost(postId,
|
blogController.loadBlogPost(postId,
|
||||||
new UiResultExceptionHandler<BlogPostItem, DbException>(
|
new UiResultExceptionHandler<BlogPostItem, DbException>(
|
||||||
getActivity()) {
|
listener) {
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(BlogPostItem post) {
|
public void onResultUi(BlogPostItem post) {
|
||||||
listener.hideLoadingScreen();
|
onBlogPostLoaded(post);
|
||||||
BlogPostFragment.this.post = post;
|
|
||||||
ui.bindItem(post);
|
|
||||||
startPeriodicUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onExceptionUi(DbException exception) {
|
public void onExceptionUi(DbException exception) {
|
||||||
// TODO: Decide how to handle errors in the UI
|
onBlogPostLoadException(exception);
|
||||||
finish();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
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.blogs.BlogPostHeader;
|
||||||
|
import org.briarproject.api.db.DbException;
|
||||||
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void loadBlogPosts(final MessageId select) {
|
||||||
|
blogController.loadBlogPosts(
|
||||||
|
new UiResultExceptionHandler<Collection<BlogPostItem>, DbException>(
|
||||||
|
listener) {
|
||||||
|
@Override
|
||||||
|
public void onResultUi(Collection<BlogPostItem> posts) {
|
||||||
|
onBlogPostsLoaded(select, posts);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onExceptionUi(DbException exception) {
|
||||||
|
onBlogPostsLoadedException(exception);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadBlogPost(BlogPostHeader header) {
|
||||||
|
blogController.loadBlogPost(header,
|
||||||
|
new UiResultExceptionHandler<BlogPostItem, DbException>(
|
||||||
|
listener) {
|
||||||
|
@Override
|
||||||
|
public void onResultUi(BlogPostItem post) {
|
||||||
|
addPost(post);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onExceptionUi(DbException exception) {
|
||||||
|
// TODO: Decide how to handle errors in the UI
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ import android.support.v4.view.ViewCompat;
|
|||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
@@ -26,7 +27,9 @@ import static android.support.v4.app.ActivityOptionsCompat.makeSceneTransitionAn
|
|||||||
import static android.view.View.GONE;
|
import static android.view.View.GONE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
import static org.briarproject.android.BriarActivity.GROUP_ID;
|
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;
|
import static org.briarproject.api.blogs.MessageType.POST;
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
@@ -81,14 +84,15 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder {
|
|||||||
|
|
||||||
void bindItem(final BlogPostItem item) {
|
void bindItem(final BlogPostItem item) {
|
||||||
setTransitionName(item.getId());
|
setTransitionName(item.getId());
|
||||||
layout.setOnClickListener(new View.OnClickListener() {
|
if (listener != null) {
|
||||||
@Override
|
layout.setClickable(true);
|
||||||
public void onClick(View v) {
|
layout.setOnClickListener(new OnClickListener() {
|
||||||
if (listener != null) {
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
listener.onBlogPostClick(item);
|
listener.onBlogPostClick(item);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
// author and date
|
// author and date
|
||||||
BlogPostHeader post = item.getPostHeader();
|
BlogPostHeader post = item.getPostHeader();
|
||||||
@@ -104,10 +108,18 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// post body
|
// post body
|
||||||
body.setText(item.getBody());
|
CharSequence bodyText = item.getBody();
|
||||||
|
if (listener == null) {
|
||||||
|
body.setTextIsSelectable(true);
|
||||||
|
} else {
|
||||||
|
body.setTextIsSelectable(false);
|
||||||
|
if (item.getBody().length() > TEASER_LENGTH)
|
||||||
|
bodyText = getTeaser(ctx, item.getBody());
|
||||||
|
}
|
||||||
|
body.setText(bodyText);
|
||||||
|
|
||||||
// reblog button
|
// reblog button
|
||||||
reblogButton.setOnClickListener(new View.OnClickListener() {
|
reblogButton.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Intent i = new Intent(ctx, ReblogActivity.class);
|
Intent i = new Intent(ctx, ReblogActivity.class);
|
||||||
@@ -154,6 +166,7 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder {
|
|||||||
// TODO make author clickable #624
|
// TODO make author clickable #624
|
||||||
|
|
||||||
body.setText(c.getComment());
|
body.setText(c.getComment());
|
||||||
|
if (listener == null) body.setTextIsSelectable(true);
|
||||||
|
|
||||||
commentContainer.addView(v);
|
commentContainer.addView(v);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ public class FeedFragment extends BaseFragment implements
|
|||||||
});
|
});
|
||||||
feedController.loadBlogPosts(
|
feedController.loadBlogPosts(
|
||||||
new UiResultExceptionHandler<Collection<BlogPostItem>, DbException>(
|
new UiResultExceptionHandler<Collection<BlogPostItem>, DbException>(
|
||||||
getActivity()) {
|
listener) {
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(Collection<BlogPostItem> posts) {
|
public void onResultUi(Collection<BlogPostItem> posts) {
|
||||||
if (posts.isEmpty()) {
|
if (posts.isEmpty()) {
|
||||||
@@ -175,7 +175,7 @@ public class FeedFragment extends BaseFragment implements
|
|||||||
public void onBlogPostAdded(BlogPostHeader header, final boolean local) {
|
public void onBlogPostAdded(BlogPostHeader header, final boolean local) {
|
||||||
feedController.loadBlogPost(header,
|
feedController.loadBlogPost(header,
|
||||||
new UiResultExceptionHandler<BlogPostItem, DbException>(
|
new UiResultExceptionHandler<BlogPostItem, DbException>(
|
||||||
getActivity()) {
|
listener) {
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(BlogPostItem post) {
|
public void onResultUi(BlogPostItem post) {
|
||||||
adapter.add(post);
|
adapter.add(post);
|
||||||
@@ -195,7 +195,12 @@ public class FeedFragment extends BaseFragment implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBlogPostClick(BlogPostItem post) {
|
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
|
@Override
|
||||||
|
|||||||
@@ -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.BasePostPagerFragment.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<BlogPostItem, DbException>(
|
||||||
|
listener) {
|
||||||
|
@Override
|
||||||
|
public void onResultUi(BlogPostItem post) {
|
||||||
|
onBlogPostLoaded(post);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onExceptionUi(DbException exception) {
|
||||||
|
onBlogPostLoadException(exception);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUniqueTag() {
|
||||||
|
return TAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
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.blogs.BlogPostHeader;
|
||||||
|
import org.briarproject.api.db.DbException;
|
||||||
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void loadBlogPosts(final MessageId select) {
|
||||||
|
feedController.loadBlogPosts(
|
||||||
|
new UiResultExceptionHandler<Collection<BlogPostItem>, DbException>(
|
||||||
|
listener) {
|
||||||
|
@Override
|
||||||
|
public void onResultUi(Collection<BlogPostItem> posts) {
|
||||||
|
onBlogPostsLoaded(select, posts);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onExceptionUi(DbException exception) {
|
||||||
|
onBlogPostsLoadedException(exception);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadBlogPost(BlogPostHeader header) {
|
||||||
|
feedController.loadBlogPost(header,
|
||||||
|
new UiResultExceptionHandler<BlogPostItem, DbException>(
|
||||||
|
listener) {
|
||||||
|
@Override
|
||||||
|
public void onResultUi(BlogPostItem post) {
|
||||||
|
addPost(post);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onExceptionUi(DbException exception) {
|
||||||
|
// TODO: Decide how to handle errors in the UI
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@ import org.briarproject.android.fragment.BaseFragment.BaseFragmentListener;
|
|||||||
import org.briarproject.api.sync.GroupId;
|
import org.briarproject.api.sync.GroupId;
|
||||||
import org.briarproject.api.sync.MessageId;
|
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
|
public class ReblogActivity extends BriarActivity implements
|
||||||
BaseFragmentListener {
|
BaseFragmentListener {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import static android.view.View.GONE;
|
|||||||
import static android.view.View.INVISIBLE;
|
import static android.view.View.INVISIBLE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
import static org.briarproject.android.BriarActivity.GROUP_ID;
|
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 {
|
public class ReblogFragment extends BaseFragment {
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ public class ReblogFragment extends BaseFragment {
|
|||||||
// TODO: Load blog post when fragment is created. #631
|
// TODO: Load blog post when fragment is created. #631
|
||||||
feedController.loadBlogPost(blogId, postId,
|
feedController.loadBlogPost(blogId, postId,
|
||||||
new UiResultExceptionHandler<BlogPostItem, DbException>(
|
new UiResultExceptionHandler<BlogPostItem, DbException>(
|
||||||
getActivity()) {
|
listener) {
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(BlogPostItem result) {
|
public void onResultUi(BlogPostItem result) {
|
||||||
item = result;
|
item = result;
|
||||||
@@ -148,7 +148,7 @@ public class ReblogFragment extends BaseFragment {
|
|||||||
private void send() {
|
private void send() {
|
||||||
String comment = getComment();
|
String comment = getComment();
|
||||||
feedController.repeatPost(item, comment,
|
feedController.repeatPost(item, comment,
|
||||||
new UiResultExceptionHandler<Void, DbException>(getActivity()) {
|
new UiResultExceptionHandler<Void, DbException>(listener) {
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(Void result) {
|
public void onResultUi(Void result) {
|
||||||
// do nothing, this fragment is gone already
|
// do nothing, this fragment is gone already
|
||||||
|
|||||||
@@ -1,33 +1,36 @@
|
|||||||
package org.briarproject.android.controller.handler;
|
package org.briarproject.android.controller.handler;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
|
|
||||||
|
import org.briarproject.android.fragment.BaseFragment.BaseFragmentListener;
|
||||||
|
|
||||||
public abstract class UiResultExceptionHandler<R, E extends Exception>
|
public abstract class UiResultExceptionHandler<R, E extends Exception>
|
||||||
implements ResultExceptionHandler<R, E> {
|
implements ResultExceptionHandler<R, E> {
|
||||||
|
|
||||||
private final Activity activity;
|
private final BaseFragmentListener listener;
|
||||||
|
|
||||||
public UiResultExceptionHandler(Activity activity) {
|
protected UiResultExceptionHandler(BaseFragmentListener listener) {
|
||||||
this.activity = activity;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResult(final R result) {
|
public void onResult(final R result) {
|
||||||
activity.runOnUiThread(new Runnable() {
|
listener.runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
onResultUi(result);
|
if (!listener.hasBeenDestroyed())
|
||||||
|
onResultUi(result);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onException(final E exception) {
|
public void onException(final E exception) {
|
||||||
activity.runOnUiThread(new Runnable() {
|
listener.runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
onExceptionUi(exception);
|
if (!listener.hasBeenDestroyed())
|
||||||
|
onExceptionUi(exception);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,24 @@
|
|||||||
package org.briarproject.android.controller.handler;
|
package org.briarproject.android.controller.handler;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
|
|
||||||
|
import org.briarproject.android.fragment.BaseFragment.BaseFragmentListener;
|
||||||
|
|
||||||
public abstract class UiResultHandler<R> implements ResultHandler<R> {
|
public abstract class UiResultHandler<R> implements ResultHandler<R> {
|
||||||
|
|
||||||
private final Activity activity;
|
private final BaseFragmentListener listener;
|
||||||
|
|
||||||
public UiResultHandler(Activity activity) {
|
protected UiResultHandler(BaseFragmentListener listener) {
|
||||||
this.activity = activity;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResult(final R result) {
|
public void onResult(final R result) {
|
||||||
activity.runOnUiThread(new Runnable() {
|
listener.runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
onResultUi(result);
|
if (!listener.hasBeenDestroyed())
|
||||||
|
onResultUi(result);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import android.support.annotation.UiThread;
|
|||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
|
|
||||||
import org.briarproject.android.ActivityComponent;
|
import org.briarproject.android.ActivityComponent;
|
||||||
|
import org.briarproject.android.Destroyable;
|
||||||
|
|
||||||
public abstract class BaseFragment extends Fragment {
|
public abstract class BaseFragment extends Fragment {
|
||||||
|
|
||||||
@@ -45,7 +46,7 @@ public abstract class BaseFragment extends Fragment {
|
|||||||
getActivity().supportFinishAfterTransition();
|
getActivity().supportFinishAfterTransition();
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface BaseFragmentListener {
|
public interface BaseFragmentListener extends Destroyable {
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
void showLoadingScreen(boolean isBlocking, int stringId);
|
void showLoadingScreen(boolean isBlocking, int stringId);
|
||||||
|
|||||||
@@ -6,7 +6,12 @@ import android.content.Context;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.support.design.widget.TextInputLayout;
|
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.format.DateUtils;
|
||||||
|
import android.text.style.ForegroundColorSpan;
|
||||||
|
|
||||||
import org.briarproject.R;
|
import org.briarproject.R;
|
||||||
import org.briarproject.util.IoUtils;
|
import org.briarproject.util.IoUtils;
|
||||||
@@ -31,6 +36,7 @@ import static android.text.format.DateUtils.WEEK_IN_MILLIS;
|
|||||||
public class AndroidUtils {
|
public class AndroidUtils {
|
||||||
|
|
||||||
public static final long MIN_RESOLUTION = MINUTE_IN_MILLIS;
|
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
|
// Fake Bluetooth address returned by BluetoothAdapter on API 23 and later
|
||||||
private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00";
|
private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00";
|
||||||
@@ -115,4 +121,25 @@ public class AndroidUtils {
|
|||||||
MIN_RESOLUTION, flags).toString();
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import de.hdodenhof.circleimageview.CircleImageView;
|
|||||||
import im.delight.android.identicons.IdenticonDrawable;
|
import im.delight.android.identicons.IdenticonDrawable;
|
||||||
|
|
||||||
import static android.content.Context.LAYOUT_INFLATER_SERVICE;
|
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.BOLD;
|
||||||
import static android.graphics.Typeface.NORMAL;
|
import static android.graphics.Typeface.NORMAL;
|
||||||
import static android.support.v4.app.ActivityOptionsCompat.makeCustomAnimation;
|
import static android.support.v4.app.ActivityOptionsCompat.makeCustomAnimation;
|
||||||
@@ -106,6 +107,7 @@ public class AuthorView extends RelativeLayout {
|
|||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Intent i = new Intent(getContext(), BlogActivity.class);
|
Intent i = new Intent(getContext(), BlogActivity.class);
|
||||||
i.putExtra(GROUP_ID, groupId.getBytes());
|
i.putExtra(GROUP_ID, groupId.getBytes());
|
||||||
|
i.setFlags(FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
ActivityOptionsCompat options =
|
ActivityOptionsCompat options =
|
||||||
makeCustomAnimation(getContext(),
|
makeCustomAnimation(getContext(),
|
||||||
android.R.anim.slide_in_left,
|
android.R.anim.slide_in_left,
|
||||||
|
|||||||
Reference in New Issue
Block a user