✨ 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.",
|
"authFactorTOTPDescription": "A one-time code generated by a TOTP authenticator such as Google Authenticator or Authy.",
|
||||||
"authFactorInAppNotify": "In-app notification",
|
"authFactorInAppNotify": "In-app notification",
|
||||||
"authFactorInAppNotifyDescription": "A one-time code sent via 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",
|
"realms": "Realms",
|
||||||
"createRealm": "Create a Realm",
|
"createRealm": "Create a Realm",
|
||||||
"createRealmHint": "Meet friends with same interests, build communities, and more.",
|
"createRealmHint": "Meet friends with same interests, build communities, and more.",
|
||||||
@ -72,6 +74,8 @@
|
|||||||
"deleteRealm": "Delete Realm",
|
"deleteRealm": "Delete Realm",
|
||||||
"deleteRealmHint": "Are you sure to delete this realm? This will also deleted all the channels, publishers, and posts under this realm.",
|
"deleteRealmHint": "Are you sure to delete this realm? This will also deleted all the channels, publishers, and posts under this realm.",
|
||||||
"explore": "Explore",
|
"explore": "Explore",
|
||||||
|
"exploreFilterSubscriptions": "Subscriptions",
|
||||||
|
"exploreFilterFriends": "Friends",
|
||||||
"account": "Account",
|
"account": "Account",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"description": "Description",
|
"description": "Description",
|
||||||
@ -460,5 +464,7 @@
|
|||||||
"unspecified": "Unspecified",
|
"unspecified": "Unspecified",
|
||||||
"added": "Added",
|
"added": "Added",
|
||||||
"preview": "Preview",
|
"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 {
|
sealed class SnSubscriptionStatus with _$SnSubscriptionStatus {
|
||||||
const factory SnSubscriptionStatus({
|
const factory SnSubscriptionStatus({
|
||||||
required bool isSubscribed,
|
required bool isSubscribed,
|
||||||
required int publisherId,
|
required String publisherId,
|
||||||
required String publisherName,
|
required String publisherName,
|
||||||
}) = _SnSubscriptionStatus;
|
}) = _SnSubscriptionStatus;
|
||||||
|
|
||||||
|
@ -789,7 +789,7 @@ as int,
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$SnSubscriptionStatus {
|
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
|
/// Create a copy of SnSubscriptionStatus
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@ -822,7 +822,7 @@ abstract mixin class $SnSubscriptionStatusCopyWith<$Res> {
|
|||||||
factory $SnSubscriptionStatusCopyWith(SnSubscriptionStatus value, $Res Function(SnSubscriptionStatus) _then) = _$SnSubscriptionStatusCopyWithImpl;
|
factory $SnSubscriptionStatusCopyWith(SnSubscriptionStatus value, $Res Function(SnSubscriptionStatus) _then) = _$SnSubscriptionStatusCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$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(
|
return _then(_self.copyWith(
|
||||||
isSubscribed: null == isSubscribed ? _self.isSubscribed : isSubscribed // ignore: cast_nullable_to_non_nullable
|
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 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,
|
as String,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -859,7 +859,7 @@ class _SnSubscriptionStatus implements SnSubscriptionStatus {
|
|||||||
factory _SnSubscriptionStatus.fromJson(Map<String, dynamic> json) => _$SnSubscriptionStatusFromJson(json);
|
factory _SnSubscriptionStatus.fromJson(Map<String, dynamic> json) => _$SnSubscriptionStatusFromJson(json);
|
||||||
|
|
||||||
@override final bool isSubscribed;
|
@override final bool isSubscribed;
|
||||||
@override final int publisherId;
|
@override final String publisherId;
|
||||||
@override final String publisherName;
|
@override final String publisherName;
|
||||||
|
|
||||||
/// Create a copy of SnSubscriptionStatus
|
/// 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;
|
factory _$SnSubscriptionStatusCopyWith(_SnSubscriptionStatus value, $Res Function(_SnSubscriptionStatus) _then) = __$SnSubscriptionStatusCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
bool isSubscribed, int publisherId, String publisherName
|
bool isSubscribed, String publisherId, String publisherName
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -916,7 +916,7 @@ class __$SnSubscriptionStatusCopyWithImpl<$Res>
|
|||||||
return _then(_SnSubscriptionStatus(
|
return _then(_SnSubscriptionStatus(
|
||||||
isSubscribed: null == isSubscribed ? _self.isSubscribed : isSubscribed // ignore: cast_nullable_to_non_nullable
|
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 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,
|
as String,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -172,7 +172,7 @@ _SnSubscriptionStatus _$SnSubscriptionStatusFromJson(
|
|||||||
Map<String, dynamic> json,
|
Map<String, dynamic> json,
|
||||||
) => _SnSubscriptionStatus(
|
) => _SnSubscriptionStatus(
|
||||||
isSubscribed: json['is_subscribed'] as bool,
|
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,
|
publisherName: json['publisher_name'] as String,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -66,10 +66,10 @@ class AccountScreen extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
extendBody: false, // Prevent conflicts with tabs navigation
|
|
||||||
noBackground: isWide,
|
noBackground: isWide,
|
||||||
appBar: AppBar(title: const Text('account').tr()),
|
appBar: AppBar(backgroundColor: Colors.transparent, toolbarHeight: 0),
|
||||||
body: SingleChildScrollView(
|
body: SingleChildScrollView(
|
||||||
|
padding: getTabbedPadding(context),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Card(
|
Card(
|
||||||
@ -144,7 +144,7 @@ class AccountScreen extends HookConsumerWidget {
|
|||||||
level: user.value!.profile.level,
|
level: user.value!.profile.level,
|
||||||
experience: user.value!.profile.experience,
|
experience: user.value!.profile.experience,
|
||||||
progress: user.value!.profile.levelingProgress,
|
progress: user.value!.profile.levelingProgress,
|
||||||
).padding(horizontal: 8),
|
).padding(horizontal: 12),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -138,13 +139,13 @@ class AuthFactorSheet extends HookConsumerWidget {
|
|||||||
children: [
|
children: [
|
||||||
if (factor.enabledAt == null)
|
if (factor.enabledAt == null)
|
||||||
Badge(
|
Badge(
|
||||||
label: Text('authFactorDisabled'.tr()),
|
label: Text('authFactorDisabled').tr(),
|
||||||
textColor: Theme.of(context).colorScheme.onSecondary,
|
textColor: Theme.of(context).colorScheme.onSecondary,
|
||||||
backgroundColor: Theme.of(context).colorScheme.secondary,
|
backgroundColor: Theme.of(context).colorScheme.secondary,
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
Badge(
|
Badge(
|
||||||
label: Text('authFactorEnabled'.tr()),
|
label: Text('authFactorEnabled').tr(),
|
||||||
textColor: Theme.of(context).colorScheme.onPrimary,
|
textColor: Theme.of(context).colorScheme.onPrimary,
|
||||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
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(
|
return SheetScaffold(
|
||||||
titleText: 'authFactorNew'.tr(),
|
titleText: 'authFactorNew'.tr(),
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -248,7 +251,7 @@ class AuthFactorNewSheet extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (factorType.value == 0)
|
if ([0].contains(factorType.value))
|
||||||
TextField(
|
TextField(
|
||||||
controller: secretController,
|
controller: secretController,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@ -259,6 +262,20 @@ class AuthFactorNewSheet extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
onTapOutside:
|
onTapOutside:
|
||||||
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
(_) => 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(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||||
|
@ -40,6 +40,7 @@ final Map<int, (String, String, IconData)> kFactorTypes = {
|
|||||||
Symbols.notifications_active,
|
Symbols.notifications_active,
|
||||||
),
|
),
|
||||||
3: ('authFactorTOTP', 'authFactorTOTPDescription', Symbols.timer),
|
3: ('authFactorTOTP', 'authFactorTOTPDescription', Symbols.timer),
|
||||||
|
4: ('authFactorPin', 'authFactorPinDescription', Symbols.nest_secure_alarm),
|
||||||
};
|
};
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
|
@ -368,10 +368,10 @@ class ChatListScreen extends HookConsumerWidget {
|
|||||||
ref.invalidate(chatroomsJoinedProvider);
|
ref.invalidate(chatroomsJoinedProvider);
|
||||||
}),
|
}),
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
padding:
|
padding: getTabbedPadding(
|
||||||
callState.isConnected
|
context,
|
||||||
? EdgeInsets.only(bottom: 96)
|
bottom: callState.isConnected ? 96 : null,
|
||||||
: EdgeInsets.zero,
|
),
|
||||||
itemCount:
|
itemCount:
|
||||||
items
|
items
|
||||||
.where(
|
.where(
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/activity.dart';
|
import 'package:island/models/activity.dart';
|
||||||
@ -46,10 +47,8 @@ class ExploreShellScreen extends ConsumerWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
class ExploreScreen extends ConsumerWidget {
|
class ExploreScreen extends HookConsumerWidget {
|
||||||
final bool isAside;
|
final bool isAside;
|
||||||
const ExploreScreen({super.key, this.isAside = false});
|
const ExploreScreen({super.key, this.isAside = false});
|
||||||
|
|
||||||
@ -60,12 +59,67 @@ class ExploreScreen extends ConsumerWidget {
|
|||||||
return const EmptyPageHolder();
|
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(
|
return TourTriggerWidget(
|
||||||
child: AppScaffold(
|
child: AppScaffold(
|
||||||
extendBody: false, // Prevent conflicts with tabs navigation
|
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(
|
floatingActionButton: FloatingActionButton(
|
||||||
heroTag: Key("explore-page-fab"),
|
heroTag: Key("explore-page-fab"),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@ -78,12 +132,29 @@ class ExploreScreen extends ConsumerWidget {
|
|||||||
child: const Icon(Symbols.edit),
|
child: const Icon(Symbols.edit),
|
||||||
),
|
),
|
||||||
floatingActionButtonLocation: TabbedFabLocation(context),
|
floatingActionButtonLocation: TabbedFabLocation(context),
|
||||||
body: RefreshIndicator(
|
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),
|
onRefresh: () => Future.sync(activitiesNotifier.forceRefresh),
|
||||||
child: PagingHelperView(
|
child: PagingHelperView(
|
||||||
provider: activityListNotifierProvider,
|
provider: activityListNotifierProvider(filter),
|
||||||
futureRefreshable: activityListNotifierProvider.future,
|
futureRefreshable: activityListNotifierProvider(filter).future,
|
||||||
notifierRefreshable: activityListNotifierProvider.notifier,
|
notifierRefreshable: activityListNotifierProvider(filter).notifier,
|
||||||
contentBuilder:
|
contentBuilder:
|
||||||
(data, widgetCount, endItemView) => Center(
|
(data, widgetCount, endItemView) => Center(
|
||||||
child: _ActivityListView(
|
child: _ActivityListView(
|
||||||
@ -91,8 +162,7 @@ class ExploreScreen extends ConsumerWidget {
|
|||||||
widgetCount: widgetCount,
|
widgetCount: widgetCount,
|
||||||
endItemView: endItemView,
|
endItemView: endItemView,
|
||||||
activitiesNotifier: activitiesNotifier,
|
activitiesNotifier: activitiesNotifier,
|
||||||
),
|
contentOnly: filter != null,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -104,6 +174,7 @@ class _ActivityListView extends HookConsumerWidget {
|
|||||||
final CursorPagingData<SnActivity> data;
|
final CursorPagingData<SnActivity> data;
|
||||||
final int widgetCount;
|
final int widgetCount;
|
||||||
final Widget endItemView;
|
final Widget endItemView;
|
||||||
|
final bool contentOnly;
|
||||||
final ActivityListNotifier activitiesNotifier;
|
final ActivityListNotifier activitiesNotifier;
|
||||||
|
|
||||||
const _ActivityListView({
|
const _ActivityListView({
|
||||||
@ -111,6 +182,7 @@ class _ActivityListView extends HookConsumerWidget {
|
|||||||
required this.widgetCount,
|
required this.widgetCount,
|
||||||
required this.endItemView,
|
required this.endItemView,
|
||||||
required this.activitiesNotifier,
|
required this.activitiesNotifier,
|
||||||
|
this.contentOnly = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -119,7 +191,8 @@ class _ActivityListView extends HookConsumerWidget {
|
|||||||
|
|
||||||
return CustomScrollView(
|
return CustomScrollView(
|
||||||
slivers: [
|
slivers: [
|
||||||
if (user.hasValue) SliverToBoxAdapter(child: CheckInWidget()),
|
if (user.hasValue && !contentOnly)
|
||||||
|
SliverToBoxAdapter(child: CheckInWidget()),
|
||||||
SliverList.builder(
|
SliverList.builder(
|
||||||
itemCount: widgetCount,
|
itemCount: widgetCount,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
@ -178,7 +251,7 @@ class _ActivityListView extends HookConsumerWidget {
|
|||||||
return Column(children: [itemWidget, const Divider(height: 1)]);
|
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
|
class ActivityListNotifier extends _$ActivityListNotifier
|
||||||
with CursorPagingNotifierMixin<SnActivity> {
|
with CursorPagingNotifierMixin<SnActivity> {
|
||||||
@override
|
@override
|
||||||
Future<CursorPagingData<SnActivity>> build() => fetch(cursor: null);
|
Future<CursorPagingData<SnActivity>> build(String? filter) =>
|
||||||
|
fetch(cursor: null);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<CursorPagingData<SnActivity>> fetch({required String? cursor}) async {
|
Future<CursorPagingData<SnActivity>> fetch({required String? cursor}) async {
|
||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
final take = 20;
|
final take = 20;
|
||||||
|
|
||||||
|
final queryParameters = {
|
||||||
|
if (cursor != null) 'cursor': cursor,
|
||||||
|
'take': take,
|
||||||
|
if (filter != null) 'filter': filter,
|
||||||
|
};
|
||||||
|
|
||||||
final response = await client.get(
|
final response = await client.get(
|
||||||
'/activities',
|
'/activities',
|
||||||
queryParameters: {if (cursor != null) 'cursor': cursor, 'take': take},
|
queryParameters: queryParameters,
|
||||||
);
|
);
|
||||||
|
|
||||||
final List<SnActivity> items =
|
final List<SnActivity> items =
|
||||||
|
@ -7,25 +7,174 @@ part of 'explore.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$activityListNotifierHash() =>
|
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].
|
/// See also [ActivityListNotifier].
|
||||||
@ProviderFor(ActivityListNotifier)
|
@ProviderFor(ActivityListNotifier)
|
||||||
final activityListNotifierProvider = AutoDisposeAsyncNotifierProvider<
|
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,
|
ActivityListNotifier,
|
||||||
CursorPagingData<SnActivity>
|
CursorPagingData<SnActivity>
|
||||||
>.internal(
|
> {
|
||||||
ActivityListNotifier.new,
|
/// See also [ActivityListNotifier].
|
||||||
|
ActivityListNotifierProvider(String? filter)
|
||||||
|
: this._internal(
|
||||||
|
() => ActivityListNotifier()..filter = filter,
|
||||||
|
from: activityListNotifierProvider,
|
||||||
name: r'activityListNotifierProvider',
|
name: r'activityListNotifierProvider',
|
||||||
debugGetCreateSourceHash:
|
debugGetCreateSourceHash:
|
||||||
const bool.fromEnvironment('dart.vm.product')
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
? null
|
? null
|
||||||
: _$activityListNotifierHash,
|
: _$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,
|
dependencies: null,
|
||||||
allTransitiveDependencies: 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: 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
|
// 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(
|
SliverToBoxAdapter(
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
spacing: 20,
|
spacing: 20,
|
||||||
children: [
|
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(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
@ -242,19 +228,49 @@ class PublisherProfileScreen extends HookConsumerWidget {
|
|||||||
uname: data.account!.name,
|
uname: data.account!.name,
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
),
|
),
|
||||||
OutlinedButton.icon(
|
subStatus
|
||||||
onPressed: () {
|
.when(
|
||||||
Navigator.pop(context);
|
data:
|
||||||
context.router.pushPath(
|
(status) => FilledButton.icon(
|
||||||
'/account/${data.name}',
|
onPressed:
|
||||||
);
|
subscribing.value
|
||||||
},
|
? null
|
||||||
icon: const Icon(Symbols.launch),
|
: (status.isSubscribed
|
||||||
label: Text('accountProfileView').tr(),
|
? unsubscribe
|
||||||
style: ButtonStyle(
|
: subscribe),
|
||||||
visualDensity: VisualDensity(vertical: -2),
|
icon: Icon(
|
||||||
|
status.isSubscribed
|
||||||
|
? Symbols.remove_circle
|
||||||
|
: Symbols.add_circle,
|
||||||
),
|
),
|
||||||
).padding(top: 8),
|
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/pods/network.dart';
|
||||||
import 'package:island/route.gr.dart';
|
import 'package:island/route.gr.dart';
|
||||||
import 'package:island/services/file.dart';
|
import 'package:island/services/file.dart';
|
||||||
|
import 'package:island/services/responsive.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/widgets/alert.dart';
|
||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/widgets/app_scaffold.dart';
|
||||||
import 'package:island/widgets/content/cloud_files.dart';
|
import 'package:island/widgets/content/cloud_files.dart';
|
||||||
@ -93,9 +94,7 @@ class RealmListScreen extends HookConsumerWidget {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
padding: EdgeInsets.only(
|
padding: getTabbedPadding(context),
|
||||||
bottom: MediaQuery.of(context).padding.bottom,
|
|
||||||
),
|
|
||||||
itemCount: value.length,
|
itemCount: value.length,
|
||||||
itemBuilder: (context, item) {
|
itemBuilder: (context, item) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
|
@ -2,7 +2,6 @@ import 'dart:ui';
|
|||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gap/gap.dart';
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/route.gr.dart';
|
import 'package:island/route.gr.dart';
|
||||||
import 'package:island/screens/notification.dart';
|
import 'package:island/screens/notification.dart';
|
||||||
@ -55,12 +54,6 @@ class TabsScreen extends HookConsumerWidget {
|
|||||||
builder: (context, child, _) {
|
builder: (context, child, _) {
|
||||||
final tabsRouter = AutoTabsRouter.of(context);
|
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(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
Positioned.fill(child: child),
|
Positioned.fill(child: child),
|
||||||
|
@ -15,3 +15,24 @@ bool isWiderScreen(BuildContext context) {
|
|||||||
bool isWidestScreen(BuildContext context) {
|
bool isWidestScreen(BuildContext context) {
|
||||||
return MediaQuery.of(context).size.width > kWidescreenWidth;
|
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(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
Text('levelingProgress').tr().fontSize(16).bold(),
|
|
||||||
Row(
|
Row(
|
||||||
spacing: 8,
|
spacing: 8,
|
||||||
crossAxisAlignment: CrossAxisAlignment.baseline,
|
crossAxisAlignment: CrossAxisAlignment.baseline,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user