Skip to content

Commit 40b61ab

Browse files
authored
Merge pull request #18 from cake-tech/CW-912-cleanup7
CW-912 [7/?] Possibly last PR in this series
2 parents a05aa90 + 6371bf2 commit 40b61ab

File tree

86 files changed

+2017
-1587
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+2017
-1587
lines changed

.env

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
MONERO_C_TAG=v0.18.3.4-RC10
1+
MONERO_C_TAG=v0.18.3.4-RC12
22
COIN=monero

.fvmrc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"flutter": "3.27.4"
2+
"flutter": "3.29.0"
33
}

.tooling/format.sh

+13
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,20 @@
22
set -x -e
33
cd "$(dirname "$0")"
44
cd ..
5+
6+
pushd lib/l10n
7+
for file in *.arb;
8+
do
9+
jq 'to_entries
10+
| group_by(.key | sub("^@"; ""))
11+
| map( sort_by(.key | startswith("@")) | map({ (.key): .value }) | add )
12+
| add' $file > $file.tmp || rm $file.tmp
13+
mv $file.tmp $file
14+
done
15+
popd
16+
517
dart run build_runner build --delete-conflicting-outputs
618
dart fix --apply .
719
dart format .
20+
821
flutter gen-l10n

.vscode/settings.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"dart.flutterSdkPath": ".fvm/versions/3.27.4"
2+
"dart.flutterSdkPath": ".fvm/versions/3.29.0"
33
}

LICENSE

+4-18
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,7 @@
1-
MIT License
1+
Copyright (C) 2025 Cake Labs LLC
22

3-
Copyright (c) 2024 Cake Labs LLC
3+
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3.
44

5-
Permission is hereby granted, free of charge, to any person obtaining a copy
6-
of this software and associated documentation files (the "Software"), to deal
7-
in the Software without restriction, including without limitation the rights
8-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9-
copies of the Software, and to permit persons to whom the Software is
10-
furnished to do so, subject to the following conditions:
5+
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
116

12-
The above copyright notice and this permission notice shall be included in all
13-
copies or substantial portions of the Software.
14-
15-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21-
SOFTWARE.
7+
You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.

Makefile

+5-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ endif
1616
./build_moneroc.sh --coin ${COIN} --tag ${MONERO_C_TAG} --triplet armv7a-linux-androideabi --location android/app/src/main/jniLibs/armeabi-v7a
1717

1818
libs_android_build_ci:
19-
./build_moneroc.sh --prebuild --coin ${COIN} --tag ${MONERO_C_TAG} --triplet aarch64-linux-android --location android/app/src/main/jniLibs/arm64-v8a
19+
./build_moneroc.sh --coin ${COIN} --tag ${MONERO_C_TAG} --triplet aarch64-linux-android --location android/app/src/main/jniLibs/arm64-v8a
2020

2121
libs_ios_download:
2222
./build_moneroc.sh --prebuild --coin ${COIN} --tag ${MONERO_C_TAG} --triplet aarch64-apple-ios --location ios/native_libs/ios-arm64
@@ -36,5 +36,9 @@ cupcake_android_monero:
3636
dart run build_runner build --delete-conflicting-outputs
3737
flutter build apk --dart-define=COIN_MONERO=true
3838

39+
cupcake_ios_monero:
40+
dart run build_runner build --delete-conflicting-outputs
41+
flutter build ios --no-codesign --dart-define=COIN_MONERO=true
42+
3943
prepare_dev:
4044
./.tooling/prepare_dev.sh

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
To build:
99

1010
```bash
11-
$ make libs_android_build # or libs_android_download
12-
$ make prepare_dev # load dev signing key
13-
$ make cupcake_android_monero
11+
$ make libs_android_build # or libs_android_download, libs_ios_build, libs_ios_download
12+
$ make prepare_dev # load dev signing key (not required on iOS)
13+
$ make cupcake_android_monero # or cupcake_
1414
```
1515

1616
### Adding other coins

analysis_options.yaml

+15
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ analyzer:
22
errors:
33
must_be_immutable: ignore
44
overridden_fields: ignore
5+
exclude:
6+
- '**.g.dart'
57
include: package:flutter_lints/flutter.yaml
68

79
linter:
@@ -14,3 +16,16 @@ linter:
1416
prefer_final_in_for_each: true
1517
prefer_final_locals: true
1618
prefer_final_parameters: true
19+
avoid_void_async: true
20+
require_trailing_commas: true
21+
sort_child_properties_last: true
22+
sort_constructors_first: true
23+
sort_unnamed_constructors_first: true
24+
unnecessary_async: true
25+
unnecessary_await_in_return: true
26+
unnecessary_string_interpolations: true
27+
always_declare_return_types: true
28+
29+
30+
formatter:
31+
page_width: 100

docs/README.md

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Cupcake Notes and Documentation
2+
3+
> This document is intended for developers. If you just want to build Cupcake, please see the top-level `README.md` and `Makefile`.
4+
5+
## Project Structure
6+
7+
Cupcake adheres to a standard project structure; currently, everything resides inside the `lib` directory. This setup may change in the future.
8+
9+
## `lib/coins`
10+
11+
This directory contains the abstract `coin` definition. To add a new currency to Cupcake, simply implement the abstract `Coin` class found here and update `lib/coins/list.dart` with the new class. The app will automatically pick it up, and a new entry will appear on the coin selection screen during creation or restoration.
12+
13+
> **NOTE:** Currently, only one coin is supported. To ensure a smooth user experience, Cupcake will not prompt the user to select an option if there is only one available.
14+
15+
## `lib/dev`
16+
17+
Cupcake's state management is implemented in a very simple way using MVVM. Since the app is designed to work entirely offline, its state doesn't change often. To keep the code simple, I opted to create an in-house state management solution instead of using an existing one-size-fits-all package. While those packages are great, I believe they would be overkill for an app with a minimal UI and limited processing.
18+
19+
This directory contains three code generation utilities that, while entirely optional, make my life much easier and the code much simpler. For example, instead of converting between `ObservableList` and `List` or wrapping widgets to notify about state changes, we simply trigger a rebuild.
20+
21+
### `@GenerateRebuild()`
22+
23+
Place this annotation around a class to ensure that all other generation annotations work correctly.
24+
25+
### `@RebuildOnChange()`
26+
27+
This annotation wraps a variable in a getter and setter that triggers a rebuild when the variable changes.
28+
29+
```dart
30+
@RebuildOnChange()
31+
Barcode? $barcode;
32+
```
33+
34+
You can then use `barcode` (or `viewModel.barcode`), and updating this value will rebuild the UI.
35+
36+
### `@ThrowOnUI(message: "message...", L: "translation_key")`
37+
38+
If you have a function that may throw an error—and that error should be presented to the user in a dismissible manner—use this annotation. It indicates that something went wrong, allowing the user to retry or correct the issue without restarting the entire action.
39+
40+
```dart
41+
@ThrowOnUI(message: "Error handling URQR scan")
42+
Future<void> $handleUR() async {
43+
if (formInvalid) {
44+
throw Exception("The form is invalid");
45+
}
46+
await wallet.handleUR(c!, ur);
47+
}
48+
```
49+
50+
You can use either `message:` or `L:`. The `message:` text will be displayed in plain text, whereas `L:` will use a translation key. The error message will appear as a dismissible alert.
51+
52+
If you do not use `@ThrowOnUI()`, you must wrap the function in a try-catch block. If an error is thrown without being caught, the app will display a panic handler screen that prevents further use.
53+
54+
### `@ExposeRebuildableAccessors()`
55+
56+
This annotation is somewhat special and is designed for the settings page. It exposes all setters and getters from a class instance, making it possible to access them as elements of the ViewModel.
57+
58+
```dart
59+
@ExposeRebuildableAccessors(extraCode: r'$config.save()')
60+
CupcakeConfig get $config => CupcakeConfig.instance;
61+
```
62+
63+
This approach lets you access settings, for example, using `viewModel.configBiometricEnabled`. It may be overkill, but I like it because it essentially removes almost all logic from the settings view model.
64+
65+
## `lib/gen`
66+
67+
The `lib/gen` directory uses `flutter_gen` to access assets. This method is preferable to using string-based paths in UI code, as it prevents accidental typos that might not be caught by the linter or at compile time.

ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
ignoresPersistentStateOnLaunch = "NO"
6060
debugDocumentVersioning = "YES"
6161
debugServiceExtension = "internal"
62+
enableGPUValidationMode = "1"
6263
allowLocationSimulation = "YES">
6364
<BuildableProductRunnable
6465
runnableDebuggingMode = "0">

lib/coins/abstract/coin.dart

+10-16
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,28 @@
11
import 'package:cupcake/coins/abstract/strings.dart';
22
import 'package:cupcake/coins/abstract/wallet.dart';
3+
import 'package:cupcake/coins/abstract/wallet_creation.dart';
34
import 'package:cupcake/coins/abstract/wallet_info.dart';
4-
import 'package:cupcake/coins/types.dart';
5+
import 'package:cupcake/l10n/app_localizations.dart';
56

67
enum Coins { monero, unknown }
78

89
abstract class Coin {
10+
static late AppLocalizations L;
911
Coins get type => Coins.unknown;
1012

1113
CoinStrings get strings;
1214

15+
String get uriScheme;
16+
1317
bool get isEnabled;
1418

1519
Future<List<CoinWalletInfo>> get coinWallets;
1620

17-
Future<CoinWallet> createNewWallet(
18-
final String walletName,
19-
final String walletPassword, {
20-
final ProgressCallback? progressCallback,
21-
required final bool? createWallet,
22-
required final String? seed,
23-
required final int? restoreHeight,
24-
required final String? primaryAddress,
25-
required final String? viewKey,
26-
required final String? spendKey,
27-
required final String? seedOffsetOrEncryption,
28-
});
29-
3021
bool isSeedSomewhatLegit(final String seed);
3122

32-
Future<CoinWallet> openWallet(final CoinWalletInfo walletInfo,
33-
{required final String password});
23+
Future<CoinWallet> openWallet(final CoinWalletInfo walletInfo, {required final String password});
24+
25+
WalletCreation creationMethod(final AppLocalizations L);
26+
27+
String getPathForWallet(final String walletName);
3428
}

lib/coins/abstract/wallet.dart

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import 'package:cupcake/coins/abstract/coin.dart';
22
import 'package:cupcake/coins/abstract/wallet_seed_detail.dart';
3-
import 'package:cupcake/l10n/app_localizations.dart';
43
import 'package:cupcake/utils/urqr.dart';
54
import 'package:flutter/widgets.dart';
65

@@ -30,6 +29,8 @@ abstract class CoinWallet {
3029

3130
String get seed;
3231

32+
String get passphrase;
33+
3334
String get primaryAddress;
3435

3536
String get walletName;
@@ -40,6 +41,5 @@ abstract class CoinWallet {
4041

4142
Future<void> close();
4243

43-
Future<List<WalletSeedDetail>> seedDetails(final AppLocalizations L) =>
44-
throw UnimplementedError();
44+
Future<List<WalletSeedDetail>> seedDetails() => throw UnimplementedError();
4545
}
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// creation = any action that results in new wallet being created, be that restore or generate
2+
// To unify the process of wallet creation we provide multiple "generators".
3+
// There is one class that defines inputs (FormElement)
4+
// And multiple WalletCreation classes
5+
// When creating wallet heuristic are being applied to see which creation method will be used,
6+
// it is entirely possible for one input of restore/creation form to have multiple outputs,
7+
8+
import 'package:cupcake/coins/abstract/coin.dart';
9+
import 'package:cupcake/coins/abstract/wallet.dart';
10+
import 'package:cupcake/utils/types.dart';
11+
import 'package:cupcake/utils/form/abstract_form_element.dart';
12+
13+
abstract class WalletCreation {
14+
Coin get coin => throw UnimplementedError();
15+
Future<CreationOutcome?> create(
16+
final CreateMethod createMethod,
17+
final String walletName,
18+
final String walletPassword,
19+
);
20+
Map<String, List<FormElement>> createMethods(final CreateMethod createMethod);
21+
22+
// wipe function clears all details from WalletCreation form
23+
void wipe();
24+
}
25+
26+
// No need for CreationMethod to exist but it makes sure that we follow some internal structure
27+
// of wallet generation.
28+
abstract class CreationMethod {
29+
CreationMethod();
30+
31+
Future<CreationOutcome> create();
32+
}
33+
34+
class CreationOutcome {
35+
CreationOutcome({
36+
required this.success,
37+
required this.method,
38+
this.wallet,
39+
this.message,
40+
}) :
41+
// We must provide a detailed feedback regarding why creation failed
42+
assert((success == false && message != null && message.isNotEmpty) || success);
43+
final bool success;
44+
final CoinWallet? wallet;
45+
final CreateMethod method;
46+
final String? message;
47+
}

lib/coins/abstract/wallet_info.dart

+1-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ abstract class CoinWalletInfo {
1818

1919
bool exists();
2020

21-
Future<CoinWallet> openWallet(final BuildContext context,
22-
{required final String password});
21+
Future<CoinWallet> openWallet(final BuildContext context, {required final String password});
2322

2423
Map<String, dynamic> toJson() {
2524
return {

lib/coins/abstract/wallet_seed_detail.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import 'package:cupcake/coins/types.dart';
1+
import 'package:cupcake/utils/types.dart';
22

33
class WalletSeedDetail {
44
WalletSeedDetail({

0 commit comments

Comments
 (0)