Skip to content

Commit 4514aa4

Browse files
committed
feat: add activation and revocation use cases for BIP85 derivations and integrate them into the locator and widget
1 parent 73b50de commit 4514aa4

7 files changed

Lines changed: 172 additions & 58 deletions

File tree

lib/core/bip85/bip85_locator.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import 'package:bb_mobile/core/bip85/data/bip85_datasource.dart';
22
import 'package:bb_mobile/core/bip85/data/bip85_repository.dart';
3+
import 'package:bb_mobile/core/bip85/domain/activate_bip85_derivation_usecase.dart';
34
import 'package:bb_mobile/core/bip85/domain/alias_bip85_derivation_usecase.dart';
45
import 'package:bb_mobile/core/bip85/domain/derive_next_bip85_hex_from_default_wallet_usecase.dart';
56
import 'package:bb_mobile/core/bip85/domain/derive_next_bip85_mnemonic_from_default_wallet_usecase.dart';
67
import 'package:bb_mobile/core/bip85/domain/fetch_all_derivations_usecase.dart';
8+
import 'package:bb_mobile/core/bip85/domain/revoke_bip85_derivation_usecase.dart';
79
import 'package:bb_mobile/core/seed/data/repository/seed_repository.dart';
810
import 'package:bb_mobile/core/storage/sqlite_database.dart';
911
import 'package:bb_mobile/core/wallet/data/repositories/wallet_repository.dart';
@@ -49,5 +51,15 @@ class Bip85DerivationsLocator {
4951
bip85Repository: locator<Bip85Repository>(),
5052
),
5153
);
54+
locator.registerFactory<RevokeBip85DerivationUsecase>(
55+
() => RevokeBip85DerivationUsecase(
56+
bip85Repository: locator<Bip85Repository>(),
57+
),
58+
);
59+
locator.registerFactory<ActivateBip85DerivationUsecase>(
60+
() => ActivateBip85DerivationUsecase(
61+
bip85Repository: locator<Bip85Repository>(),
62+
),
63+
);
5264
}
5365
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import 'package:bb_mobile/core/bip85/data/bip85_repository.dart';
2+
import 'package:bb_mobile/core/bip85/domain/bip85_derivation_entity.dart';
3+
4+
class ActivateBip85DerivationUsecase {
5+
final Bip85Repository _bip85Repository;
6+
7+
ActivateBip85DerivationUsecase({required Bip85Repository bip85Repository})
8+
: _bip85Repository = bip85Repository;
9+
10+
Future<void> execute(Bip85DerivationEntity derivation) async {
11+
try {
12+
await _bip85Repository.activate(derivation);
13+
} catch (e) {
14+
rethrow;
15+
}
16+
}
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import 'package:bb_mobile/core/bip85/data/bip85_repository.dart';
2+
import 'package:bb_mobile/core/bip85/domain/bip85_derivation_entity.dart';
3+
4+
class RevokeBip85DerivationUsecase {
5+
final Bip85Repository _bip85Repository;
6+
7+
RevokeBip85DerivationUsecase({required Bip85Repository bip85Repository})
8+
: _bip85Repository = bip85Repository;
9+
10+
Future<void> execute(Bip85DerivationEntity derivation) async {
11+
try {
12+
await _bip85Repository.revoke(derivation);
13+
} catch (e) {
14+
rethrow;
15+
}
16+
}
17+
}

lib/core/widgets/bip85_derivation_widget.dart

Lines changed: 94 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,16 @@ class Bip85DerivationWidget extends StatefulWidget {
88
final String xprvBase58;
99
final Bip85DerivationEntity derivation;
1010
final Future<void> Function(Bip85DerivationEntity, String)? onAliasChanged;
11+
final Future<void> Function(Bip85DerivationEntity)? onDerivationRevoked;
12+
final Future<void> Function(Bip85DerivationEntity)? onDerivationActivated;
1113

1214
const Bip85DerivationWidget({
1315
super.key,
1416
required this.derivation,
1517
required this.xprvBase58,
1618
this.onAliasChanged,
19+
this.onDerivationRevoked,
20+
this.onDerivationActivated,
1721
});
1822

1923
@override
@@ -46,13 +50,27 @@ class _Bip85DerivationWidgetState extends State<Bip85DerivationWidget> {
4650
}
4751
}
4852

53+
Future<void> _revokeDerivation() async {
54+
if (widget.onDerivationRevoked != null) {
55+
await widget.onDerivationRevoked!(widget.derivation);
56+
}
57+
}
58+
59+
Future<void> _activateDerivation() async {
60+
if (widget.onDerivationActivated != null) {
61+
await widget.onDerivationActivated!(widget.derivation);
62+
}
63+
}
64+
4965
@override
5066
Widget build(BuildContext context) {
5167
final data = bip85.Bip85Entropy.deriveFromHardenedPath(
5268
xprvBase58: widget.xprvBase58,
5369
path: bip85.Bip85HardenedPath(widget.derivation.path),
5470
);
5571

72+
final isRevoked = widget.derivation.status == Bip85Status.revoked;
73+
5674
return Container(
5775
padding: const EdgeInsets.all(16),
5876
decoration: BoxDecoration(
@@ -76,73 +94,91 @@ class _Bip85DerivationWidgetState extends State<Bip85DerivationWidget> {
7694
widget.derivation.status.name,
7795
style: TextStyle(color: context.appColors.text),
7896
),
97+
if (isRevoked && widget.onDerivationActivated != null)
98+
IconButton(
99+
icon: Icon(Icons.replay, color: context.appColors.success),
100+
onPressed: _activateDerivation,
101+
)
102+
else if (widget.onDerivationRevoked != null && !isRevoked)
103+
IconButton(
104+
icon: Icon(Icons.block, color: context.appColors.error),
105+
onPressed: _revokeDerivation,
106+
),
79107
],
80108
),
81-
Row(
82-
children: [
83-
Expanded(
84-
child: _isEditingAlias
85-
? TextField(
86-
controller: _aliasController,
87-
autofocus: true,
88-
style: TextStyle(color: context.appColors.text),
89-
decoration: InputDecoration(
90-
border: OutlineInputBorder(
91-
borderSide: BorderSide(
92-
color: context.appColors.border,
109+
if (!isRevoked) ...[
110+
Row(
111+
children: [
112+
Expanded(
113+
child: _isEditingAlias
114+
? TextField(
115+
controller: _aliasController,
116+
autofocus: true,
117+
style: TextStyle(color: context.appColors.text),
118+
decoration: InputDecoration(
119+
border: OutlineInputBorder(
120+
borderSide: BorderSide(
121+
color: context.appColors.border,
122+
),
93123
),
94124
),
125+
)
126+
: Text(
127+
widget.derivation.alias ?? '',
128+
style: TextStyle(color: context.appColors.text),
95129
),
96-
)
97-
: Text(
98-
widget.derivation.alias ?? '',
99-
style: TextStyle(color: context.appColors.text),
130+
),
131+
if (widget.onAliasChanged != null)
132+
if (_isEditingAlias)
133+
IconButton(
134+
icon: Icon(
135+
Icons.check,
136+
color: context.appColors.onSurface,
100137
),
101-
),
102-
if (widget.onAliasChanged != null)
103-
if (_isEditingAlias)
104-
IconButton(
105-
icon: Icon(Icons.check, color: context.appColors.onSurface),
106-
onPressed: _saveAlias,
107-
)
108-
else
109-
IconButton(
110-
icon: Icon(Icons.edit, color: context.appColors.onSurface),
111-
onPressed: () => setState(() => _isEditingAlias = true),
138+
onPressed: _saveAlias,
139+
)
140+
else
141+
IconButton(
142+
icon: Icon(
143+
Icons.edit,
144+
color: context.appColors.onSurface,
145+
),
146+
onPressed: () => setState(() => _isEditingAlias = true),
147+
),
148+
],
149+
),
150+
Row(
151+
children: [
152+
Expanded(
153+
child: TextField(
154+
controller: TextEditingController(text: data),
155+
obscureText: _isObscured,
156+
readOnly: true,
157+
decoration: const InputDecoration(border: InputBorder.none),
112158
),
113-
],
114-
),
115-
Row(
116-
children: [
117-
Expanded(
118-
child: TextField(
119-
controller: TextEditingController(text: data),
120-
obscureText: _isObscured,
121-
readOnly: true,
122-
decoration: const InputDecoration(border: InputBorder.none),
123159
),
124-
),
125-
IconButton(
126-
icon: Icon(
127-
_isObscured ? Icons.visibility : Icons.visibility_off,
128-
color: context.appColors.onSurface,
160+
IconButton(
161+
icon: Icon(
162+
_isObscured ? Icons.visibility : Icons.visibility_off,
163+
color: context.appColors.onSurface,
164+
),
165+
onPressed: () => setState(() => _isObscured = !_isObscured),
129166
),
130-
onPressed: () => setState(() => _isObscured = !_isObscured),
131-
),
132-
IconButton(
133-
icon: Icon(Icons.copy, color: context.appColors.onSurface),
134-
onPressed: () {
135-
Clipboard.setData(ClipboardData(text: data));
136-
ScaffoldMessenger.of(context).showSnackBar(
137-
const SnackBar(
138-
content: Text('Copied to clipboard'),
139-
duration: Duration(seconds: 1),
140-
),
141-
);
142-
},
143-
),
144-
],
145-
),
167+
IconButton(
168+
icon: Icon(Icons.copy, color: context.appColors.onSurface),
169+
onPressed: () {
170+
Clipboard.setData(ClipboardData(text: data));
171+
ScaffoldMessenger.of(context).showSnackBar(
172+
const SnackBar(
173+
content: Text('Copied to clipboard'),
174+
duration: Duration(seconds: 1),
175+
),
176+
);
177+
},
178+
),
179+
],
180+
),
181+
],
146182
],
147183
),
148184
);

lib/features/bip85_entropy/bip85_home_page.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ class Bip85HomePage extends StatelessWidget {
5656
xprvBase58: state.xprvBase58,
5757
derivation: derivation,
5858
onAliasChanged: cubit.aliasDerivation,
59+
onDerivationRevoked: cubit.revokeDerivation,
60+
onDerivationActivated: cubit.activateDerivation,
5961
),
6062
);
6163
}),

lib/features/bip85_entropy/locator.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import 'package:bb_mobile/core/bip85/domain/activate_bip85_derivation_usecase.dart';
12
import 'package:bb_mobile/core/bip85/domain/alias_bip85_derivation_usecase.dart';
23
import 'package:bb_mobile/core/bip85/domain/derive_next_bip85_hex_from_default_wallet_usecase.dart';
34
import 'package:bb_mobile/core/bip85/domain/derive_next_bip85_mnemonic_from_default_wallet_usecase.dart';
45
import 'package:bb_mobile/core/bip85/domain/fetch_all_derivations_usecase.dart';
6+
import 'package:bb_mobile/core/bip85/domain/revoke_bip85_derivation_usecase.dart';
57
import 'package:bb_mobile/core/seed/domain/usecases/get_default_seed_usecase.dart';
68
import 'package:bb_mobile/features/bip85_entropy/presentation/cubit.dart';
79
import 'package:bb_mobile/locator.dart';
@@ -18,6 +20,8 @@ class Bip85EntropyLocator {
1820
locator<DeriveNextBip85HexFromDefaultWalletUsecase>(),
1921
getDefaultSeedUsecase: locator<GetDefaultSeedUsecase>(),
2022
aliasBip85DerivationUsecase: locator<AliasBip85DerivationUsecase>(),
23+
revokeBip85DerivationUsecase: locator<RevokeBip85DerivationUsecase>(),
24+
activateBip85DerivationUsecase: locator<ActivateBip85DerivationUsecase>(),
2125
),
2226
);
2327
}

lib/features/bip85_entropy/presentation/cubit.dart

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import 'package:bb_mobile/core/bip85/domain/activate_bip85_derivation_usecase.dart';
12
import 'package:bb_mobile/core/bip85/domain/alias_bip85_derivation_usecase.dart';
23
import 'package:bb_mobile/core/bip85/domain/bip85_derivation_entity.dart';
34
import 'package:bb_mobile/core/bip85/domain/derive_next_bip85_hex_from_default_wallet_usecase.dart';
45
import 'package:bb_mobile/core/bip85/domain/derive_next_bip85_mnemonic_from_default_wallet_usecase.dart';
56
import 'package:bb_mobile/core/bip85/domain/fetch_all_derivations_usecase.dart';
7+
import 'package:bb_mobile/core/bip85/domain/revoke_bip85_derivation_usecase.dart';
68
import 'package:bb_mobile/core/seed/domain/usecases/get_default_seed_usecase.dart';
79
import 'package:bb_mobile/core/utils/bip32_derivation.dart';
810
import 'package:bb_mobile/core/wallet/domain/entities/wallet.dart';
@@ -18,6 +20,8 @@ class Bip85EntropyCubit extends Cubit<Bip85EntropyState> {
1820
_deriveNextBip85HexFromDefaultWalletUsecase;
1921
final GetDefaultSeedUsecase _getDefaultSeedUsecase;
2022
final AliasBip85DerivationUsecase _aliasBip85DerivationUsecase;
23+
final RevokeBip85DerivationUsecase _revokeBip85DerivationUsecase;
24+
final ActivateBip85DerivationUsecase _activateBip85DerivationUsecase;
2125

2226
Bip85EntropyCubit({
2327
required FetchAllBip85DerivationsUsecase fetchAllBip85DerivationsUsecase,
@@ -27,13 +31,17 @@ class Bip85EntropyCubit extends Cubit<Bip85EntropyState> {
2731
deriveNextBip85HexFromDefaultWalletUsecase,
2832
required GetDefaultSeedUsecase getDefaultSeedUsecase,
2933
required AliasBip85DerivationUsecase aliasBip85DerivationUsecase,
34+
required RevokeBip85DerivationUsecase revokeBip85DerivationUsecase,
35+
required ActivateBip85DerivationUsecase activateBip85DerivationUsecase,
3036
}) : _fetchAllBip85DerivationsUsecase = fetchAllBip85DerivationsUsecase,
3137
_deriveNextBip85MnemonicFromDefaultWalletUsecase =
3238
deriveNextBip85MnemonicFromDefaultWalletUsecase,
3339
_deriveNextBip85HexFromDefaultWalletUsecase =
3440
deriveNextBip85HexFromDefaultWalletUsecase,
3541
_getDefaultSeedUsecase = getDefaultSeedUsecase,
3642
_aliasBip85DerivationUsecase = aliasBip85DerivationUsecase,
43+
_revokeBip85DerivationUsecase = revokeBip85DerivationUsecase,
44+
_activateBip85DerivationUsecase = activateBip85DerivationUsecase,
3745
super(const Bip85EntropyState()) {
3846
init();
3947
}
@@ -94,6 +102,24 @@ class Bip85EntropyCubit extends Cubit<Bip85EntropyState> {
94102
}
95103
}
96104

105+
Future<void> revokeDerivation(Bip85DerivationEntity derivation) async {
106+
try {
107+
await _revokeBip85DerivationUsecase.execute(derivation);
108+
await fetchAllDerivations();
109+
} catch (e) {
110+
emit(state.copyWith(error: Bip85EntropyError(e.toString())));
111+
}
112+
}
113+
114+
Future<void> activateDerivation(Bip85DerivationEntity derivation) async {
115+
try {
116+
await _activateBip85DerivationUsecase.execute(derivation);
117+
await fetchAllDerivations();
118+
} catch (e) {
119+
emit(state.copyWith(error: Bip85EntropyError(e.toString())));
120+
}
121+
}
122+
97123
void clearError() => emit(state.copyWith(error: null));
98124

99125
void reset() => emit(const Bip85EntropyState());

0 commit comments

Comments
 (0)