Fix minor post errors (#273)

* Use nested to decrease indentation

* Fix post tap area

* Fix overflow errors

* Add changelog entry
This commit is contained in:
Marcin Wojnarowski 2021-11-03 06:21:00 +01:00 committed by GitHub
parent 18b39be0a9
commit 2b72fcce10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 191 additions and 183 deletions

View File

@ -10,6 +10,7 @@
- Fixed a bug where post would go out of sync with full version of the post
- Fixed a bug where making a comment selectable would not always result in making the comment selectable
- Full post will now open no matter where you press on the post card
## v0.6.0 - 2021-09-06

View File

@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:lemmy_api_client/v3.dart';
import 'package:nested/nested.dart';
import '../../hooks/logged_in_action.dart';
import '../../stores/accounts_store.dart';
@ -33,101 +34,106 @@ class FullPostPage extends HookWidget {
final loggedInAction =
useLoggedInAction(context.read<FullPostStore>().instanceHost);
return AsyncStoreListener(
asyncStore: context.read<FullPostStore>().fullPostState,
child: AsyncStoreListener<BlockedCommunity>(
asyncStore: context.read<FullPostStore>().communityBlockingState,
successMessageBuilder: (context, data) {
final name = data.communityView.community.originPreferredName;
return '${data.blocked ? 'Blocked' : 'Unblocked'} $name';
},
child: ObserverBuilder<FullPostStore>(
builder: (context, store) {
Future<void> refresh() async {
unawaited(HapticFeedback.mediumImpact());
await store.refresh(context
.read<AccountsStore>()
.defaultUserDataFor(store.instanceHost)
?.jwt);
}
final postStore = store.postStore;
if (postStore == null) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: (store.fullPostState.isLoading)
? const CircularProgressIndicator.adaptive()
: FailedToLoad(
message: 'Post failed to load', refresh: refresh),
),
);
}
final post = postStore.postView;
// VARIABLES
sharePost() => share(post.post.apId, context: context);
comment() async {
final newComment = await Navigator.of(context).push(
WriteComment.toPostRoute(post.post),
);
if (newComment != null) {
store.addComment(newComment);
}
}
return Scaffold(
appBar: AppBar(
centerTitle: false,
title: RevealAfterScroll(
scrollController: scrollController,
after: 65,
child: Text(
post.community.originPreferredName,
overflow: TextOverflow.fade,
),
),
actions: [
IconButton(icon: Icon(shareIcon), onPressed: sharePost),
Provider.value(
value: postStore,
child: const SavePostButton(),
),
IconButton(
icon: Icon(moreIcon),
onPressed: () => PostMoreMenuButton.show(
context: context,
postStore: postStore,
fullPostStore: store,
),
),
],
),
floatingActionButton: post.post.locked
? null
: FloatingActionButton(
onPressed: loggedInAction((_) => comment()),
child: const Icon(Icons.comment),
),
body: RefreshIndicator(
onRefresh: refresh,
child: ListView(
controller: scrollController,
physics: const AlwaysScrollableScrollPhysics(),
children: [
const SizedBox(height: 15),
PostTile.fromPostStore(postStore),
const CommentSection(),
],
),
));
return Nested(
children: [
AsyncStoreListener(
asyncStore: context.read<FullPostStore>().fullPostState,
),
AsyncStoreListener<BlockedCommunity>(
asyncStore: context.read<FullPostStore>().communityBlockingState,
successMessageBuilder: (context, data) {
final name = data.communityView.community.originPreferredName;
return '${data.blocked ? 'Blocked' : 'Unblocked'} $name';
},
),
],
child: ObserverBuilder<FullPostStore>(
builder: (context, store) {
Future<void> refresh() async {
unawaited(HapticFeedback.mediumImpact());
await store.refresh(context
.read<AccountsStore>()
.defaultUserDataFor(store.instanceHost)
?.jwt);
}
final postStore = store.postStore;
if (postStore == null) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: (store.fullPostState.isLoading)
? const CircularProgressIndicator.adaptive()
: FailedToLoad(
message: 'Post failed to load', refresh: refresh),
),
);
}
final post = postStore.postView;
// VARIABLES
sharePost() => share(post.post.apId, context: context);
comment() async {
final newComment = await Navigator.of(context).push(
WriteComment.toPostRoute(post.post),
);
if (newComment != null) {
store.addComment(newComment);
}
}
return Scaffold(
appBar: AppBar(
centerTitle: false,
title: RevealAfterScroll(
scrollController: scrollController,
after: 65,
child: Text(
post.community.originPreferredName,
overflow: TextOverflow.fade,
),
),
actions: [
IconButton(icon: Icon(shareIcon), onPressed: sharePost),
Provider.value(
value: postStore,
child: const SavePostButton(),
),
IconButton(
icon: Icon(moreIcon),
onPressed: () => PostMoreMenuButton.show(
context: context,
postStore: postStore,
fullPostStore: store,
),
),
],
),
floatingActionButton: post.post.locked
? null
: FloatingActionButton(
onPressed: loggedInAction((_) => comment()),
child: const Icon(Icons.comment),
),
body: RefreshIndicator(
onRefresh: refresh,
child: ListView(
controller: scrollController,
physics: const AlwaysScrollableScrollPhysics(),
children: [
const SizedBox(height: 15),
PostTile.fromPostStore(postStore),
const CommentSection(),
],
),
),
);
},
),
);
}

View File

@ -1,27 +1,26 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/single_child_widget.dart';
import '../l10n/l10n_from_string.dart';
import 'async_store.dart';
import 'observer_consumers.dart';
class AsyncStoreListener<T> extends StatelessWidget {
class AsyncStoreListener<T> extends SingleChildStatelessWidget {
final AsyncStore<T> asyncStore;
final String Function(
BuildContext context,
T data,
)? successMessageBuilder;
final Widget child;
const AsyncStoreListener({
Key? key,
required this.asyncStore,
this.successMessageBuilder,
required this.child,
}) : super(key: key);
Widget? child,
}) : super(key: key, child: child);
@override
Widget build(BuildContext context) {
Widget buildWithChild(BuildContext context, Widget? child) {
return ObserverListener<AsyncStore<T>>(
store: asyncStore,
listener: (context, store) {
@ -40,7 +39,7 @@ class AsyncStoreListener<T> extends StatelessWidget {
context, (store.asyncState as AsyncStateData).data))));
}
},
child: child,
child: child ?? const SizedBox(),
);
}
}

View File

@ -2,6 +2,7 @@ import 'dart:math';
import 'package:flutter/material.dart';
import 'package:lemmy_api_client/v3.dart';
import 'package:nested/nested.dart';
import '../../comment_tree.dart';
import '../../l10n/l10n.dart';
@ -89,26 +90,30 @@ class CommentWidget extends StatelessWidget {
detached: detached,
hideOnRead: hideOnRead,
),
builder: (context, child) => AsyncStoreListener<BlockedPerson>(
asyncStore: context.read<CommentStore>().blockingState,
successMessageBuilder: (context, state) {
final name = state.personView.person.preferredName;
return state.blocked ? '$name blocked' : '$name unblocked';
},
child: AsyncStoreListener(
asyncStore: context.read<CommentStore>().votingState,
child: AsyncStoreListener(
asyncStore: context.read<CommentStore>().deletingState,
child: AsyncStoreListener(
asyncStore: context.read<CommentStore>().savingState,
child: AsyncStoreListener<CommentReportView>(
asyncStore: context.read<CommentStore>().reportingState,
successMessageBuilder: (context, data) => 'Comment reported',
child: const _CommentWidget(),
),
),
builder: (context, child) => Nested(
children: [
AsyncStoreListener<BlockedPerson>(
asyncStore: context.read<CommentStore>().blockingState,
successMessageBuilder: (context, state) {
final name = state.personView.person.preferredName;
return state.blocked ? '$name blocked' : '$name unblocked';
},
),
),
AsyncStoreListener(
asyncStore: context.read<CommentStore>().votingState,
),
AsyncStoreListener(
asyncStore: context.read<CommentStore>().deletingState,
),
AsyncStoreListener(
asyncStore: context.read<CommentStore>().savingState,
),
AsyncStoreListener<CommentReportView>(
asyncStore: context.read<CommentStore>().reportingState,
successMessageBuilder: (context, data) => 'Comment reported',
),
],
child: const _CommentWidget(),
),
);
}

View File

@ -1,6 +1,7 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:lemmy_api_client/v3.dart';
import 'package:nested/nested.dart';
import 'package:provider/provider.dart';
import '../../pages/full_post/full_post.dart';
@ -25,31 +26,25 @@ class PostTile extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
return Nested(
children: [
Provider.value(value: postStore),
Provider.value(value: fullPost),
AsyncStoreListener(asyncStore: postStore.savingState),
AsyncStoreListener(asyncStore: postStore.votingState),
AsyncStoreListener<BlockedPerson>(
asyncStore: postStore.userBlockingState,
successMessageBuilder: (context, state) {
final name = state.personView.person.preferredName;
return state.blocked ? '$name blocked' : '$name unblocked';
},
),
AsyncStoreListener<PostReportView>(
asyncStore: postStore.reportingState,
successMessageBuilder: (context, data) => 'Post reported',
),
],
builder: (context, child) {
return AsyncStoreListener(
asyncStore: context.read<PostStore>().savingState,
child: AsyncStoreListener(
asyncStore: context.read<PostStore>().votingState,
child: AsyncStoreListener<BlockedPerson>(
asyncStore: context.read<PostStore>().userBlockingState,
successMessageBuilder: (context, state) {
final name = state.personView.person.preferredName;
return state.blocked ? '$name blocked' : '$name unblocked';
},
child: AsyncStoreListener<PostReportView>(
asyncStore: context.read<PostStore>().reportingState,
successMessageBuilder: (context, data) => 'Post reported',
child: const _Post(),
),
),
),
);
},
child: const _Post(),
);
}
}
@ -63,20 +58,20 @@ class _Post extends StatelessWidget {
final theme = Theme.of(context);
final isFullPost = context.read<IsFullPost>();
return Container(
decoration: BoxDecoration(
boxShadow: const [BoxShadow(blurRadius: 10, color: Colors.black45)],
color: theme.cardColor,
borderRadius: const BorderRadius.all(Radius.circular(20)),
),
child: GestureDetector(
onTap: isFullPost
? null
: () {
final postStore = context.read<PostStore>();
Navigator.of(context)
.push(FullPostPage.fromPostStoreRoute(postStore));
},
return GestureDetector(
onTap: isFullPost
? null
: () {
final postStore = context.read<PostStore>();
Navigator.of(context)
.push(FullPostPage.fromPostStoreRoute(postStore));
},
child: DecoratedBox(
decoration: BoxDecoration(
boxShadow: const [BoxShadow(blurRadius: 10, color: Colors.black45)],
color: theme.cardColor,
borderRadius: const BorderRadius.all(Radius.circular(20)),
),
child: Material(
type: MaterialType.transparency,
child: Column(

View File

@ -30,12 +30,9 @@ class PostBody extends StatelessWidget {
} else {
return LayoutBuilder(
builder: (context, constraints) {
final span = TextSpan(
text: body,
);
final tp = TextPainter(
text: span,
maxLines: 10,
text: TextSpan(text: body),
maxLines: 8,
textDirection: Directionality.of(context),
)..layout(maxWidth: constraints.maxWidth - 20);
@ -43,29 +40,30 @@ class PostBody extends StatelessWidget {
return ConstrainedBox(
constraints: BoxConstraints(maxHeight: tp.height),
child: Stack(
alignment: Alignment.bottomCenter,
children: [
ClipRect(
child: Align(
alignment: Alignment.topCenter,
heightFactor: 0.8,
child: Padding(
padding: const EdgeInsets.all(10),
child: MarkdownText(body,
instanceHost: store.postView.instanceHost),
Positioned.fill(
bottom: null,
child: Padding(
padding: const EdgeInsets.all(10),
child: MarkdownText(
body,
instanceHost: store.postView.instanceHost,
),
),
),
Container(
height: tp.preferredLineHeight * 2.5,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
theme.cardColor.withAlpha(0),
theme.cardColor,
],
Positioned.fill(
top: null,
child: Container(
height: tp.preferredLineHeight * 2.5,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
theme.cardColor.withAlpha(0),
theme.cardColor,
],
),
),
),
),
@ -74,9 +72,12 @@ class PostBody extends StatelessWidget {
);
} else {
return Padding(
padding: const EdgeInsets.all(10),
child: MarkdownText(body,
instanceHost: store.postView.instanceHost));
padding: const EdgeInsets.all(10),
child: MarkdownText(
body,
instanceHost: store.postView.instanceHost,
),
);
}
},
);

View File

@ -505,7 +505,7 @@ packages:
source: hosted
version: "2.0.0"
nested:
dependency: transitive
dependency: "direct main"
description:
name: nested
url: "https://pub.dartlang.org"

View File

@ -52,6 +52,7 @@ dependencies:
keyboard_dismisser: ^2.0.0
freezed_annotation: ^0.15.0
logging: ^1.0.1
nested: ^1.0.0
flutter:
sdk: flutter