Prefer auto dispose riverpods

This commit is contained in:
2025-12-06 21:13:18 +08:00
parent 25f23f7f93
commit 71c372ab6c
10 changed files with 600 additions and 671 deletions

View File

@@ -14,7 +14,7 @@ Future<Map<String, dynamic>?> billingUsage(Ref ref) async {
return response.data;
}
final indexedCloudFileListProvider = AsyncNotifierProvider(
final indexedCloudFileListProvider = AsyncNotifierProvider.autoDispose(
IndexedCloudFileListNotifier.new,
);
@@ -76,12 +76,12 @@ class IndexedCloudFileListNotifier extends AsyncNotifier<List<FileListItem>>
queryParameters: queryParameters,
);
final List<String> folders =
(response.data['folders'] as List).map((e) => e as String).toList();
final List<SnCloudFileIndex> files =
(response.data['files'] as List)
.map((e) => SnCloudFileIndex.fromJson(e as Map<String, dynamic>))
.toList();
final List<String> folders = (response.data['folders'] as List)
.map((e) => e as String)
.toList();
final List<SnCloudFileIndex> files = (response.data['files'] as List)
.map((e) => SnCloudFileIndex.fromJson(e as Map<String, dynamic>))
.toList();
final List<FileListItem> items = [
...folders.map((folderName) => FileListItem.folder(folderName)),
@@ -92,7 +92,7 @@ class IndexedCloudFileListNotifier extends AsyncNotifier<List<FileListItem>>
}
}
final unindexedFileListProvider = AsyncNotifierProvider(
final unindexedFileListProvider = AsyncNotifierProvider.autoDispose(
UnindexedFileListNotifier.new,
);
@@ -165,13 +165,13 @@ class UnindexedFileListNotifier extends AsyncNotifier<List<FileListItem>>
totalCount = int.tryParse(response.headers.value('x-total') ?? '0') ?? 0;
final List<SnCloudFile> files =
(response.data as List)
.map((e) => SnCloudFile.fromJson(e as Map<String, dynamic>))
.toList();
final List<SnCloudFile> files = (response.data as List)
.map((e) => SnCloudFile.fromJson(e as Map<String, dynamic>))
.toList();
final List<FileListItem> items =
files.map((file) => FileListItem.unindexedFile(file)).toList();
final List<FileListItem> items = files
.map((file) => FileListItem.unindexedFile(file))
.toList();
return items;
}

View File

@@ -23,7 +23,7 @@ Future<double> socialCredits(Ref ref) async {
return response.data?.toDouble() ?? 0.0;
}
final socialCreditHistoryNotifierProvider = AsyncNotifierProvider(
final socialCreditHistoryNotifierProvider = AsyncNotifierProvider.autoDispose(
SocialCreditHistoryNotifier.new,
);
@@ -45,11 +45,10 @@ class SocialCreditHistoryNotifier
totalCount = int.parse(response.headers.value('X-Total') ?? '0');
final records =
response.data
.map((json) => SnSocialCreditRecord.fromJson(json))
.cast<SnSocialCreditRecord>()
.toList();
final records = response.data
.map((json) => SnSocialCreditRecord.fromJson(json))
.cast<SnSocialCreditRecord>()
.toList();
return records;
}
@@ -68,39 +67,36 @@ class SocialCreditsTab extends HookConsumerWidget {
margin: const EdgeInsets.only(left: 16, right: 16, top: 8),
child: socialCredits
.when(
data:
(credits) => Stack(
data: (credits) => Stack(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
credits < 100
? 'socialCreditsLevelPoor'.tr()
: credits < 150
? 'socialCreditsLevelNormal'.tr()
: credits < 200
? 'socialCreditsLevelGood'.tr()
: 'socialCreditsLevelExcellent'.tr(),
).tr().bold().fontSize(20),
Text(
'${credits.toStringAsFixed(2)} pts',
).fontSize(14),
const Gap(8),
LinearProgressIndicator(value: credits / 200),
],
),
Positioned(
right: 0,
top: 0,
child: IconButton(
onPressed: () {},
icon: const Icon(Symbols.info),
tooltip: 'socialCreditsDescription'.tr(),
),
),
Text(
credits < 100
? 'socialCreditsLevelPoor'.tr()
: credits < 150
? 'socialCreditsLevelNormal'.tr()
: credits < 200
? 'socialCreditsLevelGood'.tr()
: 'socialCreditsLevelExcellent'.tr(),
).tr().bold().fontSize(20),
Text('${credits.toStringAsFixed(2)} pts').fontSize(14),
const Gap(8),
LinearProgressIndicator(value: credits / 200),
],
),
Positioned(
right: 0,
top: 0,
child: IconButton(
onPressed: () {},
icon: const Icon(Symbols.info),
tooltip: 'socialCreditsDescription'.tr(),
),
),
],
),
error: (_, _) => Text('Error loading credits'),
loading: () => const LinearProgressIndicator(),
)
@@ -119,15 +115,14 @@ class SocialCreditsTab extends HookConsumerWidget {
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
title: Text(
record.reason,
style:
isExpired
? TextStyle(
decoration: TextDecoration.lineThrough,
color: Theme.of(
context,
).colorScheme.onSurface.withOpacity(0.8),
)
: null,
style: isExpired
? TextStyle(
decoration: TextDecoration.lineThrough,
color: Theme.of(
context,
).colorScheme.onSurface.withOpacity(0.8),
)
: null,
),
subtitle: Row(
spacing: 4,

View File

@@ -14,7 +14,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:island/widgets/paging/pagination_list.dart';
import 'package:styled_widget/styled_widget.dart';
final levelingHistoryNotifierProvider = AsyncNotifierProvider(
final levelingHistoryNotifierProvider = AsyncNotifierProvider.autoDispose(
LevelingHistoryNotifier.new,
);
@@ -35,11 +35,10 @@ class LevelingHistoryNotifier extends AsyncNotifier<List<SnExperienceRecord>>
totalCount = int.parse(response.headers.value('X-Total') ?? '0');
final List<SnExperienceRecord> records =
response.data
.map((json) => SnExperienceRecord.fromJson(json))
.cast<SnExperienceRecord>()
.toList();
final List<SnExperienceRecord> records = response.data
.map((json) => SnExperienceRecord.fromJson(json))
.cast<SnExperienceRecord>()
.toList();
return records;
}
@@ -162,8 +161,9 @@ class LevelingScreen extends HookConsumerWidget {
stopIndicatorRadius: 0,
trackGap: 0,
color: Theme.of(context).colorScheme.primary,
backgroundColor:
Theme.of(context).colorScheme.surfaceContainerHigh,
backgroundColor: Theme.of(
context,
).colorScheme.surfaceContainerHigh,
borderRadius: BorderRadius.circular(32),
),
],
@@ -186,38 +186,35 @@ class LevelingScreen extends HookConsumerWidget {
notifier: levelingHistoryNotifierProvider.notifier,
isRefreshable: false,
isSliver: true,
itemBuilder:
(context, idx, record) => ListTile(
title: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(record.reason),
Row(
spacing: 4,
children: [
Text(
record.createdAt.formatRelative(context),
).fontSize(13),
Text('·').fontSize(13).bold(),
Text(record.createdAt.formatSystem()).fontSize(13),
],
).opacity(0.8),
],
),
subtitle: Row(
spacing: 8,
itemBuilder: (context, idx, record) => ListTile(
title: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(record.reason),
Row(
spacing: 4,
children: [
Text(
'${record.delta > 0 ? '+' : ''}${record.delta} EXP',
),
if (record.bonusMultiplier != 1.0)
Text('x${record.bonusMultiplier}'),
record.createdAt.formatRelative(context),
).fontSize(13),
Text('·').fontSize(13).bold(),
Text(record.createdAt.formatSystem()).fontSize(13),
],
),
minTileHeight: 56,
contentPadding: EdgeInsets.symmetric(horizontal: 4),
),
).opacity(0.8),
],
),
subtitle: Row(
spacing: 8,
children: [
Text('${record.delta > 0 ? '+' : ''}${record.delta} EXP'),
if (record.bonusMultiplier != 1.0)
Text('x${record.bonusMultiplier}'),
],
),
minTileHeight: 56,
contentPadding: EdgeInsets.symmetric(horizontal: 4),
),
),
SliverGap(20),
@@ -249,11 +246,10 @@ class LevelStairsPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final paint =
Paint()
..color = surfaceColor.withOpacity(0.2)
..strokeWidth = 1.5
..style = PaintingStyle.stroke;
final paint = Paint()
..color = surfaceColor.withOpacity(0.2)
..strokeWidth = 1.5
..style = PaintingStyle.stroke;
// Draw connecting lines between stairs
for (int i = 0; i < totalLevels - 1; i++) {

View File

@@ -29,7 +29,7 @@ Future<List<SnRelationship>> sentFriendRequest(Ref ref) async {
.toList();
}
final relationshipListNotifierProvider = AsyncNotifierProvider(
final relationshipListNotifierProvider = AsyncNotifierProvider.autoDispose(
RelationshipListNotifier.new,
);
@@ -45,11 +45,10 @@ class RelationshipListNotifier extends AsyncNotifier<List<SnRelationship>>
queryParameters: {'offset': fetchedCount.toString(), 'take': take},
);
final List<SnRelationship> items =
(response.data as List)
.map((e) => SnRelationship.fromJson(e as Map<String, dynamic>))
.cast<SnRelationship>()
.toList();
final List<SnRelationship> items = (response.data as List)
.map((e) => SnRelationship.fromJson(e as Map<String, dynamic>))
.cast<SnRelationship>()
.toList();
totalCount = int.tryParse(response.headers['x-total']?.first ?? '') ?? 0;
@@ -83,8 +82,9 @@ class RelationshipListTile extends StatelessWidget {
@override
Widget build(BuildContext context) {
final account =
showRelatedAccount ? relationship.related : relationship.account;
final account = showRelatedAccount
? relationship.related
: relationship.account;
final isPending =
relationship.status == 0 && relationship.relatedId == currentUserId;
final isWaiting =
@@ -138,64 +138,56 @@ class RelationshipListTile extends StatelessWidget {
],
),
subtitle: Text('@${account.name}'),
trailing:
showActions
? Row(
mainAxisSize: MainAxisSize.min,
children: [
if (isPending && onAccept != null)
IconButton(
padding: EdgeInsets.zero,
onPressed: submitting ? null : onAccept,
icon: const Icon(Symbols.check),
),
if (isPending && onDecline != null)
IconButton(
padding: EdgeInsets.zero,
onPressed: submitting ? null : onDecline,
icon: const Icon(Symbols.close),
),
if (isWaiting && onCancel != null)
IconButton(
padding: EdgeInsets.zero,
onPressed: submitting ? null : onCancel,
icon: const Icon(Symbols.close),
),
if (isEstablished && onUpdateStatus != null)
PopupMenuButton(
padding: EdgeInsets.zero,
icon: const Icon(Symbols.more_vert),
itemBuilder:
(context) => [
if (relationship.status >= 100) // If friend
PopupMenuItem(
child: ListTile(
leading: const Icon(Symbols.block),
title: Text('blockUser').tr(),
contentPadding: EdgeInsets.zero,
),
onTap:
() => onUpdateStatus?.call(
relationship,
-100,
),
)
else if (relationship.status <= -100) // If blocked
PopupMenuItem(
child: ListTile(
leading: const Icon(Symbols.person_add),
title: Text('unblockUser').tr(),
contentPadding: EdgeInsets.zero,
),
onTap:
() =>
onUpdateStatus?.call(relationship, 100),
),
],
),
],
)
: null,
trailing: showActions
? Row(
mainAxisSize: MainAxisSize.min,
children: [
if (isPending && onAccept != null)
IconButton(
padding: EdgeInsets.zero,
onPressed: submitting ? null : onAccept,
icon: const Icon(Symbols.check),
),
if (isPending && onDecline != null)
IconButton(
padding: EdgeInsets.zero,
onPressed: submitting ? null : onDecline,
icon: const Icon(Symbols.close),
),
if (isWaiting && onCancel != null)
IconButton(
padding: EdgeInsets.zero,
onPressed: submitting ? null : onCancel,
icon: const Icon(Symbols.close),
),
if (isEstablished && onUpdateStatus != null)
PopupMenuButton(
padding: EdgeInsets.zero,
icon: const Icon(Symbols.more_vert),
itemBuilder: (context) => [
if (relationship.status >= 100) // If friend
PopupMenuItem(
child: ListTile(
leading: const Icon(Symbols.block),
title: Text('blockUser').tr(),
contentPadding: EdgeInsets.zero,
),
onTap: () => onUpdateStatus?.call(relationship, -100),
)
else if (relationship.status <= -100) // If blocked
PopupMenuItem(
child: ListTile(
leading: const Icon(Symbols.person_add),
title: Text('unblockUser').tr(),
contentPadding: EdgeInsets.zero,
),
onTap: () => onUpdateStatus?.call(relationship, 100),
),
],
),
],
)
: null,
);
}
}
@@ -299,6 +291,7 @@ class RelationshipScreen extends HookConsumerWidget {
const Divider(height: 1),
Expanded(
child: PaginationList(
padding: EdgeInsets.zero,
provider: relationshipListNotifierProvider,
notifier: relationshipListNotifierProvider.notifier,
itemBuilder: (context, index, relationship) {
@@ -380,28 +373,26 @@ class _SentFriendRequestsSheet extends HookConsumerWidget {
const Divider(height: 1),
Expanded(
child: requests.when(
data:
(items) =>
items.isEmpty
? Center(
child: Text(
'friendSentRequestEmpty'.tr(),
textAlign: TextAlign.center,
),
)
: ListView.builder(
shrinkWrap: true,
itemCount: items.length,
itemBuilder: (context, index) {
final request = items[index];
return RelationshipListTile(
relationship: request,
onCancel: () => cancelRequest(request),
currentUserId: user.value?.id,
showRelatedAccount: true,
);
},
),
data: (items) => items.isEmpty
? Center(
child: Text(
'friendSentRequestEmpty'.tr(),
textAlign: TextAlign.center,
),
)
: ListView.builder(
shrinkWrap: true,
itemCount: items.length,
itemBuilder: (context, index) {
final request = items[index];
return RelationshipListTile(
relationship: request,
onCancel: () => cancelRequest(request),
currentUserId: user.value?.id,
showRelatedAccount: true,
);
},
),
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, stack) => Center(child: Text('Error: $error')),
),

View File

@@ -12,7 +12,7 @@ import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/paging/pagination_list.dart';
import 'package:material_symbols_icons/symbols.dart';
final marketplaceWebFeedsNotifierProvider = AsyncNotifierProvider(
final marketplaceWebFeedsNotifierProvider = AsyncNotifierProvider.autoDispose(
MarketplaceWebFeedsNotifier.new,
);

View File

@@ -23,7 +23,7 @@ class DiscoveryRealmsScreen extends HookConsumerWidget {
children: [
CustomScrollView(
slivers: [
SliverGap(80),
SliverGap(88),
SliverRealmList(
query: currentQuery.value,
key: ValueKey(currentQuery.value),

View File

@@ -163,7 +163,7 @@ class NotificationUnreadCountNotifier
}
}
final notificationListProvider = AsyncNotifierProvider(
final notificationListProvider = AsyncNotifierProvider.autoDispose(
NotificationListNotifier.new,
);

View File

@@ -28,9 +28,8 @@ sealed class MarketplaceStickerQuery with _$MarketplaceStickerQuery {
}) = _MarketplaceStickerQuery;
}
final marketplaceStickerPacksNotifierProvider = AsyncNotifierProvider(
MarketplaceStickerPacksNotifier.new,
);
final marketplaceStickerPacksNotifierProvider =
AsyncNotifierProvider.autoDispose(MarketplaceStickerPacksNotifier.new);
class MarketplaceStickerPacksNotifier extends AsyncNotifier<List<SnStickerPack>>
with

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,10 @@
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/realm.dart';
import 'package:island/pods/network.dart';
import 'package:island/pods/paging.dart';
import 'package:island/widgets/paging/pagination_list.dart';
import 'package:island/widgets/realm/realm_card.dart';
import 'package:island/widgets/realm/realm_list_tile.dart';
import 'package:styled_widget/styled_widget.dart';
final realmListNotifierProvider = AsyncNotifierProvider.autoDispose
@@ -51,25 +50,12 @@ class SliverRealmList extends HookConsumerWidget {
notifier: provider.notifier,
isSliver: true,
isRefreshable: false,
spacing: 8,
itemBuilder: (context, index, realm) {
return Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child:
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 540),
child: RealmCard(realm: realm),
).center(),
),
if (index <
(ref.read(provider).value?.length ?? 0) -
1) // Add gap except for last item? Actually PaginationList handles loading indicator which might look like last item.
// Wait, ref.read(provider).value?.length might change.
// Simpler to just add bottom padding to all, or Gap.
const Gap(8),
],
);
return ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 540),
child: RealmListTile(realm: realm),
).center();
},
);
}