Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import 'package:t3_vault/src/common/localization/timezone/timezone_helper.dart';
import 'package:t3_vault/src/common/notifications/domain/notifications_service.dart';
import 'package:t3_vault/src/common/notifications/state/notifications_state.dart';
import 'package:t3_vault/src/features/greatwall/states/derivation_state.dart';
import 'package:t3_vault/src/features/memorization_assistant/domain/repositories/memo_card_json_repository.dart';
import 'package:t3_vault/src/features/memorization_assistant/domain/repositories/profile_json_repository.dart';

import 'src/app.dart';
import 'src/common/settings/domain/entities/settings_service.dart';
Expand Down Expand Up @@ -37,9 +37,9 @@ void main() async {
// it is stored within the application documents directory.
final filePath = '${directory.path}/t3-profiles.json';

// Initialize the MemoCardRepository with the specified file path, allowing
// the application to read and write memo card data to the JSON file.
final memoCardRepository = MemoCardRepository(
// Initialize the ProfileRepository with the specified file path, allowing
// the application to read and write data to the JSON file.
final profileRepository = ProfileRepository(
filePath: filePath, notificationService: notificationService);

// Load the user's preferred theme while the splash screen is displayed.
Expand All @@ -57,7 +57,7 @@ void main() async {
],
child: T3Vault(
settingsController: settingsController,
memoCardRepository: memoCardRepository,
profileRepository: profileRepository,
)),
);
}
40 changes: 28 additions & 12 deletions lib/src/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:go_router/go_router.dart';
import 'package:t3_crypto_objects/crypto_objects.dart';
import 'package:t3_memassist/memory_assistant.dart';
import 'package:t3_vault/src/features/memorization_assistant/domain/repositories/profile_json_repository.dart';
import 'package:t3_vault/src/features/memorization_assistant/presentation/pages/eka_memo_card_practice_page.dart';
import 'package:t3_vault/src/features/memorization_assistant/presentation/pages/memo_card_decks_page.dart';
import 'package:t3_vault/src/features/memorization_assistant/presentation/pages/sa0_memo_card_practice_page.dart';
Expand All @@ -23,20 +25,19 @@ import 'features/landing/presentation/pages/agreement_page.dart';
import 'features/landing/presentation/pages/home_page.dart';
import 'features/landing/presentation/pages/policy_page.dart';
import 'features/landing/presentation/pages/splash_page.dart';
import 'features/memorization_assistant/domain/repositories/memo_card_json_repository.dart';
import 'features/memorization_assistant/presentation/blocs/blocs.dart';
import 'features/memorization_assistant/presentation/pages/memo_card_details_page.dart';
import 'features/memorization_assistant/presentation/pages/memo_cards_page.dart';

/// The Widget that configures your application.
class T3Vault extends StatelessWidget {
final SettingsController settingsController;
final MemoCardRepository memoCardRepository;
final ProfileRepository profileRepository;

const T3Vault({
super.key,
required this.settingsController,
required this.memoCardRepository,
required this.profileRepository,
});

@override
Expand All @@ -56,15 +57,15 @@ class T3Vault extends StatelessWidget {
create: (BuildContext context) => FormosaBloc(),
),
BlocProvider<GreatWallBloc>(
create: (BuildContext context) => GreatWallBloc(),
create: (BuildContext context) => GreatWallBloc(profileRepository),
),
BlocProvider<MemoCardSetBloc>(
create: (BuildContext context) =>
MemoCardSetBloc(memoCardRepository: memoCardRepository),
MemoCardSetBloc(profileRepository: profileRepository),
),
BlocProvider<MemoCardRatingBloc>(
create: (BuildContext context) =>
MemoCardRatingBloc(memoCardRepository: memoCardRepository),
MemoCardRatingBloc(profileRepository: profileRepository),
),
],
child: Builder(
Expand Down Expand Up @@ -301,10 +302,15 @@ class T3Vault extends StatelessWidget {
path: ConfirmationPage.routeName,
pageBuilder: (BuildContext context,
GoRouterState state) {
return const MaterialPage(
final args =
state.extra as Map<String, dynamic>;
final eka = args['eka'] as Eka;
return MaterialPage(
restorationId: 'router.root.knowledge.'
'formosa_inputs.confirmation',
child: ConfirmationPage(),
child: ConfirmationPage(
eka: eka,
),
);
},
),
Expand All @@ -325,10 +331,15 @@ class T3Vault extends StatelessWidget {
path: ConfirmationPage.routeName,
pageBuilder: (BuildContext context,
GoRouterState state) {
return const MaterialPage(
final args =
state.extra as Map<String, dynamic>;
final eka = args['eka'] as Eka;
return MaterialPage(
restorationId: 'router.root.knowledge.'
'hashviz_inputs.confirmation',
child: ConfirmationPage(),
child: ConfirmationPage(
eka: eka,
),
);
},
),
Expand All @@ -340,9 +351,14 @@ class T3Vault extends StatelessWidget {
path: ConfirmationPage.routeName,
pageBuilder:
(BuildContext context, GoRouterState state) {
return const MaterialPage(
final args =
state.extra as Map<String, dynamic>;
final eka = args['eka'] as Eka;
return MaterialPage(
restorationId: 'router.root.confirmation',
child: ConfirmationPage(),
child: ConfirmationPage(
eka: eka,
),
);
},
),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

class PasswordPrompt extends StatelessWidget {
const PasswordPrompt({super.key});
class EkaInputPromtWidget extends StatelessWidget {
const EkaInputPromtWidget({super.key});

@override
Widget build(BuildContext context) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import 'package:flutter/material.dart';

class EkaNewDeriationQuestionPromtWidget extends StatelessWidget {
const EkaNewDeriationQuestionPromtWidget({super.key});

@override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text("Is this a new derivation?"),
content: const Text(""),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(false);
},
child: const Text("No. I already have an EKA."),
),
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: const Text("Yes. First time for these parameters."),
),
],
);
}
}
53 changes: 53 additions & 0 deletions lib/src/common/cryptography/usecases/eka_flow_handler.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import 'package:flutter/material.dart';
import 'package:t3_crypto_objects/crypto_objects.dart';
import 'package:t3_vault/src/common/cryptography/presentation/widgets/eka_input_promt_widget.dart';
import 'package:t3_vault/src/common/cryptography/presentation/widgets/eka_new_deriation_question_promt_widget.dart';
import 'package:t3_vault/src/common/cryptography/presentation/widgets/eka_promt_widget.dart';
import 'package:t3_vault/src/common/cryptography/presentation/widgets/input_key_error_promt_widget.dart';

class EkaFlowHandler {
static Future<Eka?> showEkaFlow(BuildContext context) async {
String? optionalEka;
// Ask if it's a new derivation
final bool? isANewDerivation = await showDialog<bool>(
context: context,
builder: (context) => const EkaNewDeriationQuestionPromtWidget(),
);

if (isANewDerivation == null || !isANewDerivation) { // Not a new derivation, prompt for existing EKA
if (!context.mounted) return null;
optionalEka = await showDialog<String>(
context: context,
builder: (context) => const EkaInputPromtWidget(),
);
} else { // It's a new derivation, generate and show EKA
Eka eka = Eka();

// Prompt for optional EKA
if (!context.mounted) return null;
optionalEka = await showDialog<String>(
context: context,
builder: (context) => EKAPromptWidget(eka: eka.key),
);

// Ask user to input EKA
if (!context.mounted) return null;
final String? enteredEka = await showDialog<String>(
context: context,
builder: (context) => const EkaInputPromtWidget(),
);

// Validate entered EKA
if (enteredEka != eka.key) {
optionalEka = null;
if (!context.mounted) return null;
await showDialog<void>(
context: context,
builder: (context) => const InputKeyErrorPromtWidget(),
);
}
}

return optionalEka != null ? Eka.fromKey(optionalEka) : null;
}
}
6 changes: 3 additions & 3 deletions lib/src/common/localization/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@
"@inputKeyErrorWidgetTitle": {
"description": "Decryption Error Widget: Title Dialog"
},
"secretWidgetTitle": "Enter secret:",
"secretWidgetTitle": "Enter EKA:",
"@secretWidgetTitle": {
"description": "Secret Widget: Title Dialog"
"description": "EKA Widget: Title Dialog"
},

"theme": "Select Theme",
Expand Down Expand Up @@ -299,7 +299,7 @@
"@inputKeyErrorDescription": {
"description": "Decryption Error Widget: Text description"
},
"secretHint": "Enter ephemeral key to decrypt memo data.",
"secretHint": "Enter ephemeral key (EKA).",
"@secretHint": {
"description": "Secret Widget: Hint secret"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:great_wall/great_wall.dart';
import 'package:t3_crypto_objects/crypto_objects.dart';
import 'package:t3_vault/src/features/greatwall/domain/usecases/tree_input_validator.dart';
import 'package:t3_vault/src/features/memorization_assistant/domain/entities/intermediate_derivation_state_entity.dart';
import 'package:t3_vault/src/features/memorization_assistant/domain/repositories/profile_json_repository.dart';

import 'bloc.dart';

class GreatWallBloc extends Bloc<GreatWallEvent, GreatWallState> {
GreatWall? _greatWall;
int _currentLevel = 1;
final ProfileRepository profileRepository;

GreatWallBloc() : super(GreatWallInitial()) {
GreatWallBloc(this.profileRepository) : super(GreatWallInitial()) {
on<GreatWallSymmetricToggled>(_onGreatWallSymmetricToggled);
on<GreatWallPasswordVisibilityToggled>(_onPasswordVisibilityToggled);
on<GreatWallArityChanged>(_onGreatWallArityChanged);
Expand All @@ -23,6 +27,8 @@ class GreatWallBloc extends Bloc<GreatWallEvent, GreatWallState> {
on<GreatWallKAVisibilityToggled>(_onKAVisibilityToggled);
on<GreatWallPracticeLevel>(_onGreatWallPracticeLevel);
on<GreatWallPracticeStepMade>(_onGreatWallPracticeStepMade);
on<GreatWallOngoingDerivationLoadRequested>(_onGreatWallOngoingDerivationLoadRequested);
on<GreatWallOngoingDerivationAdded>(_onGreatWallOngoingDerivationAdded);
}

void _onDerivationStepMade(
Expand Down Expand Up @@ -74,12 +80,20 @@ class GreatWallBloc extends Bloc<GreatWallEvent, GreatWallState> {
GreatWallDerivationStarted event, Emitter<GreatWallState> emit) async {
emit(GreatWallDeriveInProgress());

await Future<void>.delayed(
const Duration(seconds: 1),
() {
_greatWall!.startDerivation();
},
);
_greatWall!.intermediateStatesStream.listen((List<Sa1i> sa1iList) async {
debugPrint("Intermediate states length: ${sa1iList.length}");
var intermediateStateEntities = sa1iList
.map((sa1i) => IntermediateDerivationStateEntity(
encryptedValue:
sa1i.value.toString(), // TODO: pending to encrypt
currentIteration: sa1i.currentIteration,
totalIterations: sa1i.totalIterations,
))
.toList();
await profileRepository.addIntermediateStates(intermediateStateEntities);
});

await _greatWall!.startDerivation();

emit(
GreatWallDeriveStepSuccess(
Expand Down Expand Up @@ -167,7 +181,9 @@ class GreatWallBloc extends Bloc<GreatWallEvent, GreatWallState> {
timeLockPuzzleParam: event.timeLockPuzzleParam,
tacitKnowledge: event.tacitKnowledge,
);
_greatWall!.sa0 = Sa0(Formosa.fromMnemonic(event.sa0Mnemonic, formosaTheme: FormosaTheme.global));
_greatWall!.initializeDerivation(
Sa0(Formosa.fromMnemonic(event.sa0Mnemonic, formosaTheme: FormosaTheme.global)),
[]);

emit(
GreatWallInitialSuccess(
Expand Down Expand Up @@ -195,7 +211,7 @@ class GreatWallBloc extends Bloc<GreatWallEvent, GreatWallState> {
}

void _onGreatWallReset(GreatWallReset event, Emitter<GreatWallState> emit) {
_greatWall!.initialDerivation();
_greatWall!.resetDerivation();

emit(GreatWallInitial());
}
Expand All @@ -220,4 +236,20 @@ class GreatWallBloc extends Bloc<GreatWallEvent, GreatWallState> {
),
);
}

Future<void> _onGreatWallOngoingDerivationLoadRequested(
GreatWallOngoingDerivationLoadRequested event,
Emitter<GreatWallState> emit,
) async {
await profileRepository.readProfile();
return emit(GreatWallOngoingDerivationLoaded(ongoingDerivationEntity: profileRepository.ongoingDerivation));
}

Future<void> _onGreatWallOngoingDerivationAdded(
GreatWallOngoingDerivationAdded event,
Emitter<GreatWallState> emit,
) async {
await profileRepository.setOngoingDerivation(event.ongoingDerivationEntity);
return emit(GreatWallOngoingDerivationAddSuccess(ongoingDerivationEntity: profileRepository.ongoingDerivation!));
}
}
Loading