Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-introduce comment navigator for new post page #1496

Merged
merged 2 commits into from
Jul 16, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 61 additions & 3 deletions lib/post/pages/post_page.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
Expand All @@ -15,6 +16,7 @@ import 'package:thunder/post/bloc/post_bloc.dart';
import 'package:thunder/post/utils/comment_action_helpers.dart';
import 'package:thunder/post/widgets/post_page_app_bar.dart';
import 'package:thunder/post/widgets/post_view.dart';
import 'package:thunder/shared/comment_navigator_fab.dart';
import 'package:thunder/shared/cross_posts.dart';
import 'package:thunder/shared/text/scalable_text.dart';
import 'package:thunder/shared/text/selectable_text_modal.dart';
Expand Down Expand Up @@ -48,6 +50,12 @@ class _PostPageState extends State<PostPage> {
/// Creates a [ListController] that can be used to control the list of items in the page.
final ListController listController = ListController();

/// The key for the app bar
final GlobalKey appBarKey = GlobalKey();

/// The key for the "reached end" indicator
final GlobalKey reachedEndKey = GlobalKey();

/// Whether the post source should be displayed.
bool viewSource = false;

Expand All @@ -60,6 +68,9 @@ class _PostPageState extends State<PostPage> {
/// Whether the user changed during the course of viewing the post
bool userChanged = false;

/// The height of the bottom spacer
double? bottomSpacerHeight;

@override
void initState() {
super.initState();
Expand All @@ -70,14 +81,39 @@ class _PostPageState extends State<PostPage> {
context.read<PostBloc>().add(const GetPostCommentsEvent());
}
});

// The following logic helps us to set the size of the bottom spacer so that the user can scroll the last comment to the top of the viewport but no further.
// This must be run some time after the layout has been rendered so we can measure everything.
// It also must be run after there is something to scroll, and the easiest way to do this is to do it in a scroll listener.
WidgetsBinding.instance.addPostFrameCallback((_) {
scrollController.addListener(() {
if (bottomSpacerHeight == null) {
final deviceHeight = MediaQuery.sizeOf(context).height;

// Get the height of the "reached end" indicator widget
final reachedEndHeight = (reachedEndKey.currentContext?.findRenderObject() as RenderBox?)?.size.height;

// Get the height of the app bar
final renderObject = appBarKey.currentContext?.findRenderObject() as RenderSliverFloatingPersistentHeader?;
final appBarHeight = renderObject?.geometry!.maxPaintExtent;

if (appBarHeight != null && reachedEndHeight != null) {
// We will make the bottom spacer the size of the device height, minus the size of the app bar and the size of the "reached bottom" indicator.
// This will allow the last comment to be scrolled to the top, with the "reached bottom" indicator and the spacer taking up the rest of the space.
bottomSpacerHeight = deviceHeight - appBarHeight - reachedEndHeight;
setState(() {});
}
}
});
});
}

@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final l10n = AppLocalizations.of(context)!;
final thunderState = context.read<ThunderBloc>().state;
bool hideTopBarOnScroll = thunderState.hideTopBarOnScroll;

originalUser ??= context.read<AuthBloc>().state.account;

return PopScope(
Expand All @@ -87,8 +123,28 @@ class _PostPageState extends State<PostPage> {
}
},
child: Scaffold(
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: Stack(
alignment: Alignment.center,
children: [
Positioned.fill(
child: Padding(
padding: const EdgeInsets.only(bottom: 5),
child: Align(
alignment: Alignment.bottomCenter,
child: CommentNavigatorFab(
initialIndex: 0,
maxIndex: listController.isAttached ? listController.numberOfItems - 1 : 0,
scrollController: scrollController,
listController: listController,
),
),
),
),
],
),
body: SafeArea(
top: hideTopBarOnScroll, // Don't apply to top of screen to allow for the status bar colour to extend
top: thunderState.hideTopBarOnScroll, // Don't apply to top of screen to allow for the status bar colour to extend
bottom: false,
child: BlocConsumer<PostBloc, PostState>(
listener: (context, state) {
Expand All @@ -111,6 +167,7 @@ class _PostPageState extends State<PostPage> {
controller: scrollController,
slivers: [
PostPageAppBar(
key: appBarKey,
viewSource: viewSource,
onViewSource: (value) => setState(() => viewSource = value),
onReset: () async => await scrollController.animateTo(0, duration: const Duration(milliseconds: 250), curve: Curves.easeInOutCubicEmphasized),
Expand Down Expand Up @@ -182,6 +239,7 @@ class _PostPageState extends State<PostPage> {
SliverToBoxAdapter(
child: state.hasReachedCommentEnd == true
? Container(
key: reachedEndKey,
color: theme.dividerColor.withOpacity(0.1),
padding: const EdgeInsets.symmetric(vertical: 32.0),
child: ScalableText(
Expand All @@ -201,7 +259,7 @@ class _PostPageState extends State<PostPage> {
),
),
),
const SliverToBoxAdapter(child: SizedBox(height: 100)),
SliverToBoxAdapter(child: SizedBox(height: bottomSpacerHeight)),
],
);
},
Expand Down
Loading