From e1b09bef55bfbcc53f0ced529ca255e7b352d407 Mon Sep 17 00:00:00 2001 From: fazziclay Date: Sun, 5 Mar 2023 09:11:40 +0300 Subject: [PATCH 01/21] rename ID --- .../java/com/fazziclay/opentoday/gui/activity/MainActivity.java | 2 +- app/src/main/res/layout/activity_main.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/activity/MainActivity.java b/app/src/main/java/com/fazziclay/opentoday/gui/activity/MainActivity.java index 4091f483..92bab0c8 100644 --- a/app/src/main/java/com/fazziclay/opentoday/gui/activity/MainActivity.java +++ b/app/src/main/java/com/fazziclay/opentoday/gui/activity/MainActivity.java @@ -37,7 +37,7 @@ public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; - private static final int CONTAINER_ID = R.id.content_root; + private static final int CONTAINER_ID = R.id.mainActivity_rootFragmentContainer; private ActivityMainBinding binding; private App app; diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 714c64d6..ed08b3dd 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -45,7 +45,7 @@ From 5cecaf2d2d422920490bddd3eea18b28e0030a3b Mon Sep 17 00:00:00 2001 From: fazziclay Date: Sun, 5 Mar 2023 09:12:07 +0300 Subject: [PATCH 02/21] build.gradle --- app/build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 73af0820..a58b7ee9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,9 +7,9 @@ android { defaultConfig { // ===== - var isDev = false - var verBuild = 106 - var verName = "1.0.2" + var isDev = true + var verBuild = 107 + var verName = "1.0.3dev" // ===== applicationId "com.fazziclay.opentoday" + (isDev ? ".dev" : "") From f0739ec87e71990f9393bcc02bf4cb19f10f4d05 Mon Sep 17 00:00:00 2001 From: fazziclay Date: Sun, 5 Mar 2023 11:29:02 +0300 Subject: [PATCH 03/21] pin-code support added --- .../java/com/fazziclay/opentoday/app/App.java | 30 +++- .../opentoday/app/pincode/PinCodeManager.java | 56 +++++++ .../gui/fragment/EnterPinCodeFragment.java | 89 +++++++++++ .../gui/fragment/MainRootFragment.java | 19 ++- .../gui/fragment/SettingsFragment.java | 46 ++++++ .../res/layout/fragment_enter_pincode.xml | 142 ++++++++++++++++++ app/src/main/res/layout/fragment_settings.xml | 6 + app/src/main/res/values-ru/strings.xml | 7 + app/src/main/res/values/strings.xml | 7 + 9 files changed, 396 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/com/fazziclay/opentoday/app/pincode/PinCodeManager.java create mode 100644 app/src/main/java/com/fazziclay/opentoday/gui/fragment/EnterPinCodeFragment.java create mode 100644 app/src/main/res/layout/fragment_enter_pincode.xml diff --git a/app/src/main/java/com/fazziclay/opentoday/app/App.java b/app/src/main/java/com/fazziclay/opentoday/app/App.java index 62e64e95..6a5f46d9 100644 --- a/app/src/main/java/com/fazziclay/opentoday/app/App.java +++ b/app/src/main/java/com/fazziclay/opentoday/app/App.java @@ -19,6 +19,7 @@ import com.fazziclay.opentoday.app.datafixer.DataFixer; import com.fazziclay.opentoday.app.datafixer.FixResult; import com.fazziclay.opentoday.app.items.ItemManager; +import com.fazziclay.opentoday.app.pincode.PinCodeManager; import com.fazziclay.opentoday.app.receiver.QuickNoteReceiver; import com.fazziclay.opentoday.app.settings.SettingsManager; import com.fazziclay.opentoday.gui.activity.CrashReportActivity; @@ -54,6 +55,7 @@ public class App extends Application { // Shared preference public static final String SHARED_NAME = "main"; public static final String SHARED_KEY_IS_SETUP_DONE = "isSetupDone"; + public static final String SHARED_KEY_PINCODE = "app_pinCode"; // DEBUG public static final boolean SHADOW_RELEASE = false; @@ -85,15 +87,16 @@ public static App get() { @AppInitIfNeed private SettingsManager settingsManager = null; @AppInitIfNeed private ColorHistoryManager colorHistoryManager = null; @AppInitIfNeed private Telemetry telemetry = null; + private PinCodeManager pinCodeManager = null; @AppInitIfNeed private License[] openSourceLicenses = null; private final List featureFlags = new ArrayList<>(App.DEBUG ? Arrays.asList( FeatureFlag.ITEM_DEBUG_TICK_COUNTER, - FeatureFlag.ITEM_EDITOR_SHOW_COPY_ID_BUTTON, + //FeatureFlag.ITEM_EDITOR_SHOW_COPY_ID_BUTTON, FeatureFlag.AVAILABLE_LOGS_OVERLAY, FeatureFlag.NONE, - FeatureFlag.SHOW_APP_STARTUP_TIME_IN_PREMAIN_ACTIVITY, - FeatureFlag.ALWAYS_SHOW_SAVE_STATUS, - FeatureFlag.SHOW_MAINACTIVITY_STARTUP_TIME, + //FeatureFlag.SHOW_APP_STARTUP_TIME_IN_PREMAIN_ACTIVITY, + //FeatureFlag.ALWAYS_SHOW_SAVE_STATUS, + //FeatureFlag.SHOW_MAINACTIVITY_STARTUP_TIME, FeatureFlag.AVAILABLE_UI_PERSONAL_TICK, FeatureFlag.AVAILABLE_RESTART_ACTIVITY, FeatureFlag.AVAILABLE_RESET_SETUP @@ -114,6 +117,8 @@ public void onCreate() { registryNotificationsChannels(); + this.pinCodeManager = new PinCodeManager(this); + if (fixResult.isVersionFileUpdateRequired()) updateVersionFile(); if (fixResult.isFixed()) { getTelemetry().send(new Telemetry.DataFixerLogsLPacket(fixResult.getDataVersion(), fixResult.getLogs())); @@ -124,6 +129,18 @@ public void onCreate() { this.appStartupTime = System.currentTimeMillis() - start; } + public boolean isPinCodeNeed() { + return this.pinCodeManager.isPinCodeSet(); + } + + public boolean isPinCodeAllow(String p) { + return p.equals(this.pinCodeManager.getPinCode()); + } + + public int getPinCodeLength() { + return this.pinCodeManager.getPinCode().length(); + } + private void registryNotificationsChannels() { NotificationManager notificationManager = getSystemService(NotificationManager.class); notificationManager.createNotificationChannel(new NotificationChannel(NOTIFICATION_QUCIKNOTE_CHANNEL, getString(R.string.notification_quickNote_title), NotificationManager.IMPORTANCE_HIGH)); @@ -324,6 +341,11 @@ public License[] getOpenSourcesLicenses() { preCheckOpenSourceLicenses(); return this.openSourceLicenses; } + + public PinCodeManager getPinCodeManager() { + return pinCodeManager; + } + public boolean isAppInForeground() { return appInForeground; } public void setAppInForeground(boolean appInForeground) { this.appInForeground = appInForeground; } public List getFeatureFlags() {return featureFlags;} diff --git a/app/src/main/java/com/fazziclay/opentoday/app/pincode/PinCodeManager.java b/app/src/main/java/com/fazziclay/opentoday/app/pincode/PinCodeManager.java new file mode 100644 index 00000000..2dedf72b --- /dev/null +++ b/app/src/main/java/com/fazziclay/opentoday/app/pincode/PinCodeManager.java @@ -0,0 +1,56 @@ +package com.fazziclay.opentoday.app.pincode; + +import static android.content.Context.MODE_PRIVATE; + +import android.content.Context; +import android.content.SharedPreferences; + +import com.fazziclay.javaneoutil.FileUtil; +import com.fazziclay.opentoday.app.App; + +import java.io.File; + +public class PinCodeManager { + private final SharedPreferences sharedPreferences; + private final File backupFile; + + + public PinCodeManager(Context context) { + this.sharedPreferences = context.getSharedPreferences(App.SHARED_NAME, MODE_PRIVATE); + this.backupFile = new File(context.getExternalFilesDir(""), "pcb"); + } + + public boolean isPinCodeSet() { + return sharedPreferences.contains(App.SHARED_KEY_PINCODE); + } + + public String getPinCode() { + return sharedPreferences.getString(App.SHARED_KEY_PINCODE, "0000"); + } + + public void disablePinCode() { + sharedPreferences.edit().remove(App.SHARED_KEY_PINCODE).apply(); + if (FileUtil.isExist(backupFile)) { + FileUtil.delete(backupFile); + } + } + + public void enablePinCode(String pin) { + if (pin.isEmpty()) { + throw new ContainNonDigitChars(); + } + for (char c : pin.toCharArray()) { + if (!Character.isDigit(c)) { + throw new ContainNonDigitChars(); + } + } + sharedPreferences.edit().putString(App.SHARED_KEY_PINCODE, pin).apply(); + FileUtil.setText(backupFile, pin); + } + + public static class ContainNonDigitChars extends RuntimeException { + public ContainNonDigitChars() { + super("Contains non-digit chars in pin-code!"); + } + } +} diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/EnterPinCodeFragment.java b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/EnterPinCodeFragment.java new file mode 100644 index 00000000..1a328712 --- /dev/null +++ b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/EnterPinCodeFragment.java @@ -0,0 +1,89 @@ +package com.fazziclay.opentoday.gui.fragment; + +import static com.fazziclay.opentoday.util.InlineUtil.viewClick; + +import android.graphics.Color; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import com.fazziclay.opentoday.app.App; +import com.fazziclay.opentoday.databinding.FragmentEnterPincodeBinding; +import com.fazziclay.opentoday.gui.UI; + +public class EnterPinCodeFragment extends Fragment { + private FragmentEnterPincodeBinding binding; + private App app; + private boolean isAllowed = false; + private int tryNumber = 0; + private String currentPin = ""; + private boolean isKeyboardLock = false; + + public static EnterPinCodeFragment create() { + return new EnterPinCodeFragment(); + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + this.app = App.get(requireContext()); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + binding = FragmentEnterPincodeBinding.inflate(getLayoutInflater()); + setupKeyboardEmulator(); + return binding.getRoot(); + } + + private void allow() { + isAllowed = true; + UI.findFragmentInParents(this, MainRootFragment.class).navigate(ItemsTabIncludeFragment.create(), false); + } + + private void setupKeyboardEmulator() { + viewClick(binding.number0, () -> onNumberPress((byte) 0)); + viewClick(binding.number1, () -> onNumberPress((byte) 1)); + viewClick(binding.number2, () -> onNumberPress((byte) 2)); + viewClick(binding.number3, () -> onNumberPress((byte) 3)); + viewClick(binding.number4, () -> onNumberPress((byte) 4)); + viewClick(binding.number5, () -> onNumberPress((byte) 5)); + viewClick(binding.number6, () -> onNumberPress((byte) 6)); + viewClick(binding.number7, () -> onNumberPress((byte) 7)); + viewClick(binding.number8, () -> onNumberPress((byte) 8)); + viewClick(binding.number9, () -> onNumberPress((byte) 9)); + } + + private void onNumberPress(byte n) { + if (isKeyboardLock) return; + currentPin = currentPin + n; + onPinChanged(); + } + + private void onPinChanged() { + String s = currentPin; + + binding.pin.setText(s); + if (s.length() == app.getPinCodeLength()) { + if (app.isPinCodeAllow(s)) { + binding.pin.setTextColor(Color.GREEN); + allow(); + } else { + tryNumber++; + if (tryNumber >= 5) { + isKeyboardLock = true; + binding.pin.setVisibility(View.GONE); + binding.timeout.setVisibility(View.VISIBLE); + } + currentPin = ""; + onPinChanged(); + } + } + } +} diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/MainRootFragment.java b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/MainRootFragment.java index 1da19bcb..68615aa7 100644 --- a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/MainRootFragment.java +++ b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/MainRootFragment.java @@ -14,6 +14,7 @@ import androidx.fragment.app.FragmentTransaction; import com.fazziclay.opentoday.R; +import com.fazziclay.opentoday.app.App; import com.fazziclay.opentoday.gui.interfaces.BackStackMember; import com.fazziclay.opentoday.gui.interfaces.NavigationHost; import com.fazziclay.opentoday.util.Logger; @@ -26,6 +27,15 @@ public static MainRootFragment create() { return new MainRootFragment(); } + private final FirstFragmentInterface firstFragmentInterface = () -> { + final App app = App.get(requireContext()); + if (app.isPinCodeNeed()) { + return EnterPinCodeFragment.create(); + } else { + return ItemsTabIncludeFragment.create(); + } + }; + @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -47,10 +57,11 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat Logger.d(TAG, "onViewCreated", nullStat(savedInstanceState)); if (savedInstanceState == null) { - Logger.d(TAG, "onViewCreated", "fragment replaced", ItemsTabIncludeFragment.class.getCanonicalName()); + Fragment first = firstFragmentInterface.create(); + Logger.d(TAG, "onViewCreated", "fragment replaced", first.getClass().getCanonicalName()); getChildFragmentManager() .beginTransaction() - .replace(CONTAINER_ID, ItemsTabIncludeFragment.create()) + .replace(CONTAINER_ID, first) .commit(); } } @@ -85,4 +96,8 @@ public void navigate(Fragment fragment, boolean addToBackStack) { if (addToBackStack) transaction.addToBackStack(null); transaction.commit(); } + + interface FirstFragmentInterface { + Fragment create(); + } } diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/SettingsFragment.java b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/SettingsFragment.java index 5d7eedae..532e8fe8 100644 --- a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/SettingsFragment.java +++ b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/SettingsFragment.java @@ -13,6 +13,7 @@ import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.CheckBox; +import android.widget.EditText; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; @@ -31,6 +32,7 @@ import com.fazziclay.opentoday.app.items.ItemManager; import com.fazziclay.opentoday.app.items.item.ItemsRegistry; import com.fazziclay.opentoday.app.items.tab.Tab; +import com.fazziclay.opentoday.app.pincode.PinCodeManager; import com.fazziclay.opentoday.app.receiver.QuickNoteReceiver; import com.fazziclay.opentoday.app.settings.SettingsManager; import com.fazziclay.opentoday.databinding.ExportBinding; @@ -55,6 +57,8 @@ public static SettingsFragment create() { private App app; private SettingsManager settingsManager; private ColorHistoryManager colorHistoryManager; + private PinCodeManager pinCodeManager; + private Runnable pinCodeCallback = () -> {}; private long easterEggLastClick = 0; private int easterEggCounter = 0; @@ -64,6 +68,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { app = App.get(requireContext()); settingsManager = app.getSettingsManager(); colorHistoryManager = app.getColorHistoryManager(); + pinCodeManager = app.getPinCodeManager(); } @Nullable @@ -137,6 +142,47 @@ private void setupView() { binding.defaultQuickNoteType.setText(getString(R.string.settings_defaultQuickNoteType, getString(settingsManager.getDefaultQuickNoteType().getNameResId()))); settingsManager.save(); }).show()); + + pinCodeCallback = () -> binding.pincode.setText(getString(R.string.settings_pincode, (pinCodeManager.isPinCodeSet() ? getString(R.string.settings_pincode_on) : getString(R.string.settings_pincode_off)))); + pinCodeCallback.run(); + viewClick(binding.pincode, () -> { + boolean is = pinCodeManager.isPinCodeSet(); + AlertDialog.Builder d = new AlertDialog.Builder(requireContext()) + .setTitle("App Pin-code") + .setMessage(is ? "Current Pin-code: " + pinCodeManager.getPinCode() : "Pin-code disabled") + .setNeutralButton("Cancel", null) + .setPositiveButton(is ? "Disable" : "Enable", (dialogInterface, i) -> { + if (is) { + pinCodeManager.disablePinCode(); + pinCodeCallback.run(); + Toast.makeText(app, "Success!", Toast.LENGTH_SHORT).show(); + } else { + EditText t = new EditText(requireContext()); + t.setHint("Enter pin..."); + new AlertDialog.Builder(requireContext()) + .setTitle("Enable pin-code") + .setMessage("Dont forget this. Backup file: pcb (pin code backup)") + .setView(t) + .setPositiveButton("Set", (fsdf, fdsfd) -> { + try { + pinCodeManager.enablePinCode(t.getText().toString()); + pinCodeCallback.run(); + Toast.makeText(app, "Success!", Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + if (e instanceof PinCodeManager.ContainNonDigitChars) { + Toast.makeText(app, "Error! Pin-code contains non-digit chars", Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(app, "Error!", Toast.LENGTH_SHORT).show(); + } + } + }) + .setNegativeButton("Cancel", null) + .show(); + } + }); + + d.show(); + }); } private void setupThemeSpinner() { diff --git a/app/src/main/res/layout/fragment_enter_pincode.xml b/app/src/main/res/layout/fragment_enter_pincode.xml new file mode 100644 index 00000000..41a83765 --- /dev/null +++ b/app/src/main/res/layout/fragment_enter_pincode.xml @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + +