developing chameleon theme library - this library will be released in Apache license later
This commit is contained in:
parent
ebc79bf6a2
commit
983bd4cb70
|
@ -0,0 +1 @@
|
|||
/build
|
|
@ -0,0 +1,34 @@
|
|||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 25
|
||||
buildToolsVersion "25.0.2"
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 25
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
compile 'com.android.support:appcompat-v7:25.1.0'
|
||||
compile 'com.android.support:design:25.1.0'
|
||||
|
||||
testCompile 'junit:junit:4.12'
|
||||
|
||||
androidTestCompile "com.android.support:support-annotations:$android_support_lib_version"
|
||||
androidTestCompile 'com.android.support.test:runner:0.5'
|
||||
androidTestCompile 'com.android.support.test:rules:0.5'
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /Users/mariotaku/Library/Android/sdk/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
|
@ -0,0 +1,26 @@
|
|||
package org.mariotaku.chameleon;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumentation test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() throws Exception {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
assertEquals("org.mariotaku.chameleon.test", appContext.getPackageName());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="org.mariotaku.chameleon"/>
|
|
@ -0,0 +1,205 @@
|
|||
package org.mariotaku.chameleon;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.util.ArrayMap;
|
||||
import android.support.v4.view.LayoutInflaterCompat;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.app.AppCompatDelegate;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.mariotaku.chameleon.internal.ChameleonInflationFactory;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2016/12/18.
|
||||
*/
|
||||
|
||||
public class Chameleon {
|
||||
|
||||
private final Activity activity;
|
||||
private final Theme theme;
|
||||
private final ArrayMap<ChameleonView, ChameleonView.Appearance> postApplyViews;
|
||||
|
||||
private Chameleon(Activity activity) {
|
||||
this.activity = activity;
|
||||
this.theme = getOverrideTheme(activity, activity);
|
||||
this.postApplyViews = new ArrayMap<>();
|
||||
}
|
||||
|
||||
public static Chameleon getInstance(Activity activity) {
|
||||
return new Chameleon(activity);
|
||||
}
|
||||
|
||||
public void preApply() {
|
||||
|
||||
final LayoutInflater inflater = activity.getLayoutInflater();
|
||||
AppCompatDelegate delegate = null;
|
||||
if (activity instanceof AppCompatActivity) {
|
||||
delegate = ((AppCompatActivity) activity).getDelegate();
|
||||
}
|
||||
final ChameleonInflationFactory factory = new ChameleonInflationFactory(inflater, activity,
|
||||
delegate, theme, postApplyViews);
|
||||
LayoutInflaterCompat.setFactory(inflater, factory);
|
||||
}
|
||||
|
||||
public void postApply() {
|
||||
for (int i = 0, j = postApplyViews.size(); i < j; i++) {
|
||||
postApplyViews.keyAt(i).applyAppearance(postApplyViews.valueAt(i));
|
||||
}
|
||||
postApplyViews.clear();
|
||||
|
||||
boolean statusBarColorHandled = false;
|
||||
final View rootView = getRootView();
|
||||
if (rootView instanceof ChameleonView.StatusBarThemeable) {
|
||||
if (((ChameleonView.StatusBarThemeable) rootView).isStatusBarColorHandled()) {
|
||||
statusBarColorHandled = true;
|
||||
}
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !statusBarColorHandled) {
|
||||
activity.getWindow().setStatusBarColor(theme.getStatusBarColor());
|
||||
}
|
||||
}
|
||||
|
||||
private View getRootView() {
|
||||
return ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
|
||||
}
|
||||
|
||||
public void invalidateActivity() {
|
||||
|
||||
}
|
||||
|
||||
public void cleanUp() {
|
||||
postApplyViews.clear();
|
||||
}
|
||||
|
||||
public void themeOverflow() {
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Theme getOverrideTheme(Context context, Object obj) {
|
||||
if (obj instanceof Themeable) {
|
||||
final Theme theme = ((Themeable) obj).getOverrideTheme();
|
||||
if (theme != null) {
|
||||
return theme;
|
||||
}
|
||||
}
|
||||
return Theme.from(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2016/12/18.
|
||||
*/
|
||||
|
||||
public static class Theme {
|
||||
private int colorPrimary;
|
||||
private int colorAccent;
|
||||
private int colorToolbar;
|
||||
private int colorBackground;
|
||||
private int colorForeground;
|
||||
private boolean toolbarColored;
|
||||
private int textColorPrimary;
|
||||
private int statusBarColor;
|
||||
|
||||
Theme() {
|
||||
|
||||
}
|
||||
|
||||
public int getColorAccent() {
|
||||
return colorAccent;
|
||||
}
|
||||
|
||||
public void setColorAccent(int colorAccent) {
|
||||
this.colorAccent = colorAccent;
|
||||
}
|
||||
|
||||
public int getColorPrimary() {
|
||||
return colorPrimary;
|
||||
}
|
||||
|
||||
public void setColorPrimary(int colorPrimary) {
|
||||
this.colorPrimary = colorPrimary;
|
||||
}
|
||||
|
||||
public int getColorToolbar() {
|
||||
if (colorToolbar == 0) return colorPrimary;
|
||||
return colorToolbar;
|
||||
}
|
||||
|
||||
public void setColorToolbar(int colorToolbar) {
|
||||
this.colorToolbar = colorToolbar;
|
||||
}
|
||||
|
||||
public boolean isToolbarColored() {
|
||||
return toolbarColored;
|
||||
}
|
||||
|
||||
public void setToolbarColored(boolean toolbarColored) {
|
||||
this.toolbarColored = toolbarColored;
|
||||
}
|
||||
|
||||
public int getTextColorPrimary() {
|
||||
return textColorPrimary;
|
||||
}
|
||||
|
||||
public void setTextColorPrimary(int textColorPrimary) {
|
||||
this.textColorPrimary = textColorPrimary;
|
||||
}
|
||||
|
||||
public int getColorBackground() {
|
||||
return colorBackground;
|
||||
}
|
||||
|
||||
public void setColorBackground(int colorBackground) {
|
||||
this.colorBackground = colorBackground;
|
||||
}
|
||||
|
||||
public int getColorForeground() {
|
||||
return colorForeground;
|
||||
}
|
||||
|
||||
public void setColorForeground(int colorForeground) {
|
||||
this.colorForeground = colorForeground;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Theme from(Context context) {
|
||||
Theme theme = new Theme();
|
||||
TypedArray a = context.obtainStyledAttributes(R.styleable.ChameleonTheme);
|
||||
theme.setColorPrimary(a.getColor(R.styleable.ChameleonTheme_colorPrimary, 0));
|
||||
theme.setColorAccent(a.getColor(R.styleable.ChameleonTheme_colorAccent, 0));
|
||||
theme.setColorToolbar(a.getColor(R.styleable.ChameleonTheme_colorToolbar, theme.getColorPrimary()));
|
||||
theme.setColorBackground(a.getColor(R.styleable.ChameleonTheme_android_colorBackground, 0));
|
||||
theme.setColorForeground(a.getColor(R.styleable.ChameleonTheme_android_colorForeground, 0));
|
||||
theme.setToolbarColored(a.getBoolean(R.styleable.ChameleonTheme_isToolbarColored, true));
|
||||
a.recycle();
|
||||
return theme;
|
||||
}
|
||||
|
||||
public int getStatusBarColor() {
|
||||
if (statusBarColor == 0) {
|
||||
return ChameleonUtils.darkenColor(getColorToolbar());
|
||||
}
|
||||
return statusBarColor;
|
||||
}
|
||||
|
||||
public void setStatusBarColor(int statusBarColor) {
|
||||
this.statusBarColor = statusBarColor;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2016/12/18.
|
||||
*/
|
||||
|
||||
public interface Themeable {
|
||||
@Nullable
|
||||
Theme getOverrideTheme();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package org.mariotaku.chameleon;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2016/12/18.
|
||||
*/
|
||||
|
||||
public class ChameleonTypedArray {
|
||||
private final TypedArray wrapped;
|
||||
private final boolean[] hasAttributeStates;
|
||||
private final int[] attributeReferences;
|
||||
private final Chameleon.Theme theme;
|
||||
|
||||
private ChameleonTypedArray(TypedArray wrapped, boolean[] hasAttributeStates, int[] attributeReferences, Chameleon.Theme theme) {
|
||||
this.wrapped = wrapped;
|
||||
this.hasAttributeStates = hasAttributeStates;
|
||||
this.attributeReferences = attributeReferences;
|
||||
this.theme = theme;
|
||||
}
|
||||
|
||||
public void recycle() {
|
||||
wrapped.recycle();
|
||||
}
|
||||
|
||||
public static ChameleonTypedArray obtain(Context context, AttributeSet set, int[] attrs, Chameleon.Theme theme) {
|
||||
@SuppressLint("Recycle") TypedArray array = context.obtainStyledAttributes(set, attrs);
|
||||
boolean[] hasAttribute = new boolean[attrs.length];
|
||||
int[] attributeReferences = new int[attrs.length];
|
||||
for (int i = 0; i < attrs.length; i++) {
|
||||
final int index = ChameleonUtils.findAttributeIndex(set, attrs[i]);
|
||||
if (index != -1) {
|
||||
hasAttribute[i] = true;
|
||||
String value = set.getAttributeValue(index);
|
||||
if (value != null && value.startsWith("?")) {
|
||||
attributeReferences[i] = Integer.parseInt(value.substring(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ChameleonTypedArray(array, hasAttribute, attributeReferences, theme);
|
||||
}
|
||||
|
||||
public int getColor(int index) {
|
||||
return wrapped.getColor(index, 0);
|
||||
}
|
||||
|
||||
public int getColor(int index, int defValue) {
|
||||
final int ref = attributeReferences[index];
|
||||
if (ref == android.support.design.R.attr.colorPrimary) {
|
||||
return theme.getColorPrimary();
|
||||
} else if (ref == android.support.design.R.attr.colorAccent) {
|
||||
return theme.getColorAccent();
|
||||
} else if (ref == R.attr.colorToolbar) {
|
||||
return theme.getColorToolbar();
|
||||
}
|
||||
if (!hasAttributeStates[index]) return defValue;
|
||||
return wrapped.getColor(index, defValue);
|
||||
}
|
||||
|
||||
public Drawable getDrawable(int index) {
|
||||
final int ref = attributeReferences[index];
|
||||
if (ref == android.support.design.R.attr.colorPrimary) {
|
||||
return new ColorDrawable(theme.getColorPrimary());
|
||||
} else if (ref == android.support.design.R.attr.colorAccent) {
|
||||
return new ColorDrawable(theme.getColorAccent());
|
||||
} else if (ref == R.attr.colorToolbar) {
|
||||
return new ColorDrawable(theme.getColorToolbar());
|
||||
}
|
||||
if (!hasAttributeStates[index]) return null;
|
||||
return wrapped.getDrawable(index);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package org.mariotaku.chameleon;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.graphics.Color;
|
||||
import android.support.annotation.ColorInt;
|
||||
import android.support.annotation.FloatRange;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2016/12/18.
|
||||
*/
|
||||
|
||||
public class ChameleonUtils {
|
||||
public static int findAttributeIndex(AttributeSet attributeSet, int attributeNameResource) {
|
||||
for (int i = 0, j = attributeSet.getAttributeCount(); i < j; i++) {
|
||||
if (attributeSet.getAttributeNameResource(i) == attributeNameResource) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static boolean isColorLight(@ColorInt int color) {
|
||||
if (color == Color.BLACK) return false;
|
||||
else if (color == Color.WHITE || color == Color.TRANSPARENT) return true;
|
||||
final double darkness = 1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255;
|
||||
return darkness < 0.4;
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
public static int shiftColor(@ColorInt int color, @FloatRange(from = 0.0f, to = 2.0f) float by) {
|
||||
if (by == 1f) return color;
|
||||
float[] hsv = new float[3];
|
||||
Color.colorToHSV(color, hsv);
|
||||
hsv[2] *= by; // value component
|
||||
return Color.HSVToColor(hsv);
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
public static int darkenColor(@ColorInt int color) {
|
||||
return shiftColor(color, 0.9f);
|
||||
}
|
||||
|
||||
public static Activity getActivity(Context context) {
|
||||
if (context instanceof Activity) return (Activity) context;
|
||||
if (context instanceof ContextWrapper) {
|
||||
return getActivity(((ContextWrapper) context).getBaseContext());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package org.mariotaku.chameleon;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2016/12/18.
|
||||
*/
|
||||
|
||||
public interface ChameleonView {
|
||||
|
||||
boolean isPostApplyTheme();
|
||||
|
||||
@Nullable
|
||||
Appearance createAppearance(Context context, AttributeSet attributeSet, Chameleon.Theme theme);
|
||||
|
||||
void applyAppearance(@NonNull Appearance appearance);
|
||||
|
||||
interface Appearance {
|
||||
|
||||
}
|
||||
|
||||
interface StatusBarThemeable {
|
||||
boolean isStatusBarColorHandled();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
package org.mariotaku.chameleon.internal;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.util.ArrayMap;
|
||||
import android.support.v4.view.LayoutInflaterFactory;
|
||||
import android.support.v7.app.AppCompatDelegate;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
||||
import org.mariotaku.chameleon.Chameleon;
|
||||
import org.mariotaku.chameleon.ChameleonView;
|
||||
import org.mariotaku.chameleon.view.ChameleonAutoCompleteTextView;
|
||||
import org.mariotaku.chameleon.view.ChameleonEditText;
|
||||
import org.mariotaku.chameleon.view.ChameleonFloatingActionButton;
|
||||
import org.mariotaku.chameleon.view.ChameleonMultiAutoCompleteTextView;
|
||||
import org.mariotaku.chameleon.view.ChameleonSwipeRefreshLayout;
|
||||
import org.mariotaku.chameleon.view.ChameleonTextView;
|
||||
import org.mariotaku.chameleon.view.ChameleonToolbar;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2016/12/18.
|
||||
*/
|
||||
|
||||
public class ChameleonInflationFactory implements LayoutInflaterFactory {
|
||||
|
||||
@NonNull
|
||||
private final LayoutInflater mInflater;
|
||||
@Nullable
|
||||
private final Activity mActivity;
|
||||
@Nullable
|
||||
private final AppCompatDelegate mDelegate;
|
||||
@Nullable
|
||||
private final Chameleon.Theme mTheme;
|
||||
private final ArrayMap<ChameleonView, ChameleonView.Appearance> mPostApplyViews;
|
||||
|
||||
|
||||
public ChameleonInflationFactory(@NonNull LayoutInflater inflater,
|
||||
@Nullable Activity activity,
|
||||
@Nullable AppCompatDelegate delegate,
|
||||
@Nullable Chameleon.Theme theme,
|
||||
@NonNull ArrayMap<ChameleonView, ChameleonView.Appearance> postApplyViews) {
|
||||
this.mInflater = inflater;
|
||||
this.mActivity = activity;
|
||||
this.mDelegate = delegate;
|
||||
this.mTheme = theme;
|
||||
this.mPostApplyViews = postApplyViews;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
|
||||
View view = null;
|
||||
if (shouldSkipTheming(parent)) {
|
||||
|
||||
} else switch (name) {
|
||||
case "TextView":
|
||||
case "android.support.v7.widget.AppCompatTextView": {
|
||||
view = new ChameleonTextView(context, attrs);
|
||||
break;
|
||||
}
|
||||
case "EditText":
|
||||
case "android.support.v7.widget.AppCompatEditText": {
|
||||
view = new ChameleonEditText(context, attrs);
|
||||
break;
|
||||
}
|
||||
case "AutoCompleteTextView":
|
||||
case "android.support.v7.widget.AppCompatAutoCompleteTextView": {
|
||||
view = new ChameleonAutoCompleteTextView(context, attrs);
|
||||
break;
|
||||
}
|
||||
case "MultiAutoCompleteTextView":
|
||||
case "android.support.v7.widget.AppCompatMultiAutoCompleteTextView": {
|
||||
view = new ChameleonMultiAutoCompleteTextView(context, attrs);
|
||||
break;
|
||||
}
|
||||
case "android.support.design.widget.FloatingActionButton": {
|
||||
view = new ChameleonFloatingActionButton(context, attrs);
|
||||
break;
|
||||
}
|
||||
case "android.support.v7.widget.Toolbar": {
|
||||
view = new ChameleonToolbar(context, attrs);
|
||||
break;
|
||||
}
|
||||
case "android.support.v4.widget.SwipeRefreshLayout": {
|
||||
view = new ChameleonSwipeRefreshLayout(context, attrs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (view == null) {
|
||||
// First, check if the AppCompatDelegate will give us a view, usually (maybe always) null.
|
||||
if (mDelegate != null) {
|
||||
view = mDelegate.createView(parent, name, context, attrs);
|
||||
if (view == null && mActivity != null)
|
||||
view = mActivity.onCreateView(parent, name, context, attrs);
|
||||
else view = null;
|
||||
} else {
|
||||
view = null;
|
||||
}
|
||||
|
||||
if (isExcluded(name))
|
||||
return view;
|
||||
|
||||
// Mimic code of LayoutInflater using reflection tricks (this would normally be run when this factory returns null).
|
||||
// We need to intercept the default behavior rather than allowing the LayoutInflater to handle it after this method returns.
|
||||
if (view == null) {
|
||||
try {
|
||||
Context viewContext;
|
||||
final boolean inheritContext = false; // TODO will this ever need to be true?
|
||||
//noinspection PointlessBooleanExpression,ConstantConditions
|
||||
if (parent != null && inheritContext) {
|
||||
viewContext = parent.getContext();
|
||||
} else {
|
||||
viewContext = mInflater.getContext();
|
||||
}
|
||||
Context wrappedContext = LayoutInflaterInternal.getThemeWrapper(viewContext, attrs);
|
||||
if (wrappedContext != null) {
|
||||
viewContext = wrappedContext;
|
||||
}
|
||||
|
||||
Object[] mConstructorArgs = LayoutInflaterInternal.getConstructorArgs(mInflater);
|
||||
|
||||
final Object lastContext = mConstructorArgs[0];
|
||||
mConstructorArgs[0] = viewContext;
|
||||
try {
|
||||
if (-1 == name.indexOf('.')) {
|
||||
view = LayoutInflaterInternal.onCreateView(mInflater, parent, name, attrs);
|
||||
} else {
|
||||
view = LayoutInflaterInternal.createView(mInflater, name, null, attrs);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
mConstructorArgs[0] = lastContext;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException(String.format("An error occurred while inflating View %s: %s", name, t.getMessage()), t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (view instanceof ChameleonView) {
|
||||
final ChameleonView cv = (ChameleonView) view;
|
||||
ChameleonView.Appearance appearance = cv.createAppearance(view.getContext(), attrs, mTheme);
|
||||
if (appearance != null) {
|
||||
if (cv.isPostApplyTheme()) {
|
||||
mPostApplyViews.put(cv, appearance);
|
||||
} else {
|
||||
cv.applyAppearance(appearance);
|
||||
}
|
||||
}
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
private boolean isExcluded(@NonNull String name) {
|
||||
switch (name) {
|
||||
case "android.support.design.internal.NavigationMenuItemView":
|
||||
case "ViewStub":
|
||||
case "fragment":
|
||||
case "include":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldSkipTheming(View parent) {
|
||||
if (parent == null) return false;
|
||||
return "ignore".equals(parent.getTag());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
package org.mariotaku.chameleon.internal;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.support.v7.view.ContextThemeWrapper;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2016/12/18.
|
||||
*/
|
||||
|
||||
public class LayoutInflaterInternal {
|
||||
private static Method mOnCreateViewMethod;
|
||||
private static Method mCreateViewMethod;
|
||||
private static Field mConstructorArgsField;
|
||||
private static int[] ATTRS_THEME;
|
||||
|
||||
public static View onCreateView(LayoutInflater inflater, View view, String name, AttributeSet attrs) {
|
||||
ensureAvailable();
|
||||
try {
|
||||
return (View) mOnCreateViewMethod.invoke(inflater, view, name, attrs);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static View createView(LayoutInflater inflater, String name, String prefix, AttributeSet attrs) {
|
||||
ensureAvailable();
|
||||
try {
|
||||
return (View) mCreateViewMethod.invoke(inflater, name, null, attrs);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Context getThemeWrapper(Context viewContext, AttributeSet attrs) {
|
||||
ensureAvailable();
|
||||
// Apply a theme wrapper, if requested.
|
||||
if (ATTRS_THEME != null) {
|
||||
final TypedArray ta = viewContext.obtainStyledAttributes(attrs, ATTRS_THEME);
|
||||
try {
|
||||
final int themeResId = ta.getResourceId(0, 0);
|
||||
if (themeResId != 0) return new ContextThemeWrapper(viewContext, themeResId);
|
||||
} finally {
|
||||
ta.recycle();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Object[] getConstructorArgs(LayoutInflater inflater) {
|
||||
try {
|
||||
return (Object[]) mConstructorArgsField.get(inflater);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ensureAvailable() {
|
||||
if (mOnCreateViewMethod == null) {
|
||||
try {
|
||||
mOnCreateViewMethod = LayoutInflater.class.getDeclaredMethod("onCreateView",
|
||||
View.class, String.class, AttributeSet.class);
|
||||
mOnCreateViewMethod.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException("Failed to retrieve the onCreateView method.", e);
|
||||
}
|
||||
}
|
||||
if (mCreateViewMethod == null) {
|
||||
try {
|
||||
mCreateViewMethod = LayoutInflater.class.getDeclaredMethod("createView",
|
||||
String.class, String.class, AttributeSet.class);
|
||||
mCreateViewMethod.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException("Failed to retrieve the createView method.", e);
|
||||
}
|
||||
}
|
||||
if (mConstructorArgsField == null) {
|
||||
try {
|
||||
mConstructorArgsField = LayoutInflater.class.getDeclaredField("mConstructorArgs");
|
||||
mConstructorArgsField.setAccessible(true);
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new RuntimeException("Failed to retrieve the mConstructorArgs field.", e);
|
||||
}
|
||||
}
|
||||
if (ATTRS_THEME == null) {
|
||||
try {
|
||||
final Field attrsThemeField = LayoutInflater.class.getDeclaredField("ATTRS_THEME");
|
||||
attrsThemeField.setAccessible(true);
|
||||
ATTRS_THEME = (int[]) attrsThemeField.get(null);
|
||||
} catch (Throwable t) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package org.mariotaku.chameleon.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.widget.AppCompatAutoCompleteTextView;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import org.mariotaku.chameleon.Chameleon;
|
||||
import org.mariotaku.chameleon.ChameleonView;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2016/12/18.
|
||||
*/
|
||||
|
||||
public class ChameleonAutoCompleteTextView extends AppCompatAutoCompleteTextView implements ChameleonView {
|
||||
public ChameleonAutoCompleteTextView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public ChameleonAutoCompleteTextView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public ChameleonAutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPostApplyTheme() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ChameleonEditText.Appearance createAppearance(Context context, AttributeSet attributeSet, Chameleon.Theme theme) {
|
||||
return ChameleonEditText.Appearance.create(context, attributeSet, theme);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void applyAppearance(@NonNull Appearance appearance) {
|
||||
final ChameleonEditText.Appearance a = (ChameleonEditText.Appearance) appearance;
|
||||
ChameleonEditText.Appearance.apply(this, a);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package org.mariotaku.chameleon.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.support.v7.widget.AppCompatEditText;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.mariotaku.chameleon.Chameleon;
|
||||
import org.mariotaku.chameleon.ChameleonTypedArray;
|
||||
import org.mariotaku.chameleon.ChameleonView;
|
||||
import org.mariotaku.chameleon.R;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2016/12/18.
|
||||
*/
|
||||
|
||||
public class ChameleonEditText extends AppCompatEditText implements ChameleonView {
|
||||
public ChameleonEditText(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public ChameleonEditText(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public ChameleonEditText(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPostApplyTheme() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Appearance createAppearance(Context context, AttributeSet attributeSet, Chameleon.Theme theme) {
|
||||
return Appearance.create(context, attributeSet, theme);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void applyAppearance(@NonNull ChameleonView.Appearance appearance) {
|
||||
final Appearance a = (Appearance) appearance;
|
||||
Appearance.apply(this, a);
|
||||
}
|
||||
|
||||
public static class Appearance extends ChameleonTextView.Appearance {
|
||||
private int backgroundColor;
|
||||
|
||||
public int getBackgroundColor() {
|
||||
return backgroundColor;
|
||||
}
|
||||
|
||||
public void setBackgroundColor(int backgroundColor) {
|
||||
this.backgroundColor = backgroundColor;
|
||||
}
|
||||
|
||||
public static void apply(TextView view, Appearance appearance) {
|
||||
view.setLinkTextColor(appearance.getLinkTextColor());
|
||||
ViewCompat.setBackgroundTintList(view, ColorStateList.valueOf(appearance.getBackgroundColor()));
|
||||
}
|
||||
|
||||
public static Appearance create(Context context, AttributeSet attributeSet, Chameleon.Theme theme) {
|
||||
Appearance appearance = new Appearance();
|
||||
ChameleonTypedArray a = ChameleonTypedArray.obtain(context, attributeSet,
|
||||
R.styleable.ChameleonEditText, theme);
|
||||
appearance.setLinkTextColor(a.getColor(R.styleable.ChameleonEditText_android_textColorLink, theme.getColorAccent()));
|
||||
appearance.setBackgroundColor(a.getColor(R.styleable.ChameleonEditText_backgroundTint, theme.getColorAccent()));
|
||||
a.recycle();
|
||||
return appearance;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package org.mariotaku.chameleon.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import org.mariotaku.chameleon.Chameleon;
|
||||
import org.mariotaku.chameleon.ChameleonTypedArray;
|
||||
import org.mariotaku.chameleon.ChameleonView;
|
||||
import org.mariotaku.chameleon.R;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2016/12/18.
|
||||
*/
|
||||
|
||||
public class ChameleonFloatingActionButton extends FloatingActionButton implements ChameleonView {
|
||||
public ChameleonFloatingActionButton(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public ChameleonFloatingActionButton(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public ChameleonFloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPostApplyTheme() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Appearance createAppearance(Context context, AttributeSet attributeSet, Chameleon.Theme theme) {
|
||||
Appearance appearance = new Appearance();
|
||||
ChameleonTypedArray a = ChameleonTypedArray.obtain(context, attributeSet,
|
||||
R.styleable.ChameleonFloatingActionButton, theme);
|
||||
appearance.backgroundTint = a.getColor(R.styleable.ChameleonFloatingActionButton_backgroundTint, theme.getColorAccent());
|
||||
a.recycle();
|
||||
return appearance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAppearance(@NonNull ChameleonView.Appearance appearance) {
|
||||
Appearance a = (Appearance) appearance;
|
||||
setBackgroundTintList(ColorStateList.valueOf(a.backgroundTint));
|
||||
}
|
||||
|
||||
public static class Appearance implements ChameleonView.Appearance {
|
||||
int backgroundTint;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package org.mariotaku.chameleon.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.widget.AppCompatMultiAutoCompleteTextView;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import org.mariotaku.chameleon.Chameleon;
|
||||
import org.mariotaku.chameleon.ChameleonView;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2016/12/18.
|
||||
*/
|
||||
|
||||
public class ChameleonMultiAutoCompleteTextView extends AppCompatMultiAutoCompleteTextView implements ChameleonView {
|
||||
public ChameleonMultiAutoCompleteTextView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public ChameleonMultiAutoCompleteTextView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public ChameleonMultiAutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPostApplyTheme() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ChameleonEditText.Appearance createAppearance(Context context, AttributeSet attributeSet, Chameleon.Theme theme) {
|
||||
return ChameleonEditText.Appearance.create(context, attributeSet, theme);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void applyAppearance(@NonNull ChameleonView.Appearance appearance) {
|
||||
final ChameleonEditText.Appearance a = (ChameleonEditText.Appearance) appearance;
|
||||
ChameleonEditText.Appearance.apply(this, a);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package org.mariotaku.chameleon.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import org.mariotaku.chameleon.Chameleon;
|
||||
import org.mariotaku.chameleon.ChameleonView;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2016/12/18.
|
||||
*/
|
||||
|
||||
public class ChameleonSwipeRefreshLayout extends SwipeRefreshLayout implements ChameleonView {
|
||||
|
||||
public ChameleonSwipeRefreshLayout(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public ChameleonSwipeRefreshLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPostApplyTheme() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Appearance createAppearance(Context context, AttributeSet attributeSet, Chameleon.Theme theme) {
|
||||
Appearance appearance = new Appearance();
|
||||
appearance.indicatorColor = theme.getColorAccent();
|
||||
appearance.progressBackgroundColor = theme.getColorBackground();
|
||||
return appearance;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void applyAppearance(@NonNull ChameleonView.Appearance appearance) {
|
||||
final Appearance a = (Appearance) appearance;
|
||||
setColorSchemeColors(a.indicatorColor);
|
||||
setProgressBackgroundColorSchemeColor(a.progressBackgroundColor);
|
||||
}
|
||||
|
||||
public static class Appearance implements ChameleonView.Appearance {
|
||||
int indicatorColor;
|
||||
int progressBackgroundColor;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package org.mariotaku.chameleon.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.widget.AppCompatTextView;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import org.mariotaku.chameleon.Chameleon;
|
||||
import org.mariotaku.chameleon.ChameleonTypedArray;
|
||||
import org.mariotaku.chameleon.ChameleonView;
|
||||
import org.mariotaku.chameleon.R;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2016/12/18.
|
||||
*/
|
||||
|
||||
public class ChameleonTextView extends AppCompatTextView implements ChameleonView {
|
||||
public ChameleonTextView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public ChameleonTextView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public ChameleonTextView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPostApplyTheme() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Appearance createAppearance(Context context, AttributeSet attributeSet, Chameleon.Theme theme) {
|
||||
Appearance appearance = new Appearance();
|
||||
ChameleonTypedArray a = ChameleonTypedArray.obtain(context, attributeSet,
|
||||
R.styleable.ChameleonTextView, theme);
|
||||
appearance.setLinkTextColor(a.getColor(R.styleable.ChameleonTextView_android_textColorLink, theme.getColorAccent()));
|
||||
a.recycle();
|
||||
return appearance;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void applyAppearance(@NonNull ChameleonView.Appearance appearance) {
|
||||
final Appearance a = (Appearance) appearance;
|
||||
setLinkTextColor(a.getLinkTextColor());
|
||||
}
|
||||
|
||||
public static class Appearance implements ChameleonView.Appearance {
|
||||
private int linkTextColor;
|
||||
|
||||
public int getLinkTextColor() {
|
||||
return linkTextColor;
|
||||
}
|
||||
|
||||
public void setLinkTextColor(int linkTextColor) {
|
||||
this.linkTextColor = linkTextColor;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package org.mariotaku.chameleon.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import org.mariotaku.chameleon.Chameleon;
|
||||
import org.mariotaku.chameleon.ChameleonTypedArray;
|
||||
import org.mariotaku.chameleon.ChameleonView;
|
||||
import org.mariotaku.chameleon.R;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2016/12/18.
|
||||
*/
|
||||
|
||||
public class ChameleonToolbar extends Toolbar implements ChameleonView {
|
||||
public ChameleonToolbar(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public ChameleonToolbar(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public ChameleonToolbar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPostApplyTheme() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Appearance createAppearance(Context context, AttributeSet attributeSet, Chameleon.Theme theme) {
|
||||
Appearance appearance = new Appearance();
|
||||
ChameleonTypedArray a = ChameleonTypedArray.obtain(context, attributeSet,
|
||||
R.styleable.ChameleonToolbar, theme);
|
||||
final Drawable background = a.getDrawable(R.styleable.ChameleonToolbar_android_background);
|
||||
if (background != null) {
|
||||
appearance.setBackground(background);
|
||||
} else {
|
||||
appearance.setBackground(new ColorDrawable(theme.getColorToolbar()));
|
||||
}
|
||||
appearance.setTitleTextColor(a.getColor(R.styleable.ChameleonToolbar_titleTextColor));
|
||||
appearance.setSubTitleTextColor(a.getColor(R.styleable.ChameleonToolbar_subtitleTextColor));
|
||||
a.recycle();
|
||||
return appearance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAppearance(@NonNull ChameleonView.Appearance appearance) {
|
||||
Appearance a = (Appearance) appearance;
|
||||
setBackgroundDrawable(a.getDrawable());
|
||||
setTitleTextColor(a.getTitleTextColor());
|
||||
setSubtitleTextColor(a.getSubTitleTextColor());
|
||||
}
|
||||
|
||||
public static class Appearance implements ChameleonView.Appearance {
|
||||
|
||||
private int titleTextColor;
|
||||
private int subTitleTextColor;
|
||||
private Drawable background;
|
||||
|
||||
public void setTitleTextColor(int titleTextColor) {
|
||||
this.titleTextColor = titleTextColor;
|
||||
}
|
||||
|
||||
public int getTitleTextColor() {
|
||||
return titleTextColor;
|
||||
}
|
||||
|
||||
public void setSubTitleTextColor(int subTitleTextColor) {
|
||||
this.subTitleTextColor = subTitleTextColor;
|
||||
}
|
||||
|
||||
public int getSubTitleTextColor() {
|
||||
return subTitleTextColor;
|
||||
}
|
||||
|
||||
public void setBackground(Drawable background) {
|
||||
this.background = background;
|
||||
}
|
||||
|
||||
public Drawable getDrawable() {
|
||||
return background;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<declare-styleable name="ChameleonTheme">
|
||||
<attr name="colorPrimary"/>
|
||||
<attr name="colorAccent"/>
|
||||
<attr name="colorToolbar" format="color"/>
|
||||
<attr name="android:colorForeground"/>
|
||||
<attr name="android:colorBackground"/>
|
||||
<attr name="isToolbarColored" format="boolean"/>
|
||||
</declare-styleable>
|
||||
<declare-styleable name="ChameleonTextView">
|
||||
<attr name="android:textColorLink"/>
|
||||
</declare-styleable>
|
||||
<declare-styleable name="ChameleonEditText">
|
||||
<attr name="android:textColorLink"/>
|
||||
<attr name="backgroundTint"/>
|
||||
</declare-styleable>
|
||||
<declare-styleable name="ChameleonFloatingActionButton">
|
||||
<attr name="backgroundTint"/>
|
||||
</declare-styleable>
|
||||
<declare-styleable name="ChameleonToolbar">
|
||||
<attr name="android:background"/>
|
||||
<attr name="titleTextColor"/>
|
||||
<attr name="subtitleTextColor"/>
|
||||
</declare-styleable>
|
||||
</resources>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="color_reference_primary_color">#00100001</color>
|
||||
<color name="color_reference_accent_color">#00100002</color>
|
||||
<color name="color_reference_toolbar_color">#00100003</color>
|
||||
</resources>
|
|
@ -0,0 +1,17 @@
|
|||
package org.mariotaku.chameleon;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() throws Exception {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
include ':twidere'
|
||||
include ':twidere', ':chameleon'
|
||||
include ':twidere.component.common'
|
||||
include ':twidere.library.extension'
|
||||
include ':twidere.wear'
|
||||
|
|
|
@ -73,10 +73,6 @@ public interface SharedPreferenceConstants {
|
|||
String VALUE_TAB_DISPLAY_OPTION_ICON = "icon";
|
||||
String VALUE_TAB_DISPLAY_OPTION_LABEL = "label";
|
||||
String VALUE_TAB_DISPLAY_OPTION_BOTH = "both";
|
||||
int VALUE_TAB_DISPLAY_OPTION_CODE_LABEL = 0x1;
|
||||
int VALUE_TAB_DISPLAY_OPTION_CODE_ICON = 0x2;
|
||||
int VALUE_TAB_DISPLAY_OPTION_CODE_BOTH = VALUE_TAB_DISPLAY_OPTION_CODE_ICON
|
||||
| VALUE_TAB_DISPLAY_OPTION_CODE_LABEL;
|
||||
|
||||
String VALUE_THEME_BACKGROUND_DEFAULT = "default";
|
||||
String VALUE_THEME_BACKGROUND_SOLID = "solid";
|
||||
|
|
|
@ -95,6 +95,7 @@ dependencies {
|
|||
|
||||
compile project(':twidere.component.common')
|
||||
compile project(':twidere.component.nyan')
|
||||
compile project(':chameleon')
|
||||
|
||||
// START Non-FOSS component
|
||||
googleCompile "com.google.android.gms:play-services-maps:$play_services_version"
|
||||
|
|
|
@ -1,151 +0,0 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* 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.mariotaku.twidere.activity;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
|
||||
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutSpec;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/4/20.
|
||||
*/
|
||||
public class KeyboardShortcutPreferenceCompatActivity extends BaseActivity implements
|
||||
OnClickListener {
|
||||
|
||||
public static final String EXTRA_CONTEXT_TAG = "context_tag";
|
||||
public static final String EXTRA_KEY_ACTION = "key_action";
|
||||
|
||||
private TextView mKeysLabel, mConflictLabel;
|
||||
|
||||
private KeyboardShortcutSpec mKeySpec;
|
||||
private Button mButtonPositive, mButtonNegative, mButtonNeutral;
|
||||
private int mMetaState;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getThemeBackgroundOption() {
|
||||
return VALUE_THEME_BACKGROUND_DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_keyboard_shortcut_input);
|
||||
setTitle(KeyboardShortcutsHandler.getActionLabel(this, getKeyAction()));
|
||||
|
||||
mButtonPositive.setOnClickListener(this);
|
||||
mButtonNegative.setOnClickListener(this);
|
||||
mButtonNeutral.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
switch (v.getId()) {
|
||||
case R.id.button_positive: {
|
||||
if (mKeySpec == null) return;
|
||||
keyboardShortcutsHandler.register(mKeySpec, getKeyAction());
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
case R.id.button_neutral: {
|
||||
keyboardShortcutsHandler.unregister(getKeyAction());
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
case R.id.button_negative: {
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
|
||||
if (KeyEvent.isModifierKey(keyCode)) {
|
||||
mMetaState |= KeyboardShortcutsHandler.getMetaStateForKeyCode(keyCode);
|
||||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
|
||||
if (KeyEvent.isModifierKey(keyCode)) {
|
||||
mMetaState &= ~KeyboardShortcutsHandler.getMetaStateForKeyCode(keyCode);
|
||||
}
|
||||
final String keyAction = getKeyAction();
|
||||
if (keyAction == null) return false;
|
||||
final KeyboardShortcutSpec spec = KeyboardShortcutsHandler.getKeyboardShortcutSpec(getContextTag(),
|
||||
keyCode, event, KeyEvent.normalizeMetaState(mMetaState | event.getMetaState()));
|
||||
if (spec == null || !spec.isValid()) {
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
mKeySpec = spec;
|
||||
mKeysLabel.setText(spec.toKeyString());
|
||||
final String oldAction = keyboardShortcutsHandler.findAction(spec);
|
||||
final KeyboardShortcutSpec copyOfSpec = spec.copy();
|
||||
copyOfSpec.setContextTag(null);
|
||||
final String oldGeneralAction = keyboardShortcutsHandler.findAction(copyOfSpec);
|
||||
if (!TextUtils.isEmpty(oldAction) && !keyAction.equals(oldAction)) {
|
||||
// Conflicts with keys in same context tag
|
||||
mConflictLabel.setVisibility(View.VISIBLE);
|
||||
final String label = KeyboardShortcutsHandler.getActionLabel(this, oldAction);
|
||||
mConflictLabel.setText(getString(R.string.conflicts_with_name, label));
|
||||
//noinspection UnnecessaryParentheses
|
||||
mButtonPositive.setText((R.string.overwrite));
|
||||
} else if (!TextUtils.isEmpty(oldGeneralAction) && !keyAction.equals(oldGeneralAction)) {
|
||||
// Conflicts with keys in root context
|
||||
mConflictLabel.setVisibility(View.VISIBLE);
|
||||
final String label = KeyboardShortcutsHandler.getActionLabel(this, oldGeneralAction);
|
||||
mConflictLabel.setText(getString(R.string.conflicts_with_name, label));
|
||||
mButtonPositive.setText((R.string.overwrite));
|
||||
} else {
|
||||
mConflictLabel.setVisibility(View.GONE);
|
||||
mButtonPositive.setText(android.R.string.ok);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContentChanged() {
|
||||
super.onContentChanged();
|
||||
mKeysLabel = (TextView) findViewById(R.id.keys_label);
|
||||
mConflictLabel = (TextView) findViewById(R.id.conflict_label);
|
||||
mButtonPositive = (Button) findViewById(R.id.button_positive);
|
||||
mButtonNegative = (Button) findViewById(R.id.button_negative);
|
||||
mButtonNeutral = (Button) findViewById(R.id.button_neutral);
|
||||
}
|
||||
|
||||
private String getContextTag() {
|
||||
return getIntent().getStringExtra(EXTRA_CONTEXT_TAG);
|
||||
}
|
||||
|
||||
private String getKeyAction() {
|
||||
return getIntent().getStringExtra(EXTRA_KEY_ACTION);
|
||||
}
|
||||
}
|
|
@ -64,6 +64,13 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import static android.text.TextUtils.isEmpty;
|
||||
import static org.mariotaku.twidere.TwidereConstants.LOGTAG;
|
||||
import static org.mariotaku.twidere.constant.IntentConstants.EXTRA_ACCOUNT_KEY;
|
||||
import static org.mariotaku.twidere.constant.IntentConstants.EXTRA_IS_MY_ACCOUNT;
|
||||
import static org.mariotaku.twidere.constant.IntentConstants.EXTRA_SCREEN_NAME;
|
||||
import static org.mariotaku.twidere.constant.IntentConstants.EXTRA_USER;
|
||||
import static org.mariotaku.twidere.constant.IntentConstants.EXTRA_USER_LIST;
|
||||
import static org.mariotaku.twidere.constant.IntentConstants.INTENT_ACTION_SELECT_USER;
|
||||
import static org.mariotaku.twidere.util.DataStoreUtils.getAccountScreenName;
|
||||
|
||||
public class UserListSelectorActivity extends BaseActivity implements OnClickListener,
|
||||
|
|
|
@ -102,8 +102,8 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment implements
|
|||
protected void onClick() {
|
||||
final Context context = getContext();
|
||||
final Intent intent = new Intent(context, KeyboardShortcutPreferenceCompatActivity.class);
|
||||
intent.putExtra(KeyboardShortcutPreferenceCompatActivity.EXTRA_CONTEXT_TAG, mContextTag);
|
||||
intent.putExtra(KeyboardShortcutPreferenceCompatActivity.EXTRA_KEY_ACTION, mAction);
|
||||
intent.putExtra(KeyboardShortcutPreferenceCompatActivity.Companion.getEXTRA_CONTEXT_TAG(), mContextTag);
|
||||
intent.putExtra(KeyboardShortcutPreferenceCompatActivity.Companion.getEXTRA_KEY_ACTION(), mAction);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
|
|
|
@ -128,6 +128,7 @@ import org.mariotaku.twidere.util.TwidereLinkify.HighlightStyle;
|
|||
import org.mariotaku.twidere.view.CardMediaContainer.PreviewStyle;
|
||||
import org.mariotaku.twidere.view.ShapedImageView;
|
||||
import org.mariotaku.twidere.view.ShapedImageView.ShapeStyle;
|
||||
import org.mariotaku.twidere.view.TabPagerIndicator;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
|
@ -807,10 +808,10 @@ public final class Utils implements Constants {
|
|||
|
||||
public static int getTabDisplayOptionInt(final String option) {
|
||||
if (VALUE_TAB_DISPLAY_OPTION_ICON.equals(option))
|
||||
return VALUE_TAB_DISPLAY_OPTION_CODE_ICON;
|
||||
return TabPagerIndicator.DisplayOption.ICON;
|
||||
else if (VALUE_TAB_DISPLAY_OPTION_LABEL.equals(option))
|
||||
return VALUE_TAB_DISPLAY_OPTION_CODE_LABEL;
|
||||
return VALUE_TAB_DISPLAY_OPTION_CODE_BOTH;
|
||||
return TabPagerIndicator.DisplayOption.LABEL;
|
||||
return TabPagerIndicator.DisplayOption.BOTH;
|
||||
}
|
||||
|
||||
public static boolean hasNavBar(@NonNull Context context) {
|
||||
|
|
|
@ -22,16 +22,16 @@ package org.mariotaku.twidere.view;
|
|||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import org.mariotaku.chameleon.view.ChameleonSwipeRefreshLayout;
|
||||
import org.mariotaku.twidere.view.iface.IExtendedView;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/4/25.
|
||||
*/
|
||||
public class ExtendedSwipeRefreshLayout extends SwipeRefreshLayout implements IExtendedView {
|
||||
public class ExtendedSwipeRefreshLayout extends ChameleonSwipeRefreshLayout implements IExtendedView {
|
||||
|
||||
private TouchInterceptor mTouchInterceptor;
|
||||
private OnSizeChangedListener mOnSizeChangedListener;
|
||||
|
|
|
@ -1,15 +1,22 @@
|
|||
package org.mariotaku.twidere.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.view.GravityCompat;
|
||||
import android.support.v4.widget.DrawerLayout;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
public class HomeDrawerLayout extends DrawerLayout {
|
||||
import org.mariotaku.chameleon.Chameleon;
|
||||
import org.mariotaku.chameleon.ChameleonUtils;
|
||||
import org.mariotaku.chameleon.ChameleonView;
|
||||
import org.mariotaku.twidere.util.support.WindowSupport;
|
||||
|
||||
public class HomeDrawerLayout extends DrawerLayout implements ChameleonView, ChameleonView.StatusBarThemeable {
|
||||
|
||||
private ShouldDisableDecider mShouldDisableDecider;
|
||||
private int state;
|
||||
private int mStartLockMode, mEndLockMode;
|
||||
|
||||
public HomeDrawerLayout(Context context) {
|
||||
|
@ -49,6 +56,43 @@ public class HomeDrawerLayout extends DrawerLayout {
|
|||
return super.dispatchTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPostApplyTheme() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Appearance createAppearance(Context context, AttributeSet attributeSet, Chameleon.Theme theme) {
|
||||
Appearance appearance = new Appearance();
|
||||
WindowSupport.setStatusBarColor(ChameleonUtils.getActivity(context).getWindow(), Color.TRANSPARENT);
|
||||
appearance.setStatusBarBackgroundColor(ChameleonUtils.darkenColor(theme.getColorToolbar()));
|
||||
return appearance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAppearance(@NonNull ChameleonView.Appearance appearance) {
|
||||
Appearance a = (Appearance) appearance;
|
||||
setStatusBarBackgroundColor(a.getStatusBarBackgroundColor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStatusBarColorHandled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static class Appearance implements ChameleonView.Appearance {
|
||||
int statusBarBackgroundColor;
|
||||
|
||||
public int getStatusBarBackgroundColor() {
|
||||
return statusBarBackgroundColor;
|
||||
}
|
||||
|
||||
public void setStatusBarBackgroundColor(int statusBarBackgroundColor) {
|
||||
this.statusBarBackgroundColor = statusBarBackgroundColor;
|
||||
}
|
||||
}
|
||||
|
||||
public interface ShouldDisableDecider {
|
||||
boolean shouldDisableTouch(MotionEvent e);
|
||||
}
|
||||
|
|
|
@ -4,10 +4,14 @@ import android.content.Context;
|
|||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.annotation.ColorInt;
|
||||
import android.support.annotation.IntDef;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.view.PagerAdapter;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.support.v4.view.ViewPager;
|
||||
|
@ -24,7 +28,9 @@ import android.widget.LinearLayout;
|
|||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.mariotaku.twidere.Constants;
|
||||
import org.mariotaku.chameleon.Chameleon;
|
||||
import org.mariotaku.chameleon.ChameleonUtils;
|
||||
import org.mariotaku.chameleon.ChameleonView;
|
||||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.adapter.decorator.DividerItemDecoration;
|
||||
import org.mariotaku.twidere.util.ThemeUtils;
|
||||
|
@ -36,11 +42,8 @@ import java.lang.annotation.RetentionPolicy;
|
|||
/**
|
||||
* Created by mariotaku on 14/10/21.
|
||||
*/
|
||||
public class TabPagerIndicator extends RecyclerView implements PagerIndicator, Constants {
|
||||
public class TabPagerIndicator extends RecyclerView implements PagerIndicator, ChameleonView {
|
||||
|
||||
public static final int LABEL = VALUE_TAB_DISPLAY_OPTION_CODE_LABEL;
|
||||
public static final int ICON = VALUE_TAB_DISPLAY_OPTION_CODE_ICON;
|
||||
public static final int BOTH = VALUE_TAB_DISPLAY_OPTION_CODE_BOTH;
|
||||
|
||||
private final int mStripHeight;
|
||||
private final TabPagerIndicatorAdapter mIndicatorAdapter;
|
||||
|
@ -61,7 +64,7 @@ public class TabPagerIndicator extends RecyclerView implements PagerIndicator, C
|
|||
mIndicatorAdapter = new TabPagerIndicatorAdapter(this);
|
||||
mItemDecoration = new DividerItemDecoration(context, HORIZONTAL);
|
||||
mStripHeight = res.getDimensionPixelSize(R.dimen.element_spacing_small);
|
||||
ViewCompat.setOverScrollMode(this, ViewCompat.OVER_SCROLL_NEVER);
|
||||
setOverScrollMode(OVER_SCROLL_NEVER);
|
||||
setHorizontalScrollBarEnabled(false);
|
||||
setVerticalScrollBarEnabled(false);
|
||||
setLayoutManager(mLayoutManager = new TabLayoutManager(context, this));
|
||||
|
@ -74,7 +77,8 @@ public class TabPagerIndicator extends RecyclerView implements PagerIndicator, C
|
|||
setStripColor(a.getColor(R.styleable.TabPagerIndicator_tabStripColor, 0));
|
||||
setIconColor(a.getColor(R.styleable.TabPagerIndicator_tabIconColor, 0));
|
||||
setLabelColor(a.getColor(R.styleable.TabPagerIndicator_tabLabelColor, ThemeUtils.getTextColorPrimary(context)));
|
||||
setTabDisplayOption(a.getInt(R.styleable.TabPagerIndicator_tabDisplayOption, ICON));
|
||||
//noinspection WrongConstant
|
||||
setTabDisplayOption(a.getInt(R.styleable.TabPagerIndicator_tabDisplayOption, DisplayOption.ICON));
|
||||
setTabShowDivider(a.getBoolean(R.styleable.TabPagerIndicator_tabShowDivider, false));
|
||||
final int dividerVerticalPadding = a.getDimensionPixelSize(R.styleable.TabPagerIndicator_tabDividerVerticalPadding, 0);
|
||||
final int dividerHorizontalPadding = a.getDimensionPixelSize(R.styleable.TabPagerIndicator_tabDividerHorizontalPadding, 0);
|
||||
|
@ -102,9 +106,6 @@ public class TabPagerIndicator extends RecyclerView implements PagerIndicator, C
|
|||
return mIndicatorAdapter.getItemContext();
|
||||
}
|
||||
|
||||
public void getTabSpecs() {
|
||||
}
|
||||
|
||||
public void setColumns(int columns) {
|
||||
mColumns = columns;
|
||||
notifyDataSetChanged();
|
||||
|
@ -221,6 +222,43 @@ public class TabPagerIndicator extends RecyclerView implements PagerIndicator, C
|
|||
mIndicatorAdapter.setTabProvider((TabProvider) adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPostApplyTheme() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Appearance createAppearance(Context context, AttributeSet attributeSet, Chameleon.Theme theme) {
|
||||
final Appearance appearance = new Appearance();
|
||||
final int toolbarColor = theme.getColorToolbar();
|
||||
final boolean isLight = ChameleonUtils.isColorLight(toolbarColor);
|
||||
final int itemColor = isLight ? Color.BLACK : Color.WHITE;
|
||||
appearance.setLabelColor(itemColor);
|
||||
appearance.setIconColor(itemColor);
|
||||
if (theme.isToolbarColored()) {
|
||||
appearance.setStripColor(itemColor);
|
||||
} else {
|
||||
appearance.setStripColor(theme.getColorAccent());
|
||||
}
|
||||
return appearance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAppearance(@NonNull ChameleonView.Appearance appearance) {
|
||||
Appearance a = (Appearance) appearance;
|
||||
setIconColor(a.getIconColor());
|
||||
setLabelColor(a.getLabelColor());
|
||||
setStripColor(a.getStripColor());
|
||||
updateAppearance();
|
||||
}
|
||||
|
||||
public void updateAppearance() {
|
||||
final int positionStart = mLayoutManager.findFirstVisibleItemPosition();
|
||||
final int itemCount = mLayoutManager.findLastVisibleItemPosition() - positionStart + 1;
|
||||
mIndicatorAdapter.notifyItemRangeChanged(positionStart, itemCount);
|
||||
}
|
||||
|
||||
private int getTabHorizontalPadding() {
|
||||
return mHorizontalPadding;
|
||||
}
|
||||
|
@ -230,11 +268,11 @@ public class TabPagerIndicator extends RecyclerView implements PagerIndicator, C
|
|||
}
|
||||
|
||||
private boolean isIconDisplayed() {
|
||||
return (mOption & ICON) != 0;
|
||||
return (mOption & DisplayOption.ICON) != 0;
|
||||
}
|
||||
|
||||
private boolean isLabelDisplayed() {
|
||||
return (mOption & LABEL) != 0;
|
||||
return (mOption & DisplayOption.LABEL) != 0;
|
||||
}
|
||||
|
||||
private boolean isTabExpandEnabled() {
|
||||
|
@ -261,9 +299,56 @@ public class TabPagerIndicator extends RecyclerView implements PagerIndicator, C
|
|||
mVerticalPadding = padding;
|
||||
}
|
||||
|
||||
@IntDef({ICON, LABEL, BOTH})
|
||||
private boolean isTabSelected(int position) {
|
||||
final int current = getCurrentItem();
|
||||
final int columns = getColumns();
|
||||
final int count = getCount();
|
||||
if (current + columns > count) {
|
||||
return position >= count - columns;
|
||||
}
|
||||
return position >= current && position < current + columns;
|
||||
}
|
||||
|
||||
private int getColumns() {
|
||||
if (mColumns > 0) return mColumns;
|
||||
return 1;
|
||||
}
|
||||
|
||||
public static class Appearance implements ChameleonView.Appearance {
|
||||
@ColorInt
|
||||
int iconColor, labelColor, stripColor;
|
||||
|
||||
public int getIconColor() {
|
||||
return iconColor;
|
||||
}
|
||||
|
||||
public void setIconColor(int iconColor) {
|
||||
this.iconColor = iconColor;
|
||||
}
|
||||
|
||||
public int getLabelColor() {
|
||||
return labelColor;
|
||||
}
|
||||
|
||||
public void setLabelColor(int labelColor) {
|
||||
this.labelColor = labelColor;
|
||||
}
|
||||
|
||||
public int getStripColor() {
|
||||
return stripColor;
|
||||
}
|
||||
|
||||
public void setStripColor(int stripColor) {
|
||||
this.stripColor = stripColor;
|
||||
}
|
||||
}
|
||||
|
||||
@IntDef({DisplayOption.ICON, DisplayOption.LABEL, DisplayOption.BOTH})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface DisplayOption {
|
||||
int LABEL = 0x1;
|
||||
int ICON = 0x2;
|
||||
int BOTH = LABEL | ICON;
|
||||
}
|
||||
|
||||
public static final class SampleView extends LinearLayout {
|
||||
|
@ -299,7 +384,7 @@ public class TabPagerIndicator extends RecyclerView implements PagerIndicator, C
|
|||
this.setStripColor(a.getColor(R.styleable.TabPagerIndicator_tabStripColor, 0));
|
||||
this.setIconColor(a.getColor(R.styleable.TabPagerIndicator_tabIconColor, 0));
|
||||
this.setLabelColor(a.getColor(R.styleable.TabPagerIndicator_tabLabelColor, ThemeUtils.getTextColorPrimary(context)));
|
||||
this.setTabDisplayOption(a.getInt(R.styleable.TabPagerIndicator_tabDisplayOption, ICON));
|
||||
this.setTabDisplayOption(a.getInt(R.styleable.TabPagerIndicator_tabDisplayOption, DisplayOption.ICON));
|
||||
this.setTabShowDivider(a.getBoolean(R.styleable.TabPagerIndicator_tabShowDivider, false));
|
||||
a.recycle();
|
||||
|
||||
|
@ -346,11 +431,11 @@ public class TabPagerIndicator extends RecyclerView implements PagerIndicator, C
|
|||
|
||||
tabIcon.setImageResource(icon);
|
||||
tabIcon.setColorFilter(iconColor, PorterDuff.Mode.SRC_ATOP);
|
||||
tabIcon.setVisibility((tabDisplayOption & ICON) != 0 ? VISIBLE : GONE);
|
||||
tabIcon.setVisibility((tabDisplayOption & DisplayOption.ICON) != 0 ? VISIBLE : GONE);
|
||||
|
||||
tabLabel.setText(label);
|
||||
tabLabel.setTextColor(labelColor);
|
||||
tabLabel.setVisibility((tabDisplayOption & LABEL) != 0 ? VISIBLE : GONE);
|
||||
tabLabel.setVisibility((tabDisplayOption & DisplayOption.LABEL) != 0 ? VISIBLE : GONE);
|
||||
|
||||
badgeView.setText(String.valueOf(unread));
|
||||
badgeView.setVisibility(unread != 0 ? VISIBLE : GONE);
|
||||
|
@ -420,7 +505,7 @@ public class TabPagerIndicator extends RecyclerView implements PagerIndicator, C
|
|||
private final TextView labelView;
|
||||
private final BadgeView badgeView;
|
||||
|
||||
public TabItemHolder(TabPagerIndicator indicator, View itemView) {
|
||||
TabItemHolder(TabPagerIndicator indicator, View itemView) {
|
||||
super(itemView);
|
||||
this.indicator = indicator;
|
||||
this.itemView = (ItemLayout) itemView;
|
||||
|
@ -443,17 +528,17 @@ public class TabPagerIndicator extends RecyclerView implements PagerIndicator, C
|
|||
return indicator.dispatchTabLongClick(position);
|
||||
}
|
||||
|
||||
public void setBadge(int count, boolean display) {
|
||||
void setBadge(int count, boolean display) {
|
||||
badgeView.setText(String.valueOf(count));
|
||||
badgeView.setVisibility(display && count > 0 ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
public void setDisplayOption(boolean iconDisplayed, boolean labelDisplayed) {
|
||||
void setDisplayOption(boolean iconDisplayed, boolean labelDisplayed) {
|
||||
iconView.setVisibility(iconDisplayed ? VISIBLE : GONE);
|
||||
labelView.setVisibility(labelDisplayed ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
public void setIconColor(int color) {
|
||||
void setIconColor(int color) {
|
||||
if (color != 0) {
|
||||
iconView.setColorFilter(color);
|
||||
} else {
|
||||
|
@ -461,23 +546,23 @@ public class TabPagerIndicator extends RecyclerView implements PagerIndicator, C
|
|||
}
|
||||
}
|
||||
|
||||
public void setLabelColor(int color) {
|
||||
void setLabelColor(int color) {
|
||||
labelView.setTextColor(color);
|
||||
}
|
||||
|
||||
public void setPadding(int horizontalPadding, int verticalPadding) {
|
||||
void setPadding(int horizontalPadding, int verticalPadding) {
|
||||
itemView.setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
|
||||
}
|
||||
|
||||
public void setStripColor(int color) {
|
||||
void setStripColor(int color) {
|
||||
itemView.setStripColor(color);
|
||||
}
|
||||
|
||||
public void setStripHeight(int stripHeight) {
|
||||
void setStripHeight(int stripHeight) {
|
||||
itemView.setStripHeight(stripHeight);
|
||||
}
|
||||
|
||||
public void setTabData(Drawable icon, CharSequence title, boolean activated) {
|
||||
void setTabData(Drawable icon, CharSequence title, boolean activated) {
|
||||
itemView.setContentDescription(title);
|
||||
iconView.setImageDrawable(icon);
|
||||
labelView.setText(title);
|
||||
|
@ -490,7 +575,7 @@ public class TabPagerIndicator extends RecyclerView implements PagerIndicator, C
|
|||
private boolean mTabExpandEnabled;
|
||||
private final RecyclerView mRecyclerView;
|
||||
|
||||
public TabLayoutManager(Context context, RecyclerView recyclerView) {
|
||||
TabLayoutManager(Context context, RecyclerView recyclerView) {
|
||||
super(context, HORIZONTAL, false);
|
||||
mRecyclerView = recyclerView;
|
||||
setAutoMeasureEnabled(true);
|
||||
|
@ -518,21 +603,15 @@ public class TabPagerIndicator extends RecyclerView implements PagerIndicator, C
|
|||
return false;
|
||||
}
|
||||
|
||||
public boolean isTabExpandEnabled() {
|
||||
boolean isTabExpandEnabled() {
|
||||
return mTabExpandEnabled;
|
||||
}
|
||||
|
||||
public void setTabExpandEnabled(boolean tabExpandEnabled) {
|
||||
void setTabExpandEnabled(boolean tabExpandEnabled) {
|
||||
mTabExpandEnabled = tabExpandEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
public void updateAppearance() {
|
||||
final int positionStart = mLayoutManager.findFirstVisibleItemPosition();
|
||||
final int itemCount = mLayoutManager.findLastVisibleItemPosition() - positionStart + 1;
|
||||
mIndicatorAdapter.notifyItemRangeChanged(positionStart, itemCount);
|
||||
}
|
||||
|
||||
private static class TabPagerIndicatorAdapter extends Adapter<TabItemHolder> {
|
||||
|
||||
private final TabPagerIndicator mIndicator;
|
||||
|
@ -544,16 +623,16 @@ public class TabPagerIndicator extends RecyclerView implements PagerIndicator, C
|
|||
private int mStripColor, mIconColor, mLabelColor;
|
||||
private boolean mDisplayBadge;
|
||||
|
||||
public TabPagerIndicatorAdapter(TabPagerIndicator indicator) {
|
||||
TabPagerIndicatorAdapter(TabPagerIndicator indicator) {
|
||||
mIndicator = indicator;
|
||||
mUnreadCounts = new SparseIntArray();
|
||||
}
|
||||
|
||||
public Context getItemContext() {
|
||||
Context getItemContext() {
|
||||
return mItemContext;
|
||||
}
|
||||
|
||||
public void setItemContext(Context itemContext) {
|
||||
void setItemContext(Context itemContext) {
|
||||
mItemContext = itemContext;
|
||||
mInflater = LayoutInflater.from(itemContext);
|
||||
}
|
||||
|
@ -587,49 +666,34 @@ public class TabPagerIndicator extends RecyclerView implements PagerIndicator, C
|
|||
return mTabProvider.getCount();
|
||||
}
|
||||
|
||||
public void setBadge(int position, int count) {
|
||||
void setBadge(int position, int count) {
|
||||
mUnreadCounts.put(position, count);
|
||||
notifyItemChanged(position);
|
||||
}
|
||||
|
||||
public void clearBadge() {
|
||||
void clearBadge() {
|
||||
mUnreadCounts.clear();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void setDisplayBadge(boolean display) {
|
||||
void setDisplayBadge(boolean display) {
|
||||
mDisplayBadge = display;
|
||||
}
|
||||
|
||||
public void setIconColor(int color) {
|
||||
void setIconColor(int color) {
|
||||
mIconColor = color;
|
||||
}
|
||||
|
||||
public void setLabelColor(int color) {
|
||||
void setLabelColor(int color) {
|
||||
mLabelColor = color;
|
||||
}
|
||||
|
||||
public void setStripColor(int color) {
|
||||
void setStripColor(int color) {
|
||||
mStripColor = color;
|
||||
}
|
||||
|
||||
public void setTabProvider(TabProvider tabProvider) {
|
||||
void setTabProvider(TabProvider tabProvider) {
|
||||
mTabProvider = tabProvider;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isTabSelected(int position) {
|
||||
final int current = getCurrentItem();
|
||||
final int columns = getColumns();
|
||||
final int count = getCount();
|
||||
if (current + columns > count) {
|
||||
return position >= count - columns;
|
||||
}
|
||||
return position >= current && position < current + columns;
|
||||
}
|
||||
|
||||
private int getColumns() {
|
||||
if (mColumns > 0) return mColumns;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,18 +27,23 @@ import android.graphics.Paint;
|
|||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.support.v4.view.WindowInsetsCompat;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import org.mariotaku.chameleon.Chameleon;
|
||||
import org.mariotaku.chameleon.ChameleonUtils;
|
||||
import org.mariotaku.chameleon.ChameleonView;
|
||||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.view.iface.TintedStatusLayout;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 14/11/26.
|
||||
*/
|
||||
public class TintedStatusFrameLayout extends ExtendedFrameLayout implements TintedStatusLayout {
|
||||
public class TintedStatusFrameLayout extends ExtendedFrameLayout implements TintedStatusLayout,
|
||||
ChameleonView, ChameleonView.StatusBarThemeable {
|
||||
|
||||
private final Paint mColorPaint;
|
||||
private boolean mSetPadding;
|
||||
|
@ -119,6 +124,42 @@ public class TintedStatusFrameLayout extends ExtendedFrameLayout implements Tint
|
|||
mWindowInsetsListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPostApplyTheme() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Appearance createAppearance(Context context, AttributeSet attributeSet, Chameleon.Theme theme) {
|
||||
Appearance appearance = new Appearance();
|
||||
appearance.setColor(ChameleonUtils.darkenColor(theme.getColorToolbar()));
|
||||
return appearance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAppearance(@NonNull ChameleonView.Appearance appearance) {
|
||||
Appearance a = (Appearance) appearance;
|
||||
setStatusBarColor(a.getColor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStatusBarColorHandled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static class Appearance implements ChameleonView.Appearance {
|
||||
int color;
|
||||
|
||||
public int getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public void setColor(int color) {
|
||||
this.color = color;
|
||||
}
|
||||
}
|
||||
|
||||
public interface WindowInsetsListener {
|
||||
void onApplyWindowInsets(int left, int top, int right, int bottom);
|
||||
}
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
package org.mariotaku.chameleon;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.view.LayoutInflaterCompat;
|
||||
import android.view.LayoutInflater;
|
||||
|
||||
import org.mariotaku.chameleon.internal.ChameleonInflationFactory;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2016/12/18.
|
||||
*/
|
||||
|
||||
public class Chameleon {
|
||||
|
||||
private final Activity activity;
|
||||
|
||||
private Chameleon(Activity activity) {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
public static Chameleon getInstance(Activity activity) {
|
||||
return new Chameleon(activity);
|
||||
}
|
||||
|
||||
public void preApply() {
|
||||
final LayoutInflater inflater = activity.getLayoutInflater();
|
||||
final ChameleonInflationFactory factory = new ChameleonInflationFactory();
|
||||
LayoutInflaterCompat.setFactory(inflater, factory);
|
||||
}
|
||||
|
||||
public void postApply() {
|
||||
|
||||
}
|
||||
|
||||
public void invalidateActivity() {
|
||||
|
||||
}
|
||||
|
||||
public void cleanUp() {
|
||||
|
||||
}
|
||||
|
||||
public void themeOverflow() {
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Theme getOverrideTheme(Context context, Object obj) {
|
||||
if (obj instanceof Themeable) {
|
||||
return ((Themeable) obj).getOverrideTheme();
|
||||
}
|
||||
return Theme.from(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2016/12/18.
|
||||
*/
|
||||
|
||||
public static class Theme {
|
||||
int primaryColor;
|
||||
int accentColor;
|
||||
int toolbarColor;
|
||||
boolean toolbarColored;
|
||||
int textColorPrimary;
|
||||
|
||||
public int getAccentColor() {
|
||||
return accentColor;
|
||||
}
|
||||
|
||||
public void setAccentColor(int accentColor) {
|
||||
this.accentColor = accentColor;
|
||||
}
|
||||
|
||||
public int getPrimaryColor() {
|
||||
return primaryColor;
|
||||
}
|
||||
|
||||
public void setPrimaryColor(int primaryColor) {
|
||||
this.primaryColor = primaryColor;
|
||||
}
|
||||
|
||||
public int getToolbarColor() {
|
||||
return toolbarColor;
|
||||
}
|
||||
|
||||
public void setToolbarColor(int toolbarColor) {
|
||||
this.toolbarColor = toolbarColor;
|
||||
}
|
||||
|
||||
public boolean isToolbarColored() {
|
||||
return toolbarColored;
|
||||
}
|
||||
|
||||
public void setToolbarColored(boolean toolbarColored) {
|
||||
this.toolbarColored = toolbarColored;
|
||||
}
|
||||
|
||||
public int getTextColorPrimary() {
|
||||
return textColorPrimary;
|
||||
}
|
||||
|
||||
public void setTextColorPrimary(int textColorPrimary) {
|
||||
this.textColorPrimary = textColorPrimary;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Theme from(Context context) {
|
||||
Theme theme = new Theme();
|
||||
return theme;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2016/12/18.
|
||||
*/
|
||||
|
||||
public interface Themeable {
|
||||
@Nullable
|
||||
Theme getOverrideTheme();
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package org.mariotaku.chameleon.internal;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v4.view.LayoutInflaterFactory;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2016/12/18.
|
||||
*/
|
||||
|
||||
public class ChameleonInflationFactory implements LayoutInflaterFactory {
|
||||
@Override
|
||||
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -42,7 +42,6 @@ import org.mariotaku.chameleon.Chameleon
|
|||
import org.mariotaku.chameleon.ChameleonActivity
|
||||
import org.mariotaku.kpreferences.KPreferences
|
||||
import org.mariotaku.twidere.BuildConfig
|
||||
import org.mariotaku.twidere.Constants
|
||||
import org.mariotaku.twidere.TwidereConstants.SHARED_PREFERENCES_NAME
|
||||
import org.mariotaku.twidere.activity.iface.IControlBarActivity
|
||||
import org.mariotaku.twidere.activity.iface.IExtendedActivity
|
||||
|
@ -58,7 +57,7 @@ import java.util.*
|
|||
import javax.inject.Inject
|
||||
|
||||
@SuppressLint("Registered")
|
||||
open class BaseActivity : ChameleonActivity(), Constants, IExtendedActivity, IThemedActivity,
|
||||
open class BaseActivity : ChameleonActivity(), IExtendedActivity, IThemedActivity,
|
||||
IControlBarActivity, OnFitSystemWindowsListener, SystemWindowsInsetsCallback,
|
||||
KeyboardShortcutCallback, OnPreferenceDisplayDialogCallback {
|
||||
@Inject
|
||||
|
@ -341,7 +340,13 @@ open class BaseActivity : ChameleonActivity(), Constants, IExtendedActivity, ITh
|
|||
}
|
||||
|
||||
override fun getOverrideTheme(): Chameleon.Theme {
|
||||
return Chameleon.Theme()
|
||||
val theme = Chameleon.Theme.from(this)
|
||||
theme.colorAccent = ThemeUtils.getUserAccentColor(this)
|
||||
theme.colorPrimary = ThemeUtils.getUserAccentColor(this)
|
||||
if (theme.isToolbarColored) {
|
||||
theme.colorToolbar = theme.colorPrimary
|
||||
}
|
||||
return theme
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -341,10 +341,10 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
|
|||
mainTabs.setOnPageChangeListener(this)
|
||||
mainTabs.setColumns(tabColumns)
|
||||
if (tabDisplayOptionInt == 0) {
|
||||
tabDisplayOptionInt = TabPagerIndicator.ICON
|
||||
tabDisplayOptionInt = TabPagerIndicator.DisplayOption.ICON
|
||||
}
|
||||
mainTabs.setTabDisplayOption(tabDisplayOptionInt)
|
||||
mainTabs.setTabExpandEnabled(tabDisplayOptionInt and TabPagerIndicator.LABEL == 0)
|
||||
mainTabs.setTabExpandEnabled(tabDisplayOptionInt and TabPagerIndicator.DisplayOption.LABEL == 0)
|
||||
mainTabs.setDisplayBadge(preferences.getBoolean(SharedPreferenceConstants.KEY_UNREAD_COUNT, true))
|
||||
mainTabs.updateAppearance()
|
||||
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* 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.mariotaku.twidere.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
import android.view.View.OnClickListener
|
||||
import kotlinx.android.synthetic.main.activity_keyboard_shortcut_input.*
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.constant.SharedPreferenceConstants.VALUE_THEME_BACKGROUND_DEFAULT
|
||||
import org.mariotaku.twidere.util.KeyboardShortcutsHandler
|
||||
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutSpec
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/4/20.
|
||||
*/
|
||||
class KeyboardShortcutPreferenceCompatActivity : BaseActivity(), OnClickListener {
|
||||
|
||||
private var keySpec: KeyboardShortcutSpec? = null
|
||||
private var metaState: Int = 0
|
||||
|
||||
override val themeBackgroundOption: String
|
||||
get() = VALUE_THEME_BACKGROUND_DEFAULT
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_keyboard_shortcut_input)
|
||||
title = KeyboardShortcutsHandler.getActionLabel(this, keyAction)
|
||||
|
||||
buttonPositive.setOnClickListener(this)
|
||||
buttonNegative.setOnClickListener(this)
|
||||
buttonNeutral.setOnClickListener(this)
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
when (v.id) {
|
||||
R.id.buttonPositive -> {
|
||||
if (keySpec == null) return
|
||||
keyboardShortcutsHandler.register(keySpec, keyAction)
|
||||
finish()
|
||||
}
|
||||
R.id.buttonNeutral -> {
|
||||
keyboardShortcutsHandler.unregister(keyAction)
|
||||
finish()
|
||||
}
|
||||
R.id.buttonNegative -> {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
|
||||
if (KeyEvent.isModifierKey(keyCode)) {
|
||||
metaState = metaState or KeyboardShortcutsHandler.getMetaStateForKeyCode(keyCode)
|
||||
}
|
||||
return super.onKeyDown(keyCode, event)
|
||||
}
|
||||
|
||||
override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
|
||||
if (KeyEvent.isModifierKey(keyCode)) {
|
||||
metaState = metaState and KeyboardShortcutsHandler.getMetaStateForKeyCode(keyCode).inv()
|
||||
}
|
||||
val keyAction = keyAction ?: return false
|
||||
val spec = KeyboardShortcutsHandler.getKeyboardShortcutSpec(contextTag,
|
||||
keyCode, event, KeyEvent.normalizeMetaState(metaState or event.metaState))
|
||||
if (spec == null || !spec.isValid) {
|
||||
return super.onKeyUp(keyCode, event)
|
||||
}
|
||||
keySpec = spec
|
||||
keysLabel.text = spec.toKeyString()
|
||||
val oldAction = keyboardShortcutsHandler.findAction(spec)
|
||||
val copyOfSpec = spec.copy()
|
||||
copyOfSpec.contextTag = null
|
||||
val oldGeneralAction = keyboardShortcutsHandler.findAction(copyOfSpec)
|
||||
if (!TextUtils.isEmpty(oldAction) && keyAction != oldAction) {
|
||||
// Conflicts with keys in same context tag
|
||||
conflictLabel.visibility = View.VISIBLE
|
||||
val label = KeyboardShortcutsHandler.getActionLabel(this, oldAction)
|
||||
conflictLabel.text = getString(R.string.conflicts_with_name, label)
|
||||
|
||||
buttonPositive.setText(R.string.overwrite)
|
||||
} else if (!TextUtils.isEmpty(oldGeneralAction) && keyAction != oldGeneralAction) {
|
||||
// Conflicts with keys in root context
|
||||
conflictLabel.visibility = View.VISIBLE
|
||||
val label = KeyboardShortcutsHandler.getActionLabel(this, oldGeneralAction)
|
||||
conflictLabel.text = getString(R.string.conflicts_with_name, label)
|
||||
buttonPositive.setText(R.string.overwrite)
|
||||
} else {
|
||||
conflictLabel.visibility = View.GONE
|
||||
buttonPositive.setText(android.R.string.ok)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private val contextTag: String
|
||||
get() = intent.getStringExtra(EXTRA_CONTEXT_TAG)
|
||||
|
||||
private val keyAction: String?
|
||||
get() = intent.getStringExtra(EXTRA_KEY_ACTION)
|
||||
|
||||
companion object {
|
||||
|
||||
val EXTRA_CONTEXT_TAG = "context_tag"
|
||||
val EXTRA_KEY_ACTION = "key_action"
|
||||
}
|
||||
}
|
|
@ -48,7 +48,7 @@ abstract class AbsToolbarTabPagesFragment : BaseSupportFragment(), RefreshScroll
|
|||
viewPager.offscreenPageLimit = 2
|
||||
viewPager.addOnPageChangeListener(this)
|
||||
toolbarTabs.setViewPager(viewPager)
|
||||
toolbarTabs.setTabDisplayOption(TabPagerIndicator.LABEL)
|
||||
toolbarTabs.setTabDisplayOption(TabPagerIndicator.DisplayOption.LABEL)
|
||||
|
||||
|
||||
addTabs(pagerAdapter!!)
|
||||
|
|
|
@ -79,6 +79,7 @@ import nl.komponents.kovenant.ui.promiseOnUi
|
|||
import nl.komponents.kovenant.ui.successUi
|
||||
import org.apache.commons.lang3.ObjectUtils
|
||||
import org.mariotaku.chameleon.Chameleon
|
||||
import org.mariotaku.chameleon.ChameleonUtils
|
||||
import org.mariotaku.ktextension.Bundle
|
||||
import org.mariotaku.ktextension.empty
|
||||
import org.mariotaku.ktextension.set
|
||||
|
@ -430,7 +431,7 @@ class UserFragment : BaseSupportFragment(), OnClickListener, OnLinkClickListener
|
|||
profileImage.visibility = View.GONE
|
||||
profileType.visibility = View.GONE
|
||||
val theme = Chameleon.getOverrideTheme(activity, activity)
|
||||
setUiColor(theme.primaryColor)
|
||||
setUiColor(theme.colorPrimary)
|
||||
return
|
||||
}
|
||||
val adapter = pagerAdapter
|
||||
|
@ -496,7 +497,7 @@ class UserFragment : BaseSupportFragment(), OnClickListener, OnLinkClickListener
|
|||
setUiColor(user.link_color)
|
||||
} else {
|
||||
val theme = Chameleon.getOverrideTheme(activity, activity)
|
||||
setUiColor(theme.primaryColor)
|
||||
setUiColor(theme.colorPrimary)
|
||||
}
|
||||
val defWidth = resources.displayMetrics.widthPixels
|
||||
val width = if (bannerWidth > 0) bannerWidth else defWidth
|
||||
|
@ -678,7 +679,7 @@ class UserFragment : BaseSupportFragment(), OnClickListener, OnLinkClickListener
|
|||
viewPager.offscreenPageLimit = 3
|
||||
viewPager.adapter = pagerAdapter
|
||||
toolbarTabs.setViewPager(viewPager)
|
||||
toolbarTabs.setTabDisplayOption(TabPagerIndicator.LABEL)
|
||||
toolbarTabs.setTabDisplayOption(TabPagerIndicator.DisplayOption.LABEL)
|
||||
toolbarTabs.setOnPageChangeListener(this)
|
||||
|
||||
followContainer.follow.setOnClickListener(this)
|
||||
|
@ -1277,15 +1278,12 @@ class UserFragment : BaseSupportFragment(), OnClickListener, OnLinkClickListener
|
|||
}
|
||||
val activity = activity as BaseActivity
|
||||
val theme = Chameleon.getOverrideTheme(activity, activity)
|
||||
primaryColor = theme.primaryColor
|
||||
primaryColorDark = ThemeUtils.computeDarkColor(primaryColor)
|
||||
if (theme.isToolbarColored) {
|
||||
primaryColor = color
|
||||
primaryColorDark = ThemeUtils.computeDarkColor(color)
|
||||
} else {
|
||||
primaryColor = theme.primaryColor
|
||||
primaryColorDark = Color.BLACK
|
||||
primaryColor = theme.colorToolbar
|
||||
}
|
||||
primaryColorDark = ChameleonUtils.darkenColor(primaryColor)
|
||||
if (actionBarBackground != null) {
|
||||
actionBarBackground!!.color = primaryColor
|
||||
}
|
||||
|
@ -1293,7 +1291,7 @@ class UserFragment : BaseSupportFragment(), OnClickListener, OnLinkClickListener
|
|||
if (theme.isToolbarColored) {
|
||||
taskColor = color
|
||||
} else {
|
||||
taskColor = theme.toolbarColor
|
||||
taskColor = theme.colorToolbar
|
||||
}
|
||||
if (user != null) {
|
||||
val name = userColorNameManager.getDisplayName(user, nameFirst)
|
||||
|
|
|
@ -20,13 +20,13 @@
|
|||
package org.mariotaku.twidere.view
|
||||
|
||||
import android.content.Context
|
||||
import android.support.v7.widget.AppCompatMultiAutoCompleteTextView
|
||||
import android.text.InputType
|
||||
import android.text.Selection
|
||||
import android.text.method.ArrowKeyMovementMethod
|
||||
import android.text.method.MovementMethod
|
||||
import android.util.AttributeSet
|
||||
import android.widget.AdapterView
|
||||
import org.mariotaku.chameleon.view.ChameleonMultiAutoCompleteTextView
|
||||
import org.mariotaku.twidere.adapter.ComposeAutoCompleteAdapter
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.util.EmojiSupportUtils
|
||||
|
@ -35,7 +35,7 @@ import org.mariotaku.twidere.util.widget.StatusTextTokenizer
|
|||
class ComposeEditText @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null
|
||||
) : AppCompatMultiAutoCompleteTextView(context, attrs) {
|
||||
) : ChameleonMultiAutoCompleteTextView(context, attrs) {
|
||||
|
||||
private var adapter: ComposeAutoCompleteAdapter? = null
|
||||
var accountKey: UserKey? = null
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
package org.mariotaku.twidere.view
|
||||
|
||||
import android.content.Context
|
||||
import android.support.v7.widget.AppCompatTextView
|
||||
import android.text.Spannable
|
||||
import android.text.method.MovementMethod
|
||||
import android.text.style.ClickableSpan
|
||||
|
@ -28,23 +27,20 @@ import android.util.AttributeSet
|
|||
import android.view.KeyEvent
|
||||
import android.view.MotionEvent
|
||||
import android.widget.TextView
|
||||
import org.mariotaku.chameleon.view.ChameleonTextView
|
||||
import org.mariotaku.twidere.util.EmojiSupportUtils
|
||||
|
||||
/**
|
||||
* Returns true when not clicking links
|
||||
* Created by mariotaku on 15/11/20.
|
||||
*/
|
||||
class TimelineContentTextView : AppCompatTextView {
|
||||
class TimelineContentTextView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyle: Int = 0
|
||||
) : ChameleonTextView(context, attrs, defStyle) {
|
||||
|
||||
constructor(context: Context) : super(context) {
|
||||
EmojiSupportUtils.initForTextView(this)
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||
EmojiSupportUtils.initForTextView(this)
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
|
||||
init {
|
||||
EmojiSupportUtils.initForTextView(this)
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="?actionBarSize"
|
||||
android:layout_alignParentTop="true"
|
||||
android:background="?colorPrimary"
|
||||
android:elevation="@dimen/toolbar_elevation"
|
||||
app:contentInsetEnd="0dp"
|
||||
app:contentInsetStart="0dp">
|
||||
|
@ -87,7 +86,7 @@
|
|||
android:layout_margin="@dimen/element_spacing_large"
|
||||
android:clickable="true"
|
||||
android:src="@drawable/ic_action_status_compose"
|
||||
android:tag="background|primary_color,tint|primary_color_dependent"
|
||||
app:backgroundTint="?colorToolbar"
|
||||
app:elevation="6dp"
|
||||
app:pressedTranslationZ="12dp"/>
|
||||
|
||||
|
|
|
@ -19,13 +19,13 @@
|
|||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:divider="?android:attr/dividerHorizontal"
|
||||
android:dividerPadding="0dip"
|
||||
android:orientation="vertical"
|
||||
android:showDividers="middle">
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:divider="?android:attr/dividerHorizontal"
|
||||
android:dividerPadding="0dip"
|
||||
android:orientation="vertical"
|
||||
android:showDividers="middle">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/keyboard_shortcut_input"
|
||||
|
@ -37,17 +37,17 @@
|
|||
android:padding="@dimen/element_spacing_xlarge">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/keys_label"
|
||||
android:id="@+id/keysLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/keyboard_shortcut_hint"
|
||||
android:textAppearance="?android:textAppearanceMedium" />
|
||||
android:textAppearance="?android:textAppearanceMedium"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/conflict_label"
|
||||
android:id="@+id/conflictLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone" />
|
||||
android:visibility="gone"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -61,7 +61,7 @@
|
|||
tools:ignore="UselessParent">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_negative"
|
||||
android:id="@+id/buttonNegative"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -70,10 +70,10 @@
|
|||
android:maxLines="2"
|
||||
android:minHeight="@dimen/element_size_normal"
|
||||
android:text="@android:string/cancel"
|
||||
android:textSize="14sp" />
|
||||
android:textSize="14sp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_neutral"
|
||||
android:id="@+id/buttonNeutral"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -82,10 +82,10 @@
|
|||
android:maxLines="2"
|
||||
android:minHeight="@dimen/element_size_normal"
|
||||
android:text="@string/clear"
|
||||
android:textSize="14sp" />
|
||||
android:textSize="14sp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_positive"
|
||||
android:id="@+id/buttonPositive"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -94,6 +94,6 @@
|
|||
android:maxLines="2"
|
||||
android:minHeight="@dimen/element_size_normal"
|
||||
android:text="@android:string/ok"
|
||||
android:textSize="14sp" />
|
||||
android:textSize="14sp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
|
@ -19,8 +19,8 @@
|
|||
<item name="quoteIndicatorBackgroundColor">@color/quote_indicator_background_light</item>
|
||||
<item name="mediaLabelBackground">#dddddd</item>
|
||||
|
||||
<!-- ATE attributes -->
|
||||
<item name="ateThemeKey">light</item>
|
||||
<item name="colorToolbar">?colorPrimary</item>
|
||||
<item name="isToolbarColored">true</item>
|
||||
|
||||
<item name="actionBarTheme">@null</item>
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||
|
@ -47,8 +47,8 @@
|
|||
<item name="messageBubbleColor">@color/message_bubble_color_light</item>
|
||||
<item name="quoteIndicatorBackgroundColor">@color/quote_indicator_background_light</item>
|
||||
|
||||
<!-- ATE attributes -->
|
||||
<item name="ateThemeKey">light</item>
|
||||
<item name="colorToolbar">?colorPrimary</item>
|
||||
<item name="isToolbarColored">true</item>
|
||||
|
||||
<item name="actionBarTheme">@null</item>
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||
|
@ -74,8 +74,8 @@
|
|||
<item name="messageBubbleColor">@color/message_bubble_color_light</item>
|
||||
<item name="quoteIndicatorBackgroundColor">@color/quote_indicator_background_light</item>
|
||||
|
||||
<!-- ATE attributes -->
|
||||
<item name="ateThemeKey">light</item>
|
||||
<item name="colorToolbar">?colorPrimary</item>
|
||||
<item name="isToolbarColored">true</item>
|
||||
|
||||
<item name="actionBarTheme">@null</item>
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
<attr name="quoteIndicatorBackgroundColor" format="color"/>
|
||||
<attr name="linePageIndicatorStyle" format="reference"/>
|
||||
<attr name="mediaLabelBackground" format="color"/>
|
||||
<attr name="ateThemeKey" format="string"/>
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="ColorLabelView">
|
||||
<attr name="ignorePadding" format="boolean"/>
|
||||
<attr name="backgroundColor" format="color"/>
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
<item name="quoteIndicatorBackgroundColor">@color/quote_indicator_background_dark</item>
|
||||
<item name="mediaLabelBackground">#505050</item>
|
||||
|
||||
<!-- ATE attributes -->
|
||||
<item name="ateThemeKey">dark</item>
|
||||
<item name="colorToolbar">@color/background_color_action_bar_dark</item>
|
||||
<item name="isToolbarColored">false</item>
|
||||
|
||||
<item name="actionBarTheme">@null</item>
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||
|
@ -55,8 +55,8 @@
|
|||
<item name="messageBubbleColor">@color/message_bubble_color_dark</item>
|
||||
<item name="quoteIndicatorBackgroundColor">@color/quote_indicator_background_dark</item>
|
||||
|
||||
<!-- ATE attributes -->
|
||||
<item name="ateThemeKey">dark</item>
|
||||
<item name="colorToolbar">@color/background_color_action_bar_dark</item>
|
||||
<item name="isToolbarColored">false</item>
|
||||
|
||||
<item name="actionBarTheme">@null</item>
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||
|
@ -84,8 +84,8 @@
|
|||
<item name="messageBubbleColor">@color/message_bubble_color_dark</item>
|
||||
<item name="quoteIndicatorBackgroundColor">@color/quote_indicator_background_dark</item>
|
||||
|
||||
<!-- ATE attributes -->
|
||||
<item name="ateThemeKey">dark</item>
|
||||
<item name="colorToolbar">@color/background_color_action_bar_dark</item>
|
||||
<item name="isToolbarColored">false</item>
|
||||
|
||||
<item name="actionBarTheme">@null</item>
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||
|
@ -154,8 +154,8 @@
|
|||
<item name="messageBubbleColor">@color/message_bubble_color_dark</item>
|
||||
<item name="quoteIndicatorBackgroundColor">@color/quote_indicator_background_dark</item>
|
||||
|
||||
<!-- ATE attributes -->
|
||||
<item name="ateThemeKey">dark</item>
|
||||
<item name="colorToolbar">@color/background_color_action_bar_dark</item>
|
||||
<item name="isToolbarColored">false</item>
|
||||
|
||||
<item name="actionBarTheme">@null</item>
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||
|
|
Loading…
Reference in New Issue