Some watch & pass settings

tempwork
Floens 10 years ago
parent d2eb9f6e51
commit 404720292a
  1. 9
      Clover/app/src/main/java/org/floens/chan/controller/NavigationController.java
  2. 70
      Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java
  3. 27
      Clover/app/src/main/java/org/floens/chan/ui/controller/MainSettingsController.java
  4. 153
      Clover/app/src/main/java/org/floens/chan/ui/controller/PassSettingsController.java
  5. 65
      Clover/app/src/main/java/org/floens/chan/ui/controller/WatchSettingsController.java
  6. 1
      Clover/app/src/main/java/org/floens/chan/ui/preferences/SettingView.java
  7. 18
      Clover/app/src/main/java/org/floens/chan/ui/preferences/SettingsController.java
  8. 2
      Clover/app/src/main/java/org/floens/chan/ui/toolbar/NavigationItem.java
  9. 5
      Clover/app/src/main/java/org/floens/chan/ui/toolbar/Toolbar.java
  10. 87
      Clover/app/src/main/java/org/floens/chan/ui/view/CrossfadeView.java
  11. 47
      Clover/app/src/main/java/org/floens/chan/utils/AndroidUtils.java
  12. 56
      Clover/app/src/main/java/org/floens/chan/utils/AnimationUtils.java
  13. 84
      Clover/app/src/main/res/layout/settings_pass.xml
  14. 24
      Clover/app/src/main/res/layout/settings_watch.xml
  15. 2
      Clover/app/src/main/res/layout/toolbar_menu.xml
  16. 22
      Clover/app/src/main/res/values/strings.xml

@ -104,6 +104,15 @@ public abstract class NavigationController extends Controller implements Control
return true; return true;
} }
public Controller getPreviousSibling(Controller controller) {
int index = controllerList.indexOf(controller);
if (index > 0) {
return controllerList.get(index - 1);
} else {
return null;
}
}
@Override @Override
public void onControllerTransitionCompleted() { public void onControllerTransitionCompleted() {
if (controllerTransition instanceof PushControllerTransition) { if (controllerTransition instanceof PushControllerTransition) {

@ -26,34 +26,39 @@ import org.floens.chan.utils.AndroidUtils;
import java.io.File; import java.io.File;
public class ChanSettings { public class ChanSettings {
public static StringSetting theme; public static final StringSetting theme;
public static StringSetting fontSize; public static final StringSetting fontSize;
public static BooleanSetting openLinkConfirmation; public static final BooleanSetting openLinkConfirmation;
public static BooleanSetting autoRefreshThread; public static final BooleanSetting autoRefreshThread;
public static BooleanSetting imageAutoLoad; public static final BooleanSetting imageAutoLoad;
public static BooleanSetting videoAutoLoad; public static final BooleanSetting videoAutoLoad;
public static BooleanSetting videoOpenExternal; public static final BooleanSetting videoOpenExternal;
public static StringSetting postDefaultName; public static final StringSetting postDefaultName;
public static BooleanSetting postPinThread; public static final BooleanSetting postPinThread;
public static BooleanSetting developer; public static final BooleanSetting developer;
public static StringSetting saveLocation; public static final StringSetting saveLocation;
public static BooleanSetting saveOriginalFilename; public static final BooleanSetting saveOriginalFilename;
public static BooleanSetting shareUrl; public static final BooleanSetting shareUrl;
public static BooleanSetting networkHttps; public static final BooleanSetting networkHttps;
public static BooleanSetting forcePhoneLayout; public static final BooleanSetting forcePhoneLayout;
public static BooleanSetting anonymize; public static final BooleanSetting anonymize;
public static BooleanSetting anonymizeIds; public static final BooleanSetting anonymizeIds;
public static BooleanSetting repliesButtonsBottom; public static final BooleanSetting repliesButtonsBottom;
public static BooleanSetting watchCountdown; public static final BooleanSetting watchEnabled;
public static BooleanSetting watchBackground; public static final BooleanSetting watchCountdown;
public static StringSetting watchBackgroundTimeout; public static final BooleanSetting watchBackground;
public static StringSetting watchNotifyMode; public static final StringSetting watchBackgroundTimeout;
public static StringSetting watchSound; public static final StringSetting watchNotifyMode;
public static StringSetting watchLed; public static final StringSetting watchSound;
public static final StringSetting watchLed;
public static final StringSetting passToken;
public static final StringSetting passPin;
public static final StringSetting passId;
static { static {
SharedPreferences p = AndroidUtils.getPreferences(); SharedPreferences p = AndroidUtils.getPreferences();
@ -80,18 +85,27 @@ public class ChanSettings {
anonymizeIds = new BooleanSetting(p, "preference_anonymize_ids", false); anonymizeIds = new BooleanSetting(p, "preference_anonymize_ids", false);
repliesButtonsBottom = new BooleanSetting(p, "preference_buttons_bottom", false); repliesButtonsBottom = new BooleanSetting(p, "preference_buttons_bottom", false);
watchEnabled = new BooleanSetting(p, "preference_watch_enabled", false);
watchCountdown = new BooleanSetting(p, "preference_watch_countdown", false); 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);
watchBackgroundTimeout = new StringSetting(p, "preference_watch_background_timeout", "60"); watchBackgroundTimeout = new StringSetting(p, "preference_watch_background_timeout", "60");
watchNotifyMode = new StringSetting(p, "preference_watch_notify_mode", "all"); watchNotifyMode = new StringSetting(p, "preference_watch_notify_mode", "all");
watchSound = new StringSetting(p, "preference_watch_sound", "all"); watchSound = new StringSetting(p, "preference_watch_sound", "all");
watchLed = new StringSetting(p, "preference_watch_led", "ffffffff"); watchLed = new StringSetting(p, "preference_watch_led", "ffffffff");
passToken = new StringSetting(p, "preference_pass_token", "");
passPin = new StringSetting(p, "preference_pass_pin", "");
passId = new StringSetting(p, "preference_pass_id", "");
} }
private static SharedPreferences p() { private static SharedPreferences p() {
return AndroidUtils.getPreferences(); return AndroidUtils.getPreferences();
} }
public static boolean passLoggedIn() {
return passId.get().length() > 0;
}
public static boolean getOpenLinkConfirmation() { public static boolean getOpenLinkConfirmation() {
return p().getBoolean("preference_open_link_confirmation", true); return p().getBoolean("preference_open_link_confirmation", true);
} }

@ -35,17 +35,19 @@ import org.floens.chan.ui.preferences.StringSettingView;
import org.floens.chan.ui.toolbar.ToolbarMenu; import org.floens.chan.ui.toolbar.ToolbarMenu;
import org.floens.chan.ui.toolbar.ToolbarMenuItem; import org.floens.chan.ui.toolbar.ToolbarMenuItem;
import org.floens.chan.ui.view.FloatingMenuItem; import org.floens.chan.ui.view.FloatingMenuItem;
import org.floens.chan.utils.AndroidUtils; import org.floens.chan.utils.AnimationUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
public class MainSettingsController extends SettingsController implements ToolbarMenuItem.ToolbarMenuItemCallback { public class MainSettingsController extends SettingsController implements ToolbarMenuItem.ToolbarMenuItemCallback, WatchSettingsController.WatchSettingControllerListener, PassSettingsController.PassSettingControllerListener {
private static final int ADVANCED_SETTINGS = 1; private static final int ADVANCED_SETTINGS = 1;
private SettingView imageAutoLoadView; private SettingView imageAutoLoadView;
private SettingView videoAutoLoadView; private SettingView videoAutoLoadView;
private LinkSettingView watchLink;
private LinkSettingView passLink;
private int clickCount; private int clickCount;
private SettingView developerView; private SettingView developerView;
@ -68,6 +70,9 @@ public class MainSettingsController extends SettingsController implements Toolba
populatePreferences(); populatePreferences();
onWatchEnabledChanged(ChanSettings.watchEnabled.get());
onPassEnabledChanged(ChanSettings.passLoggedIn());
buildPreferences(); buildPreferences();
onPreferenceChange(imageAutoLoadView); onPreferenceChange(imageAutoLoadView);
@ -97,6 +102,16 @@ public class MainSettingsController extends SettingsController implements Toolba
} }
} }
@Override
public void onWatchEnabledChanged(boolean enabled) {
watchLink.setDescription(s(enabled ? R.string.setting_watch_summary_enabled : R.string.setting_watch_summary_disabled));
}
@Override
public void onPassEnabledChanged(boolean enabled) {
passLink.setDescription(s(enabled ? R.string.setting_pass_summary_enabled : R.string.setting_pass_summary_disabled));
}
private void populatePreferences() { private void populatePreferences() {
// General group // General group
SettingsGroup general = new SettingsGroup(s(R.string.settings_group_general)); SettingsGroup general = new SettingsGroup(s(R.string.settings_group_general));
@ -107,17 +122,17 @@ public class MainSettingsController extends SettingsController implements Toolba
} }
})); }));
general.add(new LinkSettingView(this, s(R.string.settings_watch), null, new View.OnClickListener() { watchLink = (LinkSettingView) general.add(new LinkSettingView(this, s(R.string.settings_watch), null, new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
navigationController.pushController(new WatchSettingsController(context)); navigationController.pushController(new WatchSettingsController(context));
} }
})); }));
general.add(new LinkSettingView(this, s(R.string.settings_pass), null, new View.OnClickListener() { passLink = (LinkSettingView) general.add(new LinkSettingView(this, s(R.string.settings_pass), null, new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
navigationController.pushController(new PassSettingsController(context));
} }
})); }));
@ -181,7 +196,7 @@ public class MainSettingsController extends SettingsController implements Toolba
Toast.makeText(context, (developer ? "Enabled" : "Disabled") + " developer options", Toast.LENGTH_LONG).show(); Toast.makeText(context, (developer ? "Enabled" : "Disabled") + " developer options", Toast.LENGTH_LONG).show();
AndroidUtils.animateHeight(developerView.view, developer); AnimationUtils.animateHeight(developerView.view, developer);
} }
} }
})); }));

@ -0,0 +1,153 @@
package org.floens.chan.ui.controller;
import android.app.AlertDialog;
import android.content.Context;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.floens.chan.ChanApplication;
import org.floens.chan.R;
import org.floens.chan.controller.Controller;
import org.floens.chan.core.manager.ReplyManager;
import org.floens.chan.core.model.Pass;
import org.floens.chan.core.settings.ChanSettings;
import org.floens.chan.ui.view.CrossfadeView;
import org.floens.chan.utils.AndroidUtils;
import org.floens.chan.utils.AnimationUtils;
public class PassSettingsController extends Controller implements View.OnClickListener {
private LinearLayout container;
private CrossfadeView crossfadeView;
private TextView errors;
private Button button;
private TextView bottomDescription;
private EditText inputToken;
private EditText inputPin;
private TextView authenticated;
public PassSettingsController(Context context) {
super(context);
}
@Override
public void onCreate() {
super.onCreate();
navigationItem.title = string(R.string.settings_screen_pass);
view = inflateRes(R.layout.settings_pass);
container = (LinearLayout) view.findViewById(R.id.container);
crossfadeView = (CrossfadeView) view.findViewById(R.id.crossfade);
errors = (TextView) view.findViewById(R.id.errors);
button = (Button) view.findViewById(R.id.button);
bottomDescription = (TextView) view.findViewById(R.id.bottom_description);
inputToken = (EditText) view.findViewById(R.id.input_token);
inputPin = (EditText) view.findViewById(R.id.input_pin);
authenticated = (TextView) view.findViewById(R.id.authenticated);
AnimationUtils.setHeight(errors, false, false);
final boolean loggedIn = loggedIn();
button.setText(loggedIn ? R.string.setting_pass_logout : R.string.setting_pass_login);
button.setOnClickListener(this);
bottomDescription.setText(Html.fromHtml(string(R.string.setting_pass_bottom_description)));
bottomDescription.setMovementMethod(LinkMovementMethod.getInstance());
inputToken.setText(ChanSettings.passToken.get());
inputPin.setText(ChanSettings.passPin.get());
AndroidUtils.waitForLayout(view, new AndroidUtils.OnMeasuredCallback() {
@Override
public void onMeasured(View view) {
crossfadeView.getLayoutParams().height = crossfadeView.getHeight();
crossfadeView.requestLayout();
crossfadeView.toggle(!loggedIn, false);
}
});
}
@Override
public void onClick(View v) {
if (v == button) {
if (loggedIn()) {
ChanSettings.passId.set("");
crossfadeView.toggle(true, true);
button.setText(R.string.setting_pass_login);
hideError();
((PassSettingControllerListener) navigationController.getPreviousSibling(PassSettingsController.this)).onPassEnabledChanged(false);
} else {
auth();
}
}
}
private void auth() {
AndroidUtils.hideKeyboard(view);
inputToken.setEnabled(false);
inputPin.setEnabled(false);
button.setEnabled(false);
button.setText(R.string.setting_pass_logging_in);
hideError();
ChanSettings.passToken.set(inputToken.getText().toString());
ChanSettings.passPin.set(inputPin.getText().toString());
ChanApplication.getReplyManager().sendPass(new Pass(ChanSettings.passToken.get(), ChanSettings.passPin.get()), new ReplyManager.PassListener() {
@Override
public void onResponse(ReplyManager.PassResponse response) {
if (response.isError) {
if (response.unknownError) {
WebView webView = new WebView(context);
WebSettings settings = webView.getSettings();
settings.setSupportZoom(true);
webView.loadData(response.responseData, "text/html", null);
new AlertDialog.Builder(context)
.setView(webView)
.setNeutralButton(R.string.ok, null)
.show();
} else {
showError(response.message);
}
button.setText(R.string.setting_pass_login);
} else {
crossfadeView.toggle(false, true);
button.setText(R.string.setting_pass_logout);
ChanSettings.passId.set(response.passId);
authenticated.setText(response.message);
((PassSettingControllerListener) navigationController.getPreviousSibling(PassSettingsController.this)).onPassEnabledChanged(true);
}
button.setEnabled(true);
inputToken.setEnabled(true);
inputPin.setEnabled(true);
}
});
}
private void showError(String error) {
errors.setText(error);
AnimationUtils.setHeight(errors, true, true, container.getWidth());
}
private void hideError() {
errors.setText(null);
AnimationUtils.setHeight(errors, false, true, container.getHeight());
}
private boolean loggedIn() {
return ChanSettings.passId.get().length() > 0;
}
public interface PassSettingControllerListener {
public void onPassEnabledChanged(boolean enabled);
}
}

@ -1,7 +1,8 @@
package org.floens.chan.ui.controller; package org.floens.chan.ui.controller;
import android.content.Context; import android.content.Context;
import android.view.View; import android.support.v7.widget.SwitchCompat;
import android.widget.CompoundButton;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import org.floens.chan.R; import org.floens.chan.R;
@ -11,33 +12,58 @@ import org.floens.chan.ui.preferences.ListSettingView;
import org.floens.chan.ui.preferences.SettingView; import org.floens.chan.ui.preferences.SettingView;
import org.floens.chan.ui.preferences.SettingsController; import org.floens.chan.ui.preferences.SettingsController;
import org.floens.chan.ui.preferences.SettingsGroup; import org.floens.chan.ui.preferences.SettingsGroup;
import org.floens.chan.utils.AndroidUtils; import org.floens.chan.ui.view.CrossfadeView;
public class WatchSettingsController extends SettingsController { public class WatchSettingsController extends SettingsController implements CompoundButton.OnCheckedChangeListener {
public WatchSettingsController(Context context) { private CrossfadeView crossfadeView;
super(context);
}
private SettingView enableBackground; private SettingView enableBackground;
private SettingView backgroundTimeout; private SettingView backgroundTimeout;
private SettingView notifyMode; private SettingView notifyMode;
private SettingView soundMode; private SettingView soundMode;
private SettingView ledMode; private SettingView ledMode;
public WatchSettingsController(Context context) {
super(context);
}
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
navigationItem.title = string(R.string.settings_screen_advanced); boolean enabled = ChanSettings.watchEnabled.get();
navigationItem.title = string(R.string.settings_screen_watch);
view = inflateRes(R.layout.settings_layout); view = inflateRes(R.layout.settings_watch);
content = (LinearLayout) view.findViewById(R.id.scrollview_content); content = (LinearLayout) view.findViewById(R.id.scrollview_content);
crossfadeView = (CrossfadeView) view.findViewById(R.id.crossfade);
crossfadeView.toggle(enabled, false);
SwitchCompat globalSwitch = new SwitchCompat(context);
globalSwitch.setChecked(enabled);
globalSwitch.setOnCheckedChangeListener(this);
navigationItem.rightView = globalSwitch;
populatePreferences(); populatePreferences();
buildPreferences(); buildPreferences();
setEnabledHeights(); if (!ChanSettings.watchBackground.get()) {
setSettingViewVisibility(backgroundTimeout, false, false);
setSettingViewVisibility(notifyMode, false, false);
setSettingViewVisibility(soundMode, false, false);
setSettingViewVisibility(ledMode, false, false);
}
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
ChanSettings.watchEnabled.set(isChecked);
((WatchSettingControllerListener) navigationController.getPreviousSibling(this)).onWatchEnabledChanged(isChecked);
crossfadeView.toggle(isChecked, true);
} }
@Override @Override
@ -46,19 +72,10 @@ public class WatchSettingsController extends SettingsController {
if (item == enableBackground) { if (item == enableBackground) {
boolean enabled = ChanSettings.watchBackground.get(); boolean enabled = ChanSettings.watchBackground.get();
AndroidUtils.animateHeight(backgroundTimeout.view, enabled); setSettingViewVisibility(backgroundTimeout, enabled, true);
AndroidUtils.animateHeight(notifyMode.view, enabled); setSettingViewVisibility(notifyMode, enabled, true);
AndroidUtils.animateHeight(soundMode.view, enabled); setSettingViewVisibility(soundMode, enabled, true);
AndroidUtils.animateHeight(ledMode.view, enabled); setSettingViewVisibility(ledMode, enabled, true);
}
}
private void setEnabledHeights() {
if (!ChanSettings.watchBackground.get()) {
backgroundTimeout.view.setVisibility(View.GONE);
notifyMode.view.setVisibility(View.GONE);
soundMode.view.setVisibility(View.GONE);
ledMode.view.setVisibility(View.GONE);
} }
} }
@ -88,4 +105,8 @@ public class WatchSettingsController extends SettingsController {
groups.add(settings); groups.add(settings);
} }
public interface WatchSettingControllerListener {
public void onWatchEnabledChanged(boolean enabled);
}
} }

@ -6,6 +6,7 @@ public abstract class SettingView {
public SettingsController settingsController; public SettingsController settingsController;
public final String name; public final String name;
public View view; public View view;
public View divider;
public SettingView(SettingsController settingsController, String name) { public SettingView(SettingsController settingsController, String name) {
this.settingsController = settingsController; this.settingsController = settingsController;

@ -11,6 +11,7 @@ import android.widget.TextView;
import org.floens.chan.R; import org.floens.chan.R;
import org.floens.chan.controller.Controller; import org.floens.chan.controller.Controller;
import org.floens.chan.utils.AndroidUtils; import org.floens.chan.utils.AndroidUtils;
import org.floens.chan.utils.AnimationUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -78,6 +79,18 @@ public class SettingsController extends Controller implements AndroidUtils.OnMea
} }
} }
protected void setSettingViewVisibility(SettingView settingView, boolean visible, boolean animated) {
if (animated) {
AnimationUtils.animateHeight(settingView.view, visible);
} else {
settingView.view.setVisibility(visible ? View.VISIBLE : View.GONE);
}
if (settingView.divider != null) {
settingView.divider.setVisibility(visible ? View.VISIBLE : View.GONE);
}
}
protected void buildPreferences() { protected void buildPreferences() {
LayoutInflater inf = LayoutInflater.from(context); LayoutInflater inf = LayoutInflater.from(context);
boolean firstGroup = true; boolean firstGroup = true;
@ -112,7 +125,8 @@ public class SettingsController extends Controller implements AndroidUtils.OnMea
settingView.setView(preferenceView); settingView.setView(preferenceView);
if (i < group.settingViews.size() - 1) { if (i < group.settingViews.size() - 1) {
inf.inflate(R.layout.setting_divider, groupLayout, true); settingView.divider = inf.inflate(R.layout.setting_divider, groupLayout, false);
groupLayout.addView(settingView.divider);
} }
} }
} }
@ -130,7 +144,7 @@ public class SettingsController extends Controller implements AndroidUtils.OnMea
bottom.setText(bottomText); bottom.setText(bottomText);
} }
AndroidUtils.animateHeight(bottom, bottomText != null); AnimationUtils.animateHeight(bottom, bottomText != null);
} else { } else {
bottom.setText(bottomText); bottom.setText(bottomText);
bottom.setVisibility(bottomText == null ? View.GONE : View.VISIBLE); bottom.setVisibility(bottomText == null ? View.GONE : View.VISIBLE);

@ -18,6 +18,7 @@
package org.floens.chan.ui.toolbar; package org.floens.chan.ui.toolbar;
import android.content.Context; import android.content.Context;
import android.view.View;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import org.floens.chan.ui.view.FloatingMenu; import org.floens.chan.ui.view.FloatingMenu;
@ -31,6 +32,7 @@ public class NavigationItem {
public boolean hasBack = true; public boolean hasBack = true;
public LinearLayout view; public LinearLayout view;
public FloatingMenu middleMenu; public FloatingMenu middleMenu;
public View rightView;
public FloatingMenu createOverflow(Context context, ToolbarMenuItem.ToolbarMenuItemCallback callback, List<FloatingMenuItem> items) { public FloatingMenu createOverflow(Context context, ToolbarMenuItem.ToolbarMenuItemCallback callback, List<FloatingMenuItem> items) {
ToolbarMenuItem overflow = menu.createOverflow(callback); ToolbarMenuItem overflow = menu.createOverflow(callback);

@ -244,6 +244,11 @@ public class Toolbar extends LinearLayout implements View.OnClickListener {
wrapper.addView(item.menu, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)); wrapper.addView(item.menu, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
} }
if (item.rightView != null) {
item.rightView.setPadding(0, 0, dp(16), 0);
wrapper.addView(item.rightView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
}
AndroidUtils.waitForMeasure(titleView, new AndroidUtils.OnMeasuredCallback() { AndroidUtils.waitForMeasure(titleView, new AndroidUtils.OnMeasuredCallback() {
@Override @Override
public void onMeasured(View view) { public void onMeasured(View view) {

@ -0,0 +1,87 @@
package org.floens.chan.ui.view;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
public class CrossfadeView extends FrameLayout {
private int fadeDuration = 200;
private View viewOne;
private View viewTwo;
private boolean inited = false;
private boolean viewOneSelected = true;
public CrossfadeView(Context context) {
super(context);
}
public CrossfadeView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CrossfadeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
viewOne = getChildAt(0);
viewTwo = getChildAt(1);
}
public void toggle(boolean viewOneSelected, boolean animated) {
if (!inited || this.viewOneSelected != viewOneSelected) {
this.viewOneSelected = viewOneSelected;
doToggle(animated);
}
}
public void toggle(boolean animated) {
viewOneSelected = !viewOneSelected;
doToggle(animated);
}
private void doToggle(boolean animated) {
inited = true;
if (animated) {
if (viewOneSelected) {
viewOne.setVisibility(View.VISIBLE);
viewOne.animate().alpha(1f).setDuration(fadeDuration).setListener(null);
viewTwo.animate().alpha(0f).setDuration(fadeDuration).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
viewOne.setVisibility(View.VISIBLE);
viewTwo.setVisibility(View.GONE);
}
});
} else {
viewTwo.setVisibility(View.VISIBLE);
viewTwo.animate().alpha(1f).setDuration(fadeDuration).setListener(null);
viewOne.animate().alpha(0f).setDuration(fadeDuration).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
viewOne.setVisibility(View.GONE);
viewTwo.setVisibility(View.VISIBLE);
}
});
}
} else {
if (viewOneSelected) {
viewOne.setVisibility(View.VISIBLE);
viewOne.setAlpha(1f);
viewTwo.setVisibility(View.GONE);
viewTwo.setAlpha(0f);
} else {
viewOne.setVisibility(View.GONE);
viewOne.setAlpha(0f);
viewTwo.setVisibility(View.VISIBLE);
viewTwo.setAlpha(1f);
}
}
}
}

@ -34,13 +34,11 @@ import android.util.Log;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewTreeObserver; import android.view.ViewTreeObserver;
import android.view.animation.Animation;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.widget.Toast; import android.widget.Toast;
import org.floens.chan.ChanApplication; import org.floens.chan.ChanApplication;
import org.floens.chan.R; import org.floens.chan.R;
import org.floens.chan.ui.animation.HeightAnimation;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -143,13 +141,17 @@ public class AndroidUtils {
dialog.setOnShowListener(new DialogInterface.OnShowListener() { dialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override @Override
public void onShow(DialogInterface dialog) { public void onShow(DialogInterface dialog) {
InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService( InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService( Context.INPUT_METHOD_SERVICE);
Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(view, 0); imm.showSoftInput(view, 0);
} }
}); });
} }
public static void hideKeyboard(View view) {
InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
public static String getReadableFileSize(int bytes, boolean si) { public static String getReadableFileSize(int bytes, boolean si) {
int unit = si ? 1000 : 1024; int unit = si ? 1000 : 1024;
if (bytes < unit) if (bytes < unit)
@ -184,11 +186,11 @@ public class AndroidUtils {
waitForMeasure(false, view, callback); waitForMeasure(false, view, callback);
} }
private static void waitForMeasure(boolean returnIfZero, final View view, final OnMeasuredCallback callback) { private static void waitForMeasure(boolean returnIfNotZero, final View view, final OnMeasuredCallback callback) {
int width = view.getWidth(); int width = view.getWidth();
int height = view.getHeight(); int height = view.getHeight();
if (returnIfZero && width > 0 && height > 0) { if (returnIfNotZero && width > 0 && height > 0) {
callback.onMeasured(view); callback.onMeasured(view);
} else { } else {
view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@ -237,37 +239,4 @@ public class AndroidUtils {
return views; return views;
} }
public static void animateHeight(final View view, boolean expand) {
if (view.getAnimation() == null && ((view.getHeight() > 0 && expand) || (view.getHeight() == 0 && !expand))) {
return;
}
view.clearAnimation();
HeightAnimation heightAnimation;
if (expand) {
view.measure(
View.MeasureSpec.makeMeasureSpec(view.getWidth(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
heightAnimation = new HeightAnimation(view, 0, view.getMeasuredHeight(), 300);
} else {
heightAnimation = new HeightAnimation(view, view.getHeight(), 0, 300);
}
view.startAnimation(heightAnimation);
view.getAnimation().setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
view.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationEnd(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
} }

@ -20,8 +20,12 @@ package org.floens.chan.utils;
import android.graphics.Matrix; import android.graphics.Matrix;
import android.graphics.Point; import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.view.View;
import android.view.animation.Animation;
import android.widget.ImageView; import android.widget.ImageView;
import org.floens.chan.ui.animation.HeightAnimation;
public class AnimationUtils { public class AnimationUtils {
/** /**
* On your start view call startView.getGlobalVisibleRect(startBounds) * On your start view call startView.getGlobalVisibleRect(startBounds)
@ -65,4 +69,56 @@ public class AnimationUtils {
bounds.right = (bounds.left + (int) (imageView.getDrawable().getIntrinsicWidth() * f[Matrix.MSCALE_X])); bounds.right = (bounds.left + (int) (imageView.getDrawable().getIntrinsicWidth() * f[Matrix.MSCALE_X]));
bounds.bottom = (bounds.top + (int) (imageView.getDrawable().getIntrinsicHeight() * f[Matrix.MSCALE_Y])); bounds.bottom = (bounds.top + (int) (imageView.getDrawable().getIntrinsicHeight() * f[Matrix.MSCALE_Y]));
} }
public static void setHeight(View view, boolean expand, boolean animated) {
setHeight(view, expand, animated, -1);
}
public static void setHeight(View view, boolean expand, boolean animated, int knownWidth) {
if (animated) {
animateHeight(view, expand, knownWidth);
} else {
view.setVisibility(expand ? View.VISIBLE : View.GONE);
}
}
public static void animateHeight(final View view, boolean expand) {
animateHeight(view, expand, -1);
}
public static void animateHeight(final View view, boolean expand, int knownWidth) {
if (view.getAnimation() == null && ((view.getHeight() > 0 && expand) || (view.getHeight() == 0 && !expand))) {
return;
}
view.clearAnimation();
HeightAnimation heightAnimation;
if (expand) {
int width = knownWidth < 0 ? view.getWidth() : knownWidth;
view.measure(
View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
View.MeasureSpec.UNSPECIFIED);
heightAnimation = new HeightAnimation(view, 0, view.getMeasuredHeight(), 300);
} else {
heightAnimation = new HeightAnimation(view, view.getHeight(), 0, 300);
}
view.startAnimation(heightAnimation);
view.getAnimation().setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
view.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationEnd(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
} }

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffffff">
<LinearLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="32dp"
android:paddingLeft="32dp"
android:paddingRight="32dp"
android:paddingBottom="32dp"
android:orientation="vertical">
<TextView
android:id="@+id/errors"
android:textColor="#fff44336"
android:textSize="16sp"
android:paddingTop="8dp"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:paddingBottom="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<org.floens.chan.ui.view.CrossfadeView
android:id="@+id/crossfade"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
android:id="@+id/input_token"
android:inputType="text"
android:imeOptions="actionNext"
android:hint="@string/setting_pass_token"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/input_pin"
android:inputType="numberPassword"
android:imeOptions="actionDone"
android:hint="@string/setting_pass_pin"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<TextView
android:id="@+id/authenticated"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textColor="#dd000000"
android:textSize="20sp"
android:text="@string/setting_pass_authenticated" />
</org.floens.chan.ui.view.CrossfadeView>
<Button
android:id="@+id/button"
android:layout_width="130dp"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/bottom_description"
android:textColor="#dd000000"
android:textSize="14sp"
android:paddingTop="16dp"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<org.floens.chan.ui.view.CrossfadeView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/crossfade"
android:background="#ffe5e5e5">
<include layout="@layout/settings_layout" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp">
<TextView
style="?android:attr/textAppearanceMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="@string/setting_watch_info" />
</FrameLayout>
</org.floens.chan.ui.view.CrossfadeView>

@ -30,4 +30,6 @@
<!-- menu inserted here <!-- menu inserted here
TODO: make this layout relative and make a ViewStub but with programatically added views --> TODO: make this layout relative and make a ViewStub but with programatically added views -->
<!-- rightView inserted here -->
</LinearLayout> </LinearLayout>

@ -201,6 +201,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<string name="settings_screen_watch">Watcher settings</string> <string name="settings_screen_watch">Watcher settings</string>
<string name="settings_group_watch">Watcher settings</string> <string name="settings_group_watch">Watcher settings</string>
<string name="setting_watch_info">To watch pins for new posts, turn the thread watcher on.</string>
<string name="setting_watch_summary_enabled">Watching pinned threads</string>
<string name="setting_watch_summary_disabled">Off</string>
<string name="setting_watch_countdown">Show countdown</string> <string name="setting_watch_countdown">Show countdown</string>
<string name="setting_watch_countdown_description">Show a countdown left of the new post counter</string> <string name="setting_watch_countdown_description">Show a countdown left of the new post counter</string>
<string name="setting_watch_enable_background">Enable in the background</string> <string name="setting_watch_enable_background">Enable in the background</string>
@ -228,8 +231,23 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<item>Purple</item> <item>Purple</item>
</string-array> </string-array>
<string name="settings_screen_pass">4chan pass</string>
<string name="setting_pass_token">Token</string>
<string name="setting_pass_pin">PIN</string>
<string name="setting_pass_authenticated">Device authorized!</string>
<string name="setting_pass_login">Submit</string>
<string name="setting_pass_logout">Logout</string>
<string name="setting_pass_logging_in">Loading&#8230;</string>
<string name="setting_pass_authenticate_success">Success! Your device is now authorized.</string>
<string name="setting_pass_bottom_description">
"Forgot your 4chan Pass login details?&lt;br>
&lt;a href=\"https://www.4chan.org/pass?reset\">Go here to reset your PIN.&lt;/a>&lt;&lt;br>
&lt;br>
Don't have a 4chan Pass?&lt;br>
&lt;a href=\"https://www.4chan.org/pass\">Click here to learn more.&lt;/a>"
</string>
<string name="setting_pass_summary_enabled">Using 4chan pass</string>
<string name="setting_pass_summary_disabled">Off</string>
<string name="preference_board_edit">Edit boards</string> <string name="preference_board_edit">Edit boards</string>
<string name="preference_board_edit_summary">Add or remove boards</string> <string name="preference_board_edit_summary">Add or remove boards</string>

Loading…
Cancel
Save