Solian/lib/screens/explore.dart

308 lines
10 KiB
Dart
Raw Normal View History

import 'dart:async';
2024-05-18 10:17:16 +00:00
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
2024-05-18 10:17:16 +00:00
import 'package:get/get.dart';
2024-07-25 06:42:50 +00:00
import 'package:solian/controllers/post_list_controller.dart';
2024-05-19 10:01:00 +00:00
import 'package:solian/providers/auth.dart';
import 'package:solian/providers/navigation.dart';
2024-05-19 10:01:00 +00:00
import 'package:solian/router.dart';
2024-05-25 05:00:40 +00:00
import 'package:solian/screens/account/notification.dart';
import 'package:solian/theme.dart';
import 'package:solian/widgets/account/signin_required_overlay.dart';
2024-06-06 12:23:50 +00:00
import 'package:solian/widgets/current_state_action.dart';
import 'package:solian/widgets/app_bar_leading.dart';
import 'package:solian/widgets/navigation/realm_switcher.dart';
2024-07-25 08:08:46 +00:00
import 'package:solian/widgets/posts/post_shuffle_swiper.dart';
2024-07-31 17:21:27 +00:00
import 'package:solian/widgets/posts/post_warped_list.dart';
2024-05-18 10:17:16 +00:00
class ExploreScreen extends StatefulWidget {
const ExploreScreen({super.key});
2024-05-18 10:17:16 +00:00
@override
State<ExploreScreen> createState() => _ExploreScreenState();
2024-05-18 10:17:16 +00:00
}
class _ExploreScreenState extends State<ExploreScreen>
2024-07-24 18:00:29 +00:00
with SingleTickerProviderStateMixin {
2024-07-25 08:08:46 +00:00
late final PostListController _postController;
2024-07-24 18:00:29 +00:00
late final TabController _tabController;
List<StreamSubscription>? _subscriptions;
2024-05-18 10:17:16 +00:00
@override
void initState() {
super.initState();
final navState = Get.find<NavigationStateProvider>();
2024-07-26 06:21:00 +00:00
_postController = PostListController();
_postController.realm = navState.focusedRealm.value?.alias;
_tabController = TabController(length: 3, vsync: this);
2024-07-24 18:00:29 +00:00
_tabController.addListener(() {
if (_postController.mode.value == _tabController.index) return;
_postController.mode.value = _tabController.index;
_postController.reloadAllOver();
2024-07-24 18:00:29 +00:00
});
_subscriptions = [
Get.find<NavigationStateProvider>().focusedRealm.listen((value) {
if (value?.alias != _postController.realm) {
_postController.realm = value?.alias;
_postController.reloadAllOver();
}
}),
];
2024-05-18 10:17:16 +00:00
}
@override
Widget build(BuildContext context) {
final AuthProvider auth = Get.find();
2024-07-24 17:43:50 +00:00
return Material(
color: Theme.of(context).colorScheme.surface,
child: Scaffold(
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
2024-08-04 10:13:59 +00:00
onPressed: () async {
final value = await showModalBottomSheet(
useRootNavigator: true,
isScrollControlled: true,
context: context,
2024-08-04 10:13:59 +00:00
builder: (context) => const PostCreatePopup(),
);
2024-08-04 10:13:59 +00:00
if (value is Future) {
value.then((_) {
_postController.reloadAllOver();
});
} else if (value != null) {
_postController.reloadAllOver();
}
},
),
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [
SliverAppBar(
flexibleSpace: SizedBox(
height: 48,
child: const Row(
children: [
RealmSwitcher(),
],
).paddingSymmetric(horizontal: 8),
).paddingOnly(top: MediaQuery.of(context).padding.top),
floating: true,
toolbarHeight: AppTheme.toolbarHeight(context),
leading: AppBarLeadingButton.adaptive(context),
actions: [
const BackgroundStateWidget(),
const NotificationButton(),
SizedBox(
width: AppTheme.isLargeScreen(context) ? 8 : 16,
2024-07-25 08:08:46 +00:00
),
2024-07-25 06:42:50 +00:00
],
bottom: TabBar(
controller: _tabController,
dividerHeight: 0.3,
tabAlignment: TabAlignment.fill,
tabs: [
Tab(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.feed, size: 20),
const Gap(8),
Text('postListNews'.tr),
],
),
),
Tab(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.people, size: 20),
const Gap(8),
Text('postListFriends'.tr),
],
),
),
Tab(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.shuffle_on_outlined, size: 20),
const Gap(8),
Text('postListShuffle'.tr),
],
),
),
],
),
)
];
},
body: Obx(() {
if (_postController.isPreparing.isTrue) {
return const Center(
child: CircularProgressIndicator(),
2024-07-25 08:08:46 +00:00
);
}
return Column(
children: [
Expanded(
child: TabBarView(
physics: const NeverScrollableScrollPhysics(),
controller: _tabController,
children: [
RefreshIndicator(
onRefresh: () => _postController.reloadAllOver(),
child: CustomScrollView(slivers: [
PostWarpedListWidget(
controller: _postController.pagingController,
onUpdate: () => _postController.reloadAllOver(),
),
]),
),
Obx(() {
if (auth.isAuthorized.value) {
return RefreshIndicator(
onRefresh: () => _postController.reloadAllOver(),
child: CustomScrollView(slivers: [
PostWarpedListWidget(
controller: _postController.pagingController,
onUpdate: () => _postController.reloadAllOver(),
),
]),
);
} else {
return SigninRequiredOverlay(
onDone: () => _postController.reloadAllOver(),
);
}
}),
PostShuffleSwiper(controller: _postController),
],
),
),
],
);
}),
2024-05-18 16:56:32 +00:00
),
2024-05-18 10:17:16 +00:00
),
);
}
2024-07-09 14:39:44 +00:00
@override
void dispose() {
2024-07-25 06:42:50 +00:00
_postController.dispose();
if (_subscriptions != null) {
for (final subscription in _subscriptions!) {
subscription.cancel();
}
}
2024-07-09 14:39:44 +00:00
super.dispose();
}
2024-05-18 10:17:16 +00:00
}
2024-07-06 12:55:53 +00:00
2024-07-24 17:43:50 +00:00
class PostCreatePopup extends StatelessWidget {
2024-07-09 14:39:44 +00:00
final bool hideDraftBox;
2024-07-06 19:02:10 +00:00
2024-07-24 17:43:50 +00:00
const PostCreatePopup({
2024-07-09 14:39:44 +00:00
super.key,
this.hideDraftBox = false,
});
2024-07-06 12:55:53 +00:00
@override
Widget build(BuildContext context) {
final AuthProvider auth = Get.find();
2024-07-24 17:18:47 +00:00
if (auth.isAuthorized.isFalse) {
return const SizedBox.shrink();
2024-07-24 17:18:47 +00:00
}
2024-07-24 17:43:50 +00:00
final List<dynamic> actionList = [
(
2024-07-30 08:53:13 +00:00
icon: const Icon(Icons.post_add),
2024-07-30 03:50:26 +00:00
label: 'postEditorModeStory'.tr,
2024-07-24 17:43:50 +00:00
onTap: () {
2024-08-04 10:13:59 +00:00
Navigator.pop(
context,
AppRouter.instance.pushNamed(
'postEditor',
queryParameters: {
'mode': 0.toString(),
},
),
);
2024-07-30 08:53:13 +00:00
},
),
(
icon: const Icon(Icons.description),
label: 'postEditorModeArticle'.tr,
onTap: () {
2024-08-04 10:13:59 +00:00
Navigator.pop(
context,
AppRouter.instance.pushNamed(
'postEditor',
queryParameters: {
'mode': 1.toString(),
},
),
);
2024-07-24 17:43:50 +00:00
},
),
(
icon: const Icon(Icons.drafts),
label: 'draftBoxOpen'.tr,
onTap: () {
2024-08-04 10:13:59 +00:00
Navigator.pop(
context,
AppRouter.instance.pushNamed('draftBox'),
);
2024-07-24 17:43:50 +00:00
},
),
];
return SizedBox(
2024-07-27 11:20:53 +00:00
height: MediaQuery.of(context).size.height * 0.38,
2024-07-24 17:43:50 +00:00
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'postNew'.tr,
style: Theme.of(context).textTheme.headlineSmall,
).paddingOnly(left: 24, right: 24, top: 32, bottom: 16),
Expanded(
child: GridView.count(
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 3,
children: actionList
.map((x) => Card(
color: Theme.of(context).colorScheme.surfaceContainer,
child: InkWell(
borderRadius:
const BorderRadius.all(Radius.circular(8)),
onTap: x.onTap,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
x.icon,
const Gap(8),
2024-08-10 17:57:58 +00:00
Expanded(
child: Text(
x.label,
overflow: TextOverflow.fade,
),
),
2024-07-24 17:43:50 +00:00
],
).paddingAll(18),
),
))
.toList(),
).paddingSymmetric(horizontal: 20),
2024-07-24 17:18:47 +00:00
),
2024-07-24 17:43:50 +00:00
],
),
2024-07-24 17:18:47 +00:00
);
2024-07-06 12:55:53 +00:00
}
}