Focused realm linked with feed stream

This commit is contained in:
LittleSheep 2024-09-13 00:17:56 +08:00
parent 6daa04c208
commit dd01f964d4
5 changed files with 171 additions and 114 deletions

View File

@ -9,6 +9,7 @@ import 'package:solian/providers/last_read.dart';
class PostListController extends GetxController { class PostListController extends GetxController {
String? author; String? author;
String? realm;
/// The polling source modifier. /// The polling source modifier.
/// - `0`: default recommendations /// - `0`: default recommendations
@ -99,8 +100,10 @@ class PostListController extends GetxController {
final idx = <dynamic>{}; final idx = <dynamic>{};
postList.retainWhere((x) => idx.add(x.id)); postList.retainWhere((x) => idx.add(x.id));
if (postList.isNotEmpty) {
var lastId = postList.map((x) => x.id).reduce(max); var lastId = postList.map((x) => x.id).reduce(max);
Get.find<LastReadProvider>().feedLastReadAt = lastId; Get.find<LastReadProvider>().feedLastReadAt = lastId;
}
return result; return result;
} }
@ -123,16 +126,21 @@ class PostListController extends GetxController {
resp = await provider.listRecommendations( resp = await provider.listRecommendations(
pageKey, pageKey,
channel: 'shuffle', channel: 'shuffle',
realm: realm,
); );
break; break;
case 1: case 1:
resp = await provider.listRecommendations( resp = await provider.listRecommendations(
pageKey, pageKey,
channel: 'friends', channel: 'friends',
realm: realm,
); );
break; break;
default: default:
resp = await provider.listRecommendations(pageKey); resp = await provider.listRecommendations(
pageKey,
realm: realm,
);
break; break;
} }
} }

View File

@ -15,6 +15,7 @@ import 'package:solian/providers/attachment_uploader.dart';
import 'package:solian/providers/daily_sign.dart'; import 'package:solian/providers/daily_sign.dart';
import 'package:solian/providers/last_read.dart'; import 'package:solian/providers/last_read.dart';
import 'package:solian/providers/link_expander.dart'; import 'package:solian/providers/link_expander.dart';
import 'package:solian/providers/navigation.dart';
import 'package:solian/providers/stickers.dart'; import 'package:solian/providers/stickers.dart';
import 'package:solian/providers/theme_switcher.dart'; import 'package:solian/providers/theme_switcher.dart';
import 'package:solian/providers/websocket.dart'; import 'package:solian/providers/websocket.dart';
@ -123,6 +124,8 @@ class SolianApp extends StatelessWidget {
} }
void _initializeProviders(BuildContext context) async { void _initializeProviders(BuildContext context) async {
Get.put(NavigationStateProvider());
Get.lazyPut(() => AuthProvider()); Get.lazyPut(() => AuthProvider());
Get.lazyPut(() => RelationshipProvider()); Get.lazyPut(() => RelationshipProvider());
Get.lazyPut(() => PostProvider()); Get.lazyPut(() => PostProvider());

View File

@ -0,0 +1,6 @@
import 'package:get/get.dart';
import 'package:solian/models/realm.dart';
class NavigationStateProvider extends GetxController {
final Rx<Realm?> focusedRealm = Rx(null);
}

View File

@ -1,8 +1,11 @@
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:solian/controllers/post_list_controller.dart'; import 'package:solian/controllers/post_list_controller.dart';
import 'package:solian/providers/auth.dart'; import 'package:solian/providers/auth.dart';
import 'package:solian/providers/navigation.dart';
import 'package:solian/router.dart'; import 'package:solian/router.dart';
import 'package:solian/screens/account/notification.dart'; import 'package:solian/screens/account/notification.dart';
import 'package:solian/theme.dart'; import 'package:solian/theme.dart';
@ -25,21 +28,34 @@ class _FeedScreenState extends State<FeedScreen>
late final PostListController _postController; late final PostListController _postController;
late final TabController _tabController; late final TabController _tabController;
List<StreamSubscription>? _subscriptions;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
final navState = Get.find<NavigationStateProvider>();
_postController = PostListController(); _postController = PostListController();
_postController.realm = navState.focusedRealm.value?.alias;
_tabController = TabController(length: 3, vsync: this); _tabController = TabController(length: 3, vsync: this);
_tabController.addListener(() { _tabController.addListener(() {
if (_postController.mode.value == _tabController.index) return; if (_postController.mode.value == _tabController.index) return;
_postController.mode.value = _tabController.index; _postController.mode.value = _tabController.index;
_postController.reloadAllOver(); _postController.reloadAllOver();
}); });
_subscriptions = [
Get.find<NavigationStateProvider>().focusedRealm.listen((value) {
if (value?.alias != _postController.realm) {
_postController.realm = value?.alias;
_postController.reloadAllOver();
}
}),
];
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final AuthProvider auth = Get.find(); final AuthProvider auth = Get.find();
final NavigationStateProvider navState = Get.find();
return Material( return Material(
color: Theme.of(context).colorScheme.surface, color: Theme.of(context).colorScheme.surface,
@ -96,7 +112,18 @@ class _FeedScreenState extends State<FeedScreen>
); );
} }
return TabBarView( return Column(
children: [
if (navState.focusedRealm.value != null)
MaterialBanner(
leading: const Icon(Icons.layers),
content: Text(
'Browsing in realm #${navState.focusedRealm.value!.alias}',
),
actions: const [SizedBox.shrink()],
),
Expanded(
child: TabBarView(
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
controller: _tabController, controller: _tabController,
children: [ children: [
@ -128,6 +155,9 @@ class _FeedScreenState extends State<FeedScreen>
}), }),
PostShuffleSwiper(controller: _postController), PostShuffleSwiper(controller: _postController),
], ],
),
),
],
); );
}), }),
), ),
@ -138,6 +168,11 @@ class _FeedScreenState extends State<FeedScreen>
@override @override
void dispose() { void dispose() {
_postController.dispose(); _postController.dispose();
if (_subscriptions != null) {
for (final subscription in _subscriptions!) {
subscription.cancel();
}
}
super.dispose(); super.dispose();
} }
} }

View File

@ -4,6 +4,7 @@ import 'package:solian/models/realm.dart';
import 'package:solian/providers/auth.dart'; import 'package:solian/providers/auth.dart';
import 'package:solian/providers/content/channel.dart'; import 'package:solian/providers/content/channel.dart';
import 'package:solian/providers/content/realm.dart'; import 'package:solian/providers/content/realm.dart';
import 'package:solian/providers/navigation.dart';
import 'package:solian/widgets/account/account_avatar.dart'; import 'package:solian/widgets/account/account_avatar.dart';
import 'package:solian/widgets/channel/channel_list.dart'; import 'package:solian/widgets/channel/channel_list.dart';
@ -21,8 +22,6 @@ class AppNavigationRegion extends StatefulWidget {
class _AppNavigationRegionState extends State<AppNavigationRegion> class _AppNavigationRegionState extends State<AppNavigationRegion>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
Realm? _focusedRealm;
bool _isTryingExit = false; bool _isTryingExit = false;
late final AnimationController _animationController = AnimationController( late final AnimationController _animationController = AnimationController(
@ -39,14 +38,18 @@ class _AppNavigationRegionState extends State<AppNavigationRegion>
void _focusRealm(Realm item) { void _focusRealm(Realm item) {
_animationController.animateTo(1).then((_) { _animationController.animateTo(1).then((_) {
setState(() => _focusedRealm = item); setState(
() => Get.find<NavigationStateProvider>().focusedRealm.value = item,
);
_animationController.animateTo(0); _animationController.animateTo(0);
}); });
} }
void _unFocusRealm() { void _unFocusRealm() {
_animationController.animateTo(1).then((_) { _animationController.animateTo(1).then((_) {
setState(() => _focusedRealm = null); setState(
() => Get.find<NavigationStateProvider>().focusedRealm.value = null,
);
_animationController.animateTo(0); _animationController.animateTo(0);
}); });
} }
@ -58,6 +61,7 @@ class _AppNavigationRegionState extends State<AppNavigationRegion>
} }
Widget _buildRealmFocusAvatar() { Widget _buildRealmFocusAvatar() {
final focusedRealm = Get.find<NavigationStateProvider>().focusedRealm.value;
return MouseRegion( return MouseRegion(
child: AnimatedSwitcher( child: AnimatedSwitcher(
switchInCurve: Curves.fastOutSlowIn, switchInCurve: Curves.fastOutSlowIn,
@ -83,7 +87,7 @@ class _AppNavigationRegionState extends State<AppNavigationRegion>
), ),
onTap: () => _unFocusRealm(), onTap: () => _unFocusRealm(),
) )
: _buildEntryAvatar(_focusedRealm!), : _buildEntryAvatar(focusedRealm!),
), ),
onEnter: (_) => setState(() => _isTryingExit = true), onEnter: (_) => setState(() => _isTryingExit = true),
onExit: (_) => setState(() => _isTryingExit = false), onExit: (_) => setState(() => _isTryingExit = false),
@ -137,8 +141,10 @@ class _AppNavigationRegionState extends State<AppNavigationRegion>
final RealmProvider realms = Get.find(); final RealmProvider realms = Get.find();
final ChannelProvider channels = Get.find(); final ChannelProvider channels = Get.find();
final AuthProvider auth = Get.find(); final AuthProvider auth = Get.find();
final NavigationStateProvider navState = Get.find();
return AnimatedBuilder( return Obx(
() => AnimatedBuilder(
animation: _animationController, animation: _animationController,
builder: (context, child) { builder: (context, child) {
return SlideTransition( return SlideTransition(
@ -146,10 +152,9 @@ class _AppNavigationRegionState extends State<AppNavigationRegion>
child: child, child: child,
); );
}, },
child: _focusedRealm == null child: navState.focusedRealm.value == null
? Obx(() { ? widget.isCollapsed
if (widget.isCollapsed) { ? CustomScrollView(
return CustomScrollView(
slivers: [ slivers: [
const SliverPadding(padding: EdgeInsets.only(top: 8)), const SliverPadding(padding: EdgeInsets.only(top: 8)),
SliverList.builder( SliverList.builder(
@ -163,10 +168,8 @@ class _AppNavigationRegionState extends State<AppNavigationRegion>
}, },
), ),
], ],
); )
} : CustomScrollView(
return CustomScrollView(
slivers: [ slivers: [
const SliverPadding(padding: EdgeInsets.only(top: 8)), const SliverPadding(padding: EdgeInsets.only(top: 8)),
SliverList.builder( SliverList.builder(
@ -178,13 +181,12 @@ class _AppNavigationRegionState extends State<AppNavigationRegion>
), ),
const SliverPadding(padding: EdgeInsets.only(bottom: 8)), const SliverPadding(padding: EdgeInsets.only(bottom: 8)),
], ],
); )
})
: Column( : Column(
children: [ children: [
if (widget.isCollapsed) if (widget.isCollapsed)
Tooltip( Tooltip(
message: _focusedRealm!.name, message: navState.focusedRealm.value!.name,
child: _buildRealmFocusAvatar().paddingSymmetric( child: _buildRealmFocusAvatar().paddingSymmetric(
vertical: 8, vertical: 8,
), ),
@ -195,11 +197,11 @@ class _AppNavigationRegionState extends State<AppNavigationRegion>
tileColor: tileColor:
Theme.of(context).colorScheme.surfaceContainerLow, Theme.of(context).colorScheme.surfaceContainerLow,
leading: _buildRealmFocusAvatar(), leading: _buildRealmFocusAvatar(),
contentPadding: contentPadding: const EdgeInsets.symmetric(
const EdgeInsets.symmetric(horizontal: 20, vertical: 8), horizontal: 20, vertical: 8),
title: Text(_focusedRealm!.name), title: Text(navState.focusedRealm.value!.name),
subtitle: Text( subtitle: Text(
_focusedRealm!.description, navState.focusedRealm.value!.description,
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
@ -209,7 +211,9 @@ class _AppNavigationRegionState extends State<AppNavigationRegion>
() => ChannelListWidget( () => ChannelListWidget(
channels: channels.availableChannels channels: channels.availableChannels
.where( .where(
(x) => x.realm?.externalId == _focusedRealm?.id, (x) =>
x.realm?.id ==
navState.focusedRealm.value?.id,
) )
.toList(), .toList(),
selfId: auth.userProfile.value!['id'], selfId: auth.userProfile.value!['id'],
@ -219,6 +223,7 @@ class _AppNavigationRegionState extends State<AppNavigationRegion>
), ),
], ],
), ),
),
); );
} }
} }