Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
68e0ce9
feat: setup l10n and implement to auth wrapper
dewabisma May 19, 2026
56434fc
feat: localize wallet init screen
dewabisma May 19, 2026
f1ea219
feat: onboarding flow localized
dewabisma May 19, 2026
4b3027c
feat: localize home and activity
dewabisma May 19, 2026
57cb374
feat: localize manage account flow
dewabisma May 19, 2026
c46df93
feat: localized send flow
dewabisma May 19, 2026
8a78bf6
feat: localize activity related screen and widgets
dewabisma May 19, 2026
d1c1ef9
feat: localize receive and pos screens
dewabisma May 19, 2026
e920e72
feat: localize setting screens
dewabisma May 19, 2026
c8a86e9
feat: localized swap screens
dewabisma May 19, 2026
d352004
feat: localized shared components
dewabisma May 19, 2026
005fc55
feat: finish integrating language localization
dewabisma May 19, 2026
cdea845
feat: address review issues
dewabisma May 20, 2026
9a47112
feat: another review fixes
dewabisma May 20, 2026
48bb5c9
Merge branch 'main' of https://github.com/Quantus-Network/quantus-app…
dewabisma May 20, 2026
68b8ae3
chore: formatting
dewabisma May 20, 2026
ff5950e
fix: lint error
dewabisma May 20, 2026
9bdcbfb
feat: address reset bug
dewabisma May 20, 2026
72f5aae
feat: remove redundant setting clear
dewabisma May 20, 2026
04306f7
fix: reset depend on setting clear
dewabisma May 20, 2026
e47947a
chore: sync lock file
dewabisma May 20, 2026
8a0ba03
fix: resolve review issues
dewabisma May 20, 2026
a690e03
feat: update activity screen
dewabisma May 20, 2026
2e6bb05
chore: formatting
dewabisma May 20, 2026
d916348
chore: excluce build folder content from flutter analyze
dewabisma May 20, 2026
245b865
Merge branch 'main' of https://github.com/Quantus-Network/quantus-app…
dewabisma May 21, 2026
68df3b7
Merge branch 'beast/language-support' of https://github.com/Quantus-N…
dewabisma May 21, 2026
4d5462c
fix: scroll interefering each filter state
dewabisma May 21, 2026
32767ca
fix: race fetch pull and scroll
dewabisma May 21, 2026
e92bb03
feat: properly debug sensitive information
dewabisma May 21, 2026
aeaad0d
fix: not waiting settings clean up
dewabisma May 21, 2026
e8afa78
feat: resolve PR issues
dewabisma May 21, 2026
b6fb284
Merge branch 'beast/language-support' of https://github.com/Quantus-N…
dewabisma May 21, 2026
0b4c4d8
Merge branch 'main' of https://github.com/Quantus-Network/quantus-app…
dewabisma May 25, 2026
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
1 change: 1 addition & 0 deletions mobile-app/analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ analyzer:
- "**/*.g.dart"
- "**/*.freezed.dart"
- "lib/generated/**"
- "build/**"
errors:
avoid_print: ignore # print is the most reliable way to debug the app
missing_required_param: error
Expand Down
36 changes: 32 additions & 4 deletions mobile-app/lib/providers/active_account_transactions_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,41 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:quantus_sdk/quantus_sdk.dart';
import 'package:resonance_network_wallet/models/combined_transactions_list.dart';
import 'package:resonance_network_wallet/models/filtered_transactions_params.dart';
import 'package:resonance_network_wallet/models/pagination_state.dart';
import 'package:resonance_network_wallet/providers/account_id_list_cache.dart';
import 'package:resonance_network_wallet/providers/account_providers.dart';
import 'package:resonance_network_wallet/providers/controllers/unified_pagination_controller.dart';
import 'package:resonance_network_wallet/providers/filtered_all_transactions_provider.dart';

FilteredTransactionsParams? activeAccountFilteredParams(DisplayAccount? activeAccount, TransactionFilter filter) {
if (activeAccount == null) return null;
return FilteredTransactionsParams(
accountIds: AccountIdListCache.get([activeAccount.account.accountId]),
filter: filter,
);
}

UnifiedPaginationController? activeAccountPaginationNotifier(WidgetRef ref, TransactionFilter filter) {
final params = activeAccountFilteredParams(ref.read(activeAccountProvider).value, filter);
if (params == null) return null;
return ref.read(filteredPaginationControllerProviderFamily(params).notifier);
}

/// Pagination state for the active account and [TransactionFilter].
final activeAccountPaginationProvider = Provider.family<PaginationState?, TransactionFilter>((ref, filter) {
final activeAccountValue = ref.watch(activeAccountProvider);

return activeAccountValue.when(
data: (activeAccount) {
final params = activeAccountFilteredParams(activeAccount, filter);
if (params == null) return null;
return ref.watch(filteredPaginationControllerProviderFamily(params));
},
loading: () => null,
error: (_, _) => null,
);
});

/// Provides a filtered list of transactions for the currently active account.
///
/// Parameterised by [TransactionFilter] so callers can independently watch
Expand All @@ -21,10 +52,7 @@ final activeAccountTransactionsProvider = Provider.family<AsyncValue<CombinedTra
if (activeAccount == null) {
return AsyncValue.data(CombinedTransactionsList.empty);
}
final params = FilteredTransactionsParams(
accountIds: AccountIdListCache.get([activeAccount.account.accountId]),
filter: filter,
);
final params = activeAccountFilteredParams(activeAccount, filter)!;
return ref.watch(filteredTransactionsProviderFamily(params));
},
loading: () => const AsyncValue.loading(),
Expand Down
3 changes: 2 additions & 1 deletion mobile-app/lib/providers/all_transactions_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ final allTransactionsProvider = Provider<AsyncValue<CombinedTransactionsList>>((
final pending = ref.watch(pendingTransactionsProvider);
final pagination = ref.watch(paginationControllerProvider);

if (pagination.error != null) {
final hasLoadedChainData = pagination.otherTransfers.isNotEmpty || pagination.scheduledReversibleTransfers.isNotEmpty;
if (pagination.error != null && !hasLoadedChainData) {
return AsyncValue.error(pagination.error!, pagination.stackTrace!);
}
if (pagination.isFetching && pagination.otherTransfers.isEmpty) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,15 @@ final filteredTransactionsProviderFamily =
final pending = ref.watch(pendingTransactionsProvider);
final pagination = ref.watch(filteredPaginationControllerProviderFamily(normalizedParams));

if (pagination.error != null) {
final hasLoadedChainData =
pagination.otherTransfers.isNotEmpty || pagination.scheduledReversibleTransfers.isNotEmpty;
if (pagination.error != null && !hasLoadedChainData) {
print('FilteredTransactionsProvider: Error: ${pagination.error}');
return AsyncValue.error(pagination.error!, pagination.stackTrace!);
}
if (pagination.error != null) {
print('FilteredTransactionsProvider: Load-more error: ${pagination.error}');
}
Comment thread
cursor[bot] marked this conversation as resolved.
Comment thread
cursor[bot] marked this conversation as resolved.
if (pagination.isFetching && pagination.otherTransfers.isEmpty) {
return const AsyncValue.loading();
}
Expand Down
133 changes: 102 additions & 31 deletions mobile-app/lib/v2/screens/activity/activity_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,41 @@ class ActivityScreen extends ConsumerStatefulWidget {
}

class _ActivityScreenState extends ConsumerState<ActivityScreen> {
static const _loadMoreThreshold = 200.0;

TransactionFilter _filterOption = TransactionFilter.all;
late final ScrollController _scrollController;

@override
void initState() {
super.initState();
_scrollController = ScrollController()..addListener(_onScroll);
}

@override
void dispose() {
_scrollController.removeListener(_onScroll);
_scrollController.dispose();
super.dispose();
}

void _onScroll() {
if (!_scrollController.hasClients) return;
final pos = _scrollController.position;
if (pos.pixels < pos.maxScrollExtent - _loadMoreThreshold) return;

final pagination = ref.read(activeAccountPaginationProvider(_filterOption));
if (pagination == null || pagination.isFetching || !pagination.hasMore) return;

activeAccountPaginationNotifier(ref, _filterOption)?.fetchMore();
Comment thread
dewabisma marked this conversation as resolved.
}

Future<void> _refresh() async {
final pagination = ref.read(activeAccountPaginationProvider(_filterOption));
if (pagination == null || pagination.isFetching) return;

await activeAccountPaginationNotifier(ref, _filterOption)?.loadingRefresh();
}
Comment thread
dewabisma marked this conversation as resolved.
Comment thread
cursor[bot] marked this conversation as resolved.
Comment thread
cursor[bot] marked this conversation as resolved.
Comment thread
dewabisma marked this conversation as resolved.

void _onFilterOptionChanged(TransactionFilter option) {
if (_filterOption == option) return;
Expand All @@ -49,6 +83,7 @@ class _ActivityScreenState extends ConsumerState<ActivityScreen> {
final text = context.themeText;
final accountAsync = ref.watch(activeAccountProvider);
final txAsync = ref.watch(activeAccountTransactionsProvider(_filterOption));
final pagination = ref.watch(activeAccountPaginationProvider(_filterOption));
final formatTxAmount = ref.watch(txAmountDisplayProvider);

final filterButtons = TransactionFilter.values
Expand Down Expand Up @@ -113,41 +148,77 @@ class _ActivityScreenState extends ConsumerState<ActivityScreen> {
otherTransfers: data.otherTransfers,
);
if (all.isEmpty) {
return Center(
child: Text(l10n.activityEmpty, style: text.paragraph?.copyWith(color: colors.textSecondary)),
return RefreshIndicator(
onRefresh: _refresh,
color: colors.textPrimary,
backgroundColor: colors.surface,
child: ListView(
controller: _scrollController,
physics: const AlwaysScrollableScrollPhysics(),
children: [
SizedBox(
height: MediaQuery.sizeOf(context).height * 0.3,
child: Center(
child: Text(
l10n.activityEmpty,
style: text.paragraph?.copyWith(color: colors.textSecondary),
),
),
),
],
),
);
}
final grouped = _groupByDate(all, l10n, appLocale.numberFormatLocale);
final showLoadMoreFooter = pagination != null && pagination.isFetching && pagination.hasMore;

return ListView.builder(
padding: EdgeInsets.zero,
itemCount: grouped.length,
itemBuilder: (context, i) {
final group = grouped[i];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (i > 0) const SizedBox(height: 32),
Text(group.label, style: text.receiveLabel?.copyWith(color: colors.textTertiary)),
...group.transactions.mapIndexed((index, tx) {
final itemData = TxItemData.from(tx, active.account.accountId, colors, l10n);
final isLastItem = index == group.transactions.length - 1;
return buildTxItem(
tx,
itemData,
colors,
text,
l10n,
Comment thread
cursor[bot] marked this conversation as resolved.
formattedAmount: formatTxAmount(itemData.amount, isSend: itemData.isSend).primaryAmount,
isLastItem: isLastItem,
onTap: () {
showTransactionDetailSheet(context, tx, active.account.accountId);
},
);
}),
],
);
},
return RefreshIndicator(
onRefresh: _refresh,
color: colors.textPrimary,
backgroundColor: colors.surface,
child: ListView.builder(
key: ValueKey(_filterOption),
controller: _scrollController,
physics: const AlwaysScrollableScrollPhysics(),
padding: EdgeInsets.zero,
itemCount: grouped.length + (showLoadMoreFooter ? 1 : 0),
itemBuilder: (context, i) {
if (showLoadMoreFooter && i == grouped.length) {
return const Padding(
padding: EdgeInsets.symmetric(vertical: 24),
child: Center(child: Loader()),
);
}

final group = grouped[i];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (i > 0) const SizedBox(height: 32),
Text(group.label, style: text.receiveLabel?.copyWith(color: colors.textTertiary)),
...group.transactions.mapIndexed((index, tx) {
final itemData = TxItemData.from(tx, active.account.accountId, colors, l10n);
final isLastItem = index == group.transactions.length - 1;
return buildTxItem(
tx,
itemData,
colors,
text,
l10n,
formattedAmount: formatTxAmount(
itemData.amount,
isSend: itemData.isSend,
).primaryAmount,
isLastItem: isLastItem,
onTap: () {
showTransactionDetailSheet(context, tx, active.account.accountId);
},
);
}),
],
);
},
),
);
},
);
Expand Down
Loading
Loading