Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 46b062bc48 | |||
| 88275c4ae6 |
1
apps/mobile_app/assets/shared/images/intro_app.json
Normal file
1
apps/mobile_app/assets/shared/images/intro_app.json
Normal file
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 469 KiB |
@@ -32,6 +32,9 @@ Future<void> initApp(EnvironmentEnum env) async {
|
||||
log: env.isDevelopment || kDebugMode,
|
||||
onTokenExpired: () => appRouter.go(AppRoutes.scaTreezor),
|
||||
onUnauthorized: () async {
|
||||
final currentLocation =
|
||||
appRouter.routerDelegate.currentConfiguration.uri.path;
|
||||
if (currentLocation == AppRoutes.splash) return;
|
||||
try {
|
||||
await GetIt.I<TreezorWalletConnectionService>().logout();
|
||||
} catch (_) {}
|
||||
|
||||
@@ -199,6 +199,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.19.1"
|
||||
confetti:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: confetti
|
||||
sha256: "979aafde2428c53947892c95eb244466c109c129b7eee9011f0a66caaca52267"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.0"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -121,6 +121,12 @@
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.4"
|
||||
},
|
||||
{
|
||||
"name": "confetti",
|
||||
"rootUri": "file:///Users/juliandalcalaf/.pub-cache/hosted/pub.dev/confetti-0.7.0",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.17"
|
||||
},
|
||||
{
|
||||
"name": "convert",
|
||||
"rootUri": "file:///Users/juliandalcalaf/.pub-cache/hosted/pub.dev/convert-3.1.2",
|
||||
|
||||
@@ -104,6 +104,7 @@
|
||||
"name": "design_system",
|
||||
"version": "0.0.1",
|
||||
"dependencies": [
|
||||
"confetti",
|
||||
"country_code_picker",
|
||||
"flutter",
|
||||
"flutter_riverpod",
|
||||
@@ -356,6 +357,14 @@
|
||||
"meta"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "confetti",
|
||||
"version": "0.7.0",
|
||||
"dependencies": [
|
||||
"flutter",
|
||||
"vector_math"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "lottie",
|
||||
"version": "3.3.2",
|
||||
|
||||
@@ -161,6 +161,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.19.1"
|
||||
confetti:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: confetti
|
||||
sha256: "979aafde2428c53947892c95eb244466c109c129b7eee9011f0a66caaca52267"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.0"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -8,10 +8,11 @@ import 'package:sf_localizations/sf_localizations.dart';
|
||||
|
||||
import '../../card_colors.dart';
|
||||
import '../../presentation/state/home_view_model.dart';
|
||||
import '../deposit/deposit_success_provider.dart';
|
||||
import 'child_wallet_view_model.dart';
|
||||
import 'wallet_actions_bar.dart';
|
||||
|
||||
class ChildWalletScreen extends ConsumerWidget {
|
||||
class ChildWalletScreen extends ConsumerStatefulWidget {
|
||||
final String childId;
|
||||
final NavigationContract navigation;
|
||||
|
||||
@@ -22,16 +23,21 @@ class ChildWalletScreen extends ConsumerWidget {
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final theme = ref.watch(themePortProvider);
|
||||
final viewState = ref.watch(childWalletViewModelProvider(childId));
|
||||
ConsumerState<ChildWalletScreen> createState() => _ChildWalletScreenState();
|
||||
}
|
||||
|
||||
ref.listen(childWalletViewModelProvider(childId), (prev, next) {
|
||||
class _ChildWalletScreenState extends ConsumerState<ChildWalletScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = ref.watch(themePortProvider);
|
||||
final viewState = ref.watch(childWalletViewModelProvider(widget.childId));
|
||||
final depositSuccess = ref.watch(depositSuccessProvider(widget.childId));
|
||||
|
||||
ref.listen(childWalletViewModelProvider(widget.childId), (prev, next) {
|
||||
if (next.cardStatusSuccess && !(prev?.cardStatusSuccess ?? false)) {
|
||||
ref.read(homeViewModelProvider.notifier).updateChildCardStatus(
|
||||
childId,
|
||||
next.cardStatus,
|
||||
);
|
||||
ref
|
||||
.read(homeViewModelProvider.notifier)
|
||||
.updateChildCardStatus(widget.childId, next.cardStatus);
|
||||
showTopSnackbar(
|
||||
context,
|
||||
message: context.translate(I18n.cardStatusSuccess),
|
||||
@@ -50,7 +56,7 @@ class ChildWalletScreen extends ConsumerWidget {
|
||||
|
||||
if (viewState.showPin) {
|
||||
final viewModel = ref.read(
|
||||
childWalletViewModelProvider(childId).notifier,
|
||||
childWalletViewModelProvider(widget.childId).notifier,
|
||||
);
|
||||
return Scaffold(
|
||||
backgroundColor: theme.getColorFor(ThemeCode.backgroundSecondary),
|
||||
@@ -117,197 +123,219 @@ class ChildWalletScreen extends ConsumerWidget {
|
||||
cardStatus: viewState.cardStatus,
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: theme.getColorFor(ThemeCode.backgroundSecondary),
|
||||
body: Stack(
|
||||
children: [
|
||||
DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomRight: Radius.circular(24),
|
||||
bottomLeft: Radius.circular(24),
|
||||
),
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: locked ? theme.getDisabledCardColors() : cardColors,
|
||||
return ConfettiOverlay(
|
||||
play: depositSuccess,
|
||||
onPlayed: () =>
|
||||
ref.read(depositSuccessProvider(widget.childId).notifier).reset(),
|
||||
child: Scaffold(
|
||||
backgroundColor: theme.getColorFor(ThemeCode.backgroundSecondary),
|
||||
body: Stack(
|
||||
children: [
|
||||
DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomRight: Radius.circular(24),
|
||||
bottomLeft: Radius.circular(24),
|
||||
),
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: locked ? theme.getDisabledCardColors() : cardColors,
|
||||
),
|
||||
),
|
||||
child: SizedBox(width: double.infinity, height: 420),
|
||||
),
|
||||
child: SizedBox(width: double.infinity, height: 420),
|
||||
),
|
||||
SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(vertical: 50, horizontal: 20),
|
||||
child: Column(
|
||||
spacing: 24,
|
||||
children: [
|
||||
Row(
|
||||
spacing: 7,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () => navigation.goBack(),
|
||||
icon: Icon(
|
||||
Icons.arrow_back_ios_new_outlined,
|
||||
color: theme.getColorFor(ThemeCode.backgroundPrimary),
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
_buildGenderAvatar(device?.carrierGenre, 50),
|
||||
Text(
|
||||
childName,
|
||||
style: TextStyle(
|
||||
color: theme.getColorFor(ThemeCode.backgroundPrimary),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
spacing: 16,
|
||||
children: [
|
||||
MoneyText(
|
||||
text: "${availableBalance.toString()}€",
|
||||
size: 60,
|
||||
secondarySize: 24,
|
||||
color: theme.getColorFor(ThemeCode.textSecondary),
|
||||
),
|
||||
Text(
|
||||
context.translate(I18n.childWalletAvailableBalance),
|
||||
style: TextStyle(
|
||||
color: theme.getColorFor(ThemeCode.backgroundPrimary),
|
||||
),
|
||||
),
|
||||
LinearProgressIndicator(
|
||||
value: 0.7,
|
||||
color: theme.getColorFor(ThemeCode.backgroundPrimary),
|
||||
backgroundColor: theme
|
||||
.getColorFor(ThemeCode.backgroundPrimary)
|
||||
.withAlpha(0x4C),
|
||||
minHeight: 10,
|
||||
borderRadius: BorderRadius.all(Radius.circular(5)),
|
||||
),
|
||||
if (CardStatus.fromString(viewState.cardStatus) == CardStatus.lost ||
|
||||
CardStatus.fromString(viewState.cardStatus) == CardStatus.stolen)
|
||||
TextButton(
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStatePropertyAll(EdgeInsets.all(0)),
|
||||
),
|
||||
onPressed: viewState.isUpdatingCard
|
||||
? null
|
||||
: () => _showDeleteConfirmation(context, ref),
|
||||
child: Row(
|
||||
spacing: 10,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.delete_outline,
|
||||
size: 24,
|
||||
color: theme.getColorFor(ThemeCode.textSecondary),
|
||||
),
|
||||
Text(
|
||||
context.translate(I18n.deleteDevice),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 16,
|
||||
color: theme.getColorFor(ThemeCode.textSecondary),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
else
|
||||
TextButton(
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStatePropertyAll(EdgeInsets.all(0)),
|
||||
),
|
||||
onPressed: () =>
|
||||
_showCardStatusSheet(context, ref, theme),
|
||||
child: Row(
|
||||
spacing: 10,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.lock_outline,
|
||||
size: 24,
|
||||
color: theme.getColorFor(ThemeCode.textSecondary),
|
||||
),
|
||||
Text(
|
||||
locked
|
||||
? context.translate(I18n.childWalletUnlockCard)
|
||||
: context.translate(I18n.childWalletLockCard),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 16,
|
||||
color: theme.getColorFor(ThemeCode.textSecondary),
|
||||
),
|
||||
),
|
||||
],
|
||||
SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(vertical: 50, horizontal: 20),
|
||||
child: Column(
|
||||
spacing: 24,
|
||||
children: [
|
||||
Row(
|
||||
spacing: 7,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () => widget.navigation.goBack(),
|
||||
icon: Icon(
|
||||
Icons.arrow_back_ios_new_outlined,
|
||||
color: theme.getColorFor(ThemeCode.backgroundPrimary),
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
spacing: 16,
|
||||
children: [
|
||||
if (!locked)
|
||||
WalletActionsBar(childId: childId, navigation: navigation),
|
||||
Container(
|
||||
padding: EdgeInsets.all(15),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.getColorFor(ThemeCode.backgroundPrimary),
|
||||
borderRadius: BorderRadius.all(Radius.circular(20)),
|
||||
_buildGenderAvatar(device?.carrierGenre, 50),
|
||||
Text(
|
||||
childName,
|
||||
style: TextStyle(
|
||||
color: theme.getColorFor(ThemeCode.backgroundPrimary),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
context.translate(
|
||||
I18n.childWalletRecentTransactions,
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
spacing: 16,
|
||||
children: [
|
||||
MoneyText(
|
||||
text: "${availableBalance.toString()}€",
|
||||
size: 60,
|
||||
secondarySize: 24,
|
||||
color: theme.getColorFor(ThemeCode.textSecondary),
|
||||
),
|
||||
Text(
|
||||
context.translate(I18n.childWalletAvailableBalance),
|
||||
style: TextStyle(
|
||||
color: theme.getColorFor(ThemeCode.backgroundPrimary),
|
||||
),
|
||||
),
|
||||
LinearProgressIndicator(
|
||||
value: 0.7,
|
||||
color: theme.getColorFor(ThemeCode.backgroundPrimary),
|
||||
backgroundColor: theme
|
||||
.getColorFor(ThemeCode.backgroundPrimary)
|
||||
.withAlpha(0x4C),
|
||||
minHeight: 10,
|
||||
borderRadius: BorderRadius.all(Radius.circular(5)),
|
||||
),
|
||||
if (CardStatus.fromString(viewState.cardStatus) ==
|
||||
CardStatus.lost ||
|
||||
CardStatus.fromString(viewState.cardStatus) ==
|
||||
CardStatus.stolen)
|
||||
TextButton(
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStatePropertyAll(EdgeInsets.all(0)),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
if (viewState.isLoadingTransactions)
|
||||
const Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(24),
|
||||
child: AppLoadingIndicator(size: 48),
|
||||
onPressed: viewState.isUpdatingCard
|
||||
? null
|
||||
: () => _showDeleteConfirmation(context, ref),
|
||||
child: Row(
|
||||
spacing: 10,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.delete_outline,
|
||||
size: 24,
|
||||
color: theme.getColorFor(
|
||||
ThemeCode.textSecondary,
|
||||
),
|
||||
),
|
||||
)
|
||||
else if (viewState.transactions.isEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Center(
|
||||
child: Text(
|
||||
context.translate(
|
||||
I18n.activityNoTransactions,
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: theme.getColorFor(
|
||||
ThemeCode.textPrimary,
|
||||
),
|
||||
Text(
|
||||
context.translate(I18n.deleteDevice),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 16,
|
||||
color: theme.getColorFor(
|
||||
ThemeCode.textSecondary,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
else
|
||||
...viewState.transactions.map(
|
||||
(tx) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
child: TransactionTile(transaction: tx),
|
||||
],
|
||||
),
|
||||
)
|
||||
else
|
||||
TextButton(
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStatePropertyAll(EdgeInsets.all(0)),
|
||||
),
|
||||
onPressed: () =>
|
||||
_showCardStatusSheet(context, ref, theme),
|
||||
child: Row(
|
||||
spacing: 10,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.lock_outline,
|
||||
size: 24,
|
||||
color: theme.getColorFor(
|
||||
ThemeCode.textSecondary,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
locked
|
||||
? context.translate(
|
||||
I18n.childWalletUnlockCard,
|
||||
)
|
||||
: context.translate(
|
||||
I18n.childWalletLockCard,
|
||||
),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 16,
|
||||
color: theme.getColorFor(
|
||||
ThemeCode.textSecondary,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
spacing: 16,
|
||||
children: [
|
||||
if (!locked)
|
||||
WalletActionsBar(
|
||||
childId: widget.childId,
|
||||
navigation: widget.navigation,
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.all(15),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.getColorFor(ThemeCode.backgroundPrimary),
|
||||
borderRadius: BorderRadius.all(Radius.circular(20)),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
context.translate(
|
||||
I18n.childWalletRecentTransactions,
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
if (viewState.isLoadingTransactions)
|
||||
const Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(24),
|
||||
child: AppLoadingIndicator(size: 48),
|
||||
),
|
||||
)
|
||||
else if (viewState.transactions.isEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Center(
|
||||
child: Text(
|
||||
context.translate(
|
||||
I18n.activityNoTransactions,
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: theme.getColorFor(
|
||||
ThemeCode.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
else
|
||||
...viewState.transactions.map(
|
||||
(tx) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
child: TransactionTile(transaction: tx),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -344,7 +372,7 @@ class ChildWalletScreen extends ConsumerWidget {
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
|
||||
),
|
||||
backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary),
|
||||
builder: (_) => _CardStatusSheet(childId: childId),
|
||||
builder: (_) => _CardStatusSheet(childId: widget.childId),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -354,9 +382,7 @@ class ChildWalletScreen extends ConsumerWidget {
|
||||
context: context,
|
||||
builder: (_) => AlertDialog(
|
||||
backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||||
title: Text(context.translate(I18n.deleteDeviceConfirmTitle)),
|
||||
content: Text(context.translate(I18n.deleteDeviceConfirmMessage)),
|
||||
actions: [
|
||||
@@ -368,17 +394,19 @@ class ChildWalletScreen extends ConsumerWidget {
|
||||
onPressed: () async {
|
||||
Navigator.of(context).pop();
|
||||
final viewModel = ref.read(
|
||||
childWalletViewModelProvider(childId).notifier,
|
||||
childWalletViewModelProvider(widget.childId).notifier,
|
||||
);
|
||||
final success = await viewModel.deleteDevice();
|
||||
if (success && context.mounted) {
|
||||
ref.read(homeViewModelProvider.notifier).removeChild(childId);
|
||||
ref
|
||||
.read(homeViewModelProvider.notifier)
|
||||
.removeChild(widget.childId);
|
||||
showTopSnackbar(
|
||||
context,
|
||||
message: context.translate(I18n.deleteDeviceSuccess),
|
||||
type: MessageType.success,
|
||||
);
|
||||
navigation.goBack();
|
||||
widget.navigation.goBack();
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
@@ -417,7 +445,11 @@ class _CardStatusSheetState extends ConsumerState<_CardStatusSheet> {
|
||||
final viewState = ref.watch(childWalletViewModelProvider(widget.childId));
|
||||
final currentStatus = viewState.cardStatus;
|
||||
final statuses = CardStatus.fromString(currentStatus) == CardStatus.unlock
|
||||
? [CardStatus.lock.value, CardStatus.lost.value, CardStatus.stolen.value]
|
||||
? [
|
||||
CardStatus.lock.value,
|
||||
CardStatus.lost.value,
|
||||
CardStatus.stolen.value,
|
||||
]
|
||||
: [CardStatus.unlock.value];
|
||||
_selected ??= statuses.first;
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:sf_localizations/sf_localizations.dart';
|
||||
|
||||
import '../../card_colors.dart';
|
||||
import '../child_wallet/child_data_provider.dart';
|
||||
import 'deposit_success_provider.dart';
|
||||
import 'deposit_view_model.dart';
|
||||
|
||||
class DepositScreen extends ConsumerWidget {
|
||||
@@ -33,6 +34,7 @@ class DepositScreen extends ConsumerWidget {
|
||||
message: context.translate(I18n.walletMoveSuccess),
|
||||
type: MessageType.success,
|
||||
);
|
||||
ref.read(depositSuccessProvider(childId).notifier).trigger();
|
||||
navigation.goBack();
|
||||
}
|
||||
if (next.errorMessage.isNotEmpty &&
|
||||
@@ -122,106 +124,6 @@ class DepositScreen extends ConsumerWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
// Container(
|
||||
// decoration: BoxDecoration(
|
||||
// color: theme.getColorFor(ThemeCode.backgroundPrimary),
|
||||
// borderRadius: const BorderRadius.all(Radius.circular(20)),
|
||||
// ),
|
||||
// padding: const EdgeInsets.all(10),
|
||||
// child: Column(
|
||||
// spacing: 10,
|
||||
// children: [
|
||||
// Text(
|
||||
// context.translate(I18n.depositReason),
|
||||
// style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
|
||||
// ),
|
||||
// Text(context.translate(I18n.watchInfo)),
|
||||
// CheckboxListTile(
|
||||
// contentPadding: EdgeInsets.zero,
|
||||
// title: Text(context.translate(I18n.depositReasonWeekly)),
|
||||
// controlAffinity: ListTileControlAffinity.leading,
|
||||
// value: viewState.reason == 'weekly',
|
||||
// onChanged: (_) => viewModel.selectReason('weekly'),
|
||||
// activeColor: theme.getColorFor(ThemeCode.buttonPrimary),
|
||||
// ),
|
||||
// CheckboxListTile(
|
||||
// contentPadding: EdgeInsets.zero,
|
||||
// title: Text(context.translate(I18n.depositReasonGoalMet)),
|
||||
// controlAffinity: ListTileControlAffinity.leading,
|
||||
// value: viewState.reason == 'goal',
|
||||
// onChanged: (_) => viewModel.selectReason('goal'),
|
||||
// activeColor: theme.getColorFor(ThemeCode.buttonPrimary),
|
||||
// ),
|
||||
// CheckboxListTile(
|
||||
// contentPadding: EdgeInsets.zero,
|
||||
// title: Text(context.translate(I18n.depositReasonExtraordinary)),
|
||||
// controlAffinity: ListTileControlAffinity.leading,
|
||||
// value: viewState.reason == 'extraordinary',
|
||||
// onChanged: (_) => viewModel.selectReason('extraordinary'),
|
||||
// activeColor: theme.getColorFor(ThemeCode.buttonPrimary),
|
||||
// ),
|
||||
// CheckboxListTile(
|
||||
// contentPadding: EdgeInsets.zero,
|
||||
// title: Text(context.translate(I18n.depositReasonOther)),
|
||||
// controlAffinity: ListTileControlAffinity.leading,
|
||||
// value: viewState.reason == 'other',
|
||||
// onChanged: (_) => viewModel.selectReason('other'),
|
||||
// activeColor: theme.getColorFor(ThemeCode.buttonPrimary),
|
||||
// ),
|
||||
// CustomTextField(
|
||||
// controller: viewModel.messageController,
|
||||
// lines: 3,
|
||||
// length: 150,
|
||||
// label: context.translate(I18n.depositMessageLabel, args: {'name': childName}),
|
||||
// hint: context.translate(I18n.allowanceMessageHint),
|
||||
// ),
|
||||
// Align(
|
||||
// alignment: Alignment.topLeft,
|
||||
// child: Text(context.translate(I18n.allowanceMaxChars, args: {'count': '150'})),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
|
||||
// Container(
|
||||
// decoration: BoxDecoration(
|
||||
// color: theme.getColorFor(ThemeCode.backgroundPrimary),
|
||||
// borderRadius: const BorderRadius.all(Radius.circular(20)),
|
||||
// ),
|
||||
// padding: const EdgeInsets.all(10),
|
||||
// child: Column(
|
||||
// spacing: 10,
|
||||
// children: [
|
||||
// Text(
|
||||
// context.translate(I18n.depositWhenSend),
|
||||
// style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
|
||||
// ),
|
||||
// Text(context.translate(I18n.watchInfo)),
|
||||
// CheckboxListTile(
|
||||
// contentPadding: EdgeInsets.zero,
|
||||
// title: Text(context.translate(I18n.depositNow)),
|
||||
// controlAffinity: ListTileControlAffinity.leading,
|
||||
// value: !viewState.program,
|
||||
// onChanged: (_) {
|
||||
// if (viewState.program) viewModel.toggleProgram();
|
||||
// },
|
||||
// activeColor: theme.getColorFor(ThemeCode.buttonPrimary),
|
||||
// ),
|
||||
// CheckboxListTile(
|
||||
// contentPadding: EdgeInsets.zero,
|
||||
// title: Text(context.translate(I18n.depositSchedule)),
|
||||
// controlAffinity: ListTileControlAffinity.leading,
|
||||
// value: viewState.program,
|
||||
// onChanged: (_) {
|
||||
// if (!viewState.program) viewModel.toggleProgram();
|
||||
// },
|
||||
// activeColor: theme.getColorFor(ThemeCode.buttonPrimary),
|
||||
// ),
|
||||
// if (viewState.program) CustomTextField(),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
final depositSuccessProvider =
|
||||
NotifierProvider.family<DepositSuccessNotifier, bool, String>(
|
||||
DepositSuccessNotifier.new,
|
||||
);
|
||||
|
||||
class DepositSuccessNotifier extends Notifier<bool> {
|
||||
final String childId;
|
||||
DepositSuccessNotifier(this.childId);
|
||||
|
||||
@override
|
||||
bool build() => false;
|
||||
|
||||
void trigger() {
|
||||
state = true;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
state = false;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
import 'dart:async';
|
||||
import 'package:animated_splash_screen/animated_splash_screen.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:navigation/app_routes.dart';
|
||||
import 'package:navigation/navigation_contract.dart';
|
||||
import 'package:page_transition/page_transition.dart';
|
||||
import 'package:lottie/lottie.dart';
|
||||
import 'package:navigation/navigation.dart';
|
||||
import 'package:splash/src/domain/check_session_use_case.dart';
|
||||
import 'package:splash/src/domain/initial_route.dart';
|
||||
|
||||
@@ -21,40 +19,61 @@ class SplashScreen extends StatefulWidget {
|
||||
State<SplashScreen> createState() => _SplashScreenState();
|
||||
}
|
||||
|
||||
class _SplashScreenState extends State<SplashScreen> {
|
||||
class _SplashScreenState extends State<SplashScreen>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late final AnimationController _controller;
|
||||
InitialRoute? _route;
|
||||
bool _animationDone = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
unawaited(nextRoute());
|
||||
_controller = AnimationController(vsync: this)
|
||||
..addStatusListener((status) {
|
||||
if (status == AnimationStatus.completed) {
|
||||
_animationDone = true;
|
||||
_navigateIfReady();
|
||||
}
|
||||
});
|
||||
unawaited(_checkSession());
|
||||
}
|
||||
|
||||
Future<void> nextRoute() async {
|
||||
final results = await Future.wait([
|
||||
widget.checkSessionUseCase.execute(),
|
||||
Future.delayed(const Duration(milliseconds: 3500)),
|
||||
]);
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
if (!mounted) return;
|
||||
Future<void> _checkSession() async {
|
||||
_route = await widget.checkSessionUseCase.execute();
|
||||
_navigateIfReady();
|
||||
}
|
||||
|
||||
final route = results[0] as InitialRoute;
|
||||
switch (route) {
|
||||
case InitialRoute.login:
|
||||
widget.navigationContract.goTo(AppRoutes.login);
|
||||
case InitialRoute.home:
|
||||
widget.navigationContract.goTo(AppRoutes.dashboardHome);
|
||||
}
|
||||
void _navigateIfReady() {
|
||||
if (!_animationDone || _route == null || !mounted) return;
|
||||
|
||||
final destination = switch (_route!) {
|
||||
InitialRoute.login => AppRoutes.login,
|
||||
InitialRoute.home => AppRoutes.dashboardHome,
|
||||
};
|
||||
widget.navigationContract.goTo(destination);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedSplashScreen(
|
||||
splash: Image.asset('assets/shared/images/splash.gif'),
|
||||
splashIconSize: 900.0,
|
||||
nextScreen: const SizedBox.shrink(),
|
||||
disableNavigation: true,
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
splashTransition: SplashTransition.fadeTransition,
|
||||
pageTransitionType: PageTransitionType.fade,
|
||||
body: Center(
|
||||
child: Lottie.asset(
|
||||
'assets/shared/images/intro_app.json',
|
||||
controller: _controller,
|
||||
onLoaded: (composition) {
|
||||
_controller
|
||||
..duration = composition.duration
|
||||
..forward();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,10 +11,9 @@ environment:
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
animated_splash_screen: ^1.3.0
|
||||
lottie: ^3.3.1
|
||||
go_router: ^17.0.0
|
||||
get_it: ^9.0.5
|
||||
page_transition: ^2.2.1
|
||||
navigation:
|
||||
path: ../../packages/navigation
|
||||
sf_infrastructure:
|
||||
|
||||
@@ -15,3 +15,4 @@ export 'src/containers/section_container.dart';
|
||||
export 'src/containers/footer_container.dart';
|
||||
export 'src/rows/editable_row.dart';
|
||||
export 'src/loading/app_loading_indicator.dart';
|
||||
export 'src/confetti/confetti_overlay.dart';
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:confetti/confetti.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ConfettiOverlay extends StatefulWidget {
|
||||
final bool play;
|
||||
final Widget child;
|
||||
final VoidCallback? onPlayed;
|
||||
final Duration duration;
|
||||
final List<Color> colors;
|
||||
|
||||
const ConfettiOverlay({
|
||||
super.key,
|
||||
required this.play,
|
||||
required this.child,
|
||||
this.onPlayed,
|
||||
this.duration = const Duration(seconds: 3),
|
||||
this.colors = const [
|
||||
Color(0xFFFF69B4),
|
||||
Color(0xFF4169E1),
|
||||
Color(0xFFFF8C00),
|
||||
Color(0xFF8A2BE2),
|
||||
Color(0xFFFFD700),
|
||||
],
|
||||
});
|
||||
|
||||
@override
|
||||
State<ConfettiOverlay> createState() => _ConfettiOverlayState();
|
||||
}
|
||||
|
||||
class _ConfettiOverlayState extends State<ConfettiOverlay> {
|
||||
late final ConfettiController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = ConfettiController(duration: widget.duration);
|
||||
if (widget.play) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_controller.play();
|
||||
widget.onPlayed?.call();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant ConfettiOverlay oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.play && !oldWidget.play) {
|
||||
_controller.play();
|
||||
if (widget.onPlayed != null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
widget.onPlayed!();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
widget.child,
|
||||
Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: ConfettiWidget(
|
||||
confettiController: _controller,
|
||||
blastDirectionality: BlastDirectionality.explosive,
|
||||
gravity: 0.1,
|
||||
numberOfParticles: 10,
|
||||
emissionFrequency: 0.2,
|
||||
colors: widget.colors,
|
||||
createParticlePath: (size) {
|
||||
final random = Random();
|
||||
final w = 10.0 + random.nextDouble() * 5.0;
|
||||
final h = 5.0 + random.nextDouble() * 2.5;
|
||||
return Path()..addRect(Rect.fromLTWH(0, 0, w, h));
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ dependencies:
|
||||
path: ../../packages/fonts
|
||||
top_snackbar_flutter: ^3.3.0
|
||||
lottie: ^3.3.1
|
||||
confetti: ^0.7.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
@@ -7,6 +7,6 @@
|
||||
<versions>
|
||||
<version>2.6.4</version>
|
||||
</versions>
|
||||
<lastUpdated>20260301000000</lastUpdated>
|
||||
<lastUpdated>20260302000000</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
|
||||
@@ -1 +1 @@
|
||||
ab3c3fa378ac166364ea7cfd739ddb6f
|
||||
9728121fa548f85a30f9c665eaf069c7
|
||||
@@ -1 +1 @@
|
||||
8a764ee335f810b5ecc8b687de8da58391118e7d
|
||||
995b4bcedd19cee87123779a9acc8835b2eac2c6
|
||||
@@ -145,6 +145,12 @@
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.4"
|
||||
},
|
||||
{
|
||||
"name": "confetti",
|
||||
"rootUri": "file:///Users/juliandalcalaf/.pub-cache/hosted/pub.dev/confetti-0.7.0",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.17"
|
||||
},
|
||||
{
|
||||
"name": "convert",
|
||||
"rootUri": "file:///Users/juliandalcalaf/.pub-cache/hosted/pub.dev/convert-3.1.2",
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
"name": "design_system",
|
||||
"version": "0.0.1",
|
||||
"dependencies": [
|
||||
"confetti",
|
||||
"country_code_picker",
|
||||
"flutter",
|
||||
"flutter_riverpod",
|
||||
@@ -349,6 +350,14 @@
|
||||
"dio"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "confetti",
|
||||
"version": "0.7.0",
|
||||
"dependencies": [
|
||||
"flutter",
|
||||
"vector_math"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "lottie",
|
||||
"version": "3.3.2",
|
||||
|
||||
@@ -193,6 +193,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.19.1"
|
||||
confetti:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: confetti
|
||||
sha256: "979aafde2428c53947892c95eb244466c109c129b7eee9011f0a66caaca52267"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.0"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
Reference in New Issue
Block a user