Skip to content
Merged
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
12 changes: 10 additions & 2 deletions lib/app_config/package_information.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,22 @@ class PackageInformation {
String? packageVersion;
String? packageName;
String? commitHash;
String? buildDate;

static const String _kCommitHash =
String.fromEnvironment('COMMIT_HASH', defaultValue: 'unknown');
static const String _kCommitHash = String.fromEnvironment(
'COMMIT_HASH',
defaultValue: 'unknown',
);
static const String _kBuildDate = String.fromEnvironment(
'BUILD_DATE',
defaultValue: 'unknown',
);

Future<void> init() async {
final PackageInfo packageInfo = await PackageInfo.fromPlatform();
packageVersion = packageInfo.version;
packageName = packageInfo.packageName;
commitHash = _kCommitHash;
buildDate = _kBuildDate;
}
}
12 changes: 8 additions & 4 deletions lib/bloc/auth_bloc/auth_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ class AuthBloc extends Bloc<AuthBlocEvent, AuthBlocState> with TrezorAuthMixin {
// Explicitly disconnect SSE on sign-out
_log.info('User signed out, disconnecting SSE...');
_kdfSdk.streaming.disconnect();

await _authChangesSubscription?.cancel();
emit(AuthBlocState.initial());
}
Expand Down Expand Up @@ -145,11 +145,11 @@ class AuthBloc extends Bloc<AuthBlocEvent, AuthBlocState> with TrezorAuthMixin {

_log.info('Successfully logged in to wallet');
emit(AuthBlocState.loggedIn(currentUser));

// Explicitly connect SSE after successful login
_log.info('User authenticated, connecting SSE for streaming...');
_kdfSdk.streaming.connectIfNeeded();

_listenToAuthStateChanges();
} catch (e, s) {
if (e is AuthException) {
Expand Down Expand Up @@ -222,6 +222,8 @@ class AuthBloc extends Bloc<AuthBlocEvent, AuthBlocState> with TrezorAuthMixin {
'Registered a new wallet, setting up metadata and logging in...',
);
await _kdfSdk.setWalletType(event.wallet.config.type);
await _kdfSdk.setWalletProvenance(WalletProvenance.generated);
await _kdfSdk.setWalletCreatedAt(DateTime.now());
await _kdfSdk.confirmSeedBackup(hasBackup: false);
// Filter out geo-blocked assets from default coins before adding to wallet
final allowedDefaultCoins = _filterBlockedAssets(enabledByDefaultCoins);
Expand Down Expand Up @@ -314,6 +316,8 @@ class AuthBloc extends Bloc<AuthBlocEvent, AuthBlocState> with TrezorAuthMixin {
'Setting up wallet metadata and logging in...',
);
await _kdfSdk.setWalletType(workingWallet.config.type);
await _kdfSdk.setWalletProvenance(WalletProvenance.imported);
await _kdfSdk.setWalletCreatedAt(DateTime.now());
await _kdfSdk.confirmSeedBackup(
hasBackup: workingWallet.config.hasBackup,
);
Expand Down Expand Up @@ -464,7 +468,7 @@ class AuthBloc extends Bloc<AuthBlocEvent, AuthBlocState> with TrezorAuthMixin {
? AuthorizeMode.logIn
: AuthorizeMode.noLogin;
add(AuthModeChanged(mode: event, currentUser: user));

// Tie SSE connection lifecycle to authentication state
if (user != null) {
// User authenticated - connect SSE for balance/tx history streaming
Expand Down
36 changes: 28 additions & 8 deletions lib/bloc/auth_bloc/trezor_auth_mixin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,15 @@ mixin TrezorAuthMixin on Bloc<AuthBlocEvent, AuthBlocState> {
switch (authState.status) {
case AuthenticationStatus.initializing:
return AuthBlocState.trezorInitializing(
message: authState.message ?? LocaleKeys.trezorInitializingMessage.tr(),
message:
authState.message ?? LocaleKeys.trezorInitializingMessage.tr(),
taskId: authState.taskId,
);
case AuthenticationStatus.waitingForDevice:
return AuthBlocState.trezorInitializing(
message:
authState.message ?? LocaleKeys.trezorWaitingForDeviceMessage.tr(),
authState.message ??
LocaleKeys.trezorWaitingForDeviceMessage.tr(),
taskId: authState.taskId,
);
case AuthenticationStatus.waitingForDeviceConfirmation:
Expand All @@ -83,24 +85,25 @@ mixin TrezorAuthMixin on Bloc<AuthBlocEvent, AuthBlocState> {
);
case AuthenticationStatus.pinRequired:
return AuthBlocState.trezorPinRequired(
message: authState.message ?? LocaleKeys.trezorPinRequiredMessage.tr(),
message:
authState.message ?? LocaleKeys.trezorPinRequiredMessage.tr(),
taskId: authState.taskId!,
);
case AuthenticationStatus.passphraseRequired:
return AuthBlocState.trezorPassphraseRequired(
message: authState.message ?? LocaleKeys.trezorPassphraseRequiredMessage.tr(),
message:
authState.message ??
LocaleKeys.trezorPassphraseRequiredMessage.tr(),
taskId: authState.taskId!,
);
case AuthenticationStatus.authenticating:
return AuthBlocState.loading();
case AuthenticationStatus.completed:
return _setupTrezorWallet(authState);
case AuthenticationStatus.error:
final mappedError = _mapTrezorErrorMessage(authState.error);
return AuthBlocState.error(
AuthException(
authState.error ?? LocaleKeys.trezorAuthFailedMessage.tr(),
type: AuthExceptionType.generalAuthError,
),
AuthException(mappedError, type: AuthExceptionType.generalAuthError),
);
case AuthenticationStatus.cancelled:
return AuthBlocState.error(
Expand All @@ -112,6 +115,23 @@ mixin TrezorAuthMixin on Bloc<AuthBlocEvent, AuthBlocState> {
}
}

String _mapTrezorErrorMessage(String? errorMessage) {
if (errorMessage == null || errorMessage.trim().isEmpty) {
return LocaleKeys.trezorAuthFailedMessage.tr();
}

final normalized = errorMessage.toLowerCase();
if (normalized.contains('cancel')) {
return LocaleKeys.trezorAuthCancelledMessage.tr();
}
if (normalized.contains('invalid pin') ||
(normalized.contains('pin') && normalized.contains('invalid'))) {
return LocaleKeys.trezorErrorInvalidPin.tr();
}

return errorMessage;
}

/// Sets up the Trezor wallet after successful authentication.
/// This includes setting the wallet type, confirming seed backup,
/// and adding the default activated coins.
Expand Down
35 changes: 27 additions & 8 deletions lib/bloc/settings/settings_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import 'package:web_dex/shared/utils/utils.dart';

class SettingsBloc extends Bloc<SettingsEvent, SettingsState> {
SettingsBloc(StoredSettings stored, SettingsRepository repository)
: _settingsRepo = repository,
super(SettingsState.fromStored(stored)) {
: _settingsRepo = repository,
super(SettingsState.fromStored(stored)) {
_storedSettings = stored;
theme.mode = state.themeMode;

// Initialize diagnostic logging with the stored setting
KdfLoggingConfig.verboseLogging = stored.diagnosticLoggingEnabled;
KdfApiClient.enableDebugLogging = stored.diagnosticLoggingEnabled;
Expand All @@ -27,6 +27,7 @@ class SettingsBloc extends Bloc<SettingsEvent, SettingsState> {
on<WeakPasswordsAllowedChanged>(_onWeakPasswordsAllowedChanged);
on<HideZeroBalanceAssetsChanged>(_onHideZeroBalanceAssetsChanged);
on<DiagnosticLoggingChanged>(_onDiagnosticLoggingChanged);
on<HideBalancesChanged>(_onHideBalancesChanged);
}

late StoredSettings _storedSettings;
Expand All @@ -51,7 +52,9 @@ class SettingsBloc extends Bloc<SettingsEvent, SettingsState> {
MarketMakerBotSettingsChanged event,
Emitter<SettingsState> emitter,
) async {
_storedSettings = _storedSettings.copyWith(marketMakerBotSettings: event.settings);
_storedSettings = _storedSettings.copyWith(
marketMakerBotSettings: event.settings,
);
await _settingsRepo.updateSettings(_storedSettings);
emitter(state.copyWith(marketMakerBotSettings: event.settings));
}
Expand All @@ -60,7 +63,9 @@ class SettingsBloc extends Bloc<SettingsEvent, SettingsState> {
TestCoinsEnabledChanged event,
Emitter<SettingsState> emitter,
) async {
_storedSettings = _storedSettings.copyWith(testCoinsEnabled: event.testCoinsEnabled);
_storedSettings = _storedSettings.copyWith(
testCoinsEnabled: event.testCoinsEnabled,
);
await _settingsRepo.updateSettings(_storedSettings);
emitter(state.copyWith(testCoinsEnabled: event.testCoinsEnabled));
}
Expand All @@ -70,7 +75,8 @@ class SettingsBloc extends Bloc<SettingsEvent, SettingsState> {
Emitter<SettingsState> emitter,
) async {
_storedSettings = _storedSettings.copyWith(
weakPasswordsAllowed: event.weakPasswordsAllowed);
weakPasswordsAllowed: event.weakPasswordsAllowed,
);
await _settingsRepo.updateSettings(_storedSettings);
emitter(state.copyWith(weakPasswordsAllowed: event.weakPasswordsAllowed));
}
Expand All @@ -94,11 +100,24 @@ class SettingsBloc extends Bloc<SettingsEvent, SettingsState> {
KdfLoggingConfig.verboseLogging = event.diagnosticLoggingEnabled;
KdfApiClient.enableDebugLogging = event.diagnosticLoggingEnabled;
KomodoDefiFramework.enableDebugLogging = event.diagnosticLoggingEnabled;

_storedSettings = _storedSettings.copyWith(
diagnosticLoggingEnabled: event.diagnosticLoggingEnabled,
);
await _settingsRepo.updateSettings(_storedSettings);
emitter(state.copyWith(diagnosticLoggingEnabled: event.diagnosticLoggingEnabled));
emitter(
state.copyWith(diagnosticLoggingEnabled: event.diagnosticLoggingEnabled),
);
}

Future<void> _onHideBalancesChanged(
HideBalancesChanged event,
Emitter<SettingsState> emitter,
) async {
_storedSettings = _storedSettings.copyWith(
hideBalances: event.hideBalances,
);
await _settingsRepo.updateSettings(_storedSettings);
emitter(state.copyWith(hideBalances: event.hideBalances));
}
}
8 changes: 8 additions & 0 deletions lib/bloc/settings/settings_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,11 @@ class DiagnosticLoggingChanged extends SettingsEvent {
@override
List<Object> get props => [diagnosticLoggingEnabled];
}

class HideBalancesChanged extends SettingsEvent {
const HideBalancesChanged({required this.hideBalances});
final bool hideBalances;

@override
List<Object> get props => [hideBalances];
}
20 changes: 13 additions & 7 deletions lib/bloc/settings/settings_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class SettingsState extends Equatable {
required this.weakPasswordsAllowed,
required this.hideZeroBalanceAssets,
required this.diagnosticLoggingEnabled,
required this.hideBalances,
});

factory SettingsState.fromStored(StoredSettings stored) {
Expand All @@ -21,6 +22,7 @@ class SettingsState extends Equatable {
weakPasswordsAllowed: stored.weakPasswordsAllowed,
hideZeroBalanceAssets: stored.hideZeroBalanceAssets,
diagnosticLoggingEnabled: stored.diagnosticLoggingEnabled,
hideBalances: stored.hideBalances,
);
}

Expand All @@ -30,16 +32,18 @@ class SettingsState extends Equatable {
final bool weakPasswordsAllowed;
final bool hideZeroBalanceAssets;
final bool diagnosticLoggingEnabled;
final bool hideBalances;

@override
List<Object?> get props => [
themeMode,
mmBotSettings,
testCoinsEnabled,
weakPasswordsAllowed,
hideZeroBalanceAssets,
diagnosticLoggingEnabled,
];
themeMode,
mmBotSettings,
testCoinsEnabled,
weakPasswordsAllowed,
hideZeroBalanceAssets,
diagnosticLoggingEnabled,
hideBalances,
];

SettingsState copyWith({
ThemeMode? mode,
Expand All @@ -48,6 +52,7 @@ class SettingsState extends Equatable {
bool? weakPasswordsAllowed,
bool? hideZeroBalanceAssets,
bool? diagnosticLoggingEnabled,
bool? hideBalances,
}) {
return SettingsState(
themeMode: mode ?? themeMode,
Expand All @@ -58,6 +63,7 @@ class SettingsState extends Equatable {
hideZeroBalanceAssets ?? this.hideZeroBalanceAssets,
diagnosticLoggingEnabled:
diagnosticLoggingEnabled ?? this.diagnosticLoggingEnabled,
hideBalances: hideBalances ?? this.hideBalances,
);
}
}
2 changes: 2 additions & 0 deletions lib/bloc/version_info/version_info_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class VersionInfoBloc extends Bloc<VersionInfoEvent, VersionInfoState> {
final commitHash = packageInformation.commitHash != null
? _tryParseCommitHash(packageInformation.commitHash!)
: null;
final buildDate = packageInformation.buildDate;

_logger.info(
'Basic app info retrieved - Version: $appVersion, '
Expand All @@ -51,6 +52,7 @@ class VersionInfoBloc extends Bloc<VersionInfoEvent, VersionInfoState> {
var currentInfo = VersionInfoLoaded(
appVersion: appVersion,
commitHash: commitHash,
buildDate: buildDate,
);
emit(currentInfo);

Expand Down
5 changes: 5 additions & 0 deletions lib/bloc/version_info/version_info_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,31 @@ class VersionInfoLoaded extends VersionInfoState {
const VersionInfoLoaded({
required this.appVersion,
required this.commitHash,
this.buildDate,
this.apiCommitHash,
this.currentCoinsCommit,
this.latestCoinsCommit,
});

final String? appVersion;
final String? commitHash;
final String? buildDate;
final String? apiCommitHash;
final String? currentCoinsCommit;
final String? latestCoinsCommit;

VersionInfoLoaded copyWith({
ValueGetter<String?>? appVersion,
ValueGetter<String?>? commitHash,
ValueGetter<String?>? buildDate,
ValueGetter<String?>? apiCommitHash,
ValueGetter<String?>? currentCoinsCommit,
ValueGetter<String?>? latestCoinsCommit,
}) {
return VersionInfoLoaded(
appVersion: appVersion?.call() ?? this.appVersion,
commitHash: commitHash?.call() ?? this.commitHash,
buildDate: buildDate?.call() ?? this.buildDate,
apiCommitHash: apiCommitHash?.call() ?? this.apiCommitHash,
currentCoinsCommit: currentCoinsCommit?.call() ?? this.currentCoinsCommit,
latestCoinsCommit: latestCoinsCommit?.call() ?? this.latestCoinsCommit,
Expand All @@ -53,6 +57,7 @@ class VersionInfoLoaded extends VersionInfoState {
List<Object?> get props => [
appVersion,
commitHash,
buildDate,
apiCommitHash,
currentCoinsCommit,
latestCoinsCommit,
Expand Down
21 changes: 21 additions & 0 deletions lib/model/kdf_auth_metadata_extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -156,4 +156,25 @@ extension KdfAuthMetadataExtension on KomodoDefiSdk {
Future<void> setWalletType(WalletType type) async {
await auth.setOrRemoveActiveUserKeyValue('type', type.name);
}

/// Sets the wallet provenance for the current user.
///
/// Stored values are used by wallet selection UIs to show quick metadata
/// tags (generated/imported).
Future<void> setWalletProvenance(WalletProvenance provenance) async {
await auth.setOrRemoveActiveUserKeyValue(
'wallet_provenance',
provenance.name,
);
}

/// Sets the wallet creation timestamp for the current user.
///
/// Stored as milliseconds since epoch.
Future<void> setWalletCreatedAt(DateTime createdAt) async {
await auth.setOrRemoveActiveUserKeyValue(
'wallet_created_at',
createdAt.millisecondsSinceEpoch,
);
}
}
Loading
Loading