✨ Basic posting
This commit is contained in:
@ -14,7 +14,6 @@ class TabsScreen extends StatelessWidget {
|
||||
builder: (context, child, _) {
|
||||
final tabsRouter = AutoTabsRouter.of(context);
|
||||
return Scaffold(
|
||||
extendBody: true,
|
||||
extendBodyBehindAppBar: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
body: child,
|
||||
|
@ -1,9 +1,11 @@
|
||||
import 'package:auto_route/annotations.dart';
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:island/route.gr.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/models/post.dart';
|
||||
import 'package:island/widgets/post/post_item.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
import 'package:very_good_infinite_list/very_good_infinite_list.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
@ -18,10 +20,24 @@ class ExploreScreen extends ConsumerWidget {
|
||||
|
||||
return AppScaffold(
|
||||
appBar: AppBar(title: const Text('Explore')),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () {
|
||||
context.router.push(PostComposeRoute()).then((value) {
|
||||
if (value != null) {
|
||||
ref.invalidate(postListProvider);
|
||||
}
|
||||
});
|
||||
},
|
||||
child: const Icon(LucideIcons.pencil),
|
||||
),
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
|
||||
body: postAsync.when(
|
||||
data:
|
||||
(controller) => RefreshIndicator(
|
||||
onRefresh: controller.refresh,
|
||||
onRefresh:
|
||||
() => Future.sync((() {
|
||||
ref.invalidate(postListProvider);
|
||||
})),
|
||||
child: InfiniteList(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).padding.bottom,
|
||||
@ -44,7 +60,7 @@ class ExploreScreen extends ConsumerWidget {
|
||||
child: Text('Error: $e', textAlign: TextAlign.center),
|
||||
),
|
||||
onTap: () {
|
||||
postAsync.value?.refresh();
|
||||
ref.invalidate(postListProvider);
|
||||
},
|
||||
),
|
||||
),
|
||||
@ -70,13 +86,6 @@ class _PostListController {
|
||||
final int take = 20;
|
||||
int total = 0;
|
||||
|
||||
Future<void> refresh() async {
|
||||
hasReachedMax = false;
|
||||
offset = 0;
|
||||
posts.clear();
|
||||
await fetchMore();
|
||||
}
|
||||
|
||||
Future<void> fetchMore() async {
|
||||
if (isLoading || hasReachedMax) return;
|
||||
isLoading = true;
|
||||
|
97
lib/screens/posts/compose.dart
Normal file
97
lib/screens/posts/compose.dart
Normal file
@ -0,0 +1,97 @@
|
||||
import 'package:auto_route/annotations.dart';
|
||||
import 'package:auto_route/auto_route.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/post.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/screens/account/me/publishers.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/content/cloud_files.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
@RoutePage()
|
||||
class PostComposeScreen extends HookConsumerWidget {
|
||||
const PostComposeScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final publishers = ref.watch(publishersManagedProvider);
|
||||
|
||||
final currentPublisher = useState<SnPublisher?>(null);
|
||||
|
||||
useEffect(() {
|
||||
if (publishers.value?.isNotEmpty ?? false) {
|
||||
currentPublisher.value = publishers.value!.first;
|
||||
}
|
||||
return null;
|
||||
}, [publishers]);
|
||||
|
||||
final contentController = useTextEditingController();
|
||||
|
||||
final submitting = useState(false);
|
||||
|
||||
Future<void> performAction() async {
|
||||
if (!contentController.text.isNotEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
submitting.value = true;
|
||||
final client = ref.watch(apiClientProvider);
|
||||
await client.post('/posts', data: {'content': contentController.text});
|
||||
if (context.mounted) {
|
||||
context.maybePop(true);
|
||||
}
|
||||
} catch (err) {
|
||||
showErrorAlert(err);
|
||||
} finally {
|
||||
submitting.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
return AppScaffold(
|
||||
appBar: AppBar(
|
||||
leading: const PageBackButton(),
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: submitting.value ? null : performAction,
|
||||
icon: const Icon(LucideIcons.upload),
|
||||
),
|
||||
const Gap(8),
|
||||
],
|
||||
),
|
||||
body: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Row(
|
||||
spacing: 12,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ProfilePictureWidget(
|
||||
item: currentPublisher.value?.picture,
|
||||
radius: 24,
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: contentController,
|
||||
decoration: InputDecoration.collapsed(
|
||||
hintText: 'What\'s happened?!',
|
||||
),
|
||||
maxLines: null,
|
||||
onTapOutside:
|
||||
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
),
|
||||
],
|
||||
).padding(all: 16),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user