✨ Two column explore
This commit is contained in:
parent
4f9bf960d9
commit
1b544c2c8b
@ -42,6 +42,12 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<provider
|
||||||
|
android:name="com.superlist.super_native_extensions.DataProvider"
|
||||||
|
android:authorities="dev.solsynth.solian.SuperClipboardDataProvider"
|
||||||
|
android:exported="true"
|
||||||
|
android:grantUriPermissions="true" >
|
||||||
|
</provider>
|
||||||
<!-- Don't delete the meta-data below.
|
<!-- Don't delete the meta-data below.
|
||||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||||
<meta-data
|
<meta-data
|
||||||
|
@ -9,7 +9,16 @@ class AppRouter extends RootStackRouter {
|
|||||||
@override
|
@override
|
||||||
List<AutoRoute> get routes => [
|
List<AutoRoute> get routes => [
|
||||||
RedirectRoute(path: '/', redirectTo: '/explore'),
|
RedirectRoute(path: '/', redirectTo: '/explore'),
|
||||||
AutoRoute(page: ExploreRoute.page, path: '/explore'),
|
AutoRoute(
|
||||||
|
page: ExploreShellRoute.page,
|
||||||
|
path: '/explore',
|
||||||
|
children: [
|
||||||
|
AutoRoute(page: ExploreRoute.page, path: ''),
|
||||||
|
AutoRoute(page: PostComposeRoute.page, path: 'posts/compose'),
|
||||||
|
AutoRoute(page: PostDetailRoute.page, path: 'posts/:id'),
|
||||||
|
AutoRoute(page: PostEditRoute.page, path: 'posts/:id/edit'),
|
||||||
|
],
|
||||||
|
),
|
||||||
AutoRoute(
|
AutoRoute(
|
||||||
page: AccountShellRoute.page,
|
page: AccountShellRoute.page,
|
||||||
path: '/account',
|
path: '/account',
|
||||||
@ -64,9 +73,6 @@ class AppRouter extends RootStackRouter {
|
|||||||
AutoRoute(page: LoginRoute.page, path: '/auth/login'),
|
AutoRoute(page: LoginRoute.page, path: '/auth/login'),
|
||||||
AutoRoute(page: CreateAccountRoute.page, path: '/auth/create-account'),
|
AutoRoute(page: CreateAccountRoute.page, path: '/auth/create-account'),
|
||||||
AutoRoute(page: SettingsRoute.page, path: '/settings'),
|
AutoRoute(page: SettingsRoute.page, path: '/settings'),
|
||||||
AutoRoute(page: PostComposeRoute.page, path: '/posts/compose'),
|
|
||||||
AutoRoute(page: PostDetailRoute.page, path: '/posts/:id'),
|
|
||||||
AutoRoute(page: PostEditRoute.page, path: '/posts/:id/edit'),
|
|
||||||
AutoRoute(page: NewRealmRoute.page, path: '/realms/new'),
|
AutoRoute(page: NewRealmRoute.page, path: '/realms/new'),
|
||||||
AutoRoute(page: RealmDetailRoute.page, path: '/realms/:slug'),
|
AutoRoute(page: RealmDetailRoute.page, path: '/realms/:slug'),
|
||||||
AutoRoute(page: EditRealmRoute.page, path: '/realms/:slug/edit'),
|
AutoRoute(page: EditRealmRoute.page, path: '/realms/:slug/edit'),
|
||||||
|
@ -598,16 +598,55 @@ class EditStickersRouteArgs {
|
|||||||
|
|
||||||
/// generated route for
|
/// generated route for
|
||||||
/// [_i13.ExploreScreen]
|
/// [_i13.ExploreScreen]
|
||||||
class ExploreRoute extends _i26.PageRouteInfo<void> {
|
class ExploreRoute extends _i26.PageRouteInfo<ExploreRouteArgs> {
|
||||||
const ExploreRoute({List<_i26.PageRouteInfo>? children})
|
ExploreRoute({
|
||||||
: super(ExploreRoute.name, initialChildren: children);
|
_i27.Key? key,
|
||||||
|
bool isAside = false,
|
||||||
|
List<_i26.PageRouteInfo>? children,
|
||||||
|
}) : super(
|
||||||
|
ExploreRoute.name,
|
||||||
|
args: ExploreRouteArgs(key: key, isAside: isAside),
|
||||||
|
initialChildren: children,
|
||||||
|
);
|
||||||
|
|
||||||
static const String name = 'ExploreRoute';
|
static const String name = 'ExploreRoute';
|
||||||
|
|
||||||
static _i26.PageInfo page = _i26.PageInfo(
|
static _i26.PageInfo page = _i26.PageInfo(
|
||||||
name,
|
name,
|
||||||
builder: (data) {
|
builder: (data) {
|
||||||
return const _i13.ExploreScreen();
|
final args = data.argsAs<ExploreRouteArgs>(
|
||||||
|
orElse: () => const ExploreRouteArgs(),
|
||||||
|
);
|
||||||
|
return _i13.ExploreScreen(key: args.key, isAside: args.isAside);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExploreRouteArgs {
|
||||||
|
const ExploreRouteArgs({this.key, this.isAside = false});
|
||||||
|
|
||||||
|
final _i27.Key? key;
|
||||||
|
|
||||||
|
final bool isAside;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'ExploreRouteArgs{key: $key, isAside: $isAside}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// generated route for
|
||||||
|
/// [_i13.ExploreShellScreen]
|
||||||
|
class ExploreShellRoute extends _i26.PageRouteInfo<void> {
|
||||||
|
const ExploreShellRoute({List<_i26.PageRouteInfo>? children})
|
||||||
|
: super(ExploreShellRoute.name, initialChildren: children);
|
||||||
|
|
||||||
|
static const String name = 'ExploreShellRoute';
|
||||||
|
|
||||||
|
static _i26.PageInfo page = _i26.PageInfo(
|
||||||
|
name,
|
||||||
|
builder: (data) {
|
||||||
|
return const _i13.ExploreShellScreen();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -31,9 +31,9 @@ class AccountShellScreen extends HookConsumerWidget {
|
|||||||
isRoot: true,
|
isRoot: true,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(width: 360, child: AccountScreen(isAside: true)),
|
Flexible(flex: 2, child: AccountScreen(isAside: true)),
|
||||||
VerticalDivider(width: 1),
|
VerticalDivider(width: 1),
|
||||||
Expanded(child: AutoRouter()),
|
Flexible(flex: 3, child: AutoRouter()),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
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';
|
||||||
@ -30,6 +31,7 @@ import 'package:super_sliver_list/super_sliver_list.dart';
|
|||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
import 'package:super_clipboard/super_clipboard.dart';
|
||||||
import 'chat.dart';
|
import 'chat.dart';
|
||||||
|
|
||||||
part 'room.g.dart';
|
part 'room.g.dart';
|
||||||
@ -667,6 +669,9 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
clone.insert(idx + delta, clone.removeAt(idx));
|
clone.insert(idx + delta, clone.removeAt(idx));
|
||||||
attachments.value = clone;
|
attachments.value = clone;
|
||||||
},
|
},
|
||||||
|
onAttachmentsChanged: (newAttachments) {
|
||||||
|
attachments.value = newAttachments;
|
||||||
|
},
|
||||||
),
|
),
|
||||||
error: (_, __) => const SizedBox.shrink(),
|
error: (_, __) => const SizedBox.shrink(),
|
||||||
loading: () => const SizedBox.shrink(),
|
loading: () => const SizedBox.shrink(),
|
||||||
@ -690,6 +695,7 @@ class _ChatInput extends ConsumerWidget {
|
|||||||
final Function(int) onUploadAttachment;
|
final Function(int) onUploadAttachment;
|
||||||
final Function(int) onDeleteAttachment;
|
final Function(int) onDeleteAttachment;
|
||||||
final Function(int, int) onMoveAttachment;
|
final Function(int, int) onMoveAttachment;
|
||||||
|
final Function(List<UniversalFile>) onAttachmentsChanged;
|
||||||
|
|
||||||
const _ChatInput({
|
const _ChatInput({
|
||||||
required this.messageController,
|
required this.messageController,
|
||||||
@ -704,14 +710,22 @@ class _ChatInput extends ConsumerWidget {
|
|||||||
required this.onUploadAttachment,
|
required this.onUploadAttachment,
|
||||||
required this.onDeleteAttachment,
|
required this.onDeleteAttachment,
|
||||||
required this.onMoveAttachment,
|
required this.onMoveAttachment,
|
||||||
|
required this.onAttachmentsChanged,
|
||||||
});
|
});
|
||||||
|
|
||||||
void _handleKeyPress(BuildContext context, WidgetRef ref, RawKeyEvent event) {
|
void _handleKeyPress(BuildContext context, WidgetRef ref, RawKeyEvent event) {
|
||||||
if (event is! RawKeyDownEvent) return;
|
if (event is! RawKeyDownEvent) return;
|
||||||
|
|
||||||
|
final isPaste = event.logicalKey == LogicalKeyboardKey.keyV;
|
||||||
|
final isModifierPressed = event.isMetaPressed || event.isControlPressed;
|
||||||
|
|
||||||
|
if (isPaste && isModifierPressed) {
|
||||||
|
_handlePaste();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final enterToSend = ref.read(appSettingsProvider).enterToSend;
|
final enterToSend = ref.read(appSettingsProvider).enterToSend;
|
||||||
final isEnter = event.logicalKey == LogicalKeyboardKey.enter;
|
final isEnter = event.logicalKey == LogicalKeyboardKey.enter;
|
||||||
final isModifierPressed = event.isMetaPressed || event.isControlPressed;
|
|
||||||
|
|
||||||
if (isEnter) {
|
if (isEnter) {
|
||||||
if (enterToSend && !isModifierPressed) {
|
if (enterToSend && !isModifierPressed) {
|
||||||
@ -722,6 +736,36 @@ class _ChatInput extends ConsumerWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _handlePaste() async {
|
||||||
|
final clipboard = SystemClipboard.instance;
|
||||||
|
if (clipboard == null) return;
|
||||||
|
|
||||||
|
final reader = await clipboard.read();
|
||||||
|
if (reader.canProvide(Formats.png)) {
|
||||||
|
reader.getFile(Formats.png, (file) async {
|
||||||
|
final stream = file.getStream();
|
||||||
|
final bytes = await stream.toList();
|
||||||
|
final imageBytes = bytes.expand((e) => e).toList();
|
||||||
|
|
||||||
|
// Create a temporary file to store the image
|
||||||
|
final tempDir = Directory.systemTemp;
|
||||||
|
final tempFile = File(
|
||||||
|
'${tempDir.path}/pasted_image_${DateTime.now().millisecondsSinceEpoch}.png',
|
||||||
|
);
|
||||||
|
await tempFile.writeAsBytes(imageBytes);
|
||||||
|
|
||||||
|
// Add the file to attachments
|
||||||
|
onAttachmentsChanged([
|
||||||
|
...attachments,
|
||||||
|
UniversalFile(
|
||||||
|
data: XFile(tempFile.path),
|
||||||
|
type: UniversalFileType.image,
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final enterToSend = ref.watch(appSettingsProvider).enterToSend;
|
final enterToSend = ref.watch(appSettingsProvider).enterToSend;
|
||||||
@ -748,7 +792,7 @@ class _ChatInput extends ConsumerWidget {
|
|||||||
},
|
},
|
||||||
separatorBuilder: (_, __) => const Gap(8),
|
separatorBuilder: (_, __) => const Gap(8),
|
||||||
),
|
),
|
||||||
),
|
).padding(top: 12),
|
||||||
if (messageReplyingTo != null ||
|
if (messageReplyingTo != null ||
|
||||||
messageForwardingTo != null ||
|
messageForwardingTo != null ||
|
||||||
messageEditingTo != null)
|
messageEditingTo != null)
|
||||||
|
@ -21,15 +21,44 @@ import 'package:island/pods/network.dart';
|
|||||||
part 'explore.g.dart';
|
part 'explore.g.dart';
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
class ExploreScreen extends ConsumerWidget {
|
class ExploreShellScreen extends ConsumerWidget {
|
||||||
const ExploreScreen({super.key});
|
const ExploreShellScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final activitiesNotifier = ref.watch(activityListNotifierProvider.notifier);
|
|
||||||
|
|
||||||
final isWide = isWideScreen(context);
|
final isWide = isWideScreen(context);
|
||||||
|
|
||||||
|
if (isWide) {
|
||||||
|
return AppBackground(
|
||||||
|
isRoot: true,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Flexible(flex: 2, child: ExploreScreen(isAside: true)),
|
||||||
|
VerticalDivider(width: 1),
|
||||||
|
Flexible(flex: 3, child: AutoRouter()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return AppBackground(isRoot: true, child: AutoRouter());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RoutePage()
|
||||||
|
class ExploreScreen extends ConsumerWidget {
|
||||||
|
final bool isAside;
|
||||||
|
const ExploreScreen({super.key, this.isAside = false});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final isWide = isWideScreen(context);
|
||||||
|
if (isWide && !isAside) {
|
||||||
|
return const EmptyPageHolder();
|
||||||
|
}
|
||||||
|
|
||||||
|
final activitiesNotifier = ref.watch(activityListNotifierProvider.notifier);
|
||||||
|
|
||||||
return TourTriggerWidget(
|
return TourTriggerWidget(
|
||||||
child: AppScaffold(
|
child: AppScaffold(
|
||||||
appBar: AppBar(title: const Text('explore').tr()),
|
appBar: AppBar(title: const Text('explore').tr()),
|
||||||
@ -53,39 +82,12 @@ class ExploreScreen extends ConsumerWidget {
|
|||||||
notifierRefreshable: activityListNotifierProvider.notifier,
|
notifierRefreshable: activityListNotifierProvider.notifier,
|
||||||
contentBuilder:
|
contentBuilder:
|
||||||
(data, widgetCount, endItemView) => Center(
|
(data, widgetCount, endItemView) => Center(
|
||||||
child: ConstrainedBox(
|
|
||||||
constraints: const BoxConstraints(
|
|
||||||
maxWidth: kWideScreenWidth - 160,
|
|
||||||
),
|
|
||||||
child:
|
|
||||||
isWide
|
|
||||||
? Card(
|
|
||||||
elevation: 8,
|
|
||||||
margin: EdgeInsets.zero,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(16),
|
|
||||||
topRight: Radius.circular(16),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
color: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.surfaceContainerLow
|
|
||||||
.withOpacity(0.8),
|
|
||||||
child: _ActivityListView(
|
child: _ActivityListView(
|
||||||
data: data,
|
data: data,
|
||||||
widgetCount: widgetCount,
|
widgetCount: widgetCount,
|
||||||
endItemView: endItemView,
|
endItemView: endItemView,
|
||||||
activitiesNotifier: activitiesNotifier,
|
activitiesNotifier: activitiesNotifier,
|
||||||
),
|
),
|
||||||
)
|
|
||||||
: _ActivityListView(
|
|
||||||
data: data,
|
|
||||||
widgetCount: widgetCount,
|
|
||||||
endItemView: endItemView,
|
|
||||||
activitiesNotifier: activitiesNotifier,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -6,6 +6,7 @@ import 'package:collection/collection.dart';
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.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/services.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.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';
|
||||||
@ -23,6 +24,7 @@ import 'package:island/widgets/content/cloud_files.dart';
|
|||||||
import 'package:island/widgets/post/publishers_modal.dart';
|
import 'package:island/widgets/post/publishers_modal.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
import 'package:super_clipboard/super_clipboard.dart';
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
class PostEditScreen extends HookConsumerWidget {
|
class PostEditScreen extends HookConsumerWidget {
|
||||||
@ -215,6 +217,47 @@ class PostComposeScreen extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _handlePaste() async {
|
||||||
|
final clipboard = SystemClipboard.instance;
|
||||||
|
if (clipboard == null) return;
|
||||||
|
|
||||||
|
final reader = await clipboard.read();
|
||||||
|
if (reader.canProvide(Formats.png)) {
|
||||||
|
reader.getFile(Formats.png, (file) async {
|
||||||
|
final stream = file.getStream();
|
||||||
|
final bytes = await stream.toList();
|
||||||
|
final imageBytes = bytes.expand((e) => e).toList();
|
||||||
|
|
||||||
|
// Create a temporary file to store the image
|
||||||
|
final tempDir = Directory.systemTemp;
|
||||||
|
final tempFile = File(
|
||||||
|
'${tempDir.path}/pasted_image_${DateTime.now().millisecondsSinceEpoch}.png',
|
||||||
|
);
|
||||||
|
await tempFile.writeAsBytes(imageBytes);
|
||||||
|
|
||||||
|
// Add the file to attachments
|
||||||
|
attachments.value = [
|
||||||
|
...attachments.value,
|
||||||
|
UniversalFile(
|
||||||
|
data: XFile(tempFile.path),
|
||||||
|
type: UniversalFileType.image,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleKeyPress(RawKeyEvent event) {
|
||||||
|
if (event is! RawKeyDownEvent) return;
|
||||||
|
|
||||||
|
final isPaste = event.logicalKey == LogicalKeyboardKey.keyV;
|
||||||
|
final isModifierPressed = event.isMetaPressed || event.isControlPressed;
|
||||||
|
|
||||||
|
if (isPaste && isModifierPressed) {
|
||||||
|
_handlePaste();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: const PageBackButton(),
|
leading: const PageBackButton(),
|
||||||
@ -291,7 +334,10 @@ class PostComposeScreen extends HookConsumerWidget {
|
|||||||
FocusManager.instance.primaryFocus?.unfocus(),
|
FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
),
|
),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
TextField(
|
RawKeyboardListener(
|
||||||
|
focusNode: FocusNode(),
|
||||||
|
onKey: _handleKeyPress,
|
||||||
|
child: TextField(
|
||||||
controller: contentController,
|
controller: contentController,
|
||||||
style: TextStyle(fontSize: 14),
|
style: TextStyle(fontSize: 14),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@ -301,7 +347,9 @@ class PostComposeScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
onTapOutside:
|
onTapOutside:
|
||||||
(_) =>
|
(_) =>
|
||||||
FocusManager.instance.primaryFocus?.unfocus(),
|
FocusManager.instance.primaryFocus
|
||||||
|
?.unfocus(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
Column(
|
Column(
|
||||||
|
@ -36,10 +36,13 @@ class PostDetailScreen extends HookConsumerWidget {
|
|||||||
appBar: AppBar(title: const Text('Post')),
|
appBar: AppBar(title: const Text('Post')),
|
||||||
body: post.when(
|
body: post.when(
|
||||||
data: (post) {
|
data: (post) {
|
||||||
final content = Stack(
|
return Stack(
|
||||||
fit: StackFit.expand,
|
fit: StackFit.expand,
|
||||||
children: [
|
children: [
|
||||||
Column(
|
CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
PostItem(
|
PostItem(
|
||||||
item: post!,
|
item: post!,
|
||||||
@ -47,8 +50,11 @@ class PostDetailScreen extends HookConsumerWidget {
|
|||||||
backgroundColor: isWide ? Colors.transparent : null,
|
backgroundColor: isWide ? Colors.transparent : null,
|
||||||
),
|
),
|
||||||
const Divider(height: 1),
|
const Divider(height: 1),
|
||||||
Expanded(child: PostRepliesList(postId: id)),
|
],
|
||||||
Gap(MediaQuery.of(context).padding.bottom),
|
),
|
||||||
|
),
|
||||||
|
PostRepliesList(postId: id),
|
||||||
|
SliverGap(MediaQuery.of(context).padding.bottom + 80),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
@ -67,30 +73,6 @@ class PostDetailScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
return isWide
|
|
||||||
? Center(
|
|
||||||
child: Card(
|
|
||||||
elevation: 8,
|
|
||||||
margin: EdgeInsets.zero,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(16),
|
|
||||||
topRight: Radius.circular(16),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
color: Theme.of(
|
|
||||||
context,
|
|
||||||
).colorScheme.surfaceContainerLow.withOpacity(0.8),
|
|
||||||
child: ConstrainedBox(
|
|
||||||
constraints: const BoxConstraints(
|
|
||||||
maxWidth: kWideScreenWidth - 160,
|
|
||||||
),
|
|
||||||
child: content,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: content;
|
|
||||||
},
|
},
|
||||||
loading: () => const Center(child: CircularProgressIndicator()),
|
loading: () => const Center(child: CircularProgressIndicator()),
|
||||||
error: (e, _) => Text('Error: $e'),
|
error: (e, _) => Text('Error: $e'),
|
||||||
|
@ -18,22 +18,9 @@ class PostRepliesList extends HookConsumerWidget {
|
|||||||
final postAsync = ref.watch(postRepliesProvider(postId));
|
final postAsync = ref.watch(postRepliesProvider(postId));
|
||||||
final isWide = isWideScreen(context);
|
final isWide = isWideScreen(context);
|
||||||
|
|
||||||
return RefreshIndicator(
|
return postAsync.when(
|
||||||
onRefresh:
|
|
||||||
() => Future.sync((() {
|
|
||||||
ref.invalidate(postRepliesProvider(postId));
|
|
||||||
})),
|
|
||||||
child: postAsync.when(
|
|
||||||
data:
|
data:
|
||||||
(controller) => RefreshIndicator(
|
(controller) => SliverInfiniteList(
|
||||||
onRefresh:
|
|
||||||
() => Future.sync((() {
|
|
||||||
ref.invalidate(postRepliesProvider(postId));
|
|
||||||
})),
|
|
||||||
child: InfiniteList(
|
|
||||||
padding: EdgeInsets.only(
|
|
||||||
bottom: MediaQuery.of(context).padding.bottom,
|
|
||||||
),
|
|
||||||
itemCount: controller.posts.length,
|
itemCount: controller.posts.length,
|
||||||
isLoading: controller.isLoading,
|
isLoading: controller.isLoading,
|
||||||
hasReachedMax: controller.hasReachedMax,
|
hasReachedMax: controller.hasReachedMax,
|
||||||
@ -47,7 +34,8 @@ class PostRepliesList extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
separatorBuilder: (_, __) => const Divider(height: 1),
|
separatorBuilder: (_, __) => const Divider(height: 1),
|
||||||
emptyBuilder: (context) {
|
emptyBuilder: (context) {
|
||||||
return Column(
|
return SliverToBoxAdapter(
|
||||||
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'No replies',
|
'No replies',
|
||||||
@ -55,13 +43,17 @@ class PostRepliesList extends HookConsumerWidget {
|
|||||||
).fontSize(18).bold(),
|
).fontSize(18).bold(),
|
||||||
Text('Why not start a discussion?'),
|
Text('Why not start a discussion?'),
|
||||||
],
|
],
|
||||||
).padding(vertical: 16);
|
).padding(vertical: 16),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
loading:
|
||||||
|
() => SliverFillRemaining(
|
||||||
|
child: const Center(child: CircularProgressIndicator()),
|
||||||
),
|
),
|
||||||
loading: () => const Center(child: CircularProgressIndicator()),
|
|
||||||
error:
|
error:
|
||||||
(e, _) => ResponseErrorWidget(
|
(e, _) => SliverFillRemaining(
|
||||||
|
child: ResponseErrorWidget(
|
||||||
error: e,
|
error: e,
|
||||||
onRetry: () {
|
onRetry: () {
|
||||||
ref.invalidate(postRepliesProvider(postId));
|
ref.invalidate(postRepliesProvider(postId));
|
||||||
|
@ -1802,6 +1802,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.4.1"
|
version: "0.4.1"
|
||||||
|
super_clipboard:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: super_clipboard
|
||||||
|
sha256: "5203c881d24033c3e6154c2ae01afd94e7f0a3201280373f28e540f1defa3f40"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.0-dev.6"
|
||||||
super_context_menu:
|
super_context_menu:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -100,6 +100,7 @@ dependencies:
|
|||||||
photo_view: ^0.15.0
|
photo_view: ^0.15.0
|
||||||
dismissible_page: ^1.0.2
|
dismissible_page: ^1.0.2
|
||||||
super_sliver_list: ^0.4.1
|
super_sliver_list: ^0.4.1
|
||||||
|
super_clipboard: ^0.9.0-dev.6
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user