From 7fd1fe34e5bf1bfa490399beb24b318a5d664b74 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Thu, 7 Aug 2025 03:00:29 +0800 Subject: [PATCH] :sparkles: Stickers marketplace --- assets/i18n/en-US.json | 9 +- lib/route.dart | 19 ++ lib/screens/account.dart | 11 +- lib/screens/stickers/marketplace.dart | 103 ++++++++ lib/screens/stickers/marketplace.g.dart | 32 +++ lib/screens/stickers/pack_detail.dart | 233 +++++++++++++++++ lib/screens/stickers/pack_detail.g.dart | 317 ++++++++++++++++++++++++ 7 files changed, 722 insertions(+), 2 deletions(-) create mode 100644 lib/screens/stickers/marketplace.dart create mode 100644 lib/screens/stickers/marketplace.g.dart create mode 100644 lib/screens/stickers/pack_detail.dart create mode 100644 lib/screens/stickers/pack_detail.g.dart diff --git a/assets/i18n/en-US.json b/assets/i18n/en-US.json index d5b7716..b947b97 100644 --- a/assets/i18n/en-US.json +++ b/assets/i18n/en-US.json @@ -761,5 +761,12 @@ "publisher": "Publisher", "publisherHint": "Enter the publisher name", "publisherCannotBeEmpty": "Publisher cannot be empty", - "operationFailed": "Operation failed: {}" + "operationFailed": "Operation failed: {}", + "stickerMarketplace": "Sticker Marketplace", + "stickerPackAdded": "Sticker pack added to your collection", + "stickerPackRemoved": "Sticker pack removed from your collection", + "addPack": "Add Pack", + "removePack": "Remove Pack", + "browseAndAddStickers": "Browse and add sticker packs", + "stickerPack": "Sticker Pack" } diff --git a/lib/route.dart b/lib/route.dart index dcd1319..cc7f743 100644 --- a/lib/route.dart +++ b/lib/route.dart @@ -28,6 +28,8 @@ import 'package:island/screens/creators/hub.dart'; import 'package:island/screens/creators/posts/post_manage_list.dart'; import 'package:island/screens/creators/stickers/stickers.dart'; import 'package:island/screens/creators/stickers/pack_detail.dart'; +import 'package:island/screens/stickers/marketplace.dart'; +import 'package:island/screens/stickers/pack_detail.dart'; import 'package:island/screens/creators/poll/poll_list.dart'; import 'package:island/screens/creators/publishers.dart'; import 'package:island/screens/creators/webfeed/webfeed_list.dart'; @@ -451,6 +453,23 @@ final routerProvider = Provider((ref) { path: '/account', builder: (context, state) => const AccountScreen(), ), + // Sticker marketplace (user-facing, no publisher) + GoRoute( + name: 'stickerMarketplace', + path: '/stickers', + builder: + (context, state) => const MarketplaceStickersScreen(), + routes: [ + GoRoute( + name: 'stickerPackDetail', + path: ':packId', + builder: (context, state) { + final packId = state.pathParameters['packId']!; + return MarketplaceStickerPackDetailScreen(id: packId); + }, + ), + ], + ), GoRoute( name: 'notifications', path: '/account/notifications', diff --git a/lib/screens/account.dart b/lib/screens/account.dart index 74b937a..65702e8 100644 --- a/lib/screens/account.dart +++ b/lib/screens/account.dart @@ -189,7 +189,6 @@ class AccountScreen extends HookConsumerWidget { ), ], ).padding(horizontal: 8), - const Gap(8), ListTile( minTileHeight: 48, leading: const Icon(Symbols.notifications), @@ -228,6 +227,16 @@ class AccountScreen extends HookConsumerWidget { context.pushNamed('relationships'); }, ), + ListTile( + minTileHeight: 48, + leading: const Icon(Symbols.emoji_emotions), + trailing: const Icon(Symbols.chevron_right), + contentPadding: EdgeInsets.symmetric(horizontal: 24), + title: Text('stickers').tr(), + onTap: () { + context.pushNamed('stickerMarketplace'); + }, + ), ListTile( minTileHeight: 48, title: Text('abuseReports').tr(), diff --git a/lib/screens/stickers/marketplace.dart b/lib/screens/stickers/marketplace.dart new file mode 100644 index 0000000..5cbd331 --- /dev/null +++ b/lib/screens/stickers/marketplace.dart @@ -0,0 +1,103 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:gap/gap.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:island/models/sticker.dart'; +import 'package:island/pods/network.dart'; +import 'package:island/widgets/app_scaffold.dart'; +import 'package:material_symbols_icons/symbols.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; +import 'package:riverpod_paging_utils/riverpod_paging_utils.dart'; + +part 'marketplace.g.dart'; + +@riverpod +class MarketplaceStickerPacksNotifier extends _$MarketplaceStickerPacksNotifier + with CursorPagingNotifierMixin { + @override + Future> build() { + return fetch(cursor: null); + } + + @override + Future> fetch({ + required String? cursor, + }) async { + final client = ref.read(apiClientProvider); + final offset = cursor == null ? 0 : int.parse(cursor); + + final response = await client.get( + '/sphere/stickers', + queryParameters: {'offset': offset, 'take': 20}, + ); + + final total = int.parse(response.headers.value('X-Total') ?? '0'); + final List data = response.data; + final stickers = data.map((e) => SnStickerPack.fromJson(e)).toList(); + + final hasMore = offset + stickers.length < total; + final nextCursor = hasMore ? (offset + stickers.length).toString() : null; + + return CursorPagingData( + items: stickers, + hasMore: hasMore, + nextCursor: nextCursor, + ); + } +} + +/// User-facing marketplace screen for browsing sticker packs. +/// This version does NOT rely on publisher name (no pubName). +class MarketplaceStickersScreen extends HookConsumerWidget { + const MarketplaceStickersScreen({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return AppScaffold( + appBar: AppBar( + title: const Text('stickers').tr(), + actions: const [Gap(8)], + ), + body: const SliverMarketplaceStickerPacksList(), + ); + } +} + +class SliverMarketplaceStickerPacksList extends HookConsumerWidget { + const SliverMarketplaceStickerPacksList({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return PagingHelperView( + provider: marketplaceStickerPacksNotifierProvider, + futureRefreshable: marketplaceStickerPacksNotifierProvider.future, + notifierRefreshable: marketplaceStickerPacksNotifierProvider.notifier, + contentBuilder: + (data, widgetCount, endItemView) => ListView.builder( + padding: EdgeInsets.zero, + itemCount: widgetCount, + itemBuilder: (context, index) { + if (index == widgetCount - 1) { + return endItemView; + } + + final pack = data.items[index]; + return ListTile( + title: Text(pack.name), + subtitle: Text(pack.description), + trailing: const Icon(Symbols.chevron_right), + onTap: () { + // Navigate to user-facing sticker pack detail page. + // Adjust the route name/parameters if your app uses different ones. + context.pushNamed( + 'stickerPackDetail', + pathParameters: {'packId': pack.id}, + ); + }, + ); + }, + ), + ); + } +} diff --git a/lib/screens/stickers/marketplace.g.dart b/lib/screens/stickers/marketplace.g.dart new file mode 100644 index 0000000..939b81f --- /dev/null +++ b/lib/screens/stickers/marketplace.g.dart @@ -0,0 +1,32 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'marketplace.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$marketplaceStickerPacksNotifierHash() => + r'b62ae8b7f5c4f8bb3be8c17fc005ea26da355187'; + +/// See also [MarketplaceStickerPacksNotifier]. +@ProviderFor(MarketplaceStickerPacksNotifier) +final marketplaceStickerPacksNotifierProvider = + AutoDisposeAsyncNotifierProvider< + MarketplaceStickerPacksNotifier, + CursorPagingData + >.internal( + MarketplaceStickerPacksNotifier.new, + name: r'marketplaceStickerPacksNotifierProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$marketplaceStickerPacksNotifierHash, + dependencies: null, + allTransitiveDependencies: null, + ); + +typedef _$MarketplaceStickerPacksNotifier = + AutoDisposeAsyncNotifier>; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/lib/screens/stickers/pack_detail.dart b/lib/screens/stickers/pack_detail.dart new file mode 100644 index 0000000..f065d50 --- /dev/null +++ b/lib/screens/stickers/pack_detail.dart @@ -0,0 +1,233 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:gap/gap.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:island/models/sticker.dart'; +import 'package:island/pods/network.dart'; +import 'package:island/screens/creators/stickers/stickers.dart'; +import 'package:island/widgets/app_scaffold.dart'; +import 'package:island/widgets/content/cloud_files.dart'; +import 'package:material_symbols_icons/symbols.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; +import 'package:styled_widget/styled_widget.dart'; + +part 'pack_detail.g.dart'; // generated by riverpod_annotation build_runner + +/// Marketplace version of sticker pack detail page (no publisher dependency). +/// Shows all stickers in the pack and provides a button to add the sticker. +/// API interactions are intentionally left blank per request. +@riverpod +Future> marketplaceStickerPackContent( + Ref ref, { + required String packId, +}) async { + final apiClient = ref.watch(apiClientProvider); + final resp = await apiClient.get('/sphere/stickers/$packId/content'); + return (resp.data as List).map((e) => SnSticker.fromJson(e)).toList(); +} + +@riverpod +Future marketplaceStickerPackOwnership( + Ref ref, { + required String packId, +}) async { + final api = ref.watch(apiClientProvider); + try { + await api.get('/sphere/stickers/$packId/own'); + // If not 404, consider owned + return true; + } on Object catch (e) { + // Dio error handling agnostic: treat 404 as not-owned, rethrow others + final msg = e.toString(); + if (msg.contains('404')) return false; + rethrow; + } +} + +class MarketplaceStickerPackDetailScreen extends HookConsumerWidget { + final String id; + const MarketplaceStickerPackDetailScreen({super.key, required this.id}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + // Pack metadata provider exists globally in creators file; reuse it. + final pack = ref.watch(stickerPackProvider(id)); + final packContent = ref.watch( + marketplaceStickerPackContentProvider(packId: id), + ); + final owned = ref.watch( + marketplaceStickerPackOwnershipProvider(packId: id), + ); + + // Add entire pack to user's collection + Future addPackToMyCollection() async { + final apiClient = ref.watch(apiClientProvider); + await apiClient.post('/sphere/stickers/$id/own'); + HapticFeedback.selectionClick(); + ref.invalidate(marketplaceStickerPackOwnershipProvider(packId: id)); + if (!context.mounted) return; + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('stickerPackAdded').tr())); + } + + // Remove ownership of the pack + Future removePackFromMyCollection() async { + final apiClient = ref.watch(apiClientProvider); + await apiClient.delete('/sphere/stickers/$id/own'); + HapticFeedback.selectionClick(); + ref.invalidate(marketplaceStickerPackOwnershipProvider(packId: id)); + if (!context.mounted) return; + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('stickerPackRemoved').tr())); + } + + return AppScaffold( + appBar: AppBar(title: Text(pack.value?.name ?? 'loading'.tr())), + body: pack.when( + data: (p) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + // Pack meta + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text(p?.description ?? ''), + Row( + spacing: 4, + children: [ + const Icon(Symbols.folder, size: 16), + Text( + '${packContent.value?.length ?? 0}/24', + style: GoogleFonts.robotoMono(), + ), + ], + ).opacity(0.85), + Row( + spacing: 4, + children: [ + const Icon(Symbols.sell, size: 16), + Text(p?.prefix ?? '', style: GoogleFonts.robotoMono()), + ], + ).opacity(0.85), + Row( + spacing: 4, + children: [ + const Icon(Symbols.tag, size: 16), + SelectableText( + p?.id ?? id, + style: GoogleFonts.robotoMono(), + ), + ], + ).opacity(0.85), + ], + ).padding(horizontal: 24, vertical: 24), + const Divider(height: 1), + // Stickers grid + Expanded( + child: packContent.when( + data: + (stickers) => RefreshIndicator( + onRefresh: + () => ref.refresh( + marketplaceStickerPackContentProvider( + packId: id, + ).future, + ), + child: GridView.builder( + padding: const EdgeInsets.symmetric( + horizontal: 24, + vertical: 20, + ), + gridDelegate: + const SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 96, + mainAxisSpacing: 12, + crossAxisSpacing: 12, + ), + itemCount: stickers.length, + itemBuilder: (context, index) { + final sticker = stickers[index]; + return Tooltip( + message: ':${p?.prefix ?? ''}${sticker.slug}:', + child: ClipRRect( + borderRadius: const BorderRadius.all( + Radius.circular(8), + ), + child: Container( + decoration: BoxDecoration( + color: + Theme.of( + context, + ).colorScheme.surfaceContainer, + borderRadius: const BorderRadius.all( + Radius.circular(8), + ), + ), + child: AspectRatio( + aspectRatio: 1, + child: CloudImageWidget( + fileId: sticker.imageId, + fit: BoxFit.contain, + ), + ), + ), + ), + ); + }, + ), + ), + error: + (err, _) => + Text( + 'Error: $err', + ).textAlignment(TextAlign.center).center(), + loading: () => const CircularProgressIndicator().center(), + ), + ), + Padding( + padding: EdgeInsets.symmetric(horizontal: 24, vertical: 8), + child: owned.when( + data: + (isOwned) => FilledButton.icon( + onPressed: + isOwned + ? removePackFromMyCollection + : addPackToMyCollection, + icon: Icon( + isOwned ? Symbols.remove_circle : Symbols.add_circle, + ), + label: Text( + isOwned ? 'removePack'.tr() : 'addPack'.tr(), + ), + ), + loading: + () => const SizedBox( + height: 32, + width: 32, + child: CircularProgressIndicator(strokeWidth: 2), + ), + error: + (_, _) => OutlinedButton.icon( + onPressed: addPackToMyCollection, + icon: const Icon(Symbols.add_circle), + label: Text('addPack').tr(), + ), + ), + ), + Gap(MediaQuery.of(context).padding.bottom), + ], + ); + }, + error: + (err, _) => + Text('Error: $err').textAlignment(TextAlign.center).center(), + loading: () => const CircularProgressIndicator().center(), + ), + ); + } +} diff --git a/lib/screens/stickers/pack_detail.g.dart b/lib/screens/stickers/pack_detail.g.dart new file mode 100644 index 0000000..dc23f1e --- /dev/null +++ b/lib/screens/stickers/pack_detail.g.dart @@ -0,0 +1,317 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'pack_detail.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$marketplaceStickerPackContentHash() => + r'886f8305c978dbea6e5d990a7d555048ac704a5d'; + +/// Copied from Dart SDK +class _SystemHash { + _SystemHash._(); + + static int combine(int hash, int value) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + value); + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); + return hash ^ (hash >> 6); + } + + static int finish(int hash) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); + // ignore: parameter_assignments + hash = hash ^ (hash >> 11); + return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); + } +} + +/// Marketplace version of sticker pack detail page (no publisher dependency). +/// Shows all stickers in the pack and provides a button to add the sticker. +/// API interactions are intentionally left blank per request. +/// +/// Copied from [marketplaceStickerPackContent]. +@ProviderFor(marketplaceStickerPackContent) +const marketplaceStickerPackContentProvider = + MarketplaceStickerPackContentFamily(); + +/// Marketplace version of sticker pack detail page (no publisher dependency). +/// Shows all stickers in the pack and provides a button to add the sticker. +/// API interactions are intentionally left blank per request. +/// +/// Copied from [marketplaceStickerPackContent]. +class MarketplaceStickerPackContentFamily + extends Family>> { + /// Marketplace version of sticker pack detail page (no publisher dependency). + /// Shows all stickers in the pack and provides a button to add the sticker. + /// API interactions are intentionally left blank per request. + /// + /// Copied from [marketplaceStickerPackContent]. + const MarketplaceStickerPackContentFamily(); + + /// Marketplace version of sticker pack detail page (no publisher dependency). + /// Shows all stickers in the pack and provides a button to add the sticker. + /// API interactions are intentionally left blank per request. + /// + /// Copied from [marketplaceStickerPackContent]. + MarketplaceStickerPackContentProvider call({required String packId}) { + return MarketplaceStickerPackContentProvider(packId: packId); + } + + @override + MarketplaceStickerPackContentProvider getProviderOverride( + covariant MarketplaceStickerPackContentProvider provider, + ) { + return call(packId: provider.packId); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'marketplaceStickerPackContentProvider'; +} + +/// Marketplace version of sticker pack detail page (no publisher dependency). +/// Shows all stickers in the pack and provides a button to add the sticker. +/// API interactions are intentionally left blank per request. +/// +/// Copied from [marketplaceStickerPackContent]. +class MarketplaceStickerPackContentProvider + extends AutoDisposeFutureProvider> { + /// Marketplace version of sticker pack detail page (no publisher dependency). + /// Shows all stickers in the pack and provides a button to add the sticker. + /// API interactions are intentionally left blank per request. + /// + /// Copied from [marketplaceStickerPackContent]. + MarketplaceStickerPackContentProvider({required String packId}) + : this._internal( + (ref) => marketplaceStickerPackContent( + ref as MarketplaceStickerPackContentRef, + packId: packId, + ), + from: marketplaceStickerPackContentProvider, + name: r'marketplaceStickerPackContentProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$marketplaceStickerPackContentHash, + dependencies: MarketplaceStickerPackContentFamily._dependencies, + allTransitiveDependencies: + MarketplaceStickerPackContentFamily._allTransitiveDependencies, + packId: packId, + ); + + MarketplaceStickerPackContentProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.packId, + }) : super.internal(); + + final String packId; + + @override + Override overrideWith( + FutureOr> Function( + MarketplaceStickerPackContentRef provider, + ) + create, + ) { + return ProviderOverride( + origin: this, + override: MarketplaceStickerPackContentProvider._internal( + (ref) => create(ref as MarketplaceStickerPackContentRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + packId: packId, + ), + ); + } + + @override + AutoDisposeFutureProviderElement> createElement() { + return _MarketplaceStickerPackContentProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is MarketplaceStickerPackContentProvider && + other.packId == packId; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, packId.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin MarketplaceStickerPackContentRef + on AutoDisposeFutureProviderRef> { + /// The parameter `packId` of this provider. + String get packId; +} + +class _MarketplaceStickerPackContentProviderElement + extends AutoDisposeFutureProviderElement> + with MarketplaceStickerPackContentRef { + _MarketplaceStickerPackContentProviderElement(super.provider); + + @override + String get packId => (origin as MarketplaceStickerPackContentProvider).packId; +} + +String _$marketplaceStickerPackOwnershipHash() => + r'e5dd301c309fac958729d13d984ce7a77edbe7e6'; + +/// See also [marketplaceStickerPackOwnership]. +@ProviderFor(marketplaceStickerPackOwnership) +const marketplaceStickerPackOwnershipProvider = + MarketplaceStickerPackOwnershipFamily(); + +/// See also [marketplaceStickerPackOwnership]. +class MarketplaceStickerPackOwnershipFamily extends Family> { + /// See also [marketplaceStickerPackOwnership]. + const MarketplaceStickerPackOwnershipFamily(); + + /// See also [marketplaceStickerPackOwnership]. + MarketplaceStickerPackOwnershipProvider call({required String packId}) { + return MarketplaceStickerPackOwnershipProvider(packId: packId); + } + + @override + MarketplaceStickerPackOwnershipProvider getProviderOverride( + covariant MarketplaceStickerPackOwnershipProvider provider, + ) { + return call(packId: provider.packId); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'marketplaceStickerPackOwnershipProvider'; +} + +/// See also [marketplaceStickerPackOwnership]. +class MarketplaceStickerPackOwnershipProvider + extends AutoDisposeFutureProvider { + /// See also [marketplaceStickerPackOwnership]. + MarketplaceStickerPackOwnershipProvider({required String packId}) + : this._internal( + (ref) => marketplaceStickerPackOwnership( + ref as MarketplaceStickerPackOwnershipRef, + packId: packId, + ), + from: marketplaceStickerPackOwnershipProvider, + name: r'marketplaceStickerPackOwnershipProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$marketplaceStickerPackOwnershipHash, + dependencies: MarketplaceStickerPackOwnershipFamily._dependencies, + allTransitiveDependencies: + MarketplaceStickerPackOwnershipFamily._allTransitiveDependencies, + packId: packId, + ); + + MarketplaceStickerPackOwnershipProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.packId, + }) : super.internal(); + + final String packId; + + @override + Override overrideWith( + FutureOr Function(MarketplaceStickerPackOwnershipRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: MarketplaceStickerPackOwnershipProvider._internal( + (ref) => create(ref as MarketplaceStickerPackOwnershipRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + packId: packId, + ), + ); + } + + @override + AutoDisposeFutureProviderElement createElement() { + return _MarketplaceStickerPackOwnershipProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is MarketplaceStickerPackOwnershipProvider && + other.packId == packId; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, packId.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin MarketplaceStickerPackOwnershipRef on AutoDisposeFutureProviderRef { + /// The parameter `packId` of this provider. + String get packId; +} + +class _MarketplaceStickerPackOwnershipProviderElement + extends AutoDisposeFutureProviderElement + with MarketplaceStickerPackOwnershipRef { + _MarketplaceStickerPackOwnershipProviderElement(super.provider); + + @override + String get packId => + (origin as MarketplaceStickerPackOwnershipProvider).packId; +} + +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package