mirror of
https://github.com/minibits-cash/minibits_wallet.git
synced 2026-07-22 07:48:28 +00:00
Theme-colored app icon and splash, new font, tuning of auth splash screen
This commit is contained in:
@@ -16,19 +16,14 @@
|
|||||||
android:usesCleartextTraffic="true"
|
android:usesCleartextTraffic="true"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
>
|
>
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
|
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:windowSoftInputMode="adjustResize"
|
android:windowSoftInputMode="adjustResize"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
</intent-filter>
|
|
||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
@@ -56,8 +51,38 @@
|
|||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<data android:scheme="cashu" />
|
<data android:scheme="cashu" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<!-- Default launcher icon alias (enabled by default) -->
|
||||||
|
<activity-alias
|
||||||
|
android:name=".MainActivityDefault"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
<!-- Golden theme launcher icon alias (disabled by default) -->
|
||||||
|
<activity-alias
|
||||||
|
android:name=".MainActivityGolden"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:icon="@mipmap/ic_launcher_golden"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:enabled="false"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
<service
|
<service
|
||||||
android:name="com.reactnativehce.services.CardService"
|
android:name="com.reactnativehce.services.CardService"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
|
|||||||
Binary file not shown.
BIN
android/app/src/main/assets/fonts/HammersmithOne-Regular.ttf
Normal file
BIN
android/app/src/main/assets/fonts/HammersmithOne-Regular.ttf
Normal file
Binary file not shown.
@@ -4,6 +4,10 @@
|
|||||||
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
|
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
|
||||||
<!-- Customize your theme here. -->
|
<!-- Customize your theme here. -->
|
||||||
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
|
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
|
||||||
|
<!-- Fixed dark window background shown before React Native renders its first frame.
|
||||||
|
Matches the dark app themes (DEFAULT/DARK/GOLDEN). For LIGHT theme, the JS
|
||||||
|
splash view overrides this immediately on first render. -->
|
||||||
|
<item name="android:windowBackground">#2e2e2e</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
"migIndex": 1,
|
"migIndex": 1,
|
||||||
"data": [
|
"data": [
|
||||||
{
|
{
|
||||||
"path": "assets/fonts/Gluten-Regular.ttf",
|
"path": "assets/fonts/HammersmithOne-Regular.ttf",
|
||||||
"sha1": "96270757924e60e26763e8814aaa2000f470d352"
|
"sha1": "132e0c6ad83dff514d1f6d2719aae6c90255d92f"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "assets/icons/nostr.png",
|
"path": "assets/icons/nostr.png",
|
||||||
|
|||||||
Binary file not shown.
BIN
assets/fonts/HammersmithOne-Regular.ttf
Normal file
BIN
assets/fonts/HammersmithOne-Regular.ttf
Normal file
Binary file not shown.
@@ -1434,6 +1434,8 @@ PODS:
|
|||||||
- React-RCTFBReactNativeSpec
|
- React-RCTFBReactNativeSpec
|
||||||
- ReactCommon/turbomodule/core
|
- ReactCommon/turbomodule/core
|
||||||
- ReactNativeDependencies
|
- ReactNativeDependencies
|
||||||
|
- react-native-change-icon (3.2.0):
|
||||||
|
- React
|
||||||
- react-native-hce (0.3.0):
|
- react-native-hce (0.3.0):
|
||||||
- React
|
- React
|
||||||
- react-native-mmkv (3.3.3):
|
- react-native-mmkv (3.3.3):
|
||||||
@@ -2444,6 +2446,7 @@ DEPENDENCIES:
|
|||||||
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
|
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
|
||||||
- React-Mapbuffer (from `../node_modules/react-native/ReactCommon`)
|
- React-Mapbuffer (from `../node_modules/react-native/ReactCommon`)
|
||||||
- React-microtasksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`)
|
- React-microtasksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`)
|
||||||
|
- react-native-change-icon (from `../node_modules/react-native-change-icon`)
|
||||||
- react-native-hce (from `../node_modules/react-native-hce`)
|
- react-native-hce (from `../node_modules/react-native-hce`)
|
||||||
- react-native-mmkv (from `../node_modules/react-native-mmkv`)
|
- react-native-mmkv (from `../node_modules/react-native-mmkv`)
|
||||||
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
|
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
|
||||||
@@ -2614,6 +2617,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: "../node_modules/react-native/ReactCommon"
|
:path: "../node_modules/react-native/ReactCommon"
|
||||||
React-microtasksnativemodule:
|
React-microtasksnativemodule:
|
||||||
:path: "../node_modules/react-native/ReactCommon/react/nativemodule/microtasks"
|
:path: "../node_modules/react-native/ReactCommon/react/nativemodule/microtasks"
|
||||||
|
react-native-change-icon:
|
||||||
|
:path: "../node_modules/react-native-change-icon"
|
||||||
react-native-hce:
|
react-native-hce:
|
||||||
:path: "../node_modules/react-native-hce"
|
:path: "../node_modules/react-native-hce"
|
||||||
react-native-mmkv:
|
react-native-mmkv:
|
||||||
@@ -2790,6 +2795,7 @@ SPEC CHECKSUMS:
|
|||||||
React-logger: dd3e5f78709d5b029336be395a67bbcdc775e2ed
|
React-logger: dd3e5f78709d5b029336be395a67bbcdc775e2ed
|
||||||
React-Mapbuffer: 2bdeed9ba58c94ac99a2711a3a722d2d5b3a8a81
|
React-Mapbuffer: 2bdeed9ba58c94ac99a2711a3a722d2d5b3a8a81
|
||||||
React-microtasksnativemodule: d1acdc86b1b2ee5622af4950f3908f2155eddfcf
|
React-microtasksnativemodule: d1acdc86b1b2ee5622af4950f3908f2155eddfcf
|
||||||
|
react-native-change-icon: af3d0eb3ffee2ab3c584d12a68c29f89b7108cf8
|
||||||
react-native-hce: ad5462e792d84e87924308dda1ee516757f1c0eb
|
react-native-hce: ad5462e792d84e87924308dda1ee516757f1c0eb
|
||||||
react-native-mmkv: 07f0ae0bd7e8d458077e1750c502ba67975b3702
|
react-native-mmkv: 07f0ae0bd7e8d458077e1750c502ba67975b3702
|
||||||
react-native-netinfo: cec9c4e86083cb5b6aba0e0711f563e2fbbff187
|
react-native-netinfo: cec9c4e86083cb5b6aba0e0711f563e2fbbff187
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
"migIndex": 1,
|
"migIndex": 1,
|
||||||
"data": [
|
"data": [
|
||||||
{
|
{
|
||||||
"path": "assets/fonts/Gluten-Regular.ttf",
|
"path": "assets/fonts/HammersmithOne-Regular.ttf",
|
||||||
"sha1": "96270757924e60e26763e8814aaa2000f470d352"
|
"sha1": "132e0c6ad83dff514d1f6d2719aae6c90255d92f"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "assets/icons/nostr.png",
|
"path": "assets/icons/nostr.png",
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
902F38392D92C792005DB998 /* OpenSSL.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 902F38382D92C792005DB998 /* OpenSSL.xcframework */; };
|
902F38392D92C792005DB998 /* OpenSSL.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 902F38382D92C792005DB998 /* OpenSSL.xcframework */; };
|
||||||
9044DC252D95937D00F918A6 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9044DC242D95937D00F918A6 /* GoogleService-Info.plist */; };
|
9044DC252D95937D00F918A6 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9044DC242D95937D00F918A6 /* GoogleService-Info.plist */; };
|
||||||
A1B9A6F7058C4F12AB677FD4 /* nostr.png in Resources */ = {isa = PBXBuildFile; fileRef = AB8A46AD84194C2583FF9193 /* nostr.png */; };
|
A1B9A6F7058C4F12AB677FD4 /* nostr.png in Resources */ = {isa = PBXBuildFile; fileRef = AB8A46AD84194C2583FF9193 /* nostr.png */; };
|
||||||
C3AB98FDBCF446F99A4EA648 /* Gluten-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6DA8A3418B7A4B348B67B9E7 /* Gluten-Regular.ttf */; };
|
A2E4F8C1D3B547A890123456 /* HammersmithOne-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B3D7A2E5F1C648B9A0234567 /* HammersmithOne-Regular.ttf */; };
|
||||||
CD7DC745CFA9F47C2D6FFA1D /* Pods_minibits_wallet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4ACC08249CA13DFDBBBD7A8B /* Pods_minibits_wallet.framework */; };
|
CD7DC745CFA9F47C2D6FFA1D /* Pods_minibits_wallet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4ACC08249CA13DFDBBBD7A8B /* Pods_minibits_wallet.framework */; };
|
||||||
D610B97F2318E8AB9D0962D2 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */; };
|
D610B97F2318E8AB9D0962D2 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
3B4392A12AC88292D35C810B /* Pods-minibits_wallet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-minibits_wallet.debug.xcconfig"; path = "Target Support Files/Pods-minibits_wallet/Pods-minibits_wallet.debug.xcconfig"; sourceTree = "<group>"; };
|
3B4392A12AC88292D35C810B /* Pods-minibits_wallet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-minibits_wallet.debug.xcconfig"; path = "Target Support Files/Pods-minibits_wallet/Pods-minibits_wallet.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
4ACC08249CA13DFDBBBD7A8B /* Pods_minibits_wallet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_minibits_wallet.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
4ACC08249CA13DFDBBBD7A8B /* Pods_minibits_wallet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_minibits_wallet.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
5709B34CF0A7D63546082F79 /* Pods-minibits_wallet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-minibits_wallet.release.xcconfig"; path = "Target Support Files/Pods-minibits_wallet/Pods-minibits_wallet.release.xcconfig"; sourceTree = "<group>"; };
|
5709B34CF0A7D63546082F79 /* Pods-minibits_wallet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-minibits_wallet.release.xcconfig"; path = "Target Support Files/Pods-minibits_wallet/Pods-minibits_wallet.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
6DA8A3418B7A4B348B67B9E7 /* Gluten-Regular.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Gluten-Regular.ttf"; path = "../assets/fonts/Gluten-Regular.ttf"; sourceTree = "<group>"; };
|
B3D7A2E5F1C648B9A0234567 /* HammersmithOne-Regular.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "HammersmithOne-Regular.ttf"; path = "../assets/fonts/HammersmithOne-Regular.ttf"; sourceTree = "<group>"; };
|
||||||
761780EC2CA45674006654EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = minibits_wallet/AppDelegate.swift; sourceTree = "<group>"; };
|
761780EC2CA45674006654EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = minibits_wallet/AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = minibits_wallet/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = minibits_wallet/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
902F38382D92C792005DB998 /* OpenSSL.xcframework */ = {isa = PBXFileReference; expectedSignature = "AppleDeveloperProgram:67RAULRX93:Marcin Krzyzanowski"; lastKnownFileType = wrapper.xcframework; name = OpenSSL.xcframework; path = "Pods/OpenSSL-Universal/OpenSSL.xcframework"; sourceTree = "<group>"; };
|
902F38382D92C792005DB998 /* OpenSSL.xcframework */ = {isa = PBXFileReference; expectedSignature = "AppleDeveloperProgram:67RAULRX93:Marcin Krzyzanowski"; lastKnownFileType = wrapper.xcframework; name = OpenSSL.xcframework; path = "Pods/OpenSSL-Universal/OpenSSL.xcframework"; sourceTree = "<group>"; };
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
4B24E47762034A51AEE63594 /* Resources */ = {
|
4B24E47762034A51AEE63594 /* Resources */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
6DA8A3418B7A4B348B67B9E7 /* Gluten-Regular.ttf */,
|
B3D7A2E5F1C648B9A0234567 /* HammersmithOne-Regular.ttf */,
|
||||||
AB8A46AD84194C2583FF9193 /* nostr.png */,
|
AB8A46AD84194C2583FF9193 /* nostr.png */,
|
||||||
);
|
);
|
||||||
name = Resources;
|
name = Resources;
|
||||||
@@ -186,7 +186,7 @@
|
|||||||
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,
|
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,
|
||||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
|
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
|
||||||
D610B97F2318E8AB9D0962D2 /* PrivacyInfo.xcprivacy in Resources */,
|
D610B97F2318E8AB9D0962D2 /* PrivacyInfo.xcprivacy in Resources */,
|
||||||
C3AB98FDBCF446F99A4EA648 /* Gluten-Regular.ttf in Resources */,
|
A2E4F8C1D3B547A890123456 /* HammersmithOne-Regular.ttf in Resources */,
|
||||||
A1B9A6F7058C4F12AB677FD4 /* nostr.png in Resources */,
|
A1B9A6F7058C4F12AB677FD4 /* nostr.png in Resources */,
|
||||||
9044DC252D95937D00F918A6 /* GoogleService-Info.plist in Resources */,
|
9044DC252D95937D00F918A6 /* GoogleService-Info.plist in Resources */,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
<true/>
|
<true/>
|
||||||
<key>UIAppFonts</key>
|
<key>UIAppFonts</key>
|
||||||
<array>
|
<array>
|
||||||
<string>Gluten-Regular.ttf</string>
|
<string>HammersmithOne-Regular.ttf</string>
|
||||||
</array>
|
</array>
|
||||||
<key>UIBackgroundModes</key>
|
<key>UIBackgroundModes</key>
|
||||||
<array>
|
<array>
|
||||||
@@ -78,5 +78,23 @@
|
|||||||
<false/>
|
<false/>
|
||||||
<key>HOT_UPDATER_FINGERPRINT_HASH</key>
|
<key>HOT_UPDATER_FINGERPRINT_HASH</key>
|
||||||
<string>98c1f26187f02f38ddef1fcb75384246a1c5fa03</string>
|
<string>98c1f26187f02f38ddef1fcb75384246a1c5fa03</string>
|
||||||
|
<key>CFBundleIcons</key>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundlePrimaryIcon</key>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleIconName</key>
|
||||||
|
<string>AppIcon</string>
|
||||||
|
</dict>
|
||||||
|
<key>CFBundleAlternateIcons</key>
|
||||||
|
<dict>
|
||||||
|
<key>Golden</key>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleIconName</key>
|
||||||
|
<string>AppIconGolden</string>
|
||||||
|
<key>UIPrerenderedIcon</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
@@ -4,8 +4,9 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"android:clean": "cd android && ./gradlew clean",
|
"android:clean": "cd android && ./gradlew clean",
|
||||||
"android:dev": "react-native run-android --active-arch-only",
|
"android:reinstall": "$HOME/Library/Android/sdk/platform-tools/adb uninstall com.minibits_wallet; yarn android:dev",
|
||||||
"android:test": "react-native run-android --mode=release --active-arch-only",
|
"android:dev": "react-native run-android --active-arch-only --main-activity .MainActivityDefault",
|
||||||
|
"android:test": "react-native run-android --mode=release --active-arch-only --main-activity .MainActivityDefault",
|
||||||
"android:bundle": "react-native build-android --mode=release",
|
"android:bundle": "react-native build-android --mode=release",
|
||||||
"android:apk": "cd android && ./gradlew assembleRelease",
|
"android:apk": "cd android && ./gradlew assembleRelease",
|
||||||
"ios:dev": "npx react-native run-ios --scheme \"minibits_wallet\"",
|
"ios:dev": "npx react-native run-ios --scheme \"minibits_wallet\"",
|
||||||
@@ -59,6 +60,7 @@
|
|||||||
"react-native": "0.84.0",
|
"react-native": "0.84.0",
|
||||||
"react-native-animated-pagination-dots": "^0.1.73",
|
"react-native-animated-pagination-dots": "^0.1.73",
|
||||||
"react-native-camera-kit": "17.0.1",
|
"react-native-camera-kit": "17.0.1",
|
||||||
|
"react-native-change-icon": "^3.0.0",
|
||||||
"react-native-exit-app": "^2.0.0",
|
"react-native-exit-app": "^2.0.0",
|
||||||
"react-native-fast-image": "^8.6.3",
|
"react-native-fast-image": "^8.6.3",
|
||||||
"react-native-flash-message": "^0.4.2",
|
"react-native-flash-message": "^0.4.2",
|
||||||
|
|||||||
43
patches/react-native-change-icon+3.2.0.patch
Normal file
43
patches/react-native-change-icon+3.2.0.patch
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
diff --git a/node_modules/react-native-change-icon/android/build.gradle b/node_modules/react-native-change-icon/android/build.gradle
|
||||||
|
index aa5226c..bf54025 100644
|
||||||
|
--- a/node_modules/react-native-change-icon/android/build.gradle
|
||||||
|
+++ b/node_modules/react-native-change-icon/android/build.gradle
|
||||||
|
@@ -4,7 +4,7 @@ buildscript {
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
- jcenter()
|
||||||
|
+ mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
@@ -52,7 +52,6 @@ android {
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
- jcenter()
|
||||||
|
google()
|
||||||
|
|
||||||
|
def found = false
|
||||||
|
diff --git a/node_modules/react-native-change-icon/android/src/main/java/com/reactnativechangeicon/ChangeIconModule.kt b/node_modules/react-native-change-icon/android/src/main/java/com/reactnativechangeicon/ChangeIconModule.kt
|
||||||
|
index 70c3e2c..724b3fe 100644
|
||||||
|
--- a/node_modules/react-native-change-icon/android/src/main/java/com/reactnativechangeicon/ChangeIconModule.kt
|
||||||
|
+++ b/node_modules/react-native-change-icon/android/src/main/java/com/reactnativechangeicon/ChangeIconModule.kt
|
||||||
|
@@ -21,7 +21,7 @@ class ChangeIconModule(reactContext: ReactApplicationContext, private val packag
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
fun changeIcon(enableIcon: String, promise: Promise) {
|
||||||
|
- val activity: Activity? = currentActivity
|
||||||
|
+ val activity: Activity? = reactApplicationContext.currentActivity
|
||||||
|
if (activity == null || enableIcon.isEmpty()) {
|
||||||
|
promise.reject("Icon string is empty.")
|
||||||
|
return
|
||||||
|
@@ -46,7 +46,7 @@ class ChangeIconModule(reactContext: ReactApplicationContext, private val packag
|
||||||
|
|
||||||
|
private fun completeIconChange() {
|
||||||
|
if (iconChanged) {
|
||||||
|
- val activity: Activity? = currentActivity
|
||||||
|
+ val activity: Activity? = reactApplicationContext.currentActivity
|
||||||
|
if (activity == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
145
src/App.tsx
145
src/App.tsx
@@ -1,28 +1,33 @@
|
|||||||
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import FlashMessage from "react-native-flash-message"
|
import FlashMessage from "react-native-flash-message"
|
||||||
import {
|
import {
|
||||||
SafeAreaProvider,
|
SafeAreaProvider,
|
||||||
} from 'react-native-safe-area-context'
|
} from 'react-native-safe-area-context'
|
||||||
import {
|
import {
|
||||||
setSizeMattersBaseHeight,
|
setSizeMattersBaseHeight,
|
||||||
setSizeMattersBaseWidth
|
setSizeMattersBaseWidth
|
||||||
} from '@gocodingnow/rn-size-matters'
|
} from '@gocodingnow/rn-size-matters'
|
||||||
import RNExitApp from 'react-native-exit-app'
|
import RNExitApp from 'react-native-exit-app'
|
||||||
|
import { changeIcon } from 'react-native-change-icon'
|
||||||
import {AppNavigator} from './navigation'
|
import {AppNavigator} from './navigation'
|
||||||
import {useInitialRootStore, useStores} from './models'
|
import {useInitialRootStore, useStores} from './models'
|
||||||
import {KeyChain, WalletKeys} from './services'
|
import {KeyChain, WalletKeys} from './services'
|
||||||
import {ErrorBoundary} from './screens/ErrorScreen/ErrorBoundary'
|
import {ErrorBoundary} from './screens/ErrorScreen/ErrorBoundary'
|
||||||
import Config from './config'
|
import Config from './config'
|
||||||
import {log} from './services'
|
import {log} from './services'
|
||||||
import { Image, Pressable, Text as RNText, TextStyle, View } from 'react-native'
|
import { Image, TextStyle, View } from 'react-native'
|
||||||
import { colors, spacing, typography } from './theme'
|
import { ThemeCode, colors, spacing, typography } from './theme'
|
||||||
|
import useColorScheme from './theme/useThemeColor'
|
||||||
import { displayName } from '../app.json'
|
import { displayName } from '../app.json'
|
||||||
import { Text } from './components/Text'
|
import { Text } from './components/Text'
|
||||||
import useIsInternetReachable from './utils/useIsInternetReachable'
|
import useIsInternetReachable from './utils/useIsInternetReachable'
|
||||||
|
import { MMKVStorage } from './services'
|
||||||
|
import { Button, Screen } from './components'
|
||||||
|
|
||||||
setSizeMattersBaseWidth(375)
|
setSizeMattersBaseWidth(375)
|
||||||
setSizeMattersBaseHeight(812)
|
setSizeMattersBaseHeight(812)
|
||||||
|
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const {
|
const {
|
||||||
userSettingsStore,
|
userSettingsStore,
|
||||||
@@ -32,9 +37,11 @@ function App() {
|
|||||||
walletProfileStore
|
walletProfileStore
|
||||||
} = useStores()
|
} = useStores()
|
||||||
|
|
||||||
|
const colorScheme = useColorScheme()
|
||||||
|
|
||||||
const [isUserAuthenticated, setIsUserAuthenticated] = useState(false)
|
const [isUserAuthenticated, setIsUserAuthenticated] = useState(false)
|
||||||
const [isDeviceAuthenticated, setIsDeviceAuthenticated] = useState(false)
|
const [isDeviceAuthenticated, setIsDeviceAuthenticated] = useState(false)
|
||||||
const [isAuthLocked, setIsAuthLocked] = useState(false)
|
const [isAppLocked, setIsAppLocked] = useState(false)
|
||||||
const isAuthInProgressRef = useRef(false)
|
const isAuthInProgressRef = useRef(false)
|
||||||
|
|
||||||
const isInternetReachable = useIsInternetReachable() // boolean | null
|
const isInternetReachable = useIsInternetReachable() // boolean | null
|
||||||
@@ -47,37 +54,40 @@ function App() {
|
|||||||
}
|
}
|
||||||
}, [isInternetReachable])
|
}, [isInternetReachable])
|
||||||
|
|
||||||
const attemptAuth = useCallback(async () => {
|
const attemptUserAuthentication = useCallback(async () => {
|
||||||
if (isAuthInProgressRef.current) {
|
if (isAuthInProgressRef.current) {
|
||||||
log.trace('[App] attemptAuth skipped, auth already in progress')
|
log.trace('[App] attemptUserAuthentication skipped, auth already in progress')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
isAuthInProgressRef.current = true
|
isAuthInProgressRef.current = true
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const isAuthEnabled = userSettingsStore.isAuthOn
|
const {isAuthOn} = userSettingsStore
|
||||||
log.trace('[App] attemptAuth called')
|
log.trace('[App] attemptUserAuthentication called', {isAuthOn})
|
||||||
|
|
||||||
const result = await KeyChain.authenticateOnAppStart(isAuthEnabled)
|
const result = await KeyChain.authenticateOnAppStart(isAuthOn)
|
||||||
log.trace('[App] attemptAuth result:', { success: result.success, shouldExitApp: result.shouldExitApp })
|
log.trace('[App] attemptUserAuthentication result:', { success: result.success, shouldExitApp: result.shouldExitApp })
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
setIsUserAuthenticated(true)
|
setIsUserAuthenticated(true)
|
||||||
setIsAuthLocked(false)
|
setIsAppLocked(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.shouldExitApp) {
|
if (result.shouldExitApp) {
|
||||||
|
// Fix: show locked UI before exiting so the user isn't stuck on a
|
||||||
|
// blank splash if exitApp() has any delay or fails silently.
|
||||||
|
setIsAppLocked(true)
|
||||||
RNExitApp.exitApp()
|
RNExitApp.exitApp()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.trace('[App] attemptAuth failed, locking app')
|
log.trace('[App] attemptUserAuthentication failed, locking app')
|
||||||
setIsAuthLocked(true)
|
setIsAppLocked(true)
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
log.error('[App] attemptAuth caught error', { message: e.message })
|
log.error('[App] attemptUserAuthentication caught error', { message: e.message })
|
||||||
setIsAuthLocked(true)
|
setIsAppLocked(true)
|
||||||
} finally {
|
} finally {
|
||||||
isAuthInProgressRef.current = false
|
isAuthInProgressRef.current = false
|
||||||
}
|
}
|
||||||
@@ -89,18 +99,23 @@ function App() {
|
|||||||
|
|
||||||
// User authentication (biometrics / PIN)
|
// User authentication (biometrics / PIN)
|
||||||
if (userSettingsStore.isAuthOn) {
|
if (userSettingsStore.isAuthOn) {
|
||||||
// Keep UI in locked mode until authentication succeeds.
|
// Keep UI in locked mode until authentication succeeds.
|
||||||
setIsAuthLocked(true)
|
attemptUserAuthentication()
|
||||||
attemptAuth()
|
|
||||||
} else {
|
} else {
|
||||||
setIsUserAuthenticated(true)
|
setIsUserAuthenticated(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Theme sync
|
// Theme sync — apply queued theme on startup and persist to dedicated MMKV key
|
||||||
if (userSettingsStore.theme !== userSettingsStore.nextTheme) {
|
const appliedTheme = MMKVStorage.loadTheme()
|
||||||
userSettingsStore.setTheme(userSettingsStore.nextTheme)
|
if (appliedTheme !== userSettingsStore.nextTheme) {
|
||||||
|
MMKVStorage.saveTheme(userSettingsStore.nextTheme)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Icon sync — keeps launcher icon in sync with the applied theme.
|
||||||
|
// Handles upgrades from versions before icon switching existed.
|
||||||
|
const targetIcon = MMKVStorage.loadTheme() === ThemeCode.GOLDEN ? 'Golden' : 'Default'
|
||||||
|
changeIcon(targetIcon).catch(() => {})
|
||||||
|
|
||||||
// Reset relay statuses
|
// Reset relay statuses
|
||||||
relaysStore.resetStatuses()
|
relaysStore.resetStatuses()
|
||||||
})
|
})
|
||||||
@@ -108,7 +123,7 @@ function App() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
isInternetReachable === null ||
|
isInternetReachable === null ||
|
||||||
isDeviceAuthenticated ||
|
isDeviceAuthenticated ||
|
||||||
!rehydrated
|
!rehydrated
|
||||||
) {
|
) {
|
||||||
log.trace('[App] Not yet ready for device auth check')
|
log.trace('[App] Not yet ready for device auth check')
|
||||||
@@ -130,10 +145,10 @@ function App() {
|
|||||||
try {
|
try {
|
||||||
const walletKeys: WalletKeys = await walletStore.getCachedWalletKeys()
|
const walletKeys: WalletKeys = await walletStore.getCachedWalletKeys()
|
||||||
const deviceId = walletProfileStore.device
|
const deviceId = walletProfileStore.device
|
||||||
|
|
||||||
await authStore.clearTokens()
|
await authStore.clearTokens()
|
||||||
await authStore.enrollDevice(walletKeys.NOSTR, deviceId)
|
await authStore.enrollDevice(walletKeys.NOSTR, deviceId)
|
||||||
|
|
||||||
log.trace('[App] Device re-enrollment successful')
|
log.trace('[App] Device re-enrollment successful')
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
log.error('[App] Device re-enrollment failed', { message: e.message })
|
log.error('[App] Device re-enrollment failed', { message: e.message })
|
||||||
@@ -146,7 +161,7 @@ function App() {
|
|||||||
log.trace('[App] Network is online and refresh token valid → device authenticated')
|
log.trace('[App] Network is online and refresh token valid → device authenticated')
|
||||||
setIsDeviceAuthenticated(true)
|
setIsDeviceAuthenticated(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Confirmed offline → skip re-enrollment, proceed safely
|
// Confirmed offline → skip re-enrollment, proceed safely
|
||||||
log.trace('[App] Network confirmed offline → skipping refresh token check, device authenticated')
|
log.trace('[App] Network confirmed offline → skipping refresh token check, device authenticated')
|
||||||
@@ -162,36 +177,53 @@ function App() {
|
|||||||
!rehydrated ||
|
!rehydrated ||
|
||||||
!isUserAuthenticated ||
|
!isUserAuthenticated ||
|
||||||
!isDeviceAuthenticated ||
|
!isDeviceAuthenticated ||
|
||||||
isAuthLocked
|
isAppLocked
|
||||||
) {
|
) {
|
||||||
|
const splashTheme = MMKVStorage.loadTheme()
|
||||||
|
const isLight = splashTheme === ThemeCode.LIGHT ||
|
||||||
|
(splashTheme === ThemeCode.DEFAULT && colorScheme === 'light')
|
||||||
|
const isGolden = splashTheme === ThemeCode.GOLDEN
|
||||||
|
const splashBg = isLight ? colors.palette.neutral200 : colors.palette.neutral700
|
||||||
|
const splashTextColor = isLight ? colors.palette.neutral800 : colors.palette.neutral100
|
||||||
|
|
||||||
|
log.trace('[App] Rendering splash/auth screen', {isAppLocked})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={{flex: 1}}>
|
<SafeAreaProvider>
|
||||||
<ErrorBoundary catchErrors={Config.catchErrors}>
|
<Screen preset='fixed' backgroundColor={splashBg} safeAreaEdges={['top', 'bottom']}>
|
||||||
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
|
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
|
||||||
<Text text={displayName} style={$title} />
|
<Image source={isGolden
|
||||||
<Image source={require('../android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png')} />
|
? require('../android/app/src/main/res/mipmap-xxhdpi/ic_launcher_golden.png')
|
||||||
</View>
|
: require('../android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png')} />
|
||||||
</ErrorBoundary>
|
</View>
|
||||||
{isAuthLocked && (
|
<Text text={displayName} style={[$title, {color: splashTextColor}]} />
|
||||||
<View style={{alignItems: 'center', paddingHorizontal: spacing.large, paddingBottom: 60}}>
|
<View style={{
|
||||||
<RNText style={{color: colors.palette.neutral400, fontSize: 14, textAlign: 'center', marginBottom: spacing.large}}>
|
paddingHorizontal: spacing.large,
|
||||||
Minibits is locked. Authentication is required to continue.
|
marginBottom: spacing.extraLarge,
|
||||||
</RNText>
|
}}>
|
||||||
<Pressable
|
|
||||||
style={{backgroundColor: colors.palette.accent400, paddingVertical: spacing.small, paddingHorizontal: spacing.extraLarge, borderRadius: spacing.small, marginBottom: spacing.medium, minWidth: 200, alignItems: 'center'}}
|
{isAppLocked && (
|
||||||
onPress={attemptAuth}
|
<>
|
||||||
>
|
<Text size='md' style={{textAlign: 'center', color: splashTextColor}}>
|
||||||
<RNText style={{color: 'white', fontSize: 16, fontWeight: '600'}}>Authenticate</RNText>
|
Minibits is locked. Authentication is required to continue.
|
||||||
</Pressable>
|
</Text>
|
||||||
<Pressable
|
<Button
|
||||||
style={{paddingVertical: spacing.small, paddingHorizontal: spacing.extraLarge, minWidth: 200, alignItems: 'center'}}
|
preset='default'
|
||||||
onPress={() => RNExitApp.exitApp()}
|
text='Authenticate'
|
||||||
>
|
onPress={attemptUserAuthentication}
|
||||||
<RNText style={{color: colors.palette.neutral400, fontSize: 16}}>Close app</RNText>
|
style={{marginVertical: spacing.large, alignSelf: 'center'}}
|
||||||
</Pressable>
|
/>
|
||||||
</View>
|
<Button
|
||||||
)}
|
preset='tertiary'
|
||||||
</View>
|
text='Exit'
|
||||||
|
onPress={() => RNExitApp.exitApp()}
|
||||||
|
style={{alignSelf: 'center'}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</Screen>
|
||||||
|
</SafeAreaProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,7 +241,6 @@ const $title: TextStyle = {
|
|||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
fontFamily: typography.logo.normal,
|
fontFamily: typography.logo.normal,
|
||||||
fontSize: spacing.large,
|
fontSize: spacing.large,
|
||||||
color: 'white'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App
|
export default App
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { ThemeCode } from '../theme'
|
|||||||
export type UserSettings = {
|
export type UserSettings = {
|
||||||
preferredUnit: MintUnit
|
preferredUnit: MintUnit
|
||||||
exchangeCurrency: CurrencyCode
|
exchangeCurrency: CurrencyCode
|
||||||
theme: ThemeCode
|
|
||||||
nextTheme: ThemeCode
|
nextTheme: ThemeCode
|
||||||
isOnboarded: boolean
|
isOnboarded: boolean
|
||||||
isAuthOn: boolean
|
isAuthOn: boolean
|
||||||
@@ -24,7 +23,6 @@ export const UserSettingsStoreModel = types
|
|||||||
.props({
|
.props({
|
||||||
preferredUnit: types.optional(types.frozen<MintUnit>(), 'sat'),
|
preferredUnit: types.optional(types.frozen<MintUnit>(), 'sat'),
|
||||||
exchangeCurrency: types.optional(types.frozen<CurrencyCode | null>(), CurrencyCode.USD),
|
exchangeCurrency: types.optional(types.frozen<CurrencyCode | null>(), CurrencyCode.USD),
|
||||||
theme: types.optional(types.frozen<ThemeCode>(), ThemeCode.DEFAULT),
|
|
||||||
nextTheme: types.optional(types.frozen<ThemeCode>(), ThemeCode.DEFAULT),
|
nextTheme: types.optional(types.frozen<ThemeCode>(), ThemeCode.DEFAULT),
|
||||||
isOnboarded: types.optional(types.boolean, false),
|
isOnboarded: types.optional(types.boolean, false),
|
||||||
isAuthOn: types.optional(types.boolean, false),
|
isAuthOn: types.optional(types.boolean, false),
|
||||||
@@ -43,11 +41,7 @@ export const UserSettingsStoreModel = types
|
|||||||
self.exchangeCurrency = exchangeCurrency
|
self.exchangeCurrency = exchangeCurrency
|
||||||
return exchangeCurrency
|
return exchangeCurrency
|
||||||
},
|
},
|
||||||
setTheme: (theme: ThemeCode) => {
|
setNextTheme: (theme: ThemeCode) => {
|
||||||
self.theme = theme
|
|
||||||
return theme
|
|
||||||
},
|
|
||||||
setNextTheme: (theme: ThemeCode) => {
|
|
||||||
self.nextTheme = theme
|
self.nextTheme = theme
|
||||||
return theme
|
return theme
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -349,7 +349,7 @@ export const OwnName = observer(function (props: {pubkey: string}) {
|
|||||||
<RNText style={$supportText}>
|
<RNText style={$supportText}>
|
||||||
<Text
|
<Text
|
||||||
text='Minibits'
|
text='Minibits'
|
||||||
style={{fontFamily: 'Gluten-Regular', fontSize: 18}}
|
style={{fontFamily: 'HammersmithOne-Regular', fontSize: 18}}
|
||||||
/>{' '}
|
/>{' '}
|
||||||
<Text tx="contactsScreen_ownName_donationSubtext" />
|
<Text tx="contactsScreen_ownName_donationSubtext" />
|
||||||
</RNText>
|
</RNText>
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import {useStores} from '../models'
|
|||||||
import AppError from '../utils/AppError'
|
import AppError from '../utils/AppError'
|
||||||
import {ResultModalInfo} from './Wallet/ResultModalInfo'
|
import {ResultModalInfo} from './Wallet/ResultModalInfo'
|
||||||
import { StaticScreenProps, useNavigation } from '@react-navigation/native'
|
import { StaticScreenProps, useNavigation } from '@react-navigation/native'
|
||||||
|
import { KeyChain } from '../services'
|
||||||
|
|
||||||
type Props = StaticScreenProps<undefined>
|
type Props = StaticScreenProps<undefined>
|
||||||
|
|
||||||
@@ -42,6 +43,9 @@ export const SecurityScreen = observer(function SecurityScreen({ route }: Props)
|
|||||||
try {
|
try {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
|
|
||||||
|
// require auth to turn on or off
|
||||||
|
await KeyChain.getOrCreateAuthToken(isBiometricAuthOn)
|
||||||
|
|
||||||
const result = await userSettingsStore.setIsAuthOn(
|
const result = await userSettingsStore.setIsAuthOn(
|
||||||
!isBiometricAuthOn,
|
!isBiometricAuthOn,
|
||||||
)
|
)
|
||||||
@@ -198,8 +202,8 @@ export const SecurityScreen = observer(function SecurityScreen({ route }: Props)
|
|||||||
title={
|
title={
|
||||||
isBiometricAuthOn ? 'Authentication is on' : 'Authentication is off'
|
isBiometricAuthOn ? 'Authentication is on' : 'Authentication is off'
|
||||||
}
|
}
|
||||||
message={resultMessage as string}
|
message={resultMessage as string}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
onBackButtonPress={toggleAuthModal}
|
onBackButtonPress={toggleAuthModal}
|
||||||
onBackdropPress={toggleAuthModal}
|
onBackdropPress={toggleAuthModal}
|
||||||
@@ -229,8 +233,8 @@ const $card: ViewStyle = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const $bottomModal: ViewStyle = {
|
const $bottomModal: ViewStyle = {
|
||||||
flex: 1,
|
// flex: 1,
|
||||||
alignItems: 'center',
|
// alignItems: 'center',
|
||||||
paddingVertical: spacing.large,
|
paddingVertical: spacing.large,
|
||||||
paddingHorizontal: spacing.small,
|
paddingHorizontal: spacing.small,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,10 +13,11 @@ import {
|
|||||||
HOT_UPDATER_URL,
|
HOT_UPDATER_URL,
|
||||||
} from '@env'
|
} from '@env'
|
||||||
import {ThemeCode, Themes, colors, spacing, useThemeColor} from '../theme'
|
import {ThemeCode, Themes, colors, spacing, useThemeColor} from '../theme'
|
||||||
|
import { changeIcon } from 'react-native-change-icon'
|
||||||
import {ListItem, Screen, Text, Card, NwcIcon, Button, BottomModal, InfoModal, Icon, Header, AnimatedHeader} from '../components'
|
import {ListItem, Screen, Text, Card, NwcIcon, Button, BottomModal, InfoModal, Icon, Header, AnimatedHeader} from '../components'
|
||||||
import {useStores} from '../models'
|
import {useStores} from '../models'
|
||||||
import {translate} from '../i18n'
|
import {translate} from '../i18n'
|
||||||
import { log } from '../services'
|
import { MMKVStorage, log } from '../services'
|
||||||
import { Currencies, CurrencyCode, availableExchangeCurrencies } from '../services/wallet/currency'
|
import { Currencies, CurrencyCode, availableExchangeCurrencies } from '../services/wallet/currency'
|
||||||
import { NotificationService } from '../services/notificationService'
|
import { NotificationService } from '../services/notificationService'
|
||||||
import { SvgXml } from 'react-native-svg'
|
import { SvgXml } from 'react-native-svg'
|
||||||
@@ -57,7 +58,7 @@ export const SettingsScreen = observer(function SettingsScreen({ route }: Props)
|
|||||||
|
|
||||||
const [isUpdateAvailable, setIsUpdateAvailable] = useState<boolean>(false)
|
const [isUpdateAvailable, setIsUpdateAvailable] = useState<boolean>(false)
|
||||||
const [updateDescription, setUpdateDescription] = useState<string>('')
|
const [updateDescription, setUpdateDescription] = useState<string>('')
|
||||||
const [currentTheme, setCurrentTheme] = useState<ThemeCode>(userSettingsStore.theme)
|
const [currentTheme, setCurrentTheme] = useState<ThemeCode>(MMKVStorage.loadTheme())
|
||||||
|
|
||||||
const [updateSize, setUpdateSize] = useState<string>('')
|
const [updateSize, setUpdateSize] = useState<string>('')
|
||||||
const [isCurrencyModalVisible, setIsCurrencyModalVisible] = useState<boolean>(false)
|
const [isCurrencyModalVisible, setIsCurrencyModalVisible] = useState<boolean>(false)
|
||||||
@@ -286,17 +287,19 @@ export const SettingsScreen = observer(function SettingsScreen({ route }: Props)
|
|||||||
toggleCurrencyModal()
|
toggleCurrencyModal()
|
||||||
}
|
}
|
||||||
|
|
||||||
const onSelectTheme = async function(theme: ThemeCode) {
|
const onSelectTheme = async function(theme: ThemeCode) {
|
||||||
if(currentTheme !== theme) {
|
if(currentTheme !== theme) {
|
||||||
try {
|
try {
|
||||||
userSettingsStore.setNextTheme(theme)
|
userSettingsStore.setNextTheme(theme)
|
||||||
setCurrentTheme(theme)
|
setCurrentTheme(theme)
|
||||||
setInfo(translate('settingsScreen_restartTheme'))
|
setInfo(translate('settingsScreen_restartTheme'))
|
||||||
|
const targetIcon = theme === ThemeCode.GOLDEN ? 'Golden' : 'Default'
|
||||||
|
await changeIcon(targetIcon)
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
log.warn('[onSelectTheme]', e.message)
|
log.warn('[onSelectTheme]', e.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
toggleThemeModal()
|
toggleThemeModal()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export const ResultModalInfo = function(props: {
|
|||||||
|
|
||||||
const $iconContainer: ViewStyle = {
|
const $iconContainer: ViewStyle = {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
width: 120,
|
width: 120,
|
||||||
height: 120,
|
height: 120,
|
||||||
}
|
}
|
||||||
@@ -446,14 +446,7 @@ const authenticateOnAppStart = async function (isAuthOn: boolean): Promise<AuthR
|
|||||||
// Handle specific error codes for user actions
|
// Handle specific error codes for user actions
|
||||||
const authErrorContext = getAuthErrorContext(e)
|
const authErrorContext = getAuthErrorContext(e)
|
||||||
|
|
||||||
log.warn('[authenticateOnAppStart]', 'Auth error caught', {
|
log.warn('[authenticateOnAppStart]', 'Auth error caught',{authErrorContext})
|
||||||
message: e.message,
|
|
||||||
code: e.code,
|
|
||||||
name: e.name,
|
|
||||||
params: e.params,
|
|
||||||
stringified: authErrorContext.serialized,
|
|
||||||
codeCandidates: authErrorContext.codeCandidates,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (authErrorContext.isBackPressed) {
|
if (authErrorContext.isBackPressed) {
|
||||||
log.trace('[authenticateOnAppStart]', 'User pressed back button')
|
log.trace('[authenticateOnAppStart]', 'User pressed back button')
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {MMKV} from 'react-native-mmkv'
|
import {MMKV} from 'react-native-mmkv'
|
||||||
import {log} from './logService'
|
import {log} from './logService'
|
||||||
import AppError, {Err} from '../utils/AppError'
|
import AppError, {Err} from '../utils/AppError'
|
||||||
|
import { ThemeCode } from '../theme'
|
||||||
|
|
||||||
const STORAGE_KEY = 'storage-v1'
|
const STORAGE_KEY = 'storage-v1'
|
||||||
let _storage: MMKV | undefined
|
let _storage: MMKV | undefined
|
||||||
@@ -154,7 +155,32 @@ const clearAll = function (): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MMKVStorage = {
|
const THEME_STORAGE_KEY = 'theme'
|
||||||
|
let _cachedTheme: ThemeCode | undefined
|
||||||
|
|
||||||
|
const loadTheme = function (): ThemeCode {
|
||||||
|
if (_cachedTheme !== undefined) return _cachedTheme
|
||||||
|
try {
|
||||||
|
const storage = getInstance()
|
||||||
|
_cachedTheme = (storage.getString(THEME_STORAGE_KEY) as ThemeCode) ?? ThemeCode.DEFAULT
|
||||||
|
return _cachedTheme
|
||||||
|
} catch (e: any) {
|
||||||
|
return ThemeCode.DEFAULT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveTheme = function (theme: ThemeCode): boolean {
|
||||||
|
try {
|
||||||
|
_cachedTheme = theme
|
||||||
|
const storage = getInstance()
|
||||||
|
storage.set(THEME_STORAGE_KEY, theme)
|
||||||
|
return true
|
||||||
|
} catch (e: any) {
|
||||||
|
throw new AppError(Err.DATABASE_ERROR, e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MMKVStorage = {
|
||||||
loadString,
|
loadString,
|
||||||
saveString,
|
saveString,
|
||||||
saveNumber,
|
saveNumber,
|
||||||
@@ -163,4 +189,6 @@ export const MMKVStorage = {
|
|||||||
save,
|
save,
|
||||||
remove,
|
remove,
|
||||||
clearAll,
|
clearAll,
|
||||||
|
loadTheme,
|
||||||
|
saveTheme,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ const fonts = {
|
|||||||
// Android only font.
|
// Android only font.
|
||||||
normal: 'monospace',
|
normal: 'monospace',
|
||||||
},
|
},
|
||||||
gluten: {
|
hammersmithOne: {
|
||||||
normal: 'Gluten-Regular',
|
normal: 'HammersmithOne-Regular',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,5 +54,5 @@ export const typography = {
|
|||||||
* Lets get fancy with a monospace font!
|
* Lets get fancy with a monospace font!
|
||||||
*/
|
*/
|
||||||
code: Platform.select({ios: fonts.courier, android: fonts.monospace}),
|
code: Platform.select({ios: fonts.courier, android: fonts.monospace}),
|
||||||
logo: fonts.gluten,
|
logo: fonts.hammersmithOne,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { rootStoreInstance, useStores } from '../models'
|
|
||||||
import {ThemeCode, colors} from '../theme'
|
import {ThemeCode, colors} from '../theme'
|
||||||
|
import { MMKVStorage } from '../services'
|
||||||
import {
|
import {
|
||||||
ColorSchemeName,
|
ColorSchemeName,
|
||||||
useColorScheme as _useColorScheme,
|
useColorScheme as _useColorScheme,
|
||||||
@@ -16,12 +16,13 @@ export default function useColorScheme(): NonNullable<ColorSchemeName> {
|
|||||||
export function useThemeColor(
|
export function useThemeColor(
|
||||||
colorName: keyof typeof colors.light & keyof typeof colors.dark & keyof typeof colors.golden,
|
colorName: keyof typeof colors.light & keyof typeof colors.dark & keyof typeof colors.golden,
|
||||||
) {
|
) {
|
||||||
const { userSettingsStore } = rootStoreInstance
|
// loadTheme() returns an in-memory cached value after first read — O(1), no MMKV overhead
|
||||||
|
const theme = MMKVStorage.loadTheme()
|
||||||
if(userSettingsStore.theme === ThemeCode.DEFAULT) {
|
|
||||||
|
if(theme === ThemeCode.DEFAULT) {
|
||||||
const colorScheme = useColorScheme()
|
const colorScheme = useColorScheme()
|
||||||
return colors[colorScheme][colorName] as ColorValue
|
return colors[colorScheme][colorName] as ColorValue
|
||||||
}
|
}
|
||||||
|
|
||||||
return colors[userSettingsStore.theme][colorName] as ColorValue
|
return colors[theme][colorName] as ColorValue
|
||||||
}
|
}
|
||||||
|
|||||||
11
yarn.lock
11
yarn.lock
@@ -14669,6 +14669,7 @@ __metadata:
|
|||||||
react-native: 0.84.0
|
react-native: 0.84.0
|
||||||
react-native-animated-pagination-dots: ^0.1.73
|
react-native-animated-pagination-dots: ^0.1.73
|
||||||
react-native-camera-kit: 17.0.1
|
react-native-camera-kit: 17.0.1
|
||||||
|
react-native-change-icon: ^3.0.0
|
||||||
react-native-clean-project: ^4.0.3
|
react-native-clean-project: ^4.0.3
|
||||||
react-native-dotenv: ^3.4.11
|
react-native-dotenv: ^3.4.11
|
||||||
react-native-exit-app: ^2.0.0
|
react-native-exit-app: ^2.0.0
|
||||||
@@ -16499,6 +16500,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"react-native-change-icon@npm:^3.0.0":
|
||||||
|
version: 3.2.0
|
||||||
|
resolution: "react-native-change-icon@npm:3.2.0"
|
||||||
|
peerDependencies:
|
||||||
|
react: "*"
|
||||||
|
react-native: "*"
|
||||||
|
checksum: d361e9e06fbd2969d85373b5e07531aa4af6a6472ede16928cd3afb0cf6bad6871a9bfa5022b5959ce50787aeb6664eea13e09cd8471ce97067cf7735ed6a20b
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"react-native-clean-project@npm:^4.0.3":
|
"react-native-clean-project@npm:^4.0.3":
|
||||||
version: 4.0.3
|
version: 4.0.3
|
||||||
resolution: "react-native-clean-project@npm:4.0.3"
|
resolution: "react-native-clean-project@npm:4.0.3"
|
||||||
|
|||||||
Reference in New Issue
Block a user