diff --git a/briar-android/res/drawable/chevron48dp_down.xml b/briar-android/res/drawable/chevron48dp_down.xml index 16dd3cd9d7093f9118d7439825363074e6705895..6f1f305dfaffc9ce196424027ea46f25e94be90a 100644 --- a/briar-android/res/drawable/chevron48dp_down.xml +++ b/briar-android/res/drawable/chevron48dp_down.xml @@ -1,4 +1,9 @@ -<vector android:height="24dp" android:viewportHeight="48.0" - android:viewportWidth="48.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> - <path android:fillColor="#FF000000" android:pathData="M9.1,19.3l14.9,11.8l14.9,-11.8l-1.9,-2.4l-13,10.4l-13,-10.4z"/> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="48.0" + android:viewportWidth="48.0"> + <path + android:fillColor="#06b9ff" + android:pathData="M9.1,19.3l14.9,11.8l14.9,-11.8l-1.9,-2.4l-13,10.4l-13,-10.4z"/> </vector> diff --git a/briar-android/res/drawable/chevron48dp_up.xml b/briar-android/res/drawable/chevron48dp_up.xml index 7d59523a92f4030ca1747b1c3941f60e152816a2..50894206ec5cbe88abf1f75335330eabb179184e 100644 --- a/briar-android/res/drawable/chevron48dp_up.xml +++ b/briar-android/res/drawable/chevron48dp_up.xml @@ -1,4 +1,9 @@ -<vector android:height="24dp" android:viewportHeight="48.0" - android:viewportWidth="48.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> - <path android:fillColor="#FF000000" android:pathData="M38.9,28.7l-14.9,-11.8l-14.9,11.8l1.9,2.4l13,-10.4l13,10.4z"/> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="48.0" + android:viewportWidth="48.0"> + <path + android:fillColor="#06b9ff" + android:pathData="M38.9,28.7l-14.9,-11.8l-14.9,11.8l1.9,2.4l13,-10.4l13,10.4z"/> </vector> diff --git a/briar-android/res/drawable/selector_chevron.xml b/briar-android/res/drawable/selector_chevron.xml index bc08694ba67a833441046c7841bb7b18db5f7f16..f3a72a87dd62e3bcfec63aef1c5c966165f6a810 100644 --- a/briar-android/res/drawable/selector_chevron.xml +++ b/briar-android/res/drawable/selector_chevron.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_selected="true" android:drawable="@drawable/chevron48dp_down"/> + <item android:drawable="@drawable/chevron48dp_down" android:state_selected="true"/> <item android:drawable="@drawable/chevron48dp_up"/> </selector> \ No newline at end of file diff --git a/briar-android/res/layout/forum_discussion_cell.xml b/briar-android/res/layout/forum_discussion_cell.xml index c8dd79dd6206ef61abfb64efb635b582694c270e..fc6e1a20adae36e573632e38439200360b3eb671 100644 --- a/briar-android/res/layout/forum_discussion_cell.xml +++ b/briar-android/res/layout/forum_discussion_cell.xml @@ -148,9 +148,7 @@ android:layout_marginRight="@dimen/margin_medium" android:layout_marginTop="@dimen/margin_small" android:clickable="true" - android:src="@drawable/selector_chevron" - android:tint="@color/briar_button_positive" - /> + android:src="@drawable/selector_chevron"/> <TextView android:id="@+id/btn_reply" diff --git a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java index e113a9a08577a2ab832c730755652840f3e8d1a0..683bc6bd409b36ef012ea9e4b9884a17b2e2b3a9 100644 --- a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java +++ b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java @@ -153,7 +153,6 @@ public class ContactListFragment extends BaseFragment implements EventListener { list.setLayoutManager(new LinearLayoutManager(getContext())); list.setAdapter(adapter); list.setEmptyText(getString(R.string.no_contacts)); - list.periodicallyUpdateContent(); return contentView; } @@ -183,6 +182,7 @@ public class ContactListFragment extends BaseFragment implements EventListener { super.onResume(); eventBus.addListener(this); loadContacts(); + list.startPeriodicUpdate(); } @Override @@ -190,6 +190,7 @@ public class ContactListFragment extends BaseFragment implements EventListener { super.onPause(); adapter.clear(); eventBus.removeListener(this); + list.stopPeriodicUpdate(); } private void loadContacts() { diff --git a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java index c85e84d8c449cbdda01c18b7420e76676347603d..4a936be8deef6a2ac8ee681a4a36b8bfcbdc94e7 100644 --- a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java +++ b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java @@ -170,7 +170,6 @@ public class ConversationActivity extends BriarActivity list.setLayoutManager(new LinearLayoutManager(this)); list.setAdapter(adapter); list.setEmptyText(getString(R.string.no_private_messages)); - list.periodicallyUpdateContent(); content = (EditText) findViewById(R.id.input_text); sendButton = findViewById(R.id.btn_send); @@ -205,6 +204,7 @@ public class ConversationActivity extends BriarActivity notificationManager.blockNotification(groupId); notificationManager.clearPrivateMessageNotification(groupId); loadData(); + list.startPeriodicUpdate(); } @Override @@ -212,6 +212,7 @@ public class ConversationActivity extends BriarActivity super.onPause(); eventBus.removeListener(this); notificationManager.unblockNotification(groupId); + list.stopPeriodicUpdate(); if (isFinishing()) markMessagesRead(); } diff --git a/briar-android/src/org/briarproject/android/forum/ForumActivity.java b/briar-android/src/org/briarproject/android/forum/ForumActivity.java index dec9c69847111484b8dfb41dfaebb712cbfbe3e2..02a78caccbc400c3b133887b3d56740ed6882594 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumActivity.java +++ b/briar-android/src/org/briarproject/android/forum/ForumActivity.java @@ -9,7 +9,6 @@ import android.content.Intent; import android.graphics.drawable.ColorDrawable; import android.os.Build; import android.os.Bundle; -import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.design.widget.Snackbar; import android.support.v4.app.ActivityCompat; @@ -63,9 +62,9 @@ public class ForumActivity extends BriarActivity implements ForumController.ForumPostListener { static final String FORUM_NAME = "briar.FORUM_NAME"; - private static final int REQUEST_FORUM_SHARED = 3; - private final static int UNDEFINED = -1; + private static final int REQUEST_FORUM_SHARED = 3; + private static final int UNDEFINED = -1; private static final String KEY_INPUT_VISIBILITY = "inputVisibility"; private static final String KEY_REPLY_ID = "replyId"; @@ -77,6 +76,9 @@ public class ForumActivity extends BriarActivity implements @Inject protected ForumController forumController; + // Protected access for testing + protected ForumAdapter forumAdapter; + private BriarRecyclerView recyclerView; private EditText textInput; private ViewGroup inputContainer; @@ -84,8 +86,6 @@ public class ForumActivity extends BriarActivity implements private volatile GroupId groupId = null; - protected ForumAdapter forumAdapter; - @Override public void onCreate(final Bundle state) { super.onCreate(state); @@ -99,50 +99,46 @@ public class ForumActivity extends BriarActivity implements String forumName = i.getStringExtra(FORUM_NAME); if (forumName != null) setTitle(forumName); + forumAdapter = new ForumAdapter(); + inputContainer = (ViewGroup) findViewById(R.id.text_input_container); inputContainer.setVisibility(GONE); textInput = (EditText) findViewById(R.id.input_text); recyclerView = (BriarRecyclerView) findViewById(R.id.forum_discussion_list); + recyclerView.setAdapter(forumAdapter); linearLayoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(linearLayoutManager); recyclerView.setEmptyText(getString(R.string.no_forum_posts)); recyclerView.showProgressBar(); - forumController.loadForum(groupId, - new UiResultHandler<Boolean>(this) { - @Override - public void onResultUi(Boolean result) { - if (result) { - Forum forum = forumController.getForum(); - if (forum != null) setTitle(forum.getName()); - forumAdapter = new ForumAdapter( - forumController.getForumEntries()); - recyclerView.setAdapter(forumAdapter); - recyclerView.periodicallyUpdateContent(); - if (state != null) { - byte[] replyId = - state.getByteArray(KEY_REPLY_ID); - if (replyId != null) { - forumAdapter.setReplyEntryById(replyId); - } - } - recyclerView.showData(); - } else { - // TODO Maybe an error dialog ? - finish(); - } + forumController.loadForum(groupId, new UiResultHandler<Boolean>(this) { + @Override + public void onResultUi(Boolean result) { + if (result) { + Forum forum = forumController.getForum(); + if (forum != null) setTitle(forum.getName()); + forumAdapter.setEntries(forumController.getForumEntries()); + if (state != null) { + byte[] replyId = state.getByteArray(KEY_REPLY_ID); + if (replyId != null) + forumAdapter.setReplyEntryById(replyId); } - }); + recyclerView.showData(); + } else { + // TODO Maybe an error dialog ? + finish(); + } + } + }); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); - inputContainer - .setVisibility( - savedInstanceState.getBoolean(KEY_INPUT_VISIBILITY) ? - VISIBLE : GONE); + inputContainer.setVisibility( + savedInstanceState.getBoolean(KEY_INPUT_VISIBILITY) ? + VISIBLE : GONE); } @@ -250,12 +246,14 @@ public class ForumActivity extends BriarActivity implements super.onResume(); notificationManager.blockNotification(groupId); notificationManager.clearForumPostNotification(groupId); + recyclerView.startPeriodicUpdate(); } @Override public void onPause() { super.onPause(); notificationManager.unblockNotification(groupId); + recyclerView.stopPeriodicUpdate(); } public void sendMessage(View view) { @@ -367,23 +365,25 @@ public class ForumActivity extends BriarActivity implements public class ForumAdapter extends RecyclerView.Adapter<ForumViewHolder> { - private final List<ForumEntry> forumEntries; + private final List<ForumEntry> forumEntries = new ArrayList<>(); + private final Map<ForumEntry, ValueAnimator> animatingEntries = + new HashMap<>(); + // highlight not dependant on time private ForumEntry replyEntry; // temporary highlight private ForumEntry addedEntry; - Map<ForumEntry, ValueAnimator> animatingEntries = new HashMap<>(); - - ForumAdapter(@NonNull List<ForumEntry> forumEntries) { - this.forumEntries = forumEntries; - } private ForumEntry getReplyEntry() { return replyEntry; } - void addEntry(int index, ForumEntry entry, - boolean isScrolling) { + void setEntries(List<ForumEntry> entries) { + forumEntries.clear(); + forumEntries.addAll(entries); + } + + void addEntry(int index, ForumEntry entry, boolean isScrolling) { forumEntries.add(index, entry); boolean isShowingDescendants = false; if (entry.getLevel() > 0) { @@ -553,7 +553,7 @@ public class ForumActivity extends BriarActivity implements return null; } - @TargetApi(Build.VERSION_CODES.HONEYCOMB) + @TargetApi(11) private void animateFadeOut(final ForumViewHolder ui, final ForumEntry addedEntry) { ui.setIsRecyclable(false); @@ -599,8 +599,8 @@ public class ForumActivity extends BriarActivity implements } @Override - public ForumViewHolder onCreateViewHolder( - ViewGroup parent, int viewType) { + public ForumViewHolder onCreateViewHolder(ViewGroup parent, + int viewType) { View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.forum_discussion_cell, parent, false); return new ForumViewHolder(v); @@ -724,5 +724,4 @@ public class ForumActivity extends BriarActivity implements } } - } diff --git a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java index 1916bce322bd3fbc27663b28aadbf2d07f5f6fc5..cca381a80fdcfd86a403740080cd4c000f170b4d 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java +++ b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java @@ -84,7 +84,6 @@ public class ForumListFragment extends BaseEventFragment implements list.setLayoutManager(new LinearLayoutManager(getActivity())); list.setAdapter(adapter); list.setEmptyText(getString(R.string.no_forums)); - list.periodicallyUpdateContent(); snackbar = Snackbar.make(list, "", LENGTH_INDEFINITE); snackbar.getView().setBackgroundResource(R.color.briar_primary); @@ -111,6 +110,7 @@ public class ForumListFragment extends BaseEventFragment implements loadForumHeaders(); loadAvailableForums(); + list.startPeriodicUpdate(); } @Override @@ -118,6 +118,7 @@ public class ForumListFragment extends BaseEventFragment implements super.onPause(); adapter.clear(); + list.stopPeriodicUpdate(); } @Override diff --git a/briar-android/src/org/briarproject/android/util/AndroidUtils.java b/briar-android/src/org/briarproject/android/util/AndroidUtils.java index 077dc8aa58f95d366a678bb18fffbd3f403047d7..0488e927f64c0ed7aa8a0566a73eb3633bc06485 100644 --- a/briar-android/src/org/briarproject/android/util/AndroidUtils.java +++ b/briar-android/src/org/briarproject/android/util/AndroidUtils.java @@ -30,6 +30,8 @@ import static android.text.format.DateUtils.WEEK_IN_MILLIS; public class AndroidUtils { + static final long MIN_RESOLUTION = MINUTE_IN_MILLIS; + // Fake Bluetooth address returned by BluetoothAdapter on API 23 and later private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00"; @@ -97,22 +99,20 @@ public class AndroidUtils { } public static String formatDate(Context ctx, long time) { - // update BriarRecyclerView#DEFAULT_REFRESH_INTERVAL along with this - long minResolution = MINUTE_IN_MILLIS; int flags = FORMAT_ABBREV_RELATIVE | FORMAT_SHOW_DATE | FORMAT_ABBREV_TIME | FORMAT_ABBREV_MONTH; long diff = System.currentTimeMillis() - time; - if (diff < minResolution) return ctx.getString(R.string.now); + if (diff < MIN_RESOLUTION) return ctx.getString(R.string.now); if (diff >= DAY_IN_MILLIS && diff < WEEK_IN_MILLIS) { // also show time when older than a day, but newer than a week - return DateUtils.getRelativeDateTimeString(ctx, time, minResolution, - WEEK_IN_MILLIS, flags).toString(); + return DateUtils.getRelativeDateTimeString(ctx, time, + MIN_RESOLUTION, WEEK_IN_MILLIS, flags).toString(); } // otherwise just show "...ago" or date string return DateUtils .getRelativeTimeSpanString(time, System.currentTimeMillis(), - minResolution, flags).toString(); + MIN_RESOLUTION, flags).toString(); } } diff --git a/briar-android/src/org/briarproject/android/util/BriarRecyclerView.java b/briar-android/src/org/briarproject/android/util/BriarRecyclerView.java index 6cd36dd6b0e71c06c815d7f4f5d0cf44ebb7d2fd..6c403747f40d5f146a459cebdaab69d5c4139412 100644 --- a/briar-android/src/org/briarproject/android/util/BriarRecyclerView.java +++ b/briar-android/src/org/briarproject/android/util/BriarRecyclerView.java @@ -16,10 +16,14 @@ import org.briarproject.R; import java.util.logging.Logger; -import static android.text.format.DateUtils.MINUTE_IN_MILLIS; +import static org.briarproject.android.util.AndroidUtils.MIN_RESOLUTION; public class BriarRecyclerView extends FrameLayout { + private static final long DEFAULT_REFRESH_INTERVAL = MIN_RESOLUTION; + private static final Logger LOG = + Logger.getLogger(BriarRecyclerView.class.getName()); + private RecyclerView recyclerView; private TextView emptyView; private ProgressBar progressBar; @@ -27,9 +31,6 @@ public class BriarRecyclerView extends FrameLayout { private Runnable refresher = null; private boolean isScrollingToEnd = false; - private final Logger LOG = Logger.getLogger(getClass().getName()); - private final long DEFAULT_REFRESH_INTERVAL = MINUTE_IN_MILLIS; - public BriarRecyclerView(Context context) { this(context, null, 0); } @@ -52,10 +53,7 @@ public class BriarRecyclerView extends FrameLayout { @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - if (refresher != null) { - LOG.info("Removing Handler Callback"); - removeCallbacks(refresher); - } + stopPeriodicUpdate(); } private void initViews() { @@ -172,7 +170,7 @@ public class BriarRecyclerView extends FrameLayout { return this.recyclerView; } - public void periodicallyUpdateContent() { + public void startPeriodicUpdate() { if (recyclerView == null || recyclerView.getAdapter() == null) { throw new IllegalStateException("Need to call setAdapter() first!"); } @@ -188,4 +186,11 @@ public class BriarRecyclerView extends FrameLayout { postDelayed(refresher, DEFAULT_REFRESH_INTERVAL); } + public void stopPeriodicUpdate() { + if (refresher != null) { + LOG.info("Removing Handler Callback"); + removeCallbacks(refresher); + } + } + } diff --git a/briar-android/test/java/briarproject/activity/TestForumActivity.java b/briar-android/test/java/briarproject/activity/TestForumActivity.java index f73d83e18f66d12e8b549b9ba5584210c90a76b2..9455ace7e9639dfca4eb22f5717903f21bb2bd5c 100644 --- a/briar-android/test/java/briarproject/activity/TestForumActivity.java +++ b/briar-android/test/java/briarproject/activity/TestForumActivity.java @@ -9,7 +9,7 @@ import org.briarproject.android.forum.ForumControllerImpl; import org.mockito.Mockito; /** - * This class exposes the SetupController and offers the possibility to + * This class exposes the ForumController and offers the possibility to * override it. */ public class TestForumActivity extends ForumActivity {