diff --git a/.gitignore b/.gitignore
index c08bf69b..4fd2b224 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,4 +36,8 @@ proguard/
*.el
.DS_Store
-.externalNativeBuild
\ No newline at end of file
+.externalNativeBuild
+
+# Node
+node_modules
+package-lock.json
diff --git a/.gitmodules b/.gitmodules
index a7400dae..e69de29b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +0,0 @@
-[submodule "colorpicker"]
- path = colorpicker
- url = https://github.com/M66B/colorpicker.git
diff --git a/app/build.gradle b/app/build.gradle
index dbd73666..4259acfa 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,14 +1,14 @@
apply plugin: "com.android.application"
-apply plugin: "kotlin-android-extensions"
apply plugin: "kotlin-android"
+apply plugin: "kotlin-android-extensions"
apply from: "${rootDir}/jdee.gradle"
android {
- compileSdkVersion 28
+ compileSdkVersion 30
defaultConfig {
applicationId "org.dystopia.email"
- minSdkVersion 23
- targetSdkVersion 28
+ minSdkVersion 21
+ targetSdkVersion 30
versionCode 115
versionName "1.3.0"
archivesBaseName = "SimpleEmail-v$versionName"
@@ -58,6 +58,9 @@ repositories {
jcenter()
maven {
url "https://repo1.maven.org/maven2/"
+ }
+ maven {
+ url "https://jitpack.io"
}
}
@@ -69,6 +72,8 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
def androidx_version = "1.0.0"
+ def appcompat_version = "1.2.0"
+ def fragment_version = "1.3.0-beta01"
def constraintlayout_version = "1.1.3"
def lifecycle_version = "2.0.0"
def room_version = "2.0.0"
@@ -78,9 +83,12 @@ dependencies {
def jcharset_version = "2.0"
def dnsjava_version = "2.1.8"
def openpgp_version = "12.0"
+ def colorpicker_version = "0.0.15"
// https://mvnrepository.com/artifact/androidx.appcompat/appcompat
- implementation "androidx.appcompat:appcompat:$androidx_version"
+ implementation "androidx.appcompat:appcompat:$appcompat_version"
+ // https://mvnrepository.com/artifact/androidx.fragment/fragment
+ implementation "androidx.fragment:fragment:$fragment_version"
// https://mvnrepository.com/artifact/androidx.annotation/annotation
implementation "androidx.annotation:annotation:$androidx_version"
// https://mvnrepository.com/artifact/androidx.recyclerview/recyclerview
@@ -122,7 +130,7 @@ dependencies {
implementation "org.sufficientlysecure:openpgp-api:$openpgp_version"
// https://android.googlesource.com/platform/frameworks/opt/colorpicker
- implementation project(path: ':colorpicker', configuration: 'default')
+ implementation "com.github.QuadFlask:colorpicker:$colorpicker_version"
// Kotlin support
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
diff --git a/app/src/main/java/org/dystopia/email/ColorDialogFragment.java b/app/src/main/java/org/dystopia/email/ColorDialogFragment.java
new file mode 100644
index 00000000..2ea62420
--- /dev/null
+++ b/app/src/main/java/org/dystopia/email/ColorDialogFragment.java
@@ -0,0 +1,157 @@
+package org.dystopia.email;
+
+/*
+ This file is part of SimpleEmail.
+
+ SimpleEmail 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.
+
+ SimpleEmail 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 SimpleEmail. If not, see .
+
+ Copyright 2018, Distopico (dystopia project) and contributors
+*/
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.graphics.Color;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.DialogFragment;
+import androidx.fragment.app.FragmentResultListener;
+
+import com.flask.colorpicker.ColorPickerView;
+import com.flask.colorpicker.OnColorChangedListener;
+import com.flask.colorpicker.builder.ColorPickerClickListener;
+import com.flask.colorpicker.builder.ColorPickerDialogBuilder;
+
+import static android.app.Activity.RESULT_OK;
+
+public class ColorDialogFragment extends DialogFragment {
+ private static int requestSequence = 0;
+ private boolean sent = false;
+ private String requestKey = null;
+ private String targetRequestKey;
+ private int targetRequestCode;
+ private int color;
+
+ public String getRequestKey() {
+ if (requestKey == null)
+ requestKey = getClass().getName() + "_" + (++requestSequence);
+ return requestKey;
+ }
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (savedInstanceState != null) {
+ requestKey = savedInstanceState.getString("dialog:request");
+ targetRequestKey = savedInstanceState.getString("dialog:key");
+ targetRequestCode = savedInstanceState.getInt("dialog:code");
+ }
+
+ getParentFragmentManager().setFragmentResultListener(getRequestKey(), this, new FragmentResultListener() {
+ @Override
+ public void onFragmentResult(@NonNull String requestKey, @NonNull Bundle result) {
+ try {
+ result.setClassLoader(ApplicationEx.class.getClassLoader());
+ int requestCode = result.getInt("requestCode");
+ int resultCode = result.getInt("resultCode");
+
+ Intent data = new Intent();
+ data.putExtra("args", result);
+ onActivityResult(requestCode, resultCode, data);
+ } catch (Throwable ex) {
+ // LOg
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onSaveInstanceState(@NonNull Bundle outState) {
+ outState.putInt("dialog:color", color);
+ outState.putString("dialog:request", requestKey);
+ outState.putString("dialog:key", targetRequestKey);
+ outState.putInt("dialog:code", targetRequestCode);
+ super.onSaveInstanceState(outState);
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+ Bundle args = getArguments();
+ color = savedInstanceState == null ? args.getInt("color") : savedInstanceState.getInt("dialog:color");
+ String title = args.getString("title");
+ boolean reset = args.getBoolean("reset", false);
+
+ Context context = getContext();
+ int editTextColor = Helper.resolveColor(context, android.R.attr.editTextColor);
+
+ ColorPickerDialogBuilder builder = ColorPickerDialogBuilder
+ .with(context)
+ .setTitle(title)
+ .showColorEdit(true)
+ .setColorEditTextColor(editTextColor)
+ .wheelType(ColorPickerView.WHEEL_TYPE.FLOWER)
+ .density(6)
+ .lightnessSliderOnly()
+ .setOnColorChangedListener(new OnColorChangedListener() {
+ @Override
+ public void onColorChanged(int selectedColor) {
+ color = selectedColor;
+ }
+ })
+ .setPositiveButton(android.R.string.ok, new ColorPickerClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int selectedColor, Integer[] allColors) {
+ getArguments().putInt("color", selectedColor);
+ sendResult(RESULT_OK);
+ }
+ });
+
+ if (color != Color.TRANSPARENT) {
+ builder.initialColor(color);
+ }
+
+ if (reset) {
+ builder.setNegativeButton(R.string.title_reset, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ getArguments().putInt("color", Color.TRANSPARENT);
+ sendResult(RESULT_OK);
+ }
+ });
+ }
+
+ return builder.build();
+ }
+
+ protected void sendResult(int resultCode) {
+ if (sent) {
+ return;
+ }
+ sent = true;
+ if (targetRequestKey != null) {
+ Bundle args = getArguments();
+ if (args == null) {
+ args = new Bundle();
+ }
+ args.putInt("requestCode", targetRequestCode);
+ args.putInt("resultCode", resultCode);
+ getParentFragmentManager().setFragmentResult(targetRequestKey, args);
+ }
+ }
+}
diff --git a/app/src/main/java/org/dystopia/email/FragmentAccount.java b/app/src/main/java/org/dystopia/email/FragmentAccount.java
index 71977f5b..f1bbee6c 100644
--- a/app/src/main/java/org/dystopia/email/FragmentAccount.java
+++ b/app/src/main/java/org/dystopia/email/FragmentAccount.java
@@ -64,8 +64,6 @@ import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.Group;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.Observer;
-import com.android.colorpicker.ColorPickerDialog;
-import com.android.colorpicker.ColorPickerSwatch;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.textfield.TextInputLayout;
import com.sun.mail.imap.IMAPFolder;
@@ -107,6 +105,8 @@ public class FragmentAccount extends FragmentEx {
private TextView tvName;
private EditText etName;
+ private ViewButtonColor btnColor;
+
private View vwColor;
private ImageView ibColorDefault;
private EditText etSignature;
@@ -141,6 +141,8 @@ public class FragmentAccount extends FragmentEx {
private int color = Color.TRANSPARENT;
private String authorized = null;
+ private static final int REQUEST_COLOR = 1;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -181,6 +183,7 @@ public class FragmentAccount extends FragmentEx {
btnAdvanced = view.findViewById(R.id.btnAdvanced);
etName = view.findViewById(R.id.etName);
+ btnColor = view.findViewById(R.id.btnColor);
tvName = view.findViewById(R.id.tvName);
vwColor = view.findViewById(R.id.vwColor);
ibColorDefault = view.findViewById(R.id.ibColorDefault);
@@ -374,18 +377,15 @@ public class FragmentAccount extends FragmentEx {
new View.OnClickListener() {
@Override
public void onClick(View v) {
- int[] colors = getContext().getResources().getIntArray(R.array.colorPicker);
- ColorPickerDialog colorPickerDialog = new ColorPickerDialog();
- colorPickerDialog.initialize(
- R.string.title_account_color, colors, color, 4, colors.length);
- colorPickerDialog.setOnColorSelectedListener(
- new ColorPickerSwatch.OnColorSelectedListener() {
- @Override
- public void onColorSelected(int color) {
- setColor(color);
- }
- });
- colorPickerDialog.show(getFragmentManager(), "colorpicker");
+ Bundle args = new Bundle();
+ args.putInt("color", btnColor.getColor());
+ args.putString("title", getString(R.string.title_color));
+ args.putBoolean("reset", true);
+
+ ColorDialogFragment fragment = new ColorDialogFragment();
+ fragment.setArguments(args);
+ fragment.setTargetFragment(FragmentAccount.this, REQUEST_COLOR);
+ fragment.show(getParentFragmentManager(), "account:color");
}
});
diff --git a/app/src/main/java/org/dystopia/email/ViewButtonColor.java b/app/src/main/java/org/dystopia/email/ViewButtonColor.java
new file mode 100644
index 00000000..43fa6118
--- /dev/null
+++ b/app/src/main/java/org/dystopia/email/ViewButtonColor.java
@@ -0,0 +1,118 @@
+package org.dystopia.email;
+
+/*
+ This file is part of SimpleEmail.
+
+ SimpleEmail 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.
+
+ SimpleEmail 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 SimpleEmail. If not, see .
+
+ Copyright 2018, Distopico (dystopia project) and contributors
+*/
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.GradientDrawable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.appcompat.widget.AppCompatButton;
+import androidx.core.graphics.ColorUtils;
+
+public class ViewButtonColor extends AppCompatButton {
+ private int color = Color.TRANSPARENT;
+
+ public ViewButtonColor(Context context) {
+ super(context);
+ }
+
+ public ViewButtonColor(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public ViewButtonColor(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ public Parcelable onSaveInstanceState() {
+ Parcelable superState = super.onSaveInstanceState();
+ return new SavedState(superState, this.color);
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state) {
+ SavedState savedState = (SavedState) state;
+ super.onRestoreInstanceState(savedState.getSuperState());
+ setColor(savedState.getColor());
+ }
+
+ void setColor(Integer color) {
+ if (color == null)
+ color = Color.TRANSPARENT;
+ this.color = color;
+
+ GradientDrawable background = new GradientDrawable();
+ background.setColor(color);
+ background.setStroke(
+ ViewHelper.dp2px(getContext(), 1),
+ Helper.resolveColor(getContext(), R.attr.colorSeparator));
+ setBackground(background);
+
+ if (color == Color.TRANSPARENT)
+ setTextColor(Helper.resolveColor(getContext(), android.R.attr.textColorPrimary));
+ else {
+ double lum = ColorUtils.calculateLuminance(color);
+ setTextColor(lum < 0.5 ? Color.WHITE : Color.BLACK);
+ }
+ }
+
+ int getColor() {
+ return this.color;
+ }
+
+ static class SavedState extends View.BaseSavedState {
+ private int color;
+
+ private SavedState(Parcelable superState, int color) {
+ super(superState);
+ this.color = color;
+ }
+
+ private SavedState(Parcel in) {
+ super(in);
+ color = in.readInt();
+ }
+
+ public int getColor() {
+ return this.color;
+ }
+
+ @Override
+ public void writeToParcel(Parcel destination, int flags) {
+ super.writeToParcel(destination, flags);
+ destination.writeInt(color);
+ }
+
+ public static final Parcelable.Creator CREATOR = new Creator() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+}
diff --git a/app/src/main/java/org/dystopia/email/ViewHelper.java b/app/src/main/java/org/dystopia/email/ViewHelper.java
new file mode 100644
index 00000000..422de403
--- /dev/null
+++ b/app/src/main/java/org/dystopia/email/ViewHelper.java
@@ -0,0 +1,45 @@
+package org.dystopia.email;
+
+/*
+ This file is part of SimpleEmail.
+
+ SimpleEmail 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.
+
+ SimpleEmail 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 SimpleEmail. If not, see .
+
+ Copyright 2018, Distopico (dystopia project) and contributors
+*/
+
+import android.content.Context;
+
+public class ViewHelper {
+
+ /**
+ * Convert density-independent pixels units to pixel units.
+ * @param context - android content context to get density
+ * @param dp - density-independent pixel value
+ */
+ static int dp2px(Context context, int dp) {
+ float scale = context.getResources().getDisplayMetrics().density;
+ return Math.round(dp * scale);
+ }
+
+ /**
+ * Convert pixel units to density-independent pixels units.
+ * @param context - android content context to get density
+ * @param px - pixels value
+ */
+ static int px2dp(Context context, float px) {
+ float scale = context.getResources().getDisplayMetrics().density;
+ return Math.round(px / scale);
+ }
+}
diff --git a/app/src/main/res/layout/fragment_account.xml b/app/src/main/res/layout/fragment_account.xml
index 57dea3ba..a7455d1c 100644
--- a/app/src/main/res/layout/fragment_account.xml
+++ b/app/src/main/res/layout/fragment_account.xml
@@ -240,7 +240,29 @@
app:layout_constraintBottom_toBottomOf="@id/vwColor"
app:layout_constraintStart_toEndOf="@id/vwColor"
app:layout_constraintTop_toBottomOf="@id/tilPassword" />
-
+
+
+
+
+