Added option for paginated/catalog board mode

Added itemviewtypes to PostAdapter
captchafix
Florens Douwes 11 years ago
parent d60e3369d1
commit 286b1093d5
  1. 4
      Clover/app/src/main/java/org/floens/chan/core/ChanPreferences.java
  2. 6
      Clover/app/src/main/java/org/floens/chan/core/manager/ThreadManager.java
  3. 11
      Clover/app/src/main/java/org/floens/chan/ui/activity/BoardActivity.java
  4. 4
      Clover/app/src/main/java/org/floens/chan/ui/activity/WatchSettingsActivity.java
  5. 201
      Clover/app/src/main/java/org/floens/chan/ui/adapter/PostAdapter.java
  6. 4
      Clover/app/src/main/java/org/floens/chan/ui/fragment/PostRepliesFragment.java
  7. 23
      Clover/app/src/main/java/org/floens/chan/ui/fragment/SettingsFragment.java
  8. 103
      Clover/app/src/main/java/org/floens/chan/ui/view/ThreadWatchCounterView.java
  9. 10
      Clover/app/src/main/res/values/strings.xml
  10. 8
      Clover/app/src/main/res/xml/preference.xml

@ -145,4 +145,8 @@ public class ChanPreferences {
public static boolean getAnonymizeIds() { public static boolean getAnonymizeIds() {
return p().getBoolean("preference_anonymize_ids", false); return p().getBoolean("preference_anonymize_ids", false);
} }
public static String getBoardMode() {
return p().getString("preference_board_mode", "catalog");
}
} }

@ -145,12 +145,14 @@ public class ThreadManager implements Loader.LoaderListener {
} }
public boolean shouldWatch() { public boolean shouldWatch() {
if (!ChanPreferences.getThreadAutoRefresh()) { if (!loader.getLoadable().isThreadMode()) {
return false;
} else if (!ChanPreferences.getThreadAutoRefresh()) {
return false; return false;
} else if (loader.getCachedPosts().size() > 0 && loader.getCachedPosts().get(0).closed) { } else if (loader.getCachedPosts().size() > 0 && loader.getCachedPosts().get(0).closed) {
return false; return false;
} else { } else {
return loader.getLoadable().isThreadMode(); return true;
} }
} }

@ -498,8 +498,11 @@ public class BoardActivity extends BaseActivity implements AdapterView.OnItemSel
boardLoadable = loadable; boardLoadable = loadable;
// TODO: make this an option if (ChanPreferences.getBoardMode().equals("catalog")) {
boardLoadable.mode = Loadable.Mode.CATALOG; boardLoadable.mode = Loadable.Mode.CATALOG;
} else if (ChanPreferences.getBoardMode().equals("pages")) {
boardLoadable.mode = Loadable.Mode.BOARD;
}
boardFragment.bindLoadable(loadable); boardFragment.bindLoadable(loadable);
boardFragment.requestData(); boardFragment.requestData();
@ -670,7 +673,7 @@ public class BoardActivity extends BaseActivity implements AdapterView.OnItemSel
public View getView(final int position, View convertView, final ViewGroup parent) { public View getView(final int position, View convertView, final ViewGroup parent) {
switch (getItemViewType(position)) { switch (getItemViewType(position)) {
case VIEW_TYPE_ITEM: { case VIEW_TYPE_ITEM: {
if (convertView == null || (Integer)convertView.getTag() != VIEW_TYPE_ITEM) { if (convertView == null || (Integer) convertView.getTag() != VIEW_TYPE_ITEM) {
convertView = LayoutInflater.from(context).inflate(R.layout.board_select_spinner, null); convertView = LayoutInflater.from(context).inflate(R.layout.board_select_spinner, null);
convertView.setTag(VIEW_TYPE_ITEM); convertView.setTag(VIEW_TYPE_ITEM);
} }
@ -680,7 +683,7 @@ public class BoardActivity extends BaseActivity implements AdapterView.OnItemSel
return textView; return textView;
} }
case VIEW_TYPE_ADD: { case VIEW_TYPE_ADD: {
if (convertView == null || (Integer)convertView.getTag() != VIEW_TYPE_ADD) { if (convertView == null || (Integer) convertView.getTag() != VIEW_TYPE_ADD) {
convertView = LayoutInflater.from(context).inflate(R.layout.board_select_add, null); convertView = LayoutInflater.from(context).inflate(R.layout.board_select_add, null);
convertView.setTag(VIEW_TYPE_ADD); convertView.setTag(VIEW_TYPE_ADD);
} }

@ -156,10 +156,10 @@ public class WatchSettingsActivity extends Activity implements OnCheckedChangeLi
} }
}); });
((CheckBoxPreference)findPreference("preference_watch_background_enabled")).setOnPreferenceChangeListener(new OnPreferenceChangeListener() { ((CheckBoxPreference) findPreference("preference_watch_background_enabled")).setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override @Override
public boolean onPreferenceChange(final Preference preference, final Object newValue) { public boolean onPreferenceChange(final Preference preference, final Object newValue) {
ChanApplication.getWatchManager().onBackgroundWatchingChanged((Boolean)newValue); ChanApplication.getWatchManager().onBackgroundWatchingChanged((Boolean) newValue);
return true; return true;
} }

@ -18,20 +18,24 @@
package org.floens.chan.ui.adapter; package org.floens.chan.ui.adapter;
import android.content.Context; import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.Gravity; import android.view.Gravity;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AbsListView; import android.widget.AbsListView;
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import org.floens.chan.R; import org.floens.chan.R;
import org.floens.chan.core.loader.Loader;
import org.floens.chan.core.manager.ThreadManager; import org.floens.chan.core.manager.ThreadManager;
import org.floens.chan.core.model.Loadable;
import org.floens.chan.core.model.Post; import org.floens.chan.core.model.Post;
import org.floens.chan.ui.ScrollerRunnable; import org.floens.chan.ui.ScrollerRunnable;
import org.floens.chan.ui.view.PostView; import org.floens.chan.ui.view.PostView;
import org.floens.chan.ui.view.ThreadWatchCounterView;
import org.floens.chan.utils.Time; import org.floens.chan.utils.Time;
import org.floens.chan.utils.Utils; import org.floens.chan.utils.Utils;
@ -39,6 +43,9 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
public class PostAdapter extends BaseAdapter { public class PostAdapter extends BaseAdapter {
private static final int VIEW_TYPE_ITEM = 0;
private static final int VIEW_TYPE_STATUS = 1;
private final Context context; private final Context context;
private final ThreadManager threadManager; private final ThreadManager threadManager;
private final AbsListView listView; private final AbsListView listView;
@ -56,17 +63,30 @@ public class PostAdapter extends BaseAdapter {
@Override @Override
public int getCount() { public int getCount() {
if ((threadManager.getLoadable() != null && threadManager.getLoadable().isBoardMode()) return postList.size() + (showStatusView() ? 1 : 0);
|| threadManager.shouldWatch()) { }
return postList.size() + 1;
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public int getItemViewType(int position) {
if (showStatusView()) {
return position == getCount() - 1 ? VIEW_TYPE_STATUS : VIEW_TYPE_ITEM;
} else { } else {
return postList.size(); return VIEW_TYPE_ITEM;
} }
} }
@Override @Override
public Post getItem(int position) { public Post getItem(int position) {
return postList.get(position); if (position >= 0 && position < postList.size()) {
return postList.get(position);
} else {
return null;
}
} }
@Override @Override
@ -76,61 +96,59 @@ public class PostAdapter extends BaseAdapter {
@Override @Override
public View getView(int position, View convertView, ViewGroup parent) { public View getView(int position, View convertView, ViewGroup parent) {
if (position >= getCount() - 1 && !endOfLine && threadManager.getLoadable().isBoardMode()) { if (position >= getCount() - 1) {
// Try to load more posts onGetBottomView();
threadManager.requestNextData();
} }
if (position >= postList.size()) { switch (getItemViewType(position)) {
if (lastPostCount != postList.size()) { case VIEW_TYPE_ITEM: {
lastPostCount = postList.size(); if (convertView == null || convertView.getTag() == null && (Integer) convertView.getTag() != VIEW_TYPE_ITEM) {
lastViewedTime = Time.get(); convertView = new PostView(context);
} convertView.setTag(VIEW_TYPE_ITEM);
}
PostView postView = (PostView) convertView;
postView.setPost(getItem(position), threadManager);
if (Time.get(lastViewedTime) > 2000L) { return postView;
lastViewedTime = Time.get();
threadManager.bottomPostViewed();
} }
case VIEW_TYPE_STATUS: {
return new StatusView(context);
}
}
return createThreadEndView(); return null;
} else { }
PostView postView = null;
if (position >= 0 && position < postList.size()) { private void onGetBottomView() {
if (convertView != null && convertView instanceof PostView) { if (threadManager.getLoadable().isBoardMode() && !endOfLine) {
postView = (PostView) convertView; // Try to load more posts
} else { threadManager.requestNextData();
postView = new PostView(context); }
}
postView.setPost(postList.get(position), threadManager); if (lastPostCount != postList.size()) {
} lastPostCount = postList.size();
lastViewedTime = Time.get();
}
return postView; if (Time.get(lastViewedTime) > 1000L) {
lastViewedTime = Time.get();
threadManager.bottomPostViewed();
} }
} }
private View createThreadEndView() { private boolean showStatusView() {
if (threadManager.shouldWatch()) { Loadable l = threadManager.getLoadable();
ThreadWatchCounterView view = new ThreadWatchCounterView(context); if (l != null) {
Utils.setPressedDrawable(view); if (l.isBoardMode()) {
view.init(threadManager, listView, this); return true;
int padding = Utils.dp(12f); } else if (l.isThreadMode() && threadManager.shouldWatch()) {
view.setPadding(padding, padding, padding, padding); return true;
int height = Utils.dp(48f);
view.setHeight(height);
view.setGravity(Gravity.CENTER);
return view;
} else {
if (endOfLine) {
TextView textView = new TextView(context);
textView.setText(context.getString(R.string.thread_load_end_of_line));
int padding = Utils.dp(12f);
textView.setPadding(padding, padding, padding, padding);
return textView;
} else { } else {
return new ProgressBar(context); return false;
} }
} else {
return false;
} }
} }
@ -193,4 +211,91 @@ public class PostAdapter extends BaseAdapter {
public String getErrorMessage() { public String getErrorMessage() {
return loadMessage; return loadMessage;
} }
public class StatusView extends LinearLayout {
boolean detached = false;
public StatusView(Context activity) {
super(activity);
init();
}
public StatusView(Context activity, AttributeSet attr) {
super(activity, attr);
init();
}
public StatusView(Context activity, AttributeSet attr, int style) {
super(activity, attr, style);
init();
}
public void init() {
Loader loader = threadManager.getLoader();
if (loader == null)
return;
setGravity(Gravity.CENTER);
if (threadManager.shouldWatch()) {
String error = getErrorMessage();
if (error != null) {
setText(error);
} else {
int time = Math.round(loader.getTimeUntilLoadMore() / 1000f);
if (time == 0) {
setText("Loading");
} else {
setText("Loading in " + time);
}
}
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (!detached) {
notifyDataSetChanged();
}
}
}, 1000);
setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Loader loader = threadManager.getLoader();
if (loader != null) {
loader.requestMoreDataAndResetTimer();
}
notifyDataSetChanged();
}
});
Utils.setPressedDrawable(this);
} else {
if (endOfLine) {
setText(context.getString(R.string.thread_load_end_of_line));
} else {
setProgressBar();
}
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
detached = true;
}
private void setText(String string) {
TextView text = new TextView(context);
text.setText(string);
text.setGravity(Gravity.CENTER);
addView(text, new LayoutParams(LayoutParams.MATCH_PARENT, Utils.dp(48)));
}
private void setProgressBar() {
addView(new ProgressBar(context));
}
}
} }

@ -96,8 +96,8 @@ public class PostRepliesFragment extends DialogFragment {
}); });
if (!ThemeHelper.getInstance().getTheme().isLightTheme) { if (!ThemeHelper.getInstance().getTheme().isLightTheme) {
((TextView)container.findViewById(R.id.replies_back_icon)).setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_action_back_dark, 0, 0, 0); ((TextView) container.findViewById(R.id.replies_back_icon)).setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_action_back_dark, 0, 0, 0);
((TextView)container.findViewById(R.id.replies_close_icon)).setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_action_done_dark, 0, 0, 0); ((TextView) container.findViewById(R.id.replies_close_icon)).setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_action_done_dark, 0, 0, 0);
} }
return container; return container;

@ -32,6 +32,7 @@ import android.widget.Toast;
import org.floens.chan.R; import org.floens.chan.R;
import org.floens.chan.core.ChanPreferences; import org.floens.chan.core.ChanPreferences;
import org.floens.chan.ui.activity.AboutActivity; import org.floens.chan.ui.activity.AboutActivity;
import org.floens.chan.ui.activity.BaseActivity;
import org.floens.chan.ui.activity.SettingsActivity; import org.floens.chan.ui.activity.SettingsActivity;
import org.floens.chan.utils.ThemeHelper; import org.floens.chan.utils.ThemeHelper;
@ -100,12 +101,12 @@ public class SettingsFragment extends PreferenceFragment {
theme.setValue((String) theme.getEntryValues()[0]); theme.setValue((String) theme.getEntryValues()[0]);
currentValue = theme.getValue(); currentValue = theme.getValue();
} }
updateThemeSummary(theme, currentValue); updateSummary(theme, currentValue);
theme.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { theme.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override @Override
public boolean onPreferenceChange(Preference preference, Object newValue) { public boolean onPreferenceChange(Preference preference, Object newValue) {
updateThemeSummary(theme, newValue.toString()); updateSummary(theme, newValue.toString());
// Thanks! https://github.com/CyanogenMod/android_packages_apps_Calculator/blob/cm-10.2/src/com/android/calculator2/view/PreferencesFragment.java // Thanks! https://github.com/CyanogenMod/android_packages_apps_Calculator/blob/cm-10.2/src/com/android/calculator2/view/PreferencesFragment.java
if (!newValue.toString().equals(ThemeHelper.getInstance().getTheme().name)) { if (!newValue.toString().equals(ThemeHelper.getInstance().getTheme().name)) {
@ -121,6 +122,22 @@ public class SettingsFragment extends PreferenceFragment {
return true; return true;
} }
}); });
final ListPreference boardMode = (ListPreference) findPreference("preference_board_mode");
String currentModeValue = boardMode.getValue();
if (currentModeValue == null) {
boardMode.setValue((String) boardMode.getEntryValues()[0]);
currentModeValue = boardMode.getValue();
}
updateSummary(boardMode, currentModeValue);
boardMode.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
updateSummary(boardMode, newValue.toString());
BaseActivity.doRestartOnResume = true;
return true;
}
});
} }
public void onStart() { public void onStart() {
@ -162,7 +179,7 @@ public class SettingsFragment extends PreferenceFragment {
} }
} }
private void updateThemeSummary(ListPreference list, String value) { private void updateSummary(ListPreference list, String value) {
int index = list.findIndexOfValue(value); int index = list.findIndexOfValue(value);
list.setSummary(list.getEntries()[index]); list.setSummary(list.getEntries()[index]);
} }

@ -1,103 +0,0 @@
/*
* Clover - 4chan browser https://github.com/Floens/Clover/
* Copyright (C) 2014 Floens
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.floens.chan.ui.view;
import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AbsListView;
import android.widget.TextView;
import org.floens.chan.core.loader.Loader;
import org.floens.chan.core.manager.ThreadManager;
import org.floens.chan.ui.adapter.PostAdapter;
public class ThreadWatchCounterView extends TextView implements View.OnClickListener {
private boolean detached = false;
private ThreadManager tm;
private PostAdapter ad;
public ThreadWatchCounterView(Context activity) {
super(activity);
}
public ThreadWatchCounterView(Context activity, AttributeSet attbs) {
super(activity, attbs);
}
public ThreadWatchCounterView(Context activity, AttributeSet attbs, int style) {
super(activity, attbs, style);
}
public void init(final ThreadManager threadManager, final AbsListView listView, final PostAdapter adapter) {
tm = threadManager;
ad = adapter;
updateCounterText(threadManager);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (!detached) {
adapter.notifyDataSetChanged();
}
}
}, 1000);
setOnClickListener(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
setOnClickListener(null);
detached = true;
}
@Override
public void onClick(View v) {
Loader loader = tm.getLoader();
if (loader != null) {
loader.requestMoreDataAndResetTimer();
}
ad.notifyDataSetChanged();
}
private void updateCounterText(ThreadManager threadManager) {
Loader loader = tm.getLoader();
if (loader == null)
return;
int time = Math.round(loader.getTimeUntilLoadMore() / 1000f);
String error = ad.getErrorMessage();
if (error != null) {
setText(error);
} else {
if (time == 0) {
setText("Loading");
} else {
setText("Loading in " + time);
}
}
}
}

@ -141,6 +141,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<item>black</item> <item>black</item>
</string-array> </string-array>
<string name="preference_board_mode">Board mode</string>
<string-array name="preference_board_modes">
<item>Catalog</item>
<item>Paginated</item>
</string-array>
<string-array name="preference_board_modes_values">
<item>catalog</item>
<item>pages</item>
</string-array>
<string name="preference_open_link_confirmation">Ask before opening links</string> <string name="preference_open_link_confirmation">Ask before opening links</string>
<string name="preference_autoplay">Start playing videos immediately</string> <string name="preference_autoplay">Start playing videos immediately</string>
<string name="preference_auto_refresh_thread">Auto refresh threads</string> <string name="preference_auto_refresh_thread">Auto refresh threads</string>

@ -52,6 +52,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
android:entryValues="@array/preference_themes_values" android:entryValues="@array/preference_themes_values"
android:title="@string/preference_theme"/> android:title="@string/preference_theme"/>
<ListPreference
android:key="preference_board_mode"
android:defaultValue="catalog"
android:dialogTitle="@string/preference_board_mode"
android:entries="@array/preference_board_modes"
android:entryValues="@array/preference_board_modes_values"
android:title="@string/preference_board_mode" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="true" android:defaultValue="true"
android:key="preference_open_link_confirmation" android:key="preference_open_link_confirmation"

Loading…
Cancel
Save