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

feat(cat-voices): guarded get started #1528

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,10 @@ final class Dependencies extends DependencyProvider {
);
registerLazySingleton<RegistrationService>(() {
return RegistrationService(
transactionConfigRepository: get<TransactionConfigRepository>(),
keychainProvider: get<KeychainProvider>(),
cardano: get<CatalystCardano>(),
keyDerivation: get<KeyDerivation>(),
get<TransactionConfigRepository>(),
get<KeychainProvider>(),
get<CatalystCardano>(),
get<KeyDerivation>(),
);
});
registerLazySingleton<UserService>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class AccountPopup extends StatelessWidget {
final String avatarLetter;
final String displayName;
final VoidCallback? onProfileKeychainTap;
final VoidCallback? onLockAccountTap;

const AccountPopup({
super.key,
required this.avatarLetter,
required this.displayName,
this.onProfileKeychainTap,
this.onLockAccountTap,
});
Expand All @@ -40,7 +40,7 @@ class AccountPopup extends StatelessWidget {
value: null,
key: const Key('PopUpMenuAccountHeader'),
child: _Header(
accountLetter: avatarLetter,
displayName: displayName,
walletName: 'Wallet name',
walletBalance: '₳ 1,750,000',
accountType: 'Basis',
Expand Down Expand Up @@ -84,22 +84,22 @@ class AccountPopup extends StatelessWidget {
offset: const Offset(0, kToolbarHeight),
child: IgnorePointer(
child: VoicesAvatar(
icon: Text(avatarLetter),
icon: Text(displayName),
),
),
);
}
}

class _Header extends StatelessWidget {
final String accountLetter;
final String displayName;
final String walletName;
final String walletBalance;
final String accountType;
final ShelleyAddress walletAddress;

const _Header({
required this.accountLetter,
required this.displayName,
required this.walletName,
required this.walletBalance,
required this.accountType,
Expand All @@ -115,7 +115,11 @@ class _Header extends StatelessWidget {
child: Row(
children: [
VoicesAvatar(
icon: Text(accountLetter),
icon: Text(
displayName.isNotEmpty
? displayName.substring(0, 1).toUpperCase()
: '',
),
),
Expanded(
child: Padding(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,13 @@ class SessionActionHeader extends StatelessWidget {
return BlocBuilder<SessionCubit, SessionState>(
builder: (context, state) {
return switch (state) {
VisitorSessionState(:final isRegistrationInProgress) =>
VisitorSessionState(
:final isRegistrationInProgress,
:final canCreateAccount,
) =>
isRegistrationInProgress
? const _FinishRegistrationButton()
: const _GetStartedButton(),
: _GetStartedButton(isEnabled: canCreateAccount),
GuestSessionState() => const _UnlockButton(),
ActiveAccountSessionState() => const _LockButton(),
};
Expand All @@ -34,13 +37,17 @@ class SessionActionHeader extends StatelessWidget {
}

class _GetStartedButton extends StatelessWidget {
const _GetStartedButton();
final bool isEnabled;

const _GetStartedButton({
required this.isEnabled,
});

@override
Widget build(BuildContext context) {
return VoicesFilledButton(
key: const Key('GetStartedButton'),
onTap: () => unawaited(RegistrationDialog.show(context)),
onTap: isEnabled ? () async => RegistrationDialog.show(context) : null,
child: Text(context.l10n.getStarted),
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ class SessionStateHeader extends StatelessWidget {
VisitorSessionState() => const _VisitorButton(),
GuestSessionState() => const _GuestButton(),
ActiveAccountSessionState(:final account) => AccountPopup(
avatarLetter: account?.acronym ?? '',
key: const Key('AccountPopupButton'),
displayName: account?.displayName ?? '',
onLockAccountTap: () => _onLockAccount(context),
onProfileKeychainTap: () => _onSeeProfile(context),
key: const Key('AccountPopupButton'),
),
};
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import 'dart:async';
import 'package:catalyst_voices/common/ext/ext.dart';
import 'package:catalyst_voices/pages/campaign/admin_tools/campaign_admin_tools_dialog.dart';
import 'package:catalyst_voices/pages/campaign/details/widgets/campaign_management.dart';
import 'package:catalyst_voices/pages/spaces/appbar/session_action_header.dart';
import 'package:catalyst_voices/pages/spaces/appbar/session_state_header.dart';
import 'package:catalyst_voices/pages/spaces/appbar/spaces_theme_mode_switch.dart';
import 'package:catalyst_voices/pages/spaces/drawer/spaces_drawer.dart';
import 'package:catalyst_voices/widgets/widgets.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import 'dart:async';
import 'package:catalyst_voices/routes/guards/route_guard.dart';
import 'package:catalyst_voices/routes/routes.dart';
import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart';
import 'package:catalyst_voices_models/catalyst_voices_models.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
Expand All @@ -25,15 +24,18 @@ final class UserAccessGuard implements RouteGuard {
state.path == const FundedProjectsRoute().location) {
return const DiscoveryRoute().location;
}
if (account.roles.any(
(role) => [AccountRole.proposer, AccountRole.drep].contains(role),
)) return null;

if (account.isProposer || account.isDrep) {
return null;
}

return const DiscoveryRoute().location;
}
}

final class AdminAccessGuard implements RouteGuard {
const AdminAccessGuard();

@override
FutureOr<String?> redirect(BuildContext context, GoRouterState state) {
final account = context.read<SessionCubit>().state.account;
Expand Down
2 changes: 0 additions & 2 deletions catalyst_voices/apps/voices/lib/widgets/widgets.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
export 'app_bar/session/session_action_header.dart';
export 'app_bar/session/session_state_header.dart';
export 'app_bar/voices_app_bar.dart';
export 'avatars/space_avatar.dart';
export 'avatars/voices_avatar.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ final class SessionCubit extends Cubit<SessionState>

Account? _account;
AdminToolsState _adminToolsState;
bool _hasWallets = false;

StreamSubscription<bool>? _keychainUnlockedSub;
StreamSubscription<Account?>? _accountSub;
Expand All @@ -44,6 +45,8 @@ final class SessionCubit extends Cubit<SessionState>
_accountSub = _userService.watchAccount.listen(_onActiveAccountChanged);

_adminToolsSub = _adminTools.stream.listen(_onAdminToolsChanged);

unawaited(_checkAvailableWallets());
}

Future<bool> unlock(LockFactor lockFactor) async {
Expand Down Expand Up @@ -119,15 +122,21 @@ final class SessionCubit extends Cubit<SessionState>
_updateState();
}

Future<void> _checkAvailableWallets() async {
final wallets = await _registrationService
.getCardanoWallets()
.onError((_, __) => const []);

_hasWallets = wallets.isNotEmpty;

if (!isClosed) {
_updateState();
}
}

void _updateState() {
if (_adminToolsState.enabled) {
unawaited(
_createMockedSessionState().then((value) {
if (!isClosed) {
emit(value);
}
}),
);
emit(_createMockedSessionState());
} else {
emit(_createSessionState());
}
Expand All @@ -136,44 +145,51 @@ final class SessionCubit extends Cubit<SessionState>
SessionState _createSessionState() {
final account = _account;
final isUnlocked = _account?.keychain.lastIsUnlocked ?? false;
final hasWallets = _hasWallets;

if (account == null) {
final isEmpty = _registrationProgressNotifier.value.isEmpty;
return VisitorSessionState(isRegistrationInProgress: !isEmpty);
return VisitorSessionState(
canCreateAccount: hasWallets,
isRegistrationInProgress: !isEmpty,
);
}

if (!isUnlocked) {
return const GuestSessionState();
return GuestSessionState(canCreateAccount: hasWallets);
}

final sessionAccount = SessionAccount.fromAccount(account);
final spaces = _accessControl.spacesAccess(account);
final overallSpaces = _accessControl.overallSpaces(account);
final spacesShortcuts = _accessControl.spacesShortcutsActivators(account);

return ActiveAccountSessionState(
account: account,
account: sessionAccount,
spaces: spaces,
overallSpaces: overallSpaces,
spacesShortcuts: spacesShortcuts,
canCreateAccount: hasWallets,
);
}

Future<SessionState> _createMockedSessionState() async {
SessionState _createMockedSessionState() {
switch (_adminToolsState.sessionStatus) {
case SessionStatus.actor:
// TODO(damian-molinski): Limiting exposed Account so its not future.
final dummyAccount = await _getDummyAccount();

return ActiveAccountSessionState(
account: dummyAccount,
account: const SessionAccount.mocked(),
spaces: Space.values,
overallSpaces: Space.values,
spacesShortcuts: AccessControl.allSpacesShortcutsActivators,
canCreateAccount: true,
);
case SessionStatus.guest:
return const GuestSessionState();
return const GuestSessionState(canCreateAccount: true);
case SessionStatus.visitor:
return const VisitorSessionState(isRegistrationInProgress: false);
return const VisitorSessionState(
isRegistrationInProgress: false,
canCreateAccount: true,
);
}
}

Expand Down
Loading
Loading