✨ Pin code
🐛 Bug fixes
This commit is contained in:
parent
f73cf10a54
commit
006841cf82
@ -65,6 +65,8 @@
|
||||
"authFactorTOTPDescription": "A one-time code generated by a TOTP authenticator such as Google Authenticator or Authy.",
|
||||
"authFactorInAppNotify": "In-app notification",
|
||||
"authFactorInAppNotifyDescription": "A one-time code sent via in-app notification.",
|
||||
"authFactorPin": "Pin Code",
|
||||
"authFactorPinDescription": "It consists of 6 digits. It cannot be used to log in. When performing some dangerous operations, the system will ask you to enter this PIN for confirmation.",
|
||||
"realms": "Realms",
|
||||
"createRealm": "Create a Realm",
|
||||
"createRealmHint": "Meet friends with same interests, build communities, and more.",
|
||||
@ -72,6 +74,8 @@
|
||||
"deleteRealm": "Delete Realm",
|
||||
"deleteRealmHint": "Are you sure to delete this realm? This will also deleted all the channels, publishers, and posts under this realm.",
|
||||
"explore": "Explore",
|
||||
"exploreFilterSubscriptions": "Subscriptions",
|
||||
"exploreFilterFriends": "Friends",
|
||||
"account": "Account",
|
||||
"name": "Name",
|
||||
"description": "Description",
|
||||
@ -460,5 +464,7 @@
|
||||
"unspecified": "Unspecified",
|
||||
"added": "Added",
|
||||
"preview": "Preview",
|
||||
"togglePreview": "Toggle Preview"
|
||||
"togglePreview": "Toggle Preview",
|
||||
"subscribe": "Subscribe",
|
||||
"unsubscribe": "Unsubscribe"
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ sealed class SnPublisherStats with _$SnPublisherStats {
|
||||
sealed class SnSubscriptionStatus with _$SnSubscriptionStatus {
|
||||
const factory SnSubscriptionStatus({
|
||||
required bool isSubscribed,
|
||||
required int publisherId,
|
||||
required String publisherId,
|
||||
required String publisherName,
|
||||
}) = _SnSubscriptionStatus;
|
||||
|
||||
|
@ -789,7 +789,7 @@ as int,
|
||||
/// @nodoc
|
||||
mixin _$SnSubscriptionStatus {
|
||||
|
||||
bool get isSubscribed; int get publisherId; String get publisherName;
|
||||
bool get isSubscribed; String get publisherId; String get publisherName;
|
||||
/// Create a copy of SnSubscriptionStatus
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@ -822,7 +822,7 @@ abstract mixin class $SnSubscriptionStatusCopyWith<$Res> {
|
||||
factory $SnSubscriptionStatusCopyWith(SnSubscriptionStatus value, $Res Function(SnSubscriptionStatus) _then) = _$SnSubscriptionStatusCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
bool isSubscribed, int publisherId, String publisherName
|
||||
bool isSubscribed, String publisherId, String publisherName
|
||||
});
|
||||
|
||||
|
||||
@ -843,7 +843,7 @@ class _$SnSubscriptionStatusCopyWithImpl<$Res>
|
||||
return _then(_self.copyWith(
|
||||
isSubscribed: null == isSubscribed ? _self.isSubscribed : isSubscribed // ignore: cast_nullable_to_non_nullable
|
||||
as bool,publisherId: null == publisherId ? _self.publisherId : publisherId // ignore: cast_nullable_to_non_nullable
|
||||
as int,publisherName: null == publisherName ? _self.publisherName : publisherName // ignore: cast_nullable_to_non_nullable
|
||||
as String,publisherName: null == publisherName ? _self.publisherName : publisherName // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
@ -859,7 +859,7 @@ class _SnSubscriptionStatus implements SnSubscriptionStatus {
|
||||
factory _SnSubscriptionStatus.fromJson(Map<String, dynamic> json) => _$SnSubscriptionStatusFromJson(json);
|
||||
|
||||
@override final bool isSubscribed;
|
||||
@override final int publisherId;
|
||||
@override final String publisherId;
|
||||
@override final String publisherName;
|
||||
|
||||
/// Create a copy of SnSubscriptionStatus
|
||||
@ -895,7 +895,7 @@ abstract mixin class _$SnSubscriptionStatusCopyWith<$Res> implements $SnSubscrip
|
||||
factory _$SnSubscriptionStatusCopyWith(_SnSubscriptionStatus value, $Res Function(_SnSubscriptionStatus) _then) = __$SnSubscriptionStatusCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
bool isSubscribed, int publisherId, String publisherName
|
||||
bool isSubscribed, String publisherId, String publisherName
|
||||
});
|
||||
|
||||
|
||||
@ -916,7 +916,7 @@ class __$SnSubscriptionStatusCopyWithImpl<$Res>
|
||||
return _then(_SnSubscriptionStatus(
|
||||
isSubscribed: null == isSubscribed ? _self.isSubscribed : isSubscribed // ignore: cast_nullable_to_non_nullable
|
||||
as bool,publisherId: null == publisherId ? _self.publisherId : publisherId // ignore: cast_nullable_to_non_nullable
|
||||
as int,publisherName: null == publisherName ? _self.publisherName : publisherName // ignore: cast_nullable_to_non_nullable
|
||||
as String,publisherName: null == publisherName ? _self.publisherName : publisherName // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ _SnSubscriptionStatus _$SnSubscriptionStatusFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _SnSubscriptionStatus(
|
||||
isSubscribed: json['is_subscribed'] as bool,
|
||||
publisherId: (json['publisher_id'] as num).toInt(),
|
||||
publisherId: json['publisher_id'] as String,
|
||||
publisherName: json['publisher_name'] as String,
|
||||
);
|
||||
|
||||
|
@ -66,10 +66,10 @@ class AccountScreen extends HookConsumerWidget {
|
||||
}
|
||||
|
||||
return AppScaffold(
|
||||
extendBody: false, // Prevent conflicts with tabs navigation
|
||||
noBackground: isWide,
|
||||
appBar: AppBar(title: const Text('account').tr()),
|
||||
appBar: AppBar(backgroundColor: Colors.transparent, toolbarHeight: 0),
|
||||
body: SingleChildScrollView(
|
||||
padding: getTabbedPadding(context),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Card(
|
||||
@ -144,7 +144,7 @@ class AccountScreen extends HookConsumerWidget {
|
||||
level: user.value!.profile.level,
|
||||
experience: user.value!.profile.experience,
|
||||
progress: user.value!.profile.levelingProgress,
|
||||
).padding(horizontal: 8),
|
||||
).padding(horizontal: 12),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -138,13 +139,13 @@ class AuthFactorSheet extends HookConsumerWidget {
|
||||
children: [
|
||||
if (factor.enabledAt == null)
|
||||
Badge(
|
||||
label: Text('authFactorDisabled'.tr()),
|
||||
label: Text('authFactorDisabled').tr(),
|
||||
textColor: Theme.of(context).colorScheme.onSecondary,
|
||||
backgroundColor: Theme.of(context).colorScheme.secondary,
|
||||
)
|
||||
else
|
||||
Badge(
|
||||
label: Text('authFactorEnabled'.tr()),
|
||||
label: Text('authFactorEnabled').tr(),
|
||||
textColor: Theme.of(context).colorScheme.onPrimary,
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
@ -217,6 +218,8 @@ class AuthFactorNewSheet extends HookConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
final width = math.min(400, MediaQuery.of(context).size.width);
|
||||
|
||||
return SheetScaffold(
|
||||
titleText: 'authFactorNew'.tr(),
|
||||
child: Column(
|
||||
@ -248,7 +251,7 @@ class AuthFactorNewSheet extends HookConsumerWidget {
|
||||
}
|
||||
},
|
||||
),
|
||||
if (factorType.value == 0)
|
||||
if ([0].contains(factorType.value))
|
||||
TextField(
|
||||
controller: secretController,
|
||||
decoration: InputDecoration(
|
||||
@ -259,6 +262,20 @@ class AuthFactorNewSheet extends HookConsumerWidget {
|
||||
),
|
||||
onTapOutside:
|
||||
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
)
|
||||
else if ([4].contains(factorType.value))
|
||||
OtpTextField(
|
||||
showCursor: false,
|
||||
numberOfFields: 6,
|
||||
obscureText: false,
|
||||
showFieldAsBox: true,
|
||||
focusedBorderColor: Theme.of(context).colorScheme.primary,
|
||||
fieldWidth: (width / 6) - 10,
|
||||
keyboardType: TextInputType.number,
|
||||
onSubmit: (String verificationCode) {
|
||||
secretController.text = verificationCode;
|
||||
},
|
||||
textStyle: Theme.of(context).textTheme.titleLarge!,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
|
@ -40,6 +40,7 @@ final Map<int, (String, String, IconData)> kFactorTypes = {
|
||||
Symbols.notifications_active,
|
||||
),
|
||||
3: ('authFactorTOTP', 'authFactorTOTPDescription', Symbols.timer),
|
||||
4: ('authFactorPin', 'authFactorPinDescription', Symbols.nest_secure_alarm),
|
||||
};
|
||||
|
||||
@RoutePage()
|
||||
|
@ -368,10 +368,10 @@ class ChatListScreen extends HookConsumerWidget {
|
||||
ref.invalidate(chatroomsJoinedProvider);
|
||||
}),
|
||||
child: ListView.builder(
|
||||
padding:
|
||||
callState.isConnected
|
||||
? EdgeInsets.only(bottom: 96)
|
||||
: EdgeInsets.zero,
|
||||
padding: getTabbedPadding(
|
||||
context,
|
||||
bottom: callState.isConnected ? 96 : null,
|
||||
),
|
||||
itemCount:
|
||||
items
|
||||
.where(
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/activity.dart';
|
||||
@ -46,10 +47,8 @@ class ExploreShellScreen extends ConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@RoutePage()
|
||||
class ExploreScreen extends ConsumerWidget {
|
||||
class ExploreScreen extends HookConsumerWidget {
|
||||
final bool isAside;
|
||||
const ExploreScreen({super.key, this.isAside = false});
|
||||
|
||||
@ -60,12 +59,67 @@ class ExploreScreen extends ConsumerWidget {
|
||||
return const EmptyPageHolder();
|
||||
}
|
||||
|
||||
final activitiesNotifier = ref.watch(activityListNotifierProvider.notifier);
|
||||
final tabController = useTabController(initialLength: 3);
|
||||
final currentFilter = useState<String?>(null);
|
||||
|
||||
useEffect(() {
|
||||
void listener() {
|
||||
switch (tabController.index) {
|
||||
case 0:
|
||||
currentFilter.value = null;
|
||||
break;
|
||||
case 1:
|
||||
currentFilter.value = 'subscriptions';
|
||||
break;
|
||||
case 2:
|
||||
currentFilter.value = 'friends';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tabController.addListener(listener);
|
||||
return () => tabController.removeListener(listener);
|
||||
}, [tabController]);
|
||||
|
||||
final activitiesNotifier = ref.watch(
|
||||
activityListNotifierProvider(currentFilter.value).notifier,
|
||||
);
|
||||
|
||||
return TourTriggerWidget(
|
||||
child: AppScaffold(
|
||||
extendBody: false, // Prevent conflicts with tabs navigation
|
||||
appBar: AppBar(title: const Text('explore').tr()),
|
||||
appBar: AppBar(
|
||||
toolbarHeight: 0,
|
||||
bottom: TabBar(
|
||||
controller: tabController,
|
||||
tabs: [
|
||||
Tab(
|
||||
child: Text(
|
||||
'explore'.tr(),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).appBarTheme.foregroundColor!,
|
||||
),
|
||||
),
|
||||
),
|
||||
Tab(
|
||||
child: Text(
|
||||
'exploreFilterSubscriptions'.tr(),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).appBarTheme.foregroundColor!,
|
||||
),
|
||||
),
|
||||
),
|
||||
Tab(
|
||||
child: Text(
|
||||
'exploreFilterFriends'.tr(),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).appBarTheme.foregroundColor!,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
heroTag: Key("explore-page-fab"),
|
||||
onPressed: () {
|
||||
@ -78,32 +132,49 @@ class ExploreScreen extends ConsumerWidget {
|
||||
child: const Icon(Symbols.edit),
|
||||
),
|
||||
floatingActionButtonLocation: TabbedFabLocation(context),
|
||||
body: RefreshIndicator(
|
||||
onRefresh: () => Future.sync(activitiesNotifier.forceRefresh),
|
||||
child: PagingHelperView(
|
||||
provider: activityListNotifierProvider,
|
||||
futureRefreshable: activityListNotifierProvider.future,
|
||||
notifierRefreshable: activityListNotifierProvider.notifier,
|
||||
contentBuilder:
|
||||
(data, widgetCount, endItemView) => Center(
|
||||
child: _ActivityListView(
|
||||
data: data,
|
||||
widgetCount: widgetCount,
|
||||
endItemView: endItemView,
|
||||
activitiesNotifier: activitiesNotifier,
|
||||
),
|
||||
),
|
||||
),
|
||||
body: TabBarView(
|
||||
controller: tabController,
|
||||
children: [
|
||||
_buildActivityList(ref, null),
|
||||
_buildActivityList(ref, 'subscriptions'),
|
||||
_buildActivityList(ref, 'friends'),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildActivityList(WidgetRef ref, String? filter) {
|
||||
final activitiesNotifier = ref.watch(
|
||||
activityListNotifierProvider(filter).notifier,
|
||||
);
|
||||
|
||||
return RefreshIndicator(
|
||||
onRefresh: () => Future.sync(activitiesNotifier.forceRefresh),
|
||||
child: PagingHelperView(
|
||||
provider: activityListNotifierProvider(filter),
|
||||
futureRefreshable: activityListNotifierProvider(filter).future,
|
||||
notifierRefreshable: activityListNotifierProvider(filter).notifier,
|
||||
contentBuilder:
|
||||
(data, widgetCount, endItemView) => Center(
|
||||
child: _ActivityListView(
|
||||
data: data,
|
||||
widgetCount: widgetCount,
|
||||
endItemView: endItemView,
|
||||
activitiesNotifier: activitiesNotifier,
|
||||
contentOnly: filter != null,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ActivityListView extends HookConsumerWidget {
|
||||
final CursorPagingData<SnActivity> data;
|
||||
final int widgetCount;
|
||||
final Widget endItemView;
|
||||
final bool contentOnly;
|
||||
final ActivityListNotifier activitiesNotifier;
|
||||
|
||||
const _ActivityListView({
|
||||
@ -111,6 +182,7 @@ class _ActivityListView extends HookConsumerWidget {
|
||||
required this.widgetCount,
|
||||
required this.endItemView,
|
||||
required this.activitiesNotifier,
|
||||
this.contentOnly = false,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -119,7 +191,8 @@ class _ActivityListView extends HookConsumerWidget {
|
||||
|
||||
return CustomScrollView(
|
||||
slivers: [
|
||||
if (user.hasValue) SliverToBoxAdapter(child: CheckInWidget()),
|
||||
if (user.hasValue && !contentOnly)
|
||||
SliverToBoxAdapter(child: CheckInWidget()),
|
||||
SliverList.builder(
|
||||
itemCount: widgetCount,
|
||||
itemBuilder: (context, index) {
|
||||
@ -178,7 +251,7 @@ class _ActivityListView extends HookConsumerWidget {
|
||||
return Column(children: [itemWidget, const Divider(height: 1)]);
|
||||
},
|
||||
),
|
||||
SliverGap(MediaQuery.of(context).padding.bottom + 16),
|
||||
SliverGap(getTabbedPadding(context).bottom),
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -188,16 +261,23 @@ class _ActivityListView extends HookConsumerWidget {
|
||||
class ActivityListNotifier extends _$ActivityListNotifier
|
||||
with CursorPagingNotifierMixin<SnActivity> {
|
||||
@override
|
||||
Future<CursorPagingData<SnActivity>> build() => fetch(cursor: null);
|
||||
Future<CursorPagingData<SnActivity>> build(String? filter) =>
|
||||
fetch(cursor: null);
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnActivity>> fetch({required String? cursor}) async {
|
||||
final client = ref.read(apiClientProvider);
|
||||
final take = 20;
|
||||
|
||||
final queryParameters = {
|
||||
if (cursor != null) 'cursor': cursor,
|
||||
'take': take,
|
||||
if (filter != null) 'filter': filter,
|
||||
};
|
||||
|
||||
final response = await client.get(
|
||||
'/activities',
|
||||
queryParameters: {if (cursor != null) 'cursor': cursor, 'take': take},
|
||||
queryParameters: queryParameters,
|
||||
);
|
||||
|
||||
final List<SnActivity> items =
|
||||
|
@ -7,25 +7,174 @@ part of 'explore.dart';
|
||||
// **************************************************************************
|
||||
|
||||
String _$activityListNotifierHash() =>
|
||||
r'c9683035f7a66a2f331689e274642b60064fbb2e';
|
||||
r'14ec2f211c86e1e64a9a34b142d0e8f78ff6361a';
|
||||
|
||||
/// 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));
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _$ActivityListNotifier
|
||||
extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnActivity>> {
|
||||
late final String? filter;
|
||||
|
||||
FutureOr<CursorPagingData<SnActivity>> build(String? filter);
|
||||
}
|
||||
|
||||
/// See also [ActivityListNotifier].
|
||||
@ProviderFor(ActivityListNotifier)
|
||||
final activityListNotifierProvider = AutoDisposeAsyncNotifierProvider<
|
||||
ActivityListNotifier,
|
||||
CursorPagingData<SnActivity>
|
||||
>.internal(
|
||||
ActivityListNotifier.new,
|
||||
name: r'activityListNotifierProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$activityListNotifierHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
const activityListNotifierProvider = ActivityListNotifierFamily();
|
||||
|
||||
/// See also [ActivityListNotifier].
|
||||
class ActivityListNotifierFamily
|
||||
extends Family<AsyncValue<CursorPagingData<SnActivity>>> {
|
||||
/// See also [ActivityListNotifier].
|
||||
const ActivityListNotifierFamily();
|
||||
|
||||
/// See also [ActivityListNotifier].
|
||||
ActivityListNotifierProvider call(String? filter) {
|
||||
return ActivityListNotifierProvider(filter);
|
||||
}
|
||||
|
||||
@override
|
||||
ActivityListNotifierProvider getProviderOverride(
|
||||
covariant ActivityListNotifierProvider provider,
|
||||
) {
|
||||
return call(provider.filter);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'activityListNotifierProvider';
|
||||
}
|
||||
|
||||
/// See also [ActivityListNotifier].
|
||||
class ActivityListNotifierProvider
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderImpl<
|
||||
ActivityListNotifier,
|
||||
CursorPagingData<SnActivity>
|
||||
> {
|
||||
/// See also [ActivityListNotifier].
|
||||
ActivityListNotifierProvider(String? filter)
|
||||
: this._internal(
|
||||
() => ActivityListNotifier()..filter = filter,
|
||||
from: activityListNotifierProvider,
|
||||
name: r'activityListNotifierProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$activityListNotifierHash,
|
||||
dependencies: ActivityListNotifierFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
ActivityListNotifierFamily._allTransitiveDependencies,
|
||||
filter: filter,
|
||||
);
|
||||
|
||||
ActivityListNotifierProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.filter,
|
||||
}) : super.internal();
|
||||
|
||||
final String? filter;
|
||||
|
||||
@override
|
||||
FutureOr<CursorPagingData<SnActivity>> runNotifierBuild(
|
||||
covariant ActivityListNotifier notifier,
|
||||
) {
|
||||
return notifier.build(filter);
|
||||
}
|
||||
|
||||
@override
|
||||
Override overrideWith(ActivityListNotifier Function() create) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: ActivityListNotifierProvider._internal(
|
||||
() => create()..filter = filter,
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
filter: filter,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeAsyncNotifierProviderElement<
|
||||
ActivityListNotifier,
|
||||
CursorPagingData<SnActivity>
|
||||
>
|
||||
createElement() {
|
||||
return _ActivityListNotifierProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is ActivityListNotifierProvider && other.filter == filter;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, filter.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin ActivityListNotifierRef
|
||||
on AutoDisposeAsyncNotifierProviderRef<CursorPagingData<SnActivity>> {
|
||||
/// The parameter `filter` of this provider.
|
||||
String? get filter;
|
||||
}
|
||||
|
||||
class _ActivityListNotifierProviderElement
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderElement<
|
||||
ActivityListNotifier,
|
||||
CursorPagingData<SnActivity>
|
||||
>
|
||||
with ActivityListNotifierRef {
|
||||
_ActivityListNotifierProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String? get filter => (origin as ActivityListNotifierProvider).filter;
|
||||
}
|
||||
|
||||
typedef _$ActivityListNotifier =
|
||||
AutoDisposeAsyncNotifier<CursorPagingData<SnActivity>>;
|
||||
// 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
|
||||
|
@ -161,48 +161,34 @@ class PublisherProfileScreen extends HookConsumerWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
subStatus.when(
|
||||
data:
|
||||
(status) => IconButton(
|
||||
onPressed:
|
||||
subscribing.value
|
||||
? null
|
||||
: (status.isSubscribed
|
||||
? unsubscribe
|
||||
: subscribe),
|
||||
icon: Icon(
|
||||
status.isSubscribed
|
||||
? Icons.remove_circle
|
||||
: Icons.add_circle,
|
||||
shadows: [appbarShadow],
|
||||
),
|
||||
),
|
||||
error: (_, _) => const SizedBox(),
|
||||
loading:
|
||||
() => const SizedBox(
|
||||
width: 48,
|
||||
height: 48,
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const Gap(8),
|
||||
],
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
spacing: 20,
|
||||
children: [
|
||||
ProfilePictureWidget(file: data.picture, radius: 32),
|
||||
GestureDetector(
|
||||
child: Badge(
|
||||
isLabelVisible: data.type == 0,
|
||||
padding: EdgeInsets.all(4),
|
||||
label: Icon(
|
||||
Symbols.launch,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onPrimary,
|
||||
),
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.primary,
|
||||
offset: Offset(0, 48),
|
||||
child: ProfilePictureWidget(
|
||||
file: data.picture,
|
||||
radius: 32,
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.pop(context, true);
|
||||
context.router.pushPath('/account/${data.name}');
|
||||
},
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
@ -242,19 +228,49 @@ class PublisherProfileScreen extends HookConsumerWidget {
|
||||
uname: data.account!.name,
|
||||
padding: EdgeInsets.zero,
|
||||
),
|
||||
OutlinedButton.icon(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
context.router.pushPath(
|
||||
'/account/${data.name}',
|
||||
);
|
||||
},
|
||||
icon: const Icon(Symbols.launch),
|
||||
label: Text('accountProfileView').tr(),
|
||||
style: ButtonStyle(
|
||||
visualDensity: VisualDensity(vertical: -2),
|
||||
),
|
||||
).padding(top: 8),
|
||||
subStatus
|
||||
.when(
|
||||
data:
|
||||
(status) => FilledButton.icon(
|
||||
onPressed:
|
||||
subscribing.value
|
||||
? null
|
||||
: (status.isSubscribed
|
||||
? unsubscribe
|
||||
: subscribe),
|
||||
icon: Icon(
|
||||
status.isSubscribed
|
||||
? Symbols.remove_circle
|
||||
: Symbols.add_circle,
|
||||
),
|
||||
label:
|
||||
Text(
|
||||
status.isSubscribed
|
||||
? 'unsubscribe'
|
||||
: 'subscribe',
|
||||
).tr(),
|
||||
style: ButtonStyle(
|
||||
visualDensity: VisualDensity(
|
||||
vertical: -2,
|
||||
),
|
||||
),
|
||||
),
|
||||
error: (_, _) => const SizedBox(),
|
||||
loading:
|
||||
() => const SizedBox(
|
||||
height: 36,
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.padding(top: 8),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -13,6 +13,7 @@ import 'package:island/pods/config.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/route.gr.dart';
|
||||
import 'package:island/services/file.dart';
|
||||
import 'package:island/services/responsive.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/content/cloud_files.dart';
|
||||
@ -93,9 +94,7 @@ class RealmListScreen extends HookConsumerWidget {
|
||||
children: [
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).padding.bottom,
|
||||
),
|
||||
padding: getTabbedPadding(context),
|
||||
itemCount: value.length,
|
||||
itemBuilder: (context, item) {
|
||||
return ListTile(
|
||||
|
@ -2,7 +2,6 @@ import 'dart:ui';
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/route.gr.dart';
|
||||
import 'package:island/screens/notification.dart';
|
||||
@ -55,12 +54,6 @@ class TabsScreen extends HookConsumerWidget {
|
||||
builder: (context, child, _) {
|
||||
final tabsRouter = AutoTabsRouter.of(context);
|
||||
|
||||
// Check if current route is a tab route
|
||||
final currentRoute = context.router.topRoute;
|
||||
final isTabRoute = routes.any(
|
||||
(route) => route.routeName == currentRoute.name,
|
||||
);
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
Positioned.fill(child: child),
|
||||
|
@ -15,3 +15,24 @@ bool isWiderScreen(BuildContext context) {
|
||||
bool isWidestScreen(BuildContext context) {
|
||||
return MediaQuery.of(context).size.width > kWidescreenWidth;
|
||||
}
|
||||
|
||||
EdgeInsets getTabbedPadding(
|
||||
BuildContext context, {
|
||||
double? horizontal,
|
||||
double? vertical,
|
||||
double? left,
|
||||
double? right,
|
||||
double? top,
|
||||
double? bottom,
|
||||
}) {
|
||||
final bottomPadding = bottom ?? MediaQuery.of(context).padding.bottom + 16;
|
||||
return EdgeInsets.only(
|
||||
left: left ?? horizontal ?? 0,
|
||||
right: right ?? horizontal ?? 0,
|
||||
top: top ?? vertical ?? 0,
|
||||
bottom:
|
||||
bottom != null
|
||||
? bottomPadding
|
||||
: MediaQuery.of(context).padding.bottom + 16,
|
||||
);
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ class LevelingProgressCard extends StatelessWidget {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text('levelingProgress').tr().fontSize(16).bold(),
|
||||
Row(
|
||||
spacing: 8,
|
||||
crossAxisAlignment: CrossAxisAlignment.baseline,
|
||||
|
Loading…
x
Reference in New Issue
Block a user