From ad02acaefe7af351e889df95495656200372820d Mon Sep 17 00:00:00 2001 From: Floens Date: Thu, 9 Apr 2015 22:32:58 +0200 Subject: [PATCH] Made pins clickable and highlight when open --- .../java/org/floens/chan/ChanApplication.java | 29 ++-- .../chan/controller/NavigationController.java | 8 ++ .../floens/chan/core/loader/LoaderPool.java | 6 +- .../chan/core/manager/WatchManager.java | 49 +++---- .../java/org/floens/chan/core/model/Pin.java | 13 +- .../chan/core/presenter/ThreadPresenter.java | 15 +-- .../chan/core/settings/ChanSettings.java | 14 +- .../floens/chan/core/watch/PinWatcher.java | 7 +- .../floens/chan/ui/activity/BaseActivity.java | 17 +-- .../chan/ui/activity/BoardActivity.java | 111 +--------------- .../chan/ui/activity/StartActivity.java | 106 +++++++++++++++ .../floens/chan/ui/adapter/PinAdapter.java | 125 +++++++++++++++--- .../floens/chan/ui/adapter/PinnedAdapter.java | 2 +- .../chan/ui/controller/BrowseController.java | 13 +- .../ui/controller/ImageViewerController.java | 2 +- .../controller/RootNavigationController.java | 37 +++++- .../chan/ui/controller/ThreadController.java | 4 + .../ui/controller/ViewThreadController.java | 54 ++++++-- .../floens/chan/ui/layout/ThreadLayout.java | 3 + .../chan/ui/toolbar/NavigationItem.java | 14 +- .../org/floens/chan/ui/toolbar/Toolbar.java | 13 +- .../chan/ui/toolbar/ToolbarMenuItem.java | 4 +- .../org/floens/chan/utils/AndroidUtils.java | 13 +- .../app/src/main/res/layout/cell_header.xml | 2 +- Clover/app/src/main/res/layout/cell_pin.xml | 15 ++- 25 files changed, 423 insertions(+), 253 deletions(-) create mode 100644 Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java diff --git a/Clover/app/src/main/java/org/floens/chan/ChanApplication.java b/Clover/app/src/main/java/org/floens/chan/ChanApplication.java index fd0ccc61..707006fd 100644 --- a/Clover/app/src/main/java/org/floens/chan/ChanApplication.java +++ b/Clover/app/src/main/java/org/floens/chan/ChanApplication.java @@ -40,8 +40,8 @@ import org.floens.chan.utils.Logger; import java.io.File; import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; + +import de.greenrobot.event.EventBus; public class ChanApplication extends Application { private static final String TAG = "ChanApplication"; @@ -62,7 +62,6 @@ public class ChanApplication extends Application { private static DatabaseManager databaseManager; private static FileCache fileCache; - private List foregroundChangedListeners = new ArrayList<>(); private int activityForegroundCounter = 0; public ChanApplication() { @@ -152,9 +151,7 @@ public class ChanApplication extends Application { activityForegroundCounter++; if (getApplicationInForeground() != lastForeground) { - for (ForegroundChangedListener listener : foregroundChangedListeners) { - listener.onForegroundChanged(getApplicationInForeground()); - } + EventBus.getDefault().post(new ForegroundChangedMessage(getApplicationInForeground())); } } @@ -167,9 +164,7 @@ public class ChanApplication extends Application { } if (getApplicationInForeground() != lastForeground) { - for (ForegroundChangedListener listener : foregroundChangedListeners) { - listener.onForegroundChanged(getApplicationInForeground()); - } + EventBus.getDefault().post(new ForegroundChangedMessage(getApplicationInForeground())); } } @@ -177,14 +172,6 @@ public class ChanApplication extends Application { return activityForegroundCounter > 0; } - public void addForegroundChangedListener(ForegroundChangedListener listener) { - foregroundChangedListeners.add(listener); - } - - public void removeForegroundChangedListener(ForegroundChangedListener listener) { - foregroundChangedListeners.remove(listener); - } - private void cleanupOutdated() { File ionCacheFolder = new File(getCacheDir() + "/ion"); if (ionCacheFolder.exists() && ionCacheFolder.isDirectory()) { @@ -202,7 +189,11 @@ public class ChanApplication extends Application { } } - public interface ForegroundChangedListener { - void onForegroundChanged(boolean foreground); + public static class ForegroundChangedMessage { + public boolean inForeground; + + public ForegroundChangedMessage(boolean inForeground) { + this.inForeground = inForeground; + } } } diff --git a/Clover/app/src/main/java/org/floens/chan/controller/NavigationController.java b/Clover/app/src/main/java/org/floens/chan/controller/NavigationController.java index e0c0e31e..634d62c6 100644 --- a/Clover/app/src/main/java/org/floens/chan/controller/NavigationController.java +++ b/Clover/app/src/main/java/org/floens/chan/controller/NavigationController.java @@ -137,6 +137,14 @@ public abstract class NavigationController extends Controller implements Control protected void controllerPopped(Controller controller) { } + public Controller getTop() { + if (controllerList.size() > 0) { + return controllerList.get(controllerList.size() - 1); + } else { + return null; + } + } + @Override public void onControllerTransitionCompleted(ControllerTransition transition) { ControllerLogic.finishTransition(transition); diff --git a/Clover/app/src/main/java/org/floens/chan/core/loader/LoaderPool.java b/Clover/app/src/main/java/org/floens/chan/core/loader/LoaderPool.java index 26519f09..070d66a0 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/loader/LoaderPool.java +++ b/Clover/app/src/main/java/org/floens/chan/core/loader/LoaderPool.java @@ -25,15 +25,11 @@ import java.util.Map; public class LoaderPool { // private static final String TAG = "LoaderPool"; - private static LoaderPool instance; + private static LoaderPool instance = new LoaderPool(); private static Map loaders = new HashMap<>(); public static LoaderPool getInstance() { - if (instance == null) { - instance = new LoaderPool(); - } - return instance; } diff --git a/Clover/app/src/main/java/org/floens/chan/core/manager/WatchManager.java b/Clover/app/src/main/java/org/floens/chan/core/manager/WatchManager.java index 59163cc2..bc5c678d 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/manager/WatchManager.java +++ b/Clover/app/src/main/java/org/floens/chan/core/manager/WatchManager.java @@ -39,12 +39,11 @@ import java.util.concurrent.TimeUnit; import de.greenrobot.event.EventBus; -public class WatchManager implements ChanApplication.ForegroundChangedListener { +public class WatchManager { private static final String TAG = "WatchManager"; private static final int FOREGROUND_TIME = 5; private final Context context; - private final List listeners = new ArrayList<>(); private final List pins; private ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); private PendingTimer pendingTimer; @@ -54,7 +53,7 @@ public class WatchManager implements ChanApplication.ForegroundChangedListener { pins = ChanApplication.getDatabaseManager().getPinned(); - ChanApplication.getInstance().addForegroundChangedListener(this); + EventBus.getDefault().register(this); updateTimerState(true); updateNotificationServiceState(); @@ -189,19 +188,20 @@ public class WatchManager implements ChanApplication.ForegroundChangedListener { ChanApplication.getDatabaseManager().updatePins(pins); } - public void addPinListener(PinListener l) { - listeners.add(l); + public void toggleWatch(Pin pin) { + pin.watching = !pin.watching; + + EventBus.getDefault().post(new PinChangedMessage(pin)); + ChanApplication.getWatchManager().onPinsChanged(); + ChanApplication.getWatchManager().invokeLoadNow(); } - public void removePinListener(PinListener l) { - listeners.remove(l); + public void pinWatcherUpdated(Pin pin) { + EventBus.getDefault().post(new PinChangedMessage(pin)); + onPinsChanged(); } public void onPinsChanged() { - for (PinListener l : listeners) { - l.onPinsChanged(); - } - updateTimerState(false); updateNotificationServiceState(); updatePinWatchers(); @@ -231,21 +231,26 @@ public class WatchManager implements ChanApplication.ForegroundChangedListener { } } + public void onEvent(ChanApplication.ForegroundChangedMessage message) { + updateNotificationServiceState(); + updateTimerState(true); + } + public void onWatchEnabledChanged(boolean watchEnabled) { updateNotificationServiceState(watchEnabled, getWatchBackgroundEnabled()); updateTimerState(watchEnabled, getWatchBackgroundEnabled(), false); updatePinWatchers(watchEnabled); + for (Pin pin : getPins()) { + EventBus.getDefault().post(new PinChangedMessage(pin)); + } } public void onBackgroundWatchingChanged(boolean backgroundEnabled) { updateNotificationServiceState(getTimerEnabled(), backgroundEnabled); updateTimerState(getTimerEnabled(), backgroundEnabled, false); - } - - @Override - public void onForegroundChanged(final boolean foreground) { - updateNotificationServiceState(); - updateTimerState(true); + for (Pin pin : getPins()) { + EventBus.getDefault().post(new PinChangedMessage(pin)); + } } private boolean getTimerEnabled() { @@ -294,7 +299,7 @@ public class WatchManager implements ChanApplication.ForegroundChangedListener { setTimer(invokeLoadNow ? 1 : FOREGROUND_TIME); } else { if (backgroundEnabled) { - setTimer(ChanSettings.getWatchBackgroundTimeout()); + setTimer(Integer.parseInt(ChanSettings.watchBackgroundTimeout.get())); } else { if (pendingTimer != null) { pendingTimer.cancel(); @@ -343,16 +348,14 @@ public class WatchManager implements ChanApplication.ForegroundChangedListener { pendingTimer = null; for (Pin pin : getWatchingPins()) { - pin.update(); + if (pin.update()) { + EventBus.getDefault().post(new PinChangedMessage(pin)); + } } updateTimerState(false); } - public interface PinListener { - void onPinsChanged(); - } - public static class PinAddedMessage { public Pin pin; diff --git a/Clover/app/src/main/java/org/floens/chan/core/model/Pin.java b/Clover/app/src/main/java/org/floens/chan/core/model/Pin.java index 07407917..6f74d7f5 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/model/Pin.java +++ b/Clover/app/src/main/java/org/floens/chan/core/model/Pin.java @@ -20,7 +20,6 @@ package org.floens.chan.core.model; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; -import org.floens.chan.ChanApplication; import org.floens.chan.core.watch.PinWatcher; @DatabaseTable @@ -80,10 +79,8 @@ public class Pin { } } - public void update() { - if (pinWatcher != null && watching) { - pinWatcher.update(); - } + public boolean update() { + return pinWatcher != null && watching && pinWatcher.update(); } public void createWatcher() { @@ -98,10 +95,4 @@ public class Pin { pinWatcher = null; } } - - public void toggleWatch() { - watching = !watching; - ChanApplication.getWatchManager().onPinsChanged(); - ChanApplication.getWatchManager().invokeLoadNow(); - } } diff --git a/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java b/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java index 473d0eb1..4760a999 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java +++ b/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java @@ -55,16 +55,13 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt } public void bindLoadable(Loadable loadable) { - if (chanLoader == null) { - if (!loadable.equals(this.loadable)) { - if (this.loadable != null) { - unbindLoadable(); - } - - this.loadable = loadable; - - chanLoader = LoaderPool.getInstance().obtain(loadable, this); + if (!loadable.equals(this.loadable)) { + if (chanLoader != null) { + unbindLoadable(); } + + this.loadable = loadable; + chanLoader = LoaderPool.getInstance().obtain(loadable, this); } } diff --git a/Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java b/Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java index d9b0de4b..3853d7e8 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java +++ b/Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java @@ -91,9 +91,19 @@ public class ChanSettings { anonymizeIds = new BooleanSetting(p, "preference_anonymize_ids", false); repliesButtonsBottom = new BooleanSetting(p, "preference_buttons_bottom", false); - watchEnabled = new BooleanSetting(p, "preference_watch_enabled", false); + watchEnabled = new BooleanSetting(p, "preference_watch_enabled", false, new Setting.SettingCallback() { + @Override + public void onValueChange(Setting setting, Boolean value) { + ChanApplication.getWatchManager().onWatchEnabledChanged(value); + } + }); watchCountdown = new BooleanSetting(p, "preference_watch_countdown", false); - watchBackground = new BooleanSetting(p, "preference_watch_background_enabled", false); + watchBackground = new BooleanSetting(p, "preference_watch_background_enabled", false, new Setting.SettingCallback() { + @Override + public void onValueChange(Setting setting, Boolean value) { + ChanApplication.getWatchManager().onBackgroundWatchingChanged(value); + } + }); watchBackgroundTimeout = new StringSetting(p, "preference_watch_background_timeout", "60"); watchNotifyMode = new StringSetting(p, "preference_watch_notify_mode", "all"); watchSound = new StringSetting(p, "preference_watch_sound", "all"); diff --git a/Clover/app/src/main/java/org/floens/chan/core/watch/PinWatcher.java b/Clover/app/src/main/java/org/floens/chan/core/watch/PinWatcher.java index 1045b4cf..4de63aef 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/watch/PinWatcher.java +++ b/Clover/app/src/main/java/org/floens/chan/core/watch/PinWatcher.java @@ -55,9 +55,12 @@ public class PinWatcher implements ChanLoader.ChanLoaderCallback { } } - public void update() { + public boolean update() { if (!pin.isError) { chanLoader.loadMoreIfTime(); + return true; + } else { + return false; } } @@ -192,7 +195,7 @@ public class PinWatcher implements ChanLoader.ChanLoaderCallback { AndroidUtils.runOnUiThread(new Runnable() { @Override public void run() { - ChanApplication.getWatchManager().onPinsChanged(); + ChanApplication.getWatchManager().pinWatcherUpdated(pin); } }); } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/BaseActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/BaseActivity.java index ce57c01b..b7e8497a 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/BaseActivity.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/activity/BaseActivity.java @@ -45,21 +45,20 @@ import android.widget.ListView; import org.floens.chan.ChanApplication; import org.floens.chan.R; -import org.floens.chan.core.manager.WatchManager; import org.floens.chan.core.model.ChanThread; import org.floens.chan.core.model.Loadable; import org.floens.chan.core.model.Pin; import org.floens.chan.core.model.Post; -import org.floens.chan.ui.animation.SwipeDismissListViewTouchListener; -import org.floens.chan.ui.animation.SwipeDismissListViewTouchListener.DismissCallbacks; import org.floens.chan.ui.ThemeActivity; import org.floens.chan.ui.adapter.PinnedAdapter; +import org.floens.chan.ui.animation.SwipeDismissListViewTouchListener; +import org.floens.chan.ui.animation.SwipeDismissListViewTouchListener.DismissCallbacks; import org.floens.chan.utils.AndroidUtils; import org.floens.chan.utils.ThemeHelper; import static org.floens.chan.utils.AndroidUtils.dp; -public abstract class BaseActivity extends ThemeActivity implements PanelSlideListener, WatchManager.PinListener { +public abstract class BaseActivity extends ThemeActivity implements PanelSlideListener { public static boolean doRestartOnResume = false; private final static int ACTION_OPEN_URL = 1; @@ -110,8 +109,6 @@ public abstract class BaseActivity extends ThemeActivity implements PanelSlideLi threadPane = (SlidingPaneLayout) findViewById(R.id.pane_container); initPane(); - ChanApplication.getWatchManager().addPinListener(this); - updateIcon(); } @@ -127,8 +124,6 @@ public abstract class BaseActivity extends ThemeActivity implements PanelSlideLi @Override protected void onDestroy() { super.onDestroy(); - - ChanApplication.getWatchManager().removePinListener(this); } @Override @@ -212,12 +207,6 @@ public abstract class BaseActivity extends ThemeActivity implements PanelSlideLi pinDrawerView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); } - @Override - public void onPinsChanged() { - pinnedAdapter.reload(); - updateIcon(); - } - private void updateIcon() { /*List list = ChanApplication.getWatchManager().getWatchingPins(); if (list.size() > 0) { diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/BoardActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/BoardActivity.java index 985ea95e..f1fe0d64 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/BoardActivity.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/activity/BoardActivity.java @@ -17,115 +17,8 @@ */ package org.floens.chan.ui.activity; -import android.app.Activity; -import android.content.res.Configuration; -import android.os.Bundle; -import android.view.ViewGroup; - -import org.floens.chan.controller.Controller; -import org.floens.chan.ui.controller.BrowseController; -import org.floens.chan.ui.controller.RootNavigationController; -import org.floens.chan.utils.ThemeHelper; - -import java.util.ArrayList; -import java.util.List; - /** - * StartActivity - *

- * (Not actually called StartActivity because then the launcher icon would disappear. - * Instead it's called like the old launcher activity, BoardActivity.) + * The old starting activity. This exists so that the launcher icon does not disappear. */ -public class BoardActivity extends Activity { - private static final String TAG = "StartActivity"; - - private ViewGroup contentView; - private List stack = new ArrayList<>(); - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - ThemeHelper.getInstance().reloadPostViewColors(this); - - contentView = (ViewGroup) findViewById(android.R.id.content); - - RootNavigationController rootNavigationController = new RootNavigationController(this); - rootNavigationController.onCreate(); - - setContentView(rootNavigationController.view); - addController(rootNavigationController); - - rootNavigationController.pushController(new BrowseController(this), false); - - rootNavigationController.onShow(); - - // Prevent overdraw - // Do this after setContentView, or the decor creating will reset the background to a default non-null drawable - getWindow().setBackgroundDrawable(null); - } - - public void addController(Controller controller) { - stack.add(controller); - } - - public void removeController(Controller controller) { - stack.remove(controller); - } - - public ViewGroup getContentView() { - return contentView; - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - for (Controller controller : stack) { - controller.onConfigurationChanged(newConfig); - } - } - - @Override - public void onBackPressed() { - if (!stackTop().onBack()) { - // Don't destroy the view, let Android do that or it'll create artifacts - stackTop().onHide(); - super.onBackPressed(); - } - } - - @Override - protected void onDestroy() { - super.onDestroy(); - - stackTop().onDestroy(); - } - - private Controller stackTop() { - return stack.get(stack.size() - 1); - } - - /* - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // http://stackoverflow.com/a/7748416/1001608 - // Possible work around for market launches. See http://code.google.com/p/android/issues/detail?id=2373 - // for more details. Essentially, the market launches the main activity on top of other activities. - // we never want this to happen. Instead, we check if we are the root and if not, we finish. - if (!isTaskRoot()) { - final Intent intent = getIntent(); - final String intentAction = intent.getAction(); - if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && intentAction != null && intentAction.equals(Intent.ACTION_MAIN)) { - Logger.w(TAG, "StartActivity is not the root. Finishing StartActivity instead of launching."); - finish(); - return; - } - } - - Intent intent = new Intent(this, ChanActivity.class); - startActivity(intent); - finish(); - }*/ +public class BoardActivity extends StartActivity { } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java new file mode 100644 index 00000000..8245de29 --- /dev/null +++ b/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java @@ -0,0 +1,106 @@ +package org.floens.chan.ui.activity; + +import android.app.Activity; +import android.content.res.Configuration; +import android.os.Bundle; +import android.view.ViewGroup; + +import org.floens.chan.ChanApplication; +import org.floens.chan.controller.Controller; +import org.floens.chan.ui.controller.BrowseController; +import org.floens.chan.ui.controller.RootNavigationController; +import org.floens.chan.utils.ThemeHelper; + +import java.util.ArrayList; +import java.util.List; + +public class StartActivity extends Activity { + private static final String TAG = "StartActivity"; + + private ViewGroup contentView; + private List stack = new ArrayList<>(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ThemeHelper.getInstance().reloadPostViewColors(this); + + contentView = (ViewGroup) findViewById(android.R.id.content); + + RootNavigationController rootNavigationController = new RootNavigationController(this); + rootNavigationController.onCreate(); + + setContentView(rootNavigationController.view); + addController(rootNavigationController); + + rootNavigationController.pushController(new BrowseController(this), false); + + rootNavigationController.onShow(); + + // Prevent overdraw + // Do this after setContentView, or the decor creating will reset the background to a default non-null drawable + getWindow().setBackgroundDrawable(null); + } + + public void addController(Controller controller) { + stack.add(controller); + } + + public void removeController(Controller controller) { + stack.remove(controller); + } + + public ViewGroup getContentView() { + return contentView; + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + for (Controller controller : stack) { + controller.onConfigurationChanged(newConfig); + } + } + + @Override + public void onBackPressed() { + if (!stackTop().onBack()) { + // Don't destroy the view, let Android do that or it'll create artifacts + stackTop().onHide(); + super.onBackPressed(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + stackTop().onDestroy(); + } + + @Override + protected void onStart() { + super.onStart(); + + ChanApplication.getInstance().activityEnteredForeground(); + } + + @Override + protected void onStop() { + super.onStop(); + + ChanApplication.getInstance().activityEnteredBackground(); + } + + @Override + protected void onPause() { + super.onPause(); + + ChanApplication.getWatchManager().updateDatabase(); + } + + private Controller stackTop() { + return stack.get(stack.size() - 1); + } +} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/adapter/PinAdapter.java b/Clover/app/src/main/java/org/floens/chan/ui/adapter/PinAdapter.java index ebc101fa..a4416268 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/adapter/PinAdapter.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/adapter/PinAdapter.java @@ -1,5 +1,6 @@ package org.floens.chan.ui.adapter; +import android.os.Build; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; @@ -10,16 +11,21 @@ import android.widget.TextView; import org.floens.chan.ChanApplication; import org.floens.chan.R; import org.floens.chan.core.model.Pin; +import org.floens.chan.core.settings.ChanSettings; import org.floens.chan.ui.helper.SwipeListener; import org.floens.chan.ui.view.ThumbnailView; +import org.floens.chan.utils.AndroidUtils; import java.util.ArrayList; import java.util.List; import static org.floens.chan.utils.AndroidUtils.ROBOTO_MEDIUM; import static org.floens.chan.utils.AndroidUtils.dp; +import static org.floens.chan.utils.AndroidUtils.getAttrDrawable; public class PinAdapter extends RecyclerView.Adapter implements SwipeListener.Callback { + private static final int PIN_OFFSET = 3; + private static final int TYPE_HEADER = 0; private static final int TYPE_PIN = 1; private static final int TYPE_LINK = 2; @@ -52,10 +58,10 @@ public class PinAdapter extends RecyclerView.Adapter im ((PinHeaderHolder) holder).text.setText(R.string.drawer_pinned); break; case TYPE_PIN: - final Pin pin = pins.get(position - 3); + final Pin pin = pins.get(position - PIN_OFFSET); PinViewHolder pinHolder = (PinViewHolder) holder; - pinHolder.textView.setText(pin.loadable.title); - pinHolder.image.setUrl(pin.thumbnailUrl, dp(40), dp(40)); + updatePinViewHolder(pinHolder, pin); + break; case TYPE_LINK: LinkHolder linkHolder = (LinkHolder) holder; @@ -75,12 +81,12 @@ public class PinAdapter extends RecyclerView.Adapter im @Override public int getItemCount() { - return pins.size() + 3; + return pins.size() + PIN_OFFSET; } @Override public long getItemId(int position) { - position -= 3; + position -= PIN_OFFSET; if (position >= 0 && position < pins.size()) { return pins.get(position).id + 10; } else { @@ -109,7 +115,7 @@ public class PinAdapter extends RecyclerView.Adapter im public void onPinAdded(Pin pin) { pins.add(pin); - notifyItemInserted(pins.size() - 1 + 3); + notifyItemInserted(pins.size() - 1 + PIN_OFFSET); } public void onPinRemoved(Pin pin) { @@ -120,12 +126,24 @@ public class PinAdapter extends RecyclerView.Adapter im } else { int location = pins.indexOf(pin); pins.remove(pin); - notifyItemRemoved(location + 3); + notifyItemRemoved(location + PIN_OFFSET); } } - public void onPinChanged(Pin pin) { - notifyItemChanged(pins.indexOf(pin) + 3); + public void onPinChanged(RecyclerView recyclerView, Pin pin) { + PinViewHolder holder = (PinViewHolder) recyclerView.findViewHolderForAdapterPosition(pins.indexOf(pin) + PIN_OFFSET); + if (holder != null) { + updatePinViewHolder(holder, pin); + } + } + + public void updateHighlighted(RecyclerView recyclerView) { + for (int i = 0; i < pins.size(); i++) { + PinViewHolder holder = (PinViewHolder) recyclerView.findViewHolderForAdapterPosition(i + PIN_OFFSET); + if (holder != null) { + updatePinViewHolder(holder, pins.get(i)); + } + } } @Override @@ -135,7 +153,7 @@ public class PinAdapter extends RecyclerView.Adapter im @Override public void removeItem(int position) { - ChanApplication.getWatchManager().removePin(pins.get(position - 3)); + ChanApplication.getWatchManager().removePin(pins.get(position - PIN_OFFSET)); } @Override @@ -145,8 +163,8 @@ public class PinAdapter extends RecyclerView.Adapter im @Override public void moveItem(int from, int to) { - Pin item = pins.remove(from - 3); - pins.add(to - 3, item); + Pin item = pins.remove(from - PIN_OFFSET); + pins.add(to - PIN_OFFSET, item); notifyItemMoved(from, to); } @@ -154,21 +172,88 @@ public class PinAdapter extends RecyclerView.Adapter im public void movingDone() { } + public void updatePinViewHolder(PinViewHolder holder, Pin pin) { + holder.textView.setText(pin.loadable.title); + holder.image.setUrl(pin.thumbnailUrl, dp(40), dp(40)); + + if (ChanSettings.watchEnabled.get()) { + String count; + if (pin.isError) { + count = "Err"; + } else { + int c = pin.getNewPostCount(); + if (c > 999) { + count = "1k+"; + } else { + count = Integer.toString(c); + } + } + holder.watchCountText.setVisibility(View.VISIBLE); + holder.watchCountText.setText(count); + + if (!pin.watching) { + holder.watchCountText.setTextColor(0xff898989); // TODO material colors + } else if (pin.getNewQuoteCount() > 0) { + holder.watchCountText.setTextColor(0xffFF4444); + } else { + holder.watchCountText.setTextColor(0xff33B5E5); + } + + // The 16dp padding now belongs to the counter, for a bigger touch area + holder.textView.setPadding(holder.textView.getPaddingLeft(), holder.textView.getPaddingTop(), + 0, holder.textView.getPaddingBottom()); + holder.watchCountText.setPadding(dp(16), holder.watchCountText.getPaddingTop(), + holder.watchCountText.getPaddingRight(), holder.watchCountText.getPaddingBottom()); + } else { + // The 16dp padding now belongs to the textview, for better ellipsize + holder.watchCountText.setVisibility(View.GONE); + holder.textView.setPadding(holder.textView.getPaddingLeft(), holder.textView.getPaddingTop(), + dp(16), holder.textView.getPaddingBottom()); + } + + boolean highlighted = callback.isHighlighted(pin); + if (highlighted && !holder.highlighted) { + holder.itemView.setBackgroundColor(0x22000000); + holder.highlighted = true; + } else if (!highlighted && holder.highlighted) { + //noinspection deprecation + holder.itemView.setBackgroundDrawable(AndroidUtils.getAttrDrawable(holder.itemView.getContext(), android.R.attr.selectableItemBackground)); + holder.highlighted = false; + } + } + public class PinViewHolder extends RecyclerView.ViewHolder { + private boolean highlighted; private ThumbnailView image; private TextView textView; + private TextView watchCountText; - public PinViewHolder(View pinCell) { - super(pinCell); - image = (ThumbnailView) pinCell.findViewById(R.id.thumb); + public PinViewHolder(View itemView) { + super(itemView); + image = (ThumbnailView) itemView.findViewById(R.id.thumb); image.setCircular(true); - textView = (TextView) pinCell.findViewById(R.id.text); + textView = (TextView) itemView.findViewById(R.id.text); textView.setTypeface(ROBOTO_MEDIUM); + watchCountText = (TextView) itemView.findViewById(R.id.watch_count); + watchCountText.setTypeface(ROBOTO_MEDIUM); - pinCell.setOnClickListener(new View.OnClickListener() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + watchCountText.setBackground(getAttrDrawable(itemView.getContext(), android.R.attr.selectableItemBackgroundBorderless)); + } else { + watchCountText.setBackgroundResource(R.drawable.gray_background_selector); + } + + itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - callback.onPinClicked(pins.get(getAdapterPosition() - 3)); + callback.onPinClicked(pins.get(getAdapterPosition() - PIN_OFFSET)); + } + }); + + watchCountText.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + callback.onWatchCountClicked(pins.get(getAdapterPosition() - PIN_OFFSET)); } }); } @@ -205,5 +290,9 @@ public class PinAdapter extends RecyclerView.Adapter im public interface Callback { void onPinClicked(Pin pin); + + void onWatchCountClicked(Pin pin); + + boolean isHighlighted(Pin pin); } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/adapter/PinnedAdapter.java b/Clover/app/src/main/java/org/floens/chan/ui/adapter/PinnedAdapter.java index 12380549..ad464dd1 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/adapter/PinnedAdapter.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/adapter/PinnedAdapter.java @@ -178,7 +178,7 @@ public class PinnedAdapter extends BaseAdapter { countContainer.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - pin.toggleWatch(); +// pin.toggleWatch(); } }); diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/BrowseController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/BrowseController.java index 1dca9abc..6e4a64b8 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/BrowseController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/BrowseController.java @@ -31,6 +31,7 @@ import org.floens.chan.chan.ChanUrls; import org.floens.chan.core.manager.BoardManager; import org.floens.chan.core.model.Board; import org.floens.chan.core.model.Loadable; +import org.floens.chan.core.model.Pin; import org.floens.chan.ui.layout.ThreadLayout; import org.floens.chan.ui.toolbar.ToolbarMenu; import org.floens.chan.ui.toolbar.ToolbarMenuItem; @@ -41,7 +42,7 @@ import org.floens.chan.utils.AndroidUtils; import java.util.ArrayList; import java.util.List; -public class BrowseController extends ThreadController implements ToolbarMenuItem.ToolbarMenuItemCallback, ThreadLayout.ThreadLayoutCallback, FloatingMenu.FloatingMenuCallback, BoardManager.BoardChangeListener { +public class BrowseController extends ThreadController implements ToolbarMenuItem.ToolbarMenuItemCallback, ThreadLayout.ThreadLayoutCallback, FloatingMenu.FloatingMenuCallback, BoardManager.BoardChangeListener, RootNavigationController.DrawerCallbacks { private static final int REFRESH_ID = 1; private static final int POST_ID = 2; private static final int SEARCH_ID = 101; @@ -144,6 +145,16 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte loadBoards(); } + @Override + public void onPinClicked(Pin pin) { + openThread(pin.loadable); + } + + @Override + public boolean isPinCurrent(Pin pin) { + return false; + } + private void loadBoard(Board board) { Loadable loadable = new Loadable(board.value); loadable.mode = Loadable.Mode.CATALOG; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerController.java index 41ad427f..cf078e16 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerController.java @@ -217,7 +217,7 @@ public class ImageViewerController extends Controller implements View.OnClickLis public void setTitle(PostImage postImage) { navigationItem.title = postImage.filename; - toolbar.updateTitle(navigationItem); + navigationItem.updateTitle(); } public void scrollTo(PostImage postImage) { diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/RootNavigationController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/RootNavigationController.java index e209ca2d..3671fc82 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/RootNavigationController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/RootNavigationController.java @@ -28,6 +28,7 @@ import android.widget.FrameLayout; import org.floens.chan.ChanApplication; import org.floens.chan.R; import org.floens.chan.controller.Controller; +import org.floens.chan.controller.ControllerTransition; import org.floens.chan.controller.NavigationController; import org.floens.chan.core.manager.WatchManager; import org.floens.chan.core.model.Pin; @@ -121,9 +122,37 @@ public class RootNavigationController extends NavigationController implements Pi setDrawerEnabled(controller.navigationItem.hasDrawer); } + @Override + public void onControllerTransitionCompleted(ControllerTransition transition) { + super.onControllerTransitionCompleted(transition); + updateHighlighted(); + } + + public void updateHighlighted() { + pinAdapter.updateHighlighted(recyclerView); + } + @Override public void onPinClicked(Pin pin) { + Controller top = getTop(); + if (top instanceof DrawerCallbacks) { + ((DrawerCallbacks) top).onPinClicked(pin); + drawerLayout.closeDrawer(Gravity.LEFT); + pinAdapter.updateHighlighted(recyclerView); + } + } + public boolean isHighlighted(Pin pin) { + Controller top = getTop(); + if (top instanceof DrawerCallbacks) { + return ((DrawerCallbacks) top).isPinCurrent(pin); + } + return false; + } + + @Override + public void onWatchCountClicked(Pin pin) { + ChanApplication.getWatchManager().toggleWatch(pin); } public void onEvent(WatchManager.PinAddedMessage message) { @@ -136,7 +165,7 @@ public class RootNavigationController extends NavigationController implements Pi } public void onEvent(WatchManager.PinChangedMessage message) { - pinAdapter.onPinChanged(message.pin); + pinAdapter.onPinChanged(recyclerView, message.pin); } private void setDrawerEnabled(boolean enabled) { @@ -153,4 +182,10 @@ public class RootNavigationController extends NavigationController implements Pi return false; } } + + public interface DrawerCallbacks { + void onPinClicked(Pin pin); + + boolean isPinCurrent(Pin pin); + } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java index 98f03644..b1d1218f 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java @@ -49,4 +49,8 @@ public abstract class ThreadController extends Controller implements ThreadLayou public void scrollTo(PostImage postImage) { threadLayout.getPresenter().scrollTo(postImage); } + + @Override + public void onShowPosts() { + } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/ViewThreadController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/ViewThreadController.java index 4ea0b1e6..b8819196 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/ViewThreadController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/ViewThreadController.java @@ -26,6 +26,7 @@ import org.floens.chan.R; import org.floens.chan.chan.ChanUrls; import org.floens.chan.core.manager.WatchManager; import org.floens.chan.core.model.Loadable; +import org.floens.chan.core.model.Pin; import org.floens.chan.ui.layout.ThreadLayout; import org.floens.chan.ui.toolbar.ToolbarMenu; import org.floens.chan.ui.toolbar.ToolbarMenuItem; @@ -36,7 +37,7 @@ import java.util.Arrays; import de.greenrobot.event.EventBus; -public class ViewThreadController extends ThreadController implements ThreadLayout.ThreadLayoutCallback, ToolbarMenuItem.ToolbarMenuItemCallback { +public class ViewThreadController extends ThreadController implements ThreadLayout.ThreadLayoutCallback, ToolbarMenuItem.ToolbarMenuItemCallback, RootNavigationController.DrawerCallbacks { private static final int POST_ID = 1; private static final int PIN_ID = 2; private static final int REFRESH_ID = 101; @@ -62,11 +63,7 @@ public class ViewThreadController extends ThreadController implements ThreadLayo view.setBackgroundColor(0xffffffff); - threadLayout.getPresenter().bindLoadable(loadable); - threadLayout.getPresenter().requestData(); - navigationItem.hasDrawer = true; - navigationItem.title = loadable.title; navigationItem.menu = new ToolbarMenu(context); navigationItem.menu.addItem(new ToolbarMenuItem(context, this, POST_ID, R.drawable.ic_action_write)); @@ -77,7 +74,15 @@ public class ViewThreadController extends ThreadController implements ThreadLayo new FloatingMenuItem(SHARE_ID, context.getString(R.string.action_share)) )); - setPinIconState(threadLayout.getPresenter().isPinned()); + loadLoadable(loadable); + } + + @Override + public void onShow() { + super.onShow(); + if (navigationController instanceof RootNavigationController) { + ((RootNavigationController)navigationController).updateHighlighted(); + } } @Override @@ -100,14 +105,17 @@ public class ViewThreadController extends ThreadController implements ThreadLayo } @Override - public void openThread(Loadable threadLoadable) { + public void openThread(final Loadable threadLoadable) { // TODO implement, scroll to post and fix title new AlertDialog.Builder(context) .setNegativeButton(R.string.cancel, null) .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(final DialogInterface dialog, final int which) { -// threadManagerListener.onOpenThread(thread, link.postId); + loadLoadable(threadLoadable); + if (navigationController instanceof RootNavigationController) { + ((RootNavigationController)navigationController).updateHighlighted(); + } } }) .setTitle(R.string.open_thread_confirmation) @@ -115,6 +123,36 @@ public class ViewThreadController extends ThreadController implements ThreadLayo .show(); } + @Override + public void onPinClicked(Pin pin) { + loadLoadable(pin.loadable); + } + + @Override + public boolean isPinCurrent(Pin pin) { + return pin.loadable.equals(loadable); + } + + private void loadLoadable(Loadable loadable) { + if (!loadable.equals(threadLayout.getPresenter().getLoadable())) { + this.loadable = loadable; + threadLayout.getPresenter().bindLoadable(loadable); + threadLayout.getPresenter().requestData(); + navigationItem.title = loadable.title; + navigationItem.updateTitle(); + setPinIconState(threadLayout.getPresenter().isPinned()); + } + } + + @Override + public void onShowPosts() { + super.onShowPosts(); + if (!navigationItem.title.equals(loadable.title)) { + navigationItem.title = loadable.title; + navigationItem.updateTitle(); + } + } + @Override public void onMenuItemClicked(ToolbarMenuItem item) { switch (item.getId()) { diff --git a/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadLayout.java b/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadLayout.java index dc3a843a..bf0b0d68 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadLayout.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadLayout.java @@ -91,6 +91,7 @@ public class ThreadLayout extends LoadView implements ThreadPresenter.ThreadPres public void showPosts(ChanThread thread) { threadListLayout.showPosts(thread, !visible); switchVisible(true); + callback.onShowPosts(); } @Override @@ -188,5 +189,7 @@ public class ThreadLayout extends LoadView implements ThreadPresenter.ThreadPres void openThread(Loadable threadLoadable); void showImages(List images, int index, Loadable loadable, ThumbnailView thumbnail); + + void onShowPosts(); } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/toolbar/NavigationItem.java b/Clover/app/src/main/java/org/floens/chan/ui/toolbar/NavigationItem.java index f4de1bdf..7d7c1d50 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/toolbar/NavigationItem.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/toolbar/NavigationItem.java @@ -20,7 +20,9 @@ package org.floens.chan.ui.toolbar; import android.content.Context; import android.view.View; import android.widget.LinearLayout; +import android.widget.TextView; +import org.floens.chan.R; import org.floens.chan.ui.view.FloatingMenu; import org.floens.chan.ui.view.FloatingMenuItem; @@ -30,15 +32,25 @@ public class NavigationItem { public String title = ""; public ToolbarMenu menu; public boolean hasBack = true; - public LinearLayout view; public FloatingMenu middleMenu; public View rightView; public boolean hasDrawer = false; + LinearLayout view; + public ToolbarMenuItem createOverflow(Context context, ToolbarMenuItem.ToolbarMenuItemCallback callback, List items) { ToolbarMenuItem overflow = menu.createOverflow(callback); FloatingMenu overflowMenu = new FloatingMenu(context, overflow.getView(), items); overflow.setSubMenu(overflowMenu); return overflow; } + + public void updateTitle() { + if (view != null) { + TextView titleView = (TextView) view.findViewById(R.id.title); + if (titleView != null) { + titleView.setText(title); + } + } + } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/toolbar/Toolbar.java b/Clover/app/src/main/java/org/floens/chan/ui/toolbar/Toolbar.java index 70b21199..ac257202 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/toolbar/Toolbar.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/toolbar/Toolbar.java @@ -89,15 +89,6 @@ public class Toolbar extends LinearLayout implements View.OnClickListener { } } - public void updateTitle(NavigationItem item) { - if (item.view != null) { - TextView title = (TextView) item.view.findViewById(R.id.title); - if (title != null) { - title.setText(item.title); - } - } - } - public void setCallback(ToolbarCallback callback) { this.callback = callback; } @@ -132,10 +123,8 @@ public class Toolbar extends LinearLayout implements View.OnClickListener { arrowMenuView.setImageDrawable(arrowMenuDrawable); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - //noinspection deprecation - arrowMenuView.setBackgroundDrawable(getAttrDrawable(android.R.attr.selectableItemBackgroundBorderless)); + arrowMenuView.setBackground(getAttrDrawable(getContext(), android.R.attr.selectableItemBackgroundBorderless)); } else { - //noinspection deprecation arrowMenuView.setBackgroundResource(R.drawable.gray_background_selector); } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/toolbar/ToolbarMenuItem.java b/Clover/app/src/main/java/org/floens/chan/ui/toolbar/ToolbarMenuItem.java index 170080f1..8586be27 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/toolbar/ToolbarMenuItem.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/toolbar/ToolbarMenuItem.java @@ -58,10 +58,8 @@ public class ToolbarMenuItem implements View.OnClickListener, FloatingMenu.Float imageView.setImageDrawable(drawable); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - //noinspection deprecation - imageView.setBackgroundDrawable(getAttrDrawable(android.R.attr.selectableItemBackgroundBorderless)); + imageView.setBackground(getAttrDrawable(context, android.R.attr.selectableItemBackgroundBorderless)); } else { - //noinspection deprecation imageView.setBackgroundResource(R.drawable.gray_background_selector); } } diff --git a/Clover/app/src/main/java/org/floens/chan/utils/AndroidUtils.java b/Clover/app/src/main/java/org/floens/chan/utils/AndroidUtils.java index 6e5ace0a..c0e17bb7 100644 --- a/Clover/app/src/main/java/org/floens/chan/utils/AndroidUtils.java +++ b/Clover/app/src/main/java/org/floens/chan/utils/AndroidUtils.java @@ -100,13 +100,6 @@ public class AndroidUtils { } } - public static int getAttrPixel(int attr) { - TypedArray typedArray = ChanApplication.con.getTheme().obtainStyledAttributes(new int[]{attr}); - int pixels = typedArray.getDimensionPixelSize(0, 0); - typedArray.recycle(); - return pixels; - } - public static int getAttrColor(Context context, int attr) { TypedArray typedArray = context.getTheme().obtainStyledAttributes(new int[]{attr}); int color = typedArray.getColor(0, 0); @@ -114,8 +107,8 @@ public class AndroidUtils { return color; } - public static Drawable getAttrDrawable(int attr) { - TypedArray typedArray = ChanApplication.con.getTheme().obtainStyledAttributes(new int[]{attr}); + public static Drawable getAttrDrawable(Context context, int attr) { + TypedArray typedArray = context.obtainStyledAttributes(new int[]{attr}); Drawable drawable = typedArray.getDrawable(0); typedArray.recycle(); return drawable; @@ -148,7 +141,7 @@ public class AndroidUtils { dialog.setOnShowListener(new DialogInterface.OnShowListener() { @Override public void onShow(DialogInterface dialog) { - InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService( Context.INPUT_METHOD_SERVICE); + InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(view, 0); } }); diff --git a/Clover/app/src/main/res/layout/cell_header.xml b/Clover/app/src/main/res/layout/cell_header.xml index 856e6338..9e02566c 100644 --- a/Clover/app/src/main/res/layout/cell_header.xml +++ b/Clover/app/src/main/res/layout/cell_header.xml @@ -7,7 +7,7 @@ + android:background="?android:attr/selectableItemBackground"> + +