mirror of
https://gitlab.com/mysocialportal/relatica
synced 2024-10-18 11:13:31 +00:00
Add scroll to position of notification in post screen
This commit is contained in:
parent
3dc6751281
commit
a1ac7a009f
9 changed files with 138 additions and 44 deletions
|
@ -25,12 +25,13 @@ class NotificationControl extends StatelessWidget {
|
|||
final manager = getIt<TimelineManager>();
|
||||
final existingPostData = manager.getPostTreeEntryBy(notification.iid);
|
||||
if (existingPostData.isSuccess) {
|
||||
context.push('/post/view/${existingPostData.value.id}');
|
||||
context
|
||||
.push('/post/view/${existingPostData.value.id}/${notification.iid}');
|
||||
return;
|
||||
}
|
||||
final loadedPost = await manager.refreshStatusChain(notification.iid);
|
||||
if (loadedPost.isSuccess) {
|
||||
context.push('/post/view/${loadedPost.value.id}');
|
||||
context.push('/post/view/${loadedPost.value.id}/${notification.iid}');
|
||||
return;
|
||||
}
|
||||
buildSnackbar(
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||
|
||||
import '../../models/entry_tree_item.dart';
|
||||
import '../../models/flattened_tree_item.dart';
|
||||
import '../../models/timeline_entry.dart';
|
||||
import '../../services/timeline_manager.dart';
|
||||
import '../../utils/entry_tree_item_flattening.dart';
|
||||
|
@ -10,14 +12,19 @@ import 'flattened_tree_entry_control.dart';
|
|||
|
||||
class PostControl extends StatefulWidget {
|
||||
final EntryTreeItem originalItem;
|
||||
final String scrollToId;
|
||||
final bool openRemote;
|
||||
final bool showStatusOpenButton;
|
||||
final bool isRoot;
|
||||
|
||||
const PostControl(
|
||||
{super.key,
|
||||
required this.originalItem,
|
||||
required this.openRemote,
|
||||
required this.showStatusOpenButton});
|
||||
const PostControl({
|
||||
super.key,
|
||||
required this.originalItem,
|
||||
required this.scrollToId,
|
||||
required this.openRemote,
|
||||
required this.showStatusOpenButton,
|
||||
required this.isRoot,
|
||||
});
|
||||
|
||||
@override
|
||||
State<PostControl> createState() => _PostControlState();
|
||||
|
@ -26,6 +33,10 @@ class PostControl extends StatefulWidget {
|
|||
class _PostControlState extends State<PostControl> {
|
||||
static final _logger = Logger('$PostControl');
|
||||
|
||||
final ItemScrollController itemScrollController = ItemScrollController();
|
||||
final ItemPositionsListener itemPositionsListener =
|
||||
ItemPositionsListener.create();
|
||||
|
||||
var showContent = true;
|
||||
|
||||
var showComments = false;
|
||||
|
@ -41,6 +52,7 @@ class _PostControlState extends State<PostControl> {
|
|||
@override
|
||||
void initState() {
|
||||
showContent = entry.spoilerText.isEmpty;
|
||||
showComments = widget.scrollToId != item.id;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -48,6 +60,19 @@ class _PostControlState extends State<PostControl> {
|
|||
final manager = context.watch<TimelineManager>();
|
||||
_logger.finest('Building ${item.entry.toShortString()}');
|
||||
final items = widget.originalItem.flatten(topLevelOnly: !showComments);
|
||||
|
||||
if (widget.isRoot) {
|
||||
return buildListView(context, items, manager);
|
||||
} else {
|
||||
return buildColumnView(context, items, manager);
|
||||
}
|
||||
}
|
||||
|
||||
Widget buildColumnView(
|
||||
BuildContext context,
|
||||
List<FlattenedTreeItem> items,
|
||||
TimelineManager manager,
|
||||
) {
|
||||
final widgets = <Widget>[];
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
final itemWidget = FlattenedTreeEntryControl(
|
||||
|
@ -76,4 +101,61 @@ class _PostControlState extends State<PostControl> {
|
|||
}
|
||||
return Column(children: widgets);
|
||||
}
|
||||
|
||||
Widget buildListView(
|
||||
BuildContext context,
|
||||
List<FlattenedTreeItem> items,
|
||||
TimelineManager manager,
|
||||
) {
|
||||
final int count;
|
||||
final int offset;
|
||||
if (hasComments && showComments) {
|
||||
count = items.length + 1;
|
||||
offset = 1;
|
||||
final scrollToIndex =
|
||||
items.indexWhere((e) => e.timelineEntry.id == widget.scrollToId);
|
||||
Future.delayed(
|
||||
const Duration(seconds: 1),
|
||||
() async => itemScrollController.jumpTo(index: scrollToIndex),
|
||||
);
|
||||
} else if (hasComments) {
|
||||
count = 2;
|
||||
offset = 0;
|
||||
} else {
|
||||
count = 1;
|
||||
offset = 0;
|
||||
}
|
||||
return ScrollablePositionedList.builder(
|
||||
itemCount: count,
|
||||
itemScrollController: itemScrollController,
|
||||
itemPositionsListener: itemPositionsListener,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == 0) {
|
||||
return FlattenedTreeEntryControl(
|
||||
originalItem: items.first,
|
||||
openRemote: widget.openRemote,
|
||||
showStatusOpenButton: widget.showStatusOpenButton,
|
||||
);
|
||||
}
|
||||
if (index == 1 && hasComments) {
|
||||
return TextButton(
|
||||
onPressed: () async {
|
||||
setState(() {
|
||||
showComments = !showComments;
|
||||
});
|
||||
if (showComments) {
|
||||
await manager.refreshStatusChain(entry.id);
|
||||
}
|
||||
},
|
||||
child:
|
||||
Text(showComments ? 'Hide Comments' : 'Load & Show Comments'),
|
||||
);
|
||||
}
|
||||
return FlattenedTreeEntryControl(
|
||||
originalItem: items[index - offset],
|
||||
openRemote: widget.openRemote,
|
||||
showStatusOpenButton: widget.showStatusOpenButton,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,8 +45,10 @@ class TimelinePanel extends StatelessWidget {
|
|||
'Building item: $itemIndex: ${item.entry.toShortString()}');
|
||||
return PostControl(
|
||||
originalItem: item,
|
||||
scrollToId: item.id,
|
||||
openRemote: false,
|
||||
showStatusOpenButton: true,
|
||||
isRoot: false,
|
||||
);
|
||||
},
|
||||
separatorBuilder: (context, index) => Divider(),
|
||||
|
|
|
@ -137,9 +137,11 @@ final appRouter = GoRouter(
|
|||
EditorScreen(id: state.params['id'] ?? 'Not Found'),
|
||||
),
|
||||
GoRoute(
|
||||
path: 'view/:id',
|
||||
builder: (context, state) =>
|
||||
PostScreen(id: state.params['id'] ?? 'Not Found'),
|
||||
path: 'view/:id/:goto_id',
|
||||
builder: (context, state) => PostScreen(
|
||||
id: state.params['id'] ?? 'Not Found',
|
||||
goToId: state.params['goto_id'] ?? 'Not Found',
|
||||
),
|
||||
),
|
||||
]),
|
||||
GoRoute(
|
||||
|
|
|
@ -7,7 +7,13 @@ import '../services/timeline_manager.dart';
|
|||
class PostScreen extends StatelessWidget {
|
||||
final String id;
|
||||
|
||||
const PostScreen({super.key, required this.id});
|
||||
final String goToId;
|
||||
|
||||
const PostScreen({
|
||||
super.key,
|
||||
required this.id,
|
||||
required this.goToId,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -17,13 +23,12 @@ class PostScreen extends StatelessWidget {
|
|||
onRefresh: () async {
|
||||
await manager.refreshStatusChain(id);
|
||||
},
|
||||
child: SingleChildScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
child: PostControl(
|
||||
originalItem: post,
|
||||
openRemote: true,
|
||||
showStatusOpenButton: true,
|
||||
),
|
||||
child: PostControl(
|
||||
originalItem: post,
|
||||
scrollToId: goToId,
|
||||
openRemote: true,
|
||||
showStatusOpenButton: true,
|
||||
isRoot: true,
|
||||
),
|
||||
),
|
||||
onError: (error) => Text('Error getting post: $error'));
|
||||
|
|
|
@ -8,7 +8,7 @@ import Foundation
|
|||
import desktop_window
|
||||
import flutter_secure_storage_macos
|
||||
import path_provider_macos
|
||||
import shared_preferences_macos
|
||||
import shared_preferences_foundation
|
||||
import sqflite
|
||||
import url_launcher_macos
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@ PODS:
|
|||
- FMDB/standard (2.7.5)
|
||||
- path_provider_macos (0.0.1):
|
||||
- FlutterMacOS
|
||||
- shared_preferences_macos (0.0.1):
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- sqflite (0.0.2):
|
||||
- FlutterMacOS
|
||||
|
@ -22,7 +23,7 @@ DEPENDENCIES:
|
|||
- flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`)
|
||||
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||
- path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`)
|
||||
- shared_preferences_macos (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos`)
|
||||
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/macos`)
|
||||
- sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`)
|
||||
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
|
||||
|
||||
|
@ -39,8 +40,8 @@ EXTERNAL SOURCES:
|
|||
:path: Flutter/ephemeral
|
||||
path_provider_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos
|
||||
shared_preferences_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos
|
||||
shared_preferences_foundation:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/macos
|
||||
sqflite:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/sqflite/macos
|
||||
url_launcher_macos:
|
||||
|
@ -51,8 +52,8 @@ SPEC CHECKSUMS:
|
|||
flutter_secure_storage_macos: 75c8cadfdba05ca007c0fa4ea0c16e5cf85e521b
|
||||
FlutterMacOS: ae6af50a8ea7d6103d888583d46bd8328a7e9811
|
||||
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
||||
path_provider_macos: 3c0c3b4b0d4a76d2bf989a913c2de869c5641a19
|
||||
shared_preferences_macos: a64dc611287ed6cbe28fd1297898db1336975727
|
||||
path_provider_macos: 05fb0ef0cedf3e5bd179b9e41a638682b37133ea
|
||||
shared_preferences_foundation: 297b3ebca31b34ec92be11acd7fb0ba932c822ca
|
||||
sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea
|
||||
url_launcher_macos: 597e05b8e514239626bcf4a850fcf9ef5c856ec3
|
||||
|
||||
|
|
38
pubspec.lock
38
pubspec.lock
|
@ -147,7 +147,7 @@ packages:
|
|||
name: file_picker
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.2.4"
|
||||
version: "5.2.5"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
|
@ -260,7 +260,7 @@ packages:
|
|||
name: flutter_widget_from_html_core
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.9.0+2"
|
||||
version: "0.9.1"
|
||||
functional_listener:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -323,7 +323,7 @@ packages:
|
|||
name: image
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.2.2"
|
||||
version: "3.3.0"
|
||||
image_picker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -351,7 +351,7 @@ packages:
|
|||
name: image_picker_ios
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.8.6+4"
|
||||
version: "0.8.6+5"
|
||||
image_picker_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -484,7 +484,7 @@ packages:
|
|||
name: path_provider_macos
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.6"
|
||||
version: "2.0.7"
|
||||
path_provider_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -562,13 +562,20 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.27.7"
|
||||
scrollable_positioned_list:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: scrollable_positioned_list
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.5"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.15"
|
||||
version: "2.0.16"
|
||||
shared_preferences_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -576,10 +583,10 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.14"
|
||||
shared_preferences_ios:
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_ios
|
||||
name: shared_preferences_foundation
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
|
@ -590,13 +597,6 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
shared_preferences_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_macos
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.4"
|
||||
shared_preferences_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -636,14 +636,14 @@ packages:
|
|||
name: sqflite
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.2.2"
|
||||
version: "2.2.3"
|
||||
sqflite_common:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqflite_common
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.4.0+2"
|
||||
version: "2.4.1"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -678,7 +678,7 @@ packages:
|
|||
name: synchronized
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.0+3"
|
||||
version: "3.0.1"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -825,7 +825,7 @@ packages:
|
|||
name: xdg_directories
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.0+2"
|
||||
version: "0.2.0+3"
|
||||
xml:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -37,6 +37,7 @@ dependencies:
|
|||
flutter_file_dialog: ^2.3.2
|
||||
multi_trigger_autocomplete: ^0.1.1
|
||||
video_player: ^2.4.10
|
||||
scrollable_positioned_list: ^0.3.5
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
Loading…
Reference in a new issue