Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PE-6709: navigate to drive explorer before wallet balance and io tokens fetch completion #1824

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
32 changes: 29 additions & 3 deletions lib/authentication/ardrive_auth.dart
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ class ArDriveAuthImpl implements ArDriveAuth {

currentUser = await _userRepository.getUser(password);

_updateBalance();

if (await _biometricAuthentication.isEnabled()) {
logger.i('Saving password in secure storage');

Expand Down Expand Up @@ -308,11 +310,33 @@ class ArDriveAuthImpl implements ArDriveAuth {

currentUser = await _userRepository.getUser(password);

_updateBalance();

_userStreamController.add(_currentUser);

return currentUser;
}

void _updateBalance() {
_userRepository.getIOTokens(currentUser.wallet).then((value) {
_currentUser = _currentUser!.copyWith(
ioTokens: value,
errorFetchingIOTokens: false,
);
_userStreamController.add(_currentUser);
}).catchError((e) {
_currentUser = _currentUser!.copyWith(
errorFetchingIOTokens: true,
);
_userStreamController.add(_currentUser);
return Future.value(null);
});
_userRepository.getBalance(currentUser.wallet).then((value) {
_currentUser = _currentUser!.copyWith(walletBalance: value);
_userStreamController.add(_currentUser);
});
}

Future<void> _saveUser(
String password,
ProfileType profileType,
Expand Down Expand Up @@ -364,11 +388,13 @@ class ArDriveAuthImpl implements ArDriveAuth {

@override
Future<void> refreshBalance() async {
final balance = await _userRepository.getBalance(currentUser.wallet);

currentUser = currentUser.copyWith(walletBalance: balance);
_currentUser = _currentUser!.copyWith(
errorFetchingIOTokens: false,
);

_userStreamController.add(_currentUser);

_updateBalance();
}
}

Expand Down
7 changes: 7 additions & 0 deletions lib/blocs/profile/profile_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ class ProfileCubit extends Cubit<ProfileState> {
_arDriveAuth = arDriveAuth,
super(ProfileCheckingAvailability()) {
promptToAuthenticate();

_arDriveAuth.onAuthStateChanged().listen((user) {
if (user != null) {
emit(ProfileLoggedIn(
user: user, useTurbo: _turboUploadService.useTurboUpload));
}
});
}

Future<bool> isCurrentProfileArConnect() async {
Expand Down
2 changes: 1 addition & 1 deletion lib/blocs/profile/profile_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class ProfileLoggedIn extends ProfileAvailable {
useTurbo;

@override
List<Object?> get props => [user];
List<Object?> get props => [user, useTurbo];
}

class ProfilePromptAdd extends ProfileUnavailable {}
Expand Down
93 changes: 64 additions & 29 deletions lib/components/profile_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import 'package:ardrive/services/config/config.dart';
import 'package:ardrive/turbo/services/payment_service.dart';
import 'package:ardrive/turbo/topup/components/turbo_balance_widget.dart';
import 'package:ardrive/turbo/utils/utils.dart';
import 'package:ardrive/user/balance/user_balance_bloc.dart';
import 'package:ardrive/user/download_wallet/download_wallet_modal.dart';
import 'package:ardrive/utils/app_localizations_wrapper.dart';
import 'package:ardrive/utils/open_url.dart';
Expand Down Expand Up @@ -477,36 +478,70 @@ class _ProfileCardState extends State<ProfileCard> {

final ioTokens = state.user.ioTokens;

return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'tIO Tokens',
style: typography.paragraphNormal(
fontWeight: ArFontWeight.semiBold,
color: colorTokens.textHigh,
),
),
if (ioTokens != null)
Text(
ioTokens,
style: typography.paragraphNormal(
color: colorTokens.textLow,
fontWeight: ArFontWeight.semiBold,
),
),
if (ioTokens == null)
Text(
'An error occurred while fetching IO tokens',
style: typography.paragraphNormal(
color: colorTokens.textLow,
fontWeight: ArFontWeight.semiBold,
return BlocProvider(
create: (context) => UserBalanceBloc(auth: context.read<ArDriveAuth>())
..add(GetUserBalance()),
child: BlocBuilder<UserBalanceBloc, UserBalanceState>(
builder: (context, state) {
if (state is UserBalanceLoaded) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'tIO Tokens',
style: typography.paragraphNormal(
fontWeight: ArFontWeight.semiBold,
color: colorTokens.textHigh,
),
),
if (state is UserBalanceLoadingIOTokens &&
!state.errorFetchingIOTokens)
const Padding(
padding: EdgeInsets.only(top: 8),
child: LinearProgressIndicator(),
),
if (ioTokens != null)
Text(
ioTokens,
style: typography.paragraphNormal(
color: colorTokens.textLow,
fontWeight: ArFontWeight.semiBold,
),
),
if (state.errorFetchingIOTokens) ...[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Error fetching tIO balance',
style: typography.paragraphNormal(
fontWeight: ArFontWeight.semiBold,
color: ArDriveTheme.of(context)
.themeData
.colors
.themeErrorDefault,
),
),
ArDriveIconButton(
icon: ArDriveIcons.refresh(),
onPressed: () {
context
.read<UserBalanceBloc>()
.add(RefreshUserBalance());
},
)
],
),
]
],
),
),
],
);
}
return const SizedBox.shrink();
},
),
);
}
Expand Down
1 change: 1 addition & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ class AppState extends State<App> {
create: (context) => UserRepository(
context.read<ProfileDao>(),
context.read<ArweaveService>(),
ArioSDKFactory().create(),
),
),
RepositoryProvider(
Expand Down
93 changes: 93 additions & 0 deletions lib/user/balance/user_balance_bloc.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import 'dart:async';

import 'package:ardrive/authentication/ardrive_auth.dart';
import 'package:ardrive/user/user.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

part 'user_balance_event.dart';
part 'user_balance_state.dart';

class UserBalanceBloc extends Bloc<UserBalanceEvent, UserBalanceState> {
final ArDriveAuth _auth;
StreamSubscription<User?>? _userSubscription;

UserBalanceBloc({required ArDriveAuth auth})
: _auth = auth,
super(UserBalanceInitial()) {
on<GetUserBalance>(_onGetUserBalance);
on<RefreshUserBalance>(_onRefreshUserBalance);
}

Future<void> _onGetUserBalance(
GetUserBalance event, Emitter<UserBalanceState> emit) async {
await _cancelSubscription();

final user = _auth.currentUser;
_emitUserBalanceState(user, emit);

_userSubscription = _auth.onAuthStateChanged().listen((user) {
if (isClosed) return;
_emitUserBalanceState(user, emit);
if (user?.ioTokens != null) {
_cancelSubscription();
}
});

await _userSubscription?.asFuture();
}

Future<void> _onRefreshUserBalance(
RefreshUserBalance event, Emitter<UserBalanceState> emit) async {
if (isClosed) return;

await _cancelSubscription();

emit(UserBalanceLoadingIOTokens(
arBalance: _auth.currentUser.walletBalance,
errorFetchingIOTokens: false,
));

_auth.refreshBalance();

_userSubscription = _auth.onAuthStateChanged().listen((user) {
if (isClosed) return;
_emitUserBalanceState(user, emit);
if (user?.ioTokens != null) {
_cancelSubscription();
}
});

await _userSubscription?.asFuture();
}

Future<void> _cancelSubscription() async {
if (_userSubscription != null) {
await _userSubscription!.cancel();
_userSubscription = null;
}
}

void _emitUserBalanceState(User? user, Emitter<UserBalanceState> emit) {
if (user == null) return;

if (user.ioTokens == null && !user.errorFetchingIOTokens) {
emit(UserBalanceLoadingIOTokens(
arBalance: user.walletBalance,
errorFetchingIOTokens: user.errorFetchingIOTokens,
));
} else {
emit(UserBalanceLoaded(
arBalance: user.walletBalance,
ioTokens: user.ioTokens,
errorFetchingIOTokens: user.errorFetchingIOTokens,
));
}
}

@override
Future<void> close() async {
await _cancelSubscription();
return super.close();
}
}
12 changes: 12 additions & 0 deletions lib/user/balance/user_balance_event.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
part of 'user_balance_bloc.dart';

sealed class UserBalanceEvent extends Equatable {
const UserBalanceEvent();

@override
List<Object> get props => [];
}

final class GetUserBalance extends UserBalanceEvent {}

final class RefreshUserBalance extends UserBalanceEvent {}
30 changes: 30 additions & 0 deletions lib/user/balance/user_balance_state.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
part of 'user_balance_bloc.dart';

sealed class UserBalanceState extends Equatable {
const UserBalanceState();

@override
List<Object> get props => [];
}

final class UserBalanceInitial extends UserBalanceState {}

final class UserBalanceLoaded extends UserBalanceState {
final BigInt arBalance;
final String? ioTokens;
final bool errorFetchingIOTokens;

const UserBalanceLoaded({
required this.arBalance,
required this.ioTokens,
required this.errorFetchingIOTokens,
});
}

final class UserBalanceLoadingIOTokens extends UserBalanceLoaded {
const UserBalanceLoadingIOTokens({
required super.arBalance,
super.ioTokens,
super.errorFetchingIOTokens = false,
});
}
Loading
Loading