app state fixed
This commit is contained in:
@@ -435,7 +435,7 @@ class ProfileSettingsScreen extends ConsumerWidget {
|
||||
style: const ButtonStyle(
|
||||
padding: WidgetStatePropertyAll(EdgeInsets.all(0)),
|
||||
),
|
||||
onPressed: () {},
|
||||
onPressed: () => _logout(context, ref),
|
||||
child: Row(
|
||||
spacing: 4,
|
||||
children: [
|
||||
|
||||
@@ -9,36 +9,31 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:profile/src/presentation/state/profile_view_model.dart';
|
||||
import 'package:profile/src/presentation/state/profile_view_state.dart';
|
||||
|
||||
class ProfileScreen extends ConsumerWidget {
|
||||
class ProfileScreen extends ConsumerStatefulWidget {
|
||||
final NavigationContract navigationContract;
|
||||
|
||||
const ProfileScreen({super.key, required this.navigationContract});
|
||||
|
||||
List<num> _expensesByDay(List<WalletTransactionEntity> transactions) {
|
||||
final result = List<num>.filled(7, 0);
|
||||
for (final tx in transactions) {
|
||||
final date = DateTime.tryParse(tx.createdDate);
|
||||
if (date == null) continue;
|
||||
final amount = double.tryParse(tx.amount) ?? 0;
|
||||
result[date.weekday - 1] += amount.abs();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@override
|
||||
ConsumerState<ProfileScreen> createState() => _ProfileScreenState();
|
||||
}
|
||||
|
||||
class _ProfileScreenState extends ConsumerState<ProfileScreen> {
|
||||
NavigationContract get navigationContract => widget.navigationContract;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
Widget build(BuildContext context) {
|
||||
final theme = ref.watch(themePortProvider);
|
||||
final viewState = ref.watch(profileViewModelProvider);
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: theme.getColorFor(ThemeCode.backgroundSecondary),
|
||||
body: _buildBody(context, ref, theme, viewState),
|
||||
body: _buildBody(context, theme, viewState),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
ThemePort theme,
|
||||
ProfileViewState viewState,
|
||||
) {
|
||||
@@ -47,12 +42,14 @@ class ProfileScreen extends ConsumerWidget {
|
||||
}
|
||||
|
||||
if (viewState.errorMessage.isNotEmpty) {
|
||||
return _buildError(context, ref, theme, viewState.errorMessage);
|
||||
return _buildError(context, theme, viewState.errorMessage);
|
||||
}
|
||||
|
||||
final balance = viewState.walletBalance;
|
||||
final balance = ref.watch(parentWalletBalanceProvider);
|
||||
final accountTotalBalance =
|
||||
ref.watch(accountTotalBalanceProvider).value ?? balance?.totalBalance ?? 0;
|
||||
|
||||
final content = <Widget>[
|
||||
final header = <Widget>[
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
@@ -78,16 +75,13 @@ class ProfileScreen extends ConsumerWidget {
|
||||
),
|
||||
if (balance != null)
|
||||
WalletBalanceBlock(
|
||||
value: balance.availableBalance,
|
||||
savings: balance.allocatedBalance,
|
||||
availableBalance: balance.availableBalance,
|
||||
allocatedBalance: balance.allocatedBalance,
|
||||
totalBalance: balance.totalBalance,
|
||||
),
|
||||
LineGraph(
|
||||
lines: [_expensesByDay(viewState.transactions)],
|
||||
lineLabels: [context.translate(I18n.profileMyAccount)],
|
||||
),
|
||||
if (balance != null)
|
||||
DepositBlock(
|
||||
max: 150 - balance.totalBalance,
|
||||
max: 150 - accountTotalBalance,
|
||||
onDeposit: (amount) async {
|
||||
final result = await showPayinBottomSheet(
|
||||
context,
|
||||
@@ -100,8 +94,10 @@ class ProfileScreen extends ConsumerWidget {
|
||||
message: context.translate(I18n.payinSuccess),
|
||||
type: MessageType.success,
|
||||
);
|
||||
ref.read(profileViewModelProvider.notifier).load();
|
||||
ref.read(parentWalletBalanceProvider.notifier).applyOptimisticPayin(amount);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
),
|
||||
Container(
|
||||
@@ -133,9 +129,15 @@ class ProfileScreen extends ConsumerWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
_buildTransactions(context, theme, viewState),
|
||||
];
|
||||
|
||||
final transactions = viewState.transactions;
|
||||
final hasTransactions = transactions.isNotEmpty;
|
||||
|
||||
final itemCount = header.length
|
||||
+ 1 // transactions title or empty message
|
||||
+ (hasTransactions ? transactions.length : 0);
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
DecoratedBox(
|
||||
@@ -158,13 +160,43 @@ class ProfileScreen extends ConsumerWidget {
|
||||
ref.read(profileViewModelProvider.notifier).load(),
|
||||
child: ListView.separated(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return content[index];
|
||||
itemCount: itemCount,
|
||||
separatorBuilder: (_, __) =>
|
||||
const Divider(color: Colors.transparent, height: 20),
|
||||
itemBuilder: (context, index) {
|
||||
// Header items
|
||||
if (index < header.length) {
|
||||
return header[index];
|
||||
}
|
||||
|
||||
final offset = index - header.length;
|
||||
|
||||
// Transactions title or empty message
|
||||
if (offset == 0) {
|
||||
if (!hasTransactions) {
|
||||
return Center(
|
||||
child: Text(
|
||||
context.translate(I18n.profileNoRecentTransactions),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: theme.getColorFor(ThemeCode.textPrimary),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return Text(
|
||||
context.translate(I18n.profileRecentTransactions),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 18,
|
||||
color: theme.getColorFor(ThemeCode.textPrimary),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final txIndex = offset - 1;
|
||||
return TransactionTile(transaction: transactions[txIndex]);
|
||||
},
|
||||
separatorBuilder: (BuildContext context, int index) {
|
||||
return Divider(color: Colors.transparent, height: 20);
|
||||
},
|
||||
itemCount: content.length,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -175,55 +207,11 @@ class ProfileScreen extends ConsumerWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTransactions(
|
||||
BuildContext context,
|
||||
ThemePort theme,
|
||||
ProfileViewState viewState,
|
||||
) {
|
||||
final transactions = viewState.transactions;
|
||||
|
||||
if (transactions.isEmpty) {
|
||||
return Center(
|
||||
child: Text(
|
||||
context.translate(I18n.profileNoRecentTransactions),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: theme.getColorFor(ThemeCode.textPrimary),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
context.translate(I18n.profileRecentTransactions),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 18,
|
||||
color: theme.getColorFor(ThemeCode.textPrimary),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
...transactions.map(
|
||||
(transaction) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
child: TransactionTile(transaction: transaction),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildError(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
ThemePort theme,
|
||||
String message,
|
||||
) {
|
||||
final viewModel = ref.read(profileViewModelProvider.notifier);
|
||||
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
@@ -246,7 +234,8 @@ class ProfileScreen extends ConsumerWidget {
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextButton(
|
||||
onPressed: () => viewModel.retry(),
|
||||
onPressed: () =>
|
||||
ref.read(profileViewModelProvider.notifier).retry(),
|
||||
child: Text(context.translate(I18n.retry)),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:sf_shared/sf_shared.dart';
|
||||
import 'package:activity/activity.dart';
|
||||
import 'profile_view_state.dart';
|
||||
|
||||
final profileViewModelProvider =
|
||||
@@ -11,18 +8,9 @@ final profileViewModelProvider =
|
||||
);
|
||||
|
||||
class ProfileViewModel extends Notifier<ProfileViewState> {
|
||||
late final GetWalletBalanceUseCase _getBalanceUseCase;
|
||||
late final GetWalletTransactionsUseCase _getTransactionsUseCase;
|
||||
late final GetPaymentProfileUseCase _getPaymentProfileUseCase;
|
||||
late final GetUserInfoUseCase _getUserInfoUseCase;
|
||||
|
||||
@override
|
||||
ProfileViewState build() {
|
||||
_getBalanceUseCase = ref.read(getWalletBalanceUseCaseProvider);
|
||||
_getTransactionsUseCase = ref.read(getWalletTransactionsUseCaseProvider);
|
||||
_getPaymentProfileUseCase = ref.read(getPaymentProfileUseCaseProvider);
|
||||
_getUserInfoUseCase = ref.read(getUserInfoUseCaseProvider);
|
||||
|
||||
ref.watch(walletRefreshProvider);
|
||||
Future.microtask(() => load());
|
||||
return const ProfileViewState(isLoading: true);
|
||||
}
|
||||
@@ -31,7 +19,7 @@ class ProfileViewModel extends Notifier<ProfileViewState> {
|
||||
state = state.copyWith(isLoading: true, errorMessage: '');
|
||||
|
||||
try {
|
||||
final user = await _getUserInfoUseCase.getUserInfo();
|
||||
final user = await ref.read(getUserInfoUseCaseProvider).getUserInfo();
|
||||
if (!ref.mounted) return;
|
||||
|
||||
final rawName = user.firstName;
|
||||
@@ -39,7 +27,7 @@ class ProfileViewModel extends Notifier<ProfileViewState> {
|
||||
? ''
|
||||
: rawName[0].toUpperCase() + rawName.substring(1).toLowerCase();
|
||||
|
||||
final paymentProfile = await _getPaymentProfileUseCase.getPaymentProfile(
|
||||
final paymentProfile = await ref.read(getPaymentProfileUseCaseProvider).getPaymentProfile(
|
||||
userId: user.id,
|
||||
);
|
||||
if (!ref.mounted) return;
|
||||
@@ -50,18 +38,21 @@ class ProfileViewModel extends Notifier<ProfileViewState> {
|
||||
return;
|
||||
}
|
||||
|
||||
final results = await Future.wait([
|
||||
_getBalanceUseCase(walletId: walletId),
|
||||
_loadTransactions(walletId),
|
||||
]);
|
||||
final query = TransactionsQuery(
|
||||
walletId: walletId,
|
||||
dateFilter: DateFilter.lastWeek,
|
||||
);
|
||||
|
||||
final transactions = await ref
|
||||
.read(walletTransactionsProvider(query).future);
|
||||
|
||||
if (!ref.mounted) return;
|
||||
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
userName: name,
|
||||
walletBalance: results[0] as WalletBalanceEntity,
|
||||
transactions: results[1] as List<WalletTransactionEntity>,
|
||||
walletId: walletId,
|
||||
transactions: transactions,
|
||||
);
|
||||
} catch (e) {
|
||||
if (!ref.mounted) return;
|
||||
@@ -69,24 +60,6 @@ class ProfileViewModel extends Notifier<ProfileViewState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<WalletTransactionEntity>> _loadTransactions(
|
||||
String walletId,
|
||||
) async {
|
||||
final filtersJson = jsonEncode({
|
||||
'createdDate': {
|
||||
'gte': DateFilter.lastWeek.startDate.toIso8601String(),
|
||||
},
|
||||
});
|
||||
final filtersBase64 = base64Encode(utf8.encode(filtersJson));
|
||||
|
||||
final response = await _getTransactionsUseCase(
|
||||
walletId: walletId,
|
||||
queryParameters: {'filters': filtersBase64},
|
||||
);
|
||||
|
||||
return response.items;
|
||||
}
|
||||
|
||||
Future<void> retry() async {
|
||||
await load();
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ abstract class ProfileViewState with _$ProfileViewState {
|
||||
const factory ProfileViewState({
|
||||
@Default(false) bool isLoading,
|
||||
@Default('') String userName,
|
||||
WalletBalanceEntity? walletBalance,
|
||||
@Default('') String walletId,
|
||||
@Default([]) List<WalletTransactionEntity> transactions,
|
||||
@Default('') String errorMessage,
|
||||
}) = _ProfileViewState;
|
||||
|
||||
@@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$ProfileViewState {
|
||||
|
||||
bool get isLoading; String get userName; WalletBalanceEntity? get walletBalance; List<WalletTransactionEntity> get transactions; String get errorMessage;
|
||||
bool get isLoading; String get userName; String get walletId; List<WalletTransactionEntity> get transactions; String get errorMessage;
|
||||
/// Create a copy of ProfileViewState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -25,16 +25,16 @@ $ProfileViewStateCopyWith<ProfileViewState> get copyWith => _$ProfileViewStateCo
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is ProfileViewState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.userName, userName) || other.userName == userName)&&(identical(other.walletBalance, walletBalance) || other.walletBalance == walletBalance)&&const DeepCollectionEquality().equals(other.transactions, transactions)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is ProfileViewState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.userName, userName) || other.userName == userName)&&(identical(other.walletId, walletId) || other.walletId == walletId)&&const DeepCollectionEquality().equals(other.transactions, transactions)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,isLoading,userName,walletBalance,const DeepCollectionEquality().hash(transactions),errorMessage);
|
||||
int get hashCode => Object.hash(runtimeType,isLoading,userName,walletId,const DeepCollectionEquality().hash(transactions),errorMessage);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProfileViewState(isLoading: $isLoading, userName: $userName, walletBalance: $walletBalance, transactions: $transactions, errorMessage: $errorMessage)';
|
||||
return 'ProfileViewState(isLoading: $isLoading, userName: $userName, walletId: $walletId, transactions: $transactions, errorMessage: $errorMessage)';
|
||||
}
|
||||
|
||||
|
||||
@@ -45,11 +45,11 @@ abstract mixin class $ProfileViewStateCopyWith<$Res> {
|
||||
factory $ProfileViewStateCopyWith(ProfileViewState value, $Res Function(ProfileViewState) _then) = _$ProfileViewStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
bool isLoading, String userName, WalletBalanceEntity? walletBalance, List<WalletTransactionEntity> transactions, String errorMessage
|
||||
bool isLoading, String userName, String walletId, List<WalletTransactionEntity> transactions, String errorMessage
|
||||
});
|
||||
|
||||
|
||||
$WalletBalanceEntityCopyWith<$Res>? get walletBalance;
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
@@ -62,29 +62,17 @@ class _$ProfileViewStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of ProfileViewState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? isLoading = null,Object? userName = null,Object? walletBalance = freezed,Object? transactions = null,Object? errorMessage = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? isLoading = null,Object? userName = null,Object? walletId = null,Object? transactions = null,Object? errorMessage = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
|
||||
as bool,userName: null == userName ? _self.userName : userName // ignore: cast_nullable_to_non_nullable
|
||||
as String,walletBalance: freezed == walletBalance ? _self.walletBalance : walletBalance // ignore: cast_nullable_to_non_nullable
|
||||
as WalletBalanceEntity?,transactions: null == transactions ? _self.transactions : transactions // ignore: cast_nullable_to_non_nullable
|
||||
as String,walletId: null == walletId ? _self.walletId : walletId // ignore: cast_nullable_to_non_nullable
|
||||
as String,transactions: null == transactions ? _self.transactions : transactions // ignore: cast_nullable_to_non_nullable
|
||||
as List<WalletTransactionEntity>,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
/// Create a copy of ProfileViewState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$WalletBalanceEntityCopyWith<$Res>? get walletBalance {
|
||||
if (_self.walletBalance == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $WalletBalanceEntityCopyWith<$Res>(_self.walletBalance!, (value) {
|
||||
return _then(_self.copyWith(walletBalance: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -166,10 +154,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isLoading, String userName, WalletBalanceEntity? walletBalance, List<WalletTransactionEntity> transactions, String errorMessage)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isLoading, String userName, String walletId, List<WalletTransactionEntity> transactions, String errorMessage)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ProfileViewState() when $default != null:
|
||||
return $default(_that.isLoading,_that.userName,_that.walletBalance,_that.transactions,_that.errorMessage);case _:
|
||||
return $default(_that.isLoading,_that.userName,_that.walletId,_that.transactions,_that.errorMessage);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -187,10 +175,10 @@ return $default(_that.isLoading,_that.userName,_that.walletBalance,_that.transac
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isLoading, String userName, WalletBalanceEntity? walletBalance, List<WalletTransactionEntity> transactions, String errorMessage) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isLoading, String userName, String walletId, List<WalletTransactionEntity> transactions, String errorMessage) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ProfileViewState():
|
||||
return $default(_that.isLoading,_that.userName,_that.walletBalance,_that.transactions,_that.errorMessage);case _:
|
||||
return $default(_that.isLoading,_that.userName,_that.walletId,_that.transactions,_that.errorMessage);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
@@ -207,10 +195,10 @@ return $default(_that.isLoading,_that.userName,_that.walletBalance,_that.transac
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isLoading, String userName, WalletBalanceEntity? walletBalance, List<WalletTransactionEntity> transactions, String errorMessage)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isLoading, String userName, String walletId, List<WalletTransactionEntity> transactions, String errorMessage)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ProfileViewState() when $default != null:
|
||||
return $default(_that.isLoading,_that.userName,_that.walletBalance,_that.transactions,_that.errorMessage);case _:
|
||||
return $default(_that.isLoading,_that.userName,_that.walletId,_that.transactions,_that.errorMessage);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -222,12 +210,12 @@ return $default(_that.isLoading,_that.userName,_that.walletBalance,_that.transac
|
||||
|
||||
|
||||
class _ProfileViewState implements ProfileViewState {
|
||||
const _ProfileViewState({this.isLoading = false, this.userName = '', this.walletBalance, final List<WalletTransactionEntity> transactions = const [], this.errorMessage = ''}): _transactions = transactions;
|
||||
const _ProfileViewState({this.isLoading = false, this.userName = '', this.walletId = '', final List<WalletTransactionEntity> transactions = const [], this.errorMessage = ''}): _transactions = transactions;
|
||||
|
||||
|
||||
@override@JsonKey() final bool isLoading;
|
||||
@override@JsonKey() final String userName;
|
||||
@override final WalletBalanceEntity? walletBalance;
|
||||
@override@JsonKey() final String walletId;
|
||||
final List<WalletTransactionEntity> _transactions;
|
||||
@override@JsonKey() List<WalletTransactionEntity> get transactions {
|
||||
if (_transactions is EqualUnmodifiableListView) return _transactions;
|
||||
@@ -247,16 +235,16 @@ _$ProfileViewStateCopyWith<_ProfileViewState> get copyWith => __$ProfileViewStat
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ProfileViewState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.userName, userName) || other.userName == userName)&&(identical(other.walletBalance, walletBalance) || other.walletBalance == walletBalance)&&const DeepCollectionEquality().equals(other._transactions, _transactions)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ProfileViewState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.userName, userName) || other.userName == userName)&&(identical(other.walletId, walletId) || other.walletId == walletId)&&const DeepCollectionEquality().equals(other._transactions, _transactions)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,isLoading,userName,walletBalance,const DeepCollectionEquality().hash(_transactions),errorMessage);
|
||||
int get hashCode => Object.hash(runtimeType,isLoading,userName,walletId,const DeepCollectionEquality().hash(_transactions),errorMessage);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProfileViewState(isLoading: $isLoading, userName: $userName, walletBalance: $walletBalance, transactions: $transactions, errorMessage: $errorMessage)';
|
||||
return 'ProfileViewState(isLoading: $isLoading, userName: $userName, walletId: $walletId, transactions: $transactions, errorMessage: $errorMessage)';
|
||||
}
|
||||
|
||||
|
||||
@@ -267,11 +255,11 @@ abstract mixin class _$ProfileViewStateCopyWith<$Res> implements $ProfileViewSta
|
||||
factory _$ProfileViewStateCopyWith(_ProfileViewState value, $Res Function(_ProfileViewState) _then) = __$ProfileViewStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
bool isLoading, String userName, WalletBalanceEntity? walletBalance, List<WalletTransactionEntity> transactions, String errorMessage
|
||||
bool isLoading, String userName, String walletId, List<WalletTransactionEntity> transactions, String errorMessage
|
||||
});
|
||||
|
||||
|
||||
@override $WalletBalanceEntityCopyWith<$Res>? get walletBalance;
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
@@ -284,30 +272,18 @@ class __$ProfileViewStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of ProfileViewState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? isLoading = null,Object? userName = null,Object? walletBalance = freezed,Object? transactions = null,Object? errorMessage = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? isLoading = null,Object? userName = null,Object? walletId = null,Object? transactions = null,Object? errorMessage = null,}) {
|
||||
return _then(_ProfileViewState(
|
||||
isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
|
||||
as bool,userName: null == userName ? _self.userName : userName // ignore: cast_nullable_to_non_nullable
|
||||
as String,walletBalance: freezed == walletBalance ? _self.walletBalance : walletBalance // ignore: cast_nullable_to_non_nullable
|
||||
as WalletBalanceEntity?,transactions: null == transactions ? _self._transactions : transactions // ignore: cast_nullable_to_non_nullable
|
||||
as String,walletId: null == walletId ? _self.walletId : walletId // ignore: cast_nullable_to_non_nullable
|
||||
as String,transactions: null == transactions ? _self._transactions : transactions // ignore: cast_nullable_to_non_nullable
|
||||
as List<WalletTransactionEntity>,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of ProfileViewState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$WalletBalanceEntityCopyWith<$Res>? get walletBalance {
|
||||
if (_self.walletBalance == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $WalletBalanceEntityCopyWith<$Res>(_self.walletBalance!, (value) {
|
||||
return _then(_self.copyWith(walletBalance: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// dart format on
|
||||
|
||||
@@ -1,27 +1,33 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:sca_treezor/sca_treezor.dart'
|
||||
show TreezorWalletConnectionService;
|
||||
import 'package:sf_infrastructure/sf_infrastructure.dart';
|
||||
// import 'package:sf_shared/sf_shared.dart' show treezorRepositoryProvider;
|
||||
import 'package:sf_shared/sf_shared.dart' show treezorRepositoryProvider;
|
||||
|
||||
final logoutProvider = FutureProvider.autoDispose<void>((ref) async {
|
||||
final repository = getIt<QuestiaRepository>();
|
||||
// final treezorRepository = ref.read(treezorRepositoryProvider);
|
||||
|
||||
// // Delete SCA wallet on the server before clearing local data
|
||||
// try {
|
||||
// final cachedWallets = await treezorRepository.scaWallets();
|
||||
// final scaWalletId = cachedWallets.item.id;
|
||||
// if (scaWalletId.isNotEmpty) {
|
||||
// await treezorRepository.deleteScaWallet(scaWalletId: scaWalletId);
|
||||
// }
|
||||
// } catch (_) {
|
||||
// // Don't block logout if SCA wallet deletion fails
|
||||
// }
|
||||
// 1. Logout from Treezor SDK (disconnect active wallet session)
|
||||
try {
|
||||
final connectionService = getIt<TreezorWalletConnectionService>();
|
||||
await connectionService.logout();
|
||||
} catch (_) {}
|
||||
|
||||
// 2. Clear treezor repository in-memory cache
|
||||
try {
|
||||
final treezorRepository = ref.read(treezorRepositoryProvider);
|
||||
await treezorRepository.resetScaWallets();
|
||||
} catch (_) {}
|
||||
|
||||
// 3. Backend logout
|
||||
try {
|
||||
await repository.post<void>('/auth/logout');
|
||||
} on DioException catch (error) {
|
||||
throw Exception(error.message ?? 'Error in logout');
|
||||
}
|
||||
|
||||
// 4. Clear local data (stops heartbeat via onBeforeSessionCleared,
|
||||
// then clears cookies + SharedPreferences)
|
||||
await clearSessionData();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user