some changes

This commit is contained in:
Thomas 2023-03-24 15:13:24 +01:00
parent 4a8d20ed6b
commit 8ffd5b3a19
63 changed files with 4050 additions and 28 deletions

View File

@ -96,12 +96,11 @@ allprojects {
}
}
dependencies {
implementation project(':autoimageslider')
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
implementation 'com.jaredrummler:colorpicker:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation "com.google.code.gson:gson:2.9.1"
@ -121,15 +120,18 @@ dependencies {
}
implementation "org.jsoup:jsoup:1.15.1"
implementation 'com.github.mergehez:ArgPlayer:v3.1'
implementation project(':autoimageslider')
implementation project(path: ':mytransl')
implementation project(path: ':ratethisapp')
implementation project(path: ':sparkbutton')
implementation project(path: ':colorPicker')
implementation project(path: ':mathjaxandroid')
implementation 'com.burhanrashid52:photoeditor:1.5.1'
implementation("com.vanniktech:android-image-cropper:4.3.3")
implementation project(path: ':mathjaxandroid')
annotationProcessor "com.github.bumptech.glide:compiler:4.12.0"
implementation 'jp.wasabeef:glide-transformations:4.3.0'
implementation 'com.github.penfeizhou.android.animation:glide-plugin:2.23.0'
@ -165,7 +167,6 @@ dependencies {
implementation 'com.r0adkll:slidableactivity:2.1.0'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
implementation "androidx.fragment:fragment:1.5.5"
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'

View File

@ -1067,6 +1067,16 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
} catch (DBException e) {
e.printStackTrace();
}
if (currentAccount != null && currentInstance == null) {
currentInstance = currentAccount.instance;
currentUserID = currentAccount.user_id;
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> {
recreate();
};
mainHandler.post(myRunnable);
}
if (currentAccount != null && currentAccount.peertube_account != null) {
//It is a peertube user
Intent intent = getIntent();

View File

@ -30,7 +30,6 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.preference.PreferenceManager;
import com.google.android.material.color.DynamicColors;
import com.vanniktech.emoji.EmojiManager;
import com.vanniktech.emoji.one.EmojiOneProvider;
@ -52,6 +51,7 @@ public class BaseActivity extends AppCompatActivity {
EmojiManager.install(new EmojiOneProvider());
}
@SuppressLint("RestrictedApi")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@ -70,9 +70,8 @@ public class BaseActivity extends AppCompatActivity {
String currentTheme = sharedpreferences.getString(getString(R.string.SET_THEME_BASE), getString(R.string.SET_DEFAULT_THEME));
//Default automatic switch
int currentNightMode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
if (currentTheme.equals(getString(R.string.SET_DEFAULT_THEME))) {
int currentNightMode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
switch (currentNightMode) {
case Configuration.UI_MODE_NIGHT_NO:
String defaultLight = sharedpreferences.getString(getString(R.string.SET_THEME_DEFAULT_LIGHT), "LIGHT");
@ -144,10 +143,8 @@ public class BaseActivity extends AppCompatActivity {
}
}
super.onCreate(savedInstanceState);
boolean dynamicColor = sharedpreferences.getBoolean(getString(R.string.SET_DYNAMICCOLOR), false);
if (dynamicColor) {
DynamicColors.applyToActivityIfAvailable(this);
}
ThemeHelper.applyThemeColor(this);
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) {
ThemeHelper.adjustFontScale(this, getResources().getConfiguration());
}

View File

@ -30,7 +30,6 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.preference.PreferenceManager;
import com.google.android.material.color.DynamicColors;
import com.vanniktech.emoji.EmojiManager;
import com.vanniktech.emoji.one.EmojiOneProvider;
@ -66,9 +65,8 @@ public class BaseBarActivity extends AppCompatActivity {
}
String currentTheme = sharedpreferences.getString(getString(R.string.SET_THEME_BASE), getString(R.string.SET_DEFAULT_THEME));
//Default automatic switch
int currentNightMode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
if (currentTheme.equals(getString(R.string.SET_DEFAULT_THEME))) {
int currentNightMode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
switch (currentNightMode) {
case Configuration.UI_MODE_NIGHT_NO:
String defaultLight = sharedpreferences.getString(getString(R.string.SET_THEME_DEFAULT_LIGHT), "LIGHT");
@ -129,10 +127,8 @@ public class BaseBarActivity extends AppCompatActivity {
}
}
super.onCreate(savedInstanceState);
boolean dynamicColor = sharedpreferences.getBoolean(getString(R.string.SET_DYNAMICCOLOR), false);
if (dynamicColor) {
DynamicColors.applyToActivityIfAvailable(this);
}
ThemeHelper.applyThemeColor(this);
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);

View File

@ -30,7 +30,6 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.preference.PreferenceManager;
import com.google.android.material.color.DynamicColors;
import com.vanniktech.emoji.EmojiManager;
import com.vanniktech.emoji.one.EmojiOneProvider;
@ -66,9 +65,9 @@ public class BaseTransparentActivity extends AppCompatActivity {
}
String currentTheme = sharedpreferences.getString(getString(R.string.SET_THEME_BASE), getString(R.string.SET_DEFAULT_THEME));
//Default automatic switch
int currentNightMode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
if (currentTheme.equals(getString(R.string.SET_DEFAULT_THEME))) {
int currentNightMode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
switch (currentNightMode) {
case Configuration.UI_MODE_NIGHT_NO:
String defaultLight = sharedpreferences.getString(getString(R.string.SET_THEME_DEFAULT_LIGHT), "LIGHT");
@ -129,10 +128,7 @@ public class BaseTransparentActivity extends AppCompatActivity {
}
}
super.onCreate(savedInstanceState);
boolean dynamicColor = sharedpreferences.getBoolean(getString(R.string.SET_DYNAMICCOLOR), false);
if (dynamicColor) {
DynamicColors.applyToActivityIfAvailable(this);
}
ThemeHelper.applyThemeColor(this);
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);

View File

@ -15,6 +15,8 @@ package app.fedilab.android.mastodon.helper;
* see <http://www.gnu.org/licenses>. */
import static android.content.Context.WINDOW_SERVICE;
import static app.fedilab.android.BaseMainActivity.currentInstance;
import static app.fedilab.android.BaseMainActivity.currentUserID;
import android.app.Activity;
import android.content.Context;
@ -23,6 +25,8 @@ import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.os.Build;
import android.util.DisplayMetrics;
import android.util.TypedValue;
@ -37,6 +41,9 @@ import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;
import com.google.android.material.color.DynamicColors;
import com.google.android.material.color.DynamicColorsOptions;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
@ -278,6 +285,31 @@ public class ThemeHelper {
}
}
public static void applyThemeColor(Activity activity) {
int currentNightMode = activity.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
final SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(activity);
boolean dynamicColor = sharedpreferences.getBoolean(activity.getString(R.string.SET_DYNAMICCOLOR), false);
boolean customAccentEnabled = sharedpreferences.getBoolean(activity.getString(R.string.SET_CUSTOM_ACCENT) + currentUserID + currentInstance, false);
int customAccentLight = sharedpreferences.getInt(activity.getString(R.string.SET_CUSTOM_ACCENT_LIGHT_VALUE) + currentUserID + currentInstance, -1);
int customAccentDark = sharedpreferences.getInt(activity.getString(R.string.SET_CUSTOM_ACCENT_DARK_VALUE) + currentUserID + currentInstance, -1);
if (customAccentEnabled) {
Bitmap bmp = Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
//Light theme enabled
if (currentNightMode == Configuration.UI_MODE_NIGHT_NO && customAccentLight != -1) {
canvas.drawColor(customAccentLight);
} else if (customAccentDark != -1) {
canvas.drawColor(customAccentDark);
}
DynamicColorsOptions.Builder builder = new DynamicColorsOptions.Builder();
builder.setContentBasedSource(bmp);
DynamicColorsOptions dynamicColorsOptions = builder.build();
DynamicColors.applyToActivityIfAvailable(activity, dynamicColorsOptions);
} else if (dynamicColor) {
DynamicColors.applyToActivityIfAvailable(activity);
}
}
public enum themes {
LIGHT,
DARK,

View File

@ -15,8 +15,13 @@ package app.fedilab.android.mastodon.ui.fragment.settings;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentInstance;
import static app.fedilab.android.BaseMainActivity.currentUserID;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AlertDialog;
import androidx.navigation.NavOptions;
@ -24,16 +29,21 @@ import androidx.navigation.Navigation;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceManager;
import androidx.preference.SwitchPreferenceCompat;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.jaredrummler.android.colorpicker.ColorPreferenceCompat;
import app.fedilab.android.R;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.mastodon.helper.Helper;
import es.dmoral.toasty.Toasty;
public class FragmentThemingSettings extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener {
boolean prefChanged = false;
@Override
public void onCreatePreferences(Bundle bundle, String s) {
createPref();
@ -55,22 +65,45 @@ public class FragmentThemingSettings extends PreferenceFragmentCompat implements
if (getPreferenceScreen() != null && getPreferenceScreen().getSharedPreferences() != null) {
getPreferenceScreen().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(this);
if (prefChanged) {
Helper.recreateMainActivity(requireActivity());
prefChanged = false;
}
}
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity());
SharedPreferences.Editor editor = sharedpreferences.edit();
prefChanged = true;
if (key.compareTo(getString(R.string.SET_THEME_BASE)) == 0) {
ListPreference SET_THEME_BASE = findPreference(getString(R.string.SET_THEME_BASE));
if (SET_THEME_BASE != null) {
requireActivity().finish();
startActivity(requireActivity().getIntent());
}
Helper.recreateMainActivity(requireActivity());
} else if (key.compareTo(getString(R.string.SET_CUSTOM_ACCENT)) == 0) {
SwitchPreferenceCompat SET_CUSTOM_ACCENT = findPreference(getString(R.string.SET_CUSTOM_ACCENT));
if (SET_CUSTOM_ACCENT != null) {
editor.putBoolean(getString(R.string.SET_CUSTOM_ACCENT) + MainActivity.currentUserID + MainActivity.currentInstance, SET_CUSTOM_ACCENT.isChecked());
}
} else if (key.compareTo(getString(R.string.SET_CUSTOM_ACCENT_LIGHT_VALUE)) == 0) {
ColorPreferenceCompat SET_CUSTOM_ACCENT_VALUE = findPreference(getString(R.string.SET_CUSTOM_ACCENT_LIGHT_VALUE));
if (SET_CUSTOM_ACCENT_VALUE != null) {
editor.putInt(getString(R.string.SET_CUSTOM_ACCENT_LIGHT_VALUE) + MainActivity.currentUserID + MainActivity.currentInstance, SET_CUSTOM_ACCENT_VALUE.getColor());
}
} else if (key.compareTo(getString(R.string.SET_CUSTOM_ACCENT_DARK_VALUE)) == 0) {
ColorPreferenceCompat SET_CUSTOM_ACCENT_VALUE = findPreference(getString(R.string.SET_CUSTOM_ACCENT_DARK_VALUE));
if (SET_CUSTOM_ACCENT_VALUE != null) {
editor.putInt(getString(R.string.SET_CUSTOM_ACCENT_DARK_VALUE) + MainActivity.currentUserID + MainActivity.currentInstance, SET_CUSTOM_ACCENT_VALUE.getColor());
}
}
//TODO: check if can be removed
Helper.recreateMainActivity(requireActivity());
Log.v(Helper.TAG, "currentUserID: " + currentUserID);
Log.v(Helper.TAG, "currentInstance: " + currentInstance);
editor.apply();
}
@ -83,6 +116,24 @@ public class FragmentThemingSettings extends PreferenceFragmentCompat implements
Toasty.error(requireActivity(), getString(R.string.toast_error), Toasty.LENGTH_SHORT).show();
}
SwitchPreferenceCompat SET_DYNAMIC_COLOR = findPreference(getString(R.string.SET_DYNAMICCOLOR));
SwitchPreferenceCompat SET_CUSTOM_ACCENT = findPreference(getString(R.string.SET_CUSTOM_ACCENT));
ColorPreferenceCompat SET_CUSTOM_ACCENT_DARK_VALUE = findPreference(getString(R.string.SET_CUSTOM_ACCENT_DARK_VALUE));
ColorPreferenceCompat SET_CUSTOM_ACCENT_LIGHT_VALUE = findPreference(getString(R.string.SET_CUSTOM_ACCENT_LIGHT_VALUE));
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
if (SET_DYNAMIC_COLOR != null) {
getPreferenceScreen().removePreference(SET_DYNAMIC_COLOR);
}
if (SET_CUSTOM_ACCENT != null) {
getPreferenceScreen().removePreference(SET_CUSTOM_ACCENT);
}
if (SET_CUSTOM_ACCENT_DARK_VALUE != null) {
getPreferenceScreen().removePreference(SET_CUSTOM_ACCENT_DARK_VALUE);
}
if (SET_CUSTOM_ACCENT_LIGHT_VALUE != null) {
getPreferenceScreen().removePreference(SET_CUSTOM_ACCENT_LIGHT_VALUE);
}
}
Preference SET_CUSTOMIZE_LIGHT_COLORS_ACTION = findPreference(getString(R.string.SET_CUSTOMIZE_LIGHT_COLORS_ACTION));
if (SET_CUSTOMIZE_LIGHT_COLORS_ACTION != null) {

View File

@ -3,4 +3,10 @@
<string name="auto">Auto</string>
<string name="set_custom_accent">Custom accent color</string>
<string name="set_custom_accent_indication">Define a theme color per account</string>
<string name="set_custom_accent_light_value">Light accent color</string>
<string name="set_custom_accent_dark_value">Dark accent color</string>
<string name="set_custom_accent_value_light_description">Color that will be applied to the light theme</string>
<string name="set_custom_accent_value_dark_description">Color that will be applied to the dark theme</string>
</resources>

View File

@ -1037,6 +1037,10 @@
<string name="SET_THEME_BASE" translatable="false">SET_THEME_BASE</string>
<string name="SET_DYNAMICCOLOR" translatable="false">SET_DYNAMICCOLOR</string>
<string name="SET_CUSTOM_ACCENT" translatable="false">SET_CUSTOM_ACCENT</string>
<string name="SET_CUSTOM_ACCENT_LIGHT_VALUE" translatable="false">SET_CUSTOM_ACCENT_LIGHT_VALUE</string>
<string name="SET_CUSTOM_ACCENT_DARK_VALUE" translatable="false">SET_CUSTOM_ACCENT_DARK_VALUE</string>
<string name="SET_CARDVIEW" translatable="false">SET_CARDVIEW</string>
<string name="SET_CUSTOMIZE_LIGHT_COLORS" translatable="false">SET_CUSTOMIZE_LIGHT_COLORS</string>
<string name="SET_CHAT_FOR_CONVERSATION" translatable="false">SET_CHAT_FOR_CONVERSATION</string>

View File

@ -24,6 +24,28 @@
app:summary="@string/set_dynamic_color_indication"
app:title="@string/set_dynamic_color" />
<SwitchPreferenceCompat
app:defaultValue="false"
app:iconSpaceReserved="false"
app:key="@string/SET_CUSTOM_ACCENT"
app:singleLineTitle="false"
app:summary="@string/set_custom_accent_indication"
app:title="@string/set_custom_accent" />
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
android:dependency="@string/SET_CUSTOM_ACCENT"
android:key="@string/SET_CUSTOM_ACCENT_LIGHT_VALUE"
app:iconSpaceReserved="false"
app:summary="@string/set_custom_accent_value_light_description"
app:title="@string/set_custom_accent_light_value" />
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
android:dependency="@string/SET_CUSTOM_ACCENT"
android:key="@string/SET_CUSTOM_ACCENT_DARK_VALUE"
app:iconSpaceReserved="false"
app:summary="@string/set_custom_accent_value_dark_description"
app:title="@string/set_custom_accent_dark_value" />
<ListPreference
app:defaultValue="LIGHT"
app:dialogTitle="@string/type_default_theme_light"

1
colorPicker/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

39
colorPicker/build.gradle Normal file
View File

@ -0,0 +1,39 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 33
defaultConfig {
minSdkVersion 15
targetSdkVersion 33
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
// Add a new configuration to hold your dependencies
configurations {
libConfig
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
//noinspection GradleCompatible
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'androidx.preference:preference:1.2.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test:runner:1.5.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
}

View File

@ -0,0 +1,19 @@
VERSION_NAME=1.1.0
VERSION_CODE=110
GROUP=com.jaredrummler
ARTIFACT_ID=colorpicker
POM_NAME=colorpicker
POM_ARTIFACT_ID=colorpicker
POM_PACKAGING=aar
POM_DESCRIPTION=A simply good looking color picker component for Android
POM_URL=https://github.com/jaredrummler/ColorPicker
POM_SCM_URL=https://github.com/jaredrummler/ColorPicker
POM_SCM_CONNECTION=scm:git@github.com:jaredrummler/ColorPicker.git
POM_SCM_DEV_CONNECTION=scm:git@github.com:jaredrummler/ColorPicker.git
POM_LICENCE_NAME=The Apache Software License, Version 2.0
POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
POM_LICENCE_DIST=repo
POM_DEVELOPER_ID=jaredrummler
POM_DEVELOPER_NAME=Jared Rummler
SNAPSHOT_REPOSITORY_URL=https://oss.sonatype.org/content/repositories/snapshots
RELEASE_REPOSITORY_URL=https://oss.sonatype.org/service/local/staging/deploy/maven2

17
colorPicker/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\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 *;
#}

View File

@ -0,0 +1 @@
<manifest package="com.jaredrummler.android.colorpicker" />

View File

@ -0,0 +1,113 @@
/*
* Copyright (C) 2017 Jared Rummler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jaredrummler.android.colorpicker;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
/**
* This drawable will draw a simple white and gray chessboard pattern.
* It's the pattern you will often see as a background behind a partly transparent image in many applications.
*/
class AlphaPatternDrawable extends Drawable {
private final Paint paint = new Paint();
private final Paint paintWhite = new Paint();
private final Paint paintGray = new Paint();
private int rectangleSize = 10;
private int numRectanglesHorizontal;
private int numRectanglesVertical;
/**
* Bitmap in which the pattern will be cached.
* This is so the pattern will not have to be recreated each time draw() gets called.
* Because recreating the pattern i rather expensive. I will only be recreated if the size changes.
*/
private Bitmap bitmap;
AlphaPatternDrawable(int rectangleSize) {
this.rectangleSize = rectangleSize;
paintWhite.setColor(0xFFFFFFFF);
paintGray.setColor(0xFFCBCBCB);
}
@Override
public void draw(Canvas canvas) {
if (bitmap != null && !bitmap.isRecycled()) {
canvas.drawBitmap(bitmap, null, getBounds(), paint);
}
}
@Override
public int getOpacity() {
return 0;
}
@Override
public void setAlpha(int alpha) {
throw new UnsupportedOperationException("Alpha is not supported by this drawable.");
}
@Override
public void setColorFilter(ColorFilter cf) {
throw new UnsupportedOperationException("ColorFilter is not supported by this drawable.");
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
int height = bounds.height();
int width = bounds.width();
numRectanglesHorizontal = (int) Math.ceil((width / rectangleSize));
numRectanglesVertical = (int) Math.ceil(height / rectangleSize);
generatePatternBitmap();
}
/**
* This will generate a bitmap with the pattern as big as the rectangle we were allow to draw on.
* We do this to chache the bitmap so we don't need to recreate it each time draw() is called since it takes a few
* milliseconds
*/
private void generatePatternBitmap() {
if (getBounds().width() <= 0 || getBounds().height() <= 0) {
return;
}
bitmap = Bitmap.createBitmap(getBounds().width(), getBounds().height(), Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Rect r = new Rect();
boolean verticalStartWhite = true;
for (int i = 0; i <= numRectanglesVertical; i++) {
boolean isWhite = verticalStartWhite;
for (int j = 0; j <= numRectanglesHorizontal; j++) {
r.top = i * rectangleSize;
r.left = j * rectangleSize;
r.bottom = r.top + rectangleSize;
r.right = r.left + rectangleSize;
canvas.drawRect(r, isWhite ? paintWhite : paintGray);
isWhite = !isWhite;
}
verticalStartWhite = !verticalStartWhite;
}
}
}

View File

@ -0,0 +1,150 @@
/*
* Copyright (C) 2017 Jared Rummler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jaredrummler.android.colorpicker;
import android.content.Context;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import androidx.core.graphics.ColorUtils;
class ColorPaletteAdapter extends BaseAdapter {
/*package*/ final OnColorSelectedListener listener;
/*package*/ final int[] colors;
/*package*/ int selectedPosition;
/*package*/ int colorShape;
ColorPaletteAdapter(OnColorSelectedListener listener, int[] colors, int selectedPosition,
@ColorShape int colorShape) {
this.listener = listener;
this.colors = colors;
this.selectedPosition = selectedPosition;
this.colorShape = colorShape;
}
@Override
public int getCount() {
return colors.length;
}
@Override
public Object getItem(int position) {
return colors[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder(parent.getContext());
convertView = holder.view;
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.setup(position);
return convertView;
}
void selectNone() {
selectedPosition = -1;
notifyDataSetChanged();
}
interface OnColorSelectedListener {
void onColorSelected(int color);
}
private final class ViewHolder {
View view;
ColorPanelView colorPanelView;
ImageView imageView;
int originalBorderColor;
ViewHolder(Context context) {
int layoutResId;
if (colorShape == ColorShape.SQUARE) {
layoutResId = R.layout.cpv_color_item_square;
} else {
layoutResId = R.layout.cpv_color_item_circle;
}
view = View.inflate(context, layoutResId, null);
colorPanelView = view.findViewById(R.id.cpv_color_panel_view);
imageView = view.findViewById(R.id.cpv_color_image_view);
originalBorderColor = colorPanelView.getBorderColor();
view.setTag(this);
}
void setup(int position) {
int color = colors[position];
int alpha = Color.alpha(color);
colorPanelView.setColor(color);
imageView.setImageResource(selectedPosition == position ? R.drawable.cpv_preset_checked : 0);
if (alpha != 255) {
if (alpha <= ColorPickerDialog.ALPHA_THRESHOLD) {
colorPanelView.setBorderColor(color | 0xFF000000);
imageView.setColorFilter(/*color | 0xFF000000*/Color.BLACK, PorterDuff.Mode.SRC_IN);
} else {
colorPanelView.setBorderColor(originalBorderColor);
imageView.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN);
}
} else {
setColorFilter(position);
}
setOnClickListener(position);
}
private void setOnClickListener(final int position) {
colorPanelView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (selectedPosition != position) {
selectedPosition = position;
notifyDataSetChanged();
}
listener.onColorSelected(colors[position]);
}
});
colorPanelView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
colorPanelView.showHint();
return true;
}
});
}
private void setColorFilter(int position) {
if (position == selectedPosition && ColorUtils.calculateLuminance(colors[position]) >= 0.65) {
imageView.setColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN);
} else {
imageView.setColorFilter(null);
}
}
}
}

View File

@ -0,0 +1,316 @@
/*
* Copyright (C) 2017 Jared Rummler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jaredrummler.android.colorpicker;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.ColorInt;
import androidx.core.view.GravityCompat;
import androidx.core.view.ViewCompat;
import java.util.Locale;
/**
* This class draws a panel which which will be filled with a color which can be set. It can be used to show the
* currently selected color which you will get from the {@link ColorPickerView}.
*/
public class ColorPanelView extends View {
private final static int DEFAULT_BORDER_COLOR = 0xFF6E6E6E;
private Drawable alphaPattern;
private Paint borderPaint;
private Paint colorPaint;
private Paint alphaPaint;
private Paint originalPaint;
private Rect drawingRect;
private Rect colorRect;
private RectF centerRect = new RectF();
private boolean showOldColor;
/* The width in pixels of the border surrounding the color panel. */
private int borderWidthPx;
private int borderColor = DEFAULT_BORDER_COLOR;
private int color = Color.BLACK;
private int shape;
public ColorPanelView(Context context) {
this(context, null);
}
public ColorPanelView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ColorPanelView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
@Override
public Parcelable onSaveInstanceState() {
Bundle state = new Bundle();
state.putParcelable("instanceState", super.onSaveInstanceState());
state.putInt("color", color);
return state;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
Bundle bundle = (Bundle) state;
color = bundle.getInt("color");
state = bundle.getParcelable("instanceState");
}
super.onRestoreInstanceState(state);
}
private void init(Context context, AttributeSet attrs) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ColorPanelView);
shape = a.getInt(R.styleable.ColorPanelView_cpv_colorShape, ColorShape.CIRCLE);
showOldColor = a.getBoolean(R.styleable.ColorPanelView_cpv_showOldColor, false);
if (showOldColor && shape != ColorShape.CIRCLE) {
throw new IllegalStateException("Color preview is only available in circle mode");
}
borderColor = a.getColor(R.styleable.ColorPanelView_cpv_borderColor, DEFAULT_BORDER_COLOR);
a.recycle();
if (borderColor == DEFAULT_BORDER_COLOR) {
// If no specific border color has been set we take the default secondary text color as border/slider color.
// Thus it will adopt to theme changes automatically.
final TypedValue value = new TypedValue();
TypedArray typedArray =
context.obtainStyledAttributes(value.data, new int[]{android.R.attr.textColorSecondary});
borderColor = typedArray.getColor(0, borderColor);
typedArray.recycle();
}
borderWidthPx = DrawingUtils.dpToPx(context, 1);
borderPaint = new Paint();
borderPaint.setAntiAlias(true);
colorPaint = new Paint();
colorPaint.setAntiAlias(true);
if (showOldColor) {
originalPaint = new Paint();
}
if (shape == ColorShape.CIRCLE) {
Bitmap bitmap = ((BitmapDrawable) context.getResources().getDrawable(R.drawable.cpv_alpha)).getBitmap();
alphaPaint = new Paint();
alphaPaint.setAntiAlias(true);
BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
alphaPaint.setShader(shader);
}
}
@Override
protected void onDraw(Canvas canvas) {
borderPaint.setColor(borderColor);
colorPaint.setColor(color);
if (shape == ColorShape.SQUARE) {
if (borderWidthPx > 0) {
canvas.drawRect(drawingRect, borderPaint);
}
if (alphaPattern != null) {
alphaPattern.draw(canvas);
}
canvas.drawRect(colorRect, colorPaint);
} else if (shape == ColorShape.CIRCLE) {
final int outerRadius = getMeasuredWidth() / 2;
if (borderWidthPx > 0) {
canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, outerRadius, borderPaint);
}
if (Color.alpha(color) < 255) {
canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, outerRadius - borderWidthPx, alphaPaint);
}
if (showOldColor) {
canvas.drawArc(centerRect, 90, 180, true, originalPaint);
canvas.drawArc(centerRect, 270, 180, true, colorPaint);
} else {
canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, outerRadius - borderWidthPx, colorPaint);
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (shape == ColorShape.SQUARE) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
} else if (shape == ColorShape.CIRCLE) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth());
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (shape == ColorShape.SQUARE || showOldColor) {
drawingRect = new Rect();
drawingRect.left = getPaddingLeft();
drawingRect.right = w - getPaddingRight();
drawingRect.top = getPaddingTop();
drawingRect.bottom = h - getPaddingBottom();
if (showOldColor) {
setUpCenterRect();
} else {
setUpColorRect();
}
}
}
private void setUpCenterRect() {
final Rect dRect = drawingRect;
int left = dRect.left + borderWidthPx;
int top = dRect.top + borderWidthPx;
int bottom = dRect.bottom - borderWidthPx;
int right = dRect.right - borderWidthPx;
centerRect = new RectF(left, top, right, bottom);
}
private void setUpColorRect() {
final Rect dRect = drawingRect;
int left = dRect.left + borderWidthPx;
int top = dRect.top + borderWidthPx;
int bottom = dRect.bottom - borderWidthPx;
int right = dRect.right - borderWidthPx;
colorRect = new Rect(left, top, right, bottom);
alphaPattern = new AlphaPatternDrawable(DrawingUtils.dpToPx(getContext(), 4));
alphaPattern.setBounds(Math.round(colorRect.left), Math.round(colorRect.top), Math.round(colorRect.right),
Math.round(colorRect.bottom));
}
/**
* Get the color currently show by this view.
*
* @return the color value
*/
public int getColor() {
return color;
}
/**
* Set the color that should be shown by this view.
*
* @param color the color value
*/
public void setColor(int color) {
this.color = color;
invalidate();
}
/**
* Set the original color. This is only used for previewing colors.
*
* @param color The original color
*/
public void setOriginalColor(@ColorInt int color) {
if (originalPaint != null) {
originalPaint.setColor(color);
}
}
/**
* @return the color of the border surrounding the panel.
*/
public int getBorderColor() {
return borderColor;
}
/**
* Set the color of the border surrounding the panel.
*
* @param color the color value
*/
public void setBorderColor(int color) {
borderColor = color;
invalidate();
}
/**
* Get the shape
*
* @return Either {@link ColorShape#SQUARE} or {@link ColorShape#CIRCLE}.
*/
@ColorShape
public int getShape() {
return shape;
}
/**
* Set the shape.
*
* @param shape Either {@link ColorShape#SQUARE} or {@link ColorShape#CIRCLE}.
*/
public void setShape(@ColorShape int shape) {
this.shape = shape;
invalidate();
}
/**
* Show a toast message with the hex color code below the view.
*/
public void showHint() {
final int[] screenPos = new int[2];
final Rect displayFrame = new Rect();
getLocationOnScreen(screenPos);
getWindowVisibleDisplayFrame(displayFrame);
final Context context = getContext();
final int width = getWidth();
final int height = getHeight();
final int midy = screenPos[1] + height / 2;
int referenceX = screenPos[0] + width / 2;
if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_LTR) {
final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
referenceX = screenWidth - referenceX; // mirror
}
StringBuilder hint = new StringBuilder("#");
if (Color.alpha(color) != 255) {
hint.append(Integer.toHexString(color).toUpperCase(Locale.ENGLISH));
} else {
hint.append(String.format("%06X", 0xFFFFFF & color).toUpperCase(Locale.ENGLISH));
}
Toast cheatSheet = Toast.makeText(context, hint.toString(), Toast.LENGTH_SHORT);
if (midy < displayFrame.height()) {
// Show along the top; follow action buttons
cheatSheet.setGravity(Gravity.TOP | GravityCompat.END, referenceX, screenPos[1] + height - displayFrame.top);
} else {
// Show along the bottom center
cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height);
}
cheatSheet.show();
}
}

View File

@ -0,0 +1,968 @@
/*
* Copyright (C) 2017 Jared Rummler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jaredrummler.android.colorpicker;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.text.Editable;
import android.text.InputFilter;
import android.text.TextWatcher;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AlertDialog;
import androidx.core.graphics.ColorUtils;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity;
import java.util.Arrays;
import java.util.Locale;
/**
* <p>A dialog to pick a color.</p>
*
* <p>The {@link Activity activity} that shows this dialog should implement {@link ColorPickerDialogListener}</p>
*
* <p>Example usage:</p>
*
* <pre>
* ColorPickerDialog.newBuilder().show(activity);
* </pre>
*/
public class ColorPickerDialog extends DialogFragment implements ColorPickerView.OnColorChangedListener, TextWatcher {
public static final int TYPE_CUSTOM = 0;
public static final int TYPE_PRESETS = 1;
/**
* Material design colors used as the default color presets
*/
public static final int[] MATERIAL_COLORS = {
0xFFF44336, // RED 500
0xFFE91E63, // PINK 500
0xFFFF2C93, // LIGHT PINK 500
0xFF9C27B0, // PURPLE 500
0xFF673AB7, // DEEP PURPLE 500
0xFF3F51B5, // INDIGO 500
0xFF2196F3, // BLUE 500
0xFF03A9F4, // LIGHT BLUE 500
0xFF00BCD4, // CYAN 500
0xFF009688, // TEAL 500
0xFF4CAF50, // GREEN 500
0xFF8BC34A, // LIGHT GREEN 500
0xFFCDDC39, // LIME 500
0xFFFFEB3B, // YELLOW 500
0xFFFFC107, // AMBER 500
0xFFFF9800, // ORANGE 500
0xFF795548, // BROWN 500
0xFF607D8B, // BLUE GREY 500
0xFF9E9E9E, // GREY 500
};
static final int ALPHA_THRESHOLD = 165;
private static final String TAG = "ColorPickerDialog";
private static final String ARG_ID = "id";
private static final String ARG_TYPE = "dialogType";
private static final String ARG_COLOR = "color";
private static final String ARG_ALPHA = "alpha";
private static final String ARG_PRESETS = "presets";
private static final String ARG_ALLOW_PRESETS = "allowPresets";
private static final String ARG_ALLOW_CUSTOM = "allowCustom";
private static final String ARG_DIALOG_TITLE = "dialogTitle";
private static final String ARG_SHOW_COLOR_SHADES = "showColorShades";
private static final String ARG_COLOR_SHAPE = "colorShape";
private static final String ARG_PRESETS_BUTTON_TEXT = "presetsButtonText";
private static final String ARG_CUSTOM_BUTTON_TEXT = "customButtonText";
private static final String ARG_SELECTED_BUTTON_TEXT = "selectedButtonText";
ColorPickerDialogListener colorPickerDialogListener;
FrameLayout rootView;
int[] presets;
@ColorInt
int color;
int dialogType;
int dialogId;
boolean showColorShades;
int colorShape;
// -- PRESETS --------------------------
ColorPaletteAdapter adapter;
LinearLayout shadesLayout;
SeekBar transparencySeekBar;
TextView transparencyPercText;
// -- CUSTOM ---------------------------
ColorPickerView colorPicker;
ColorPanelView newColorPanel;
EditText hexEditText;
private final OnTouchListener onPickerTouchListener = new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (v != hexEditText && hexEditText.hasFocus()) {
hexEditText.clearFocus();
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(hexEditText.getWindowToken(), 0);
hexEditText.clearFocus();
return true;
}
return false;
}
};
boolean showAlphaSlider;
private int presetsButtonStringRes;
private boolean fromEditText;
private int customButtonStringRes;
/**
* Create a new Builder for creating a {@link ColorPickerDialog} instance
*
* @return The {@link Builder builder} to create the {@link ColorPickerDialog}.
*/
public static Builder newBuilder() {
return new Builder();
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
dialogId = getArguments().getInt(ARG_ID);
showAlphaSlider = getArguments().getBoolean(ARG_ALPHA);
showColorShades = getArguments().getBoolean(ARG_SHOW_COLOR_SHADES);
colorShape = getArguments().getInt(ARG_COLOR_SHAPE);
if (savedInstanceState == null) {
color = getArguments().getInt(ARG_COLOR);
dialogType = getArguments().getInt(ARG_TYPE);
} else {
color = savedInstanceState.getInt(ARG_COLOR);
dialogType = savedInstanceState.getInt(ARG_TYPE);
}