Batch of changes addressing CR comments

post_info_section.dart
* Hook -> Stateless
* remove mysterious Rows & Columns

post_body.dart
* extract into variable instead of !-ing

post_media.dart
* extract url into variable, give reason for unwrapping
* make spinner adaptive

post_link_preview.dart
* extract url into a variable
* use ?? operator

full_post.dart
* fix bug from previous commit :^)

post_more_menu.dart
* remove useless column

post_title.dart
* rework variables to make it more safe

save_post_button.dart
* remove TODO comment that has been resolved

post_voting.dart
* spinner -> adaprive

post_voting.dart
* spinner -> adaptive
* stop manually adding myVote
This commit is contained in:
Filip Krawczyk 2021-10-19 01:30:30 +02:00
parent 1a1d001052
commit cff87e0682
9 changed files with 138 additions and 159 deletions

View File

@ -58,19 +58,15 @@ class FullPostPage extends StatelessWidget {
); );
} }
static Jwt? _tryGetJwt(BuildContext context) { static Jwt? _tryGetJwt(BuildContext context, String instanceHost) {
final store = context.read<FullPostStore>(); return context.read<AccountsStore>().defaultUserDataFor(instanceHost)?.jwt;
return context
.read<AccountsStore>()
.defaultUserDataFor(store.instanceHost)
?.jwt;
} }
static Route route(int id, String instanceHost) => MaterialPageRoute( static Route route(int id, String instanceHost) => MaterialPageRoute(
builder: (context) => Provider( builder: (context) => Provider(
create: (context) => create: (context) =>
FullPostStore(instanceHost: instanceHost, postId: id) FullPostStore(instanceHost: instanceHost, postId: id)
..refresh(_tryGetJwt(context)), ..refresh(_tryGetJwt(context, instanceHost)),
child: FullPostPage( child: FullPostPage(
id: id, id: id,
instanceHost: instanceHost, instanceHost: instanceHost,
@ -81,14 +77,14 @@ class FullPostPage extends StatelessWidget {
static Route fromPostViewRoute(PostView postView) => MaterialPageRoute( static Route fromPostViewRoute(PostView postView) => MaterialPageRoute(
builder: (context) => Provider( builder: (context) => Provider(
create: (context) => FullPostStore.fromPostView(postView) create: (context) => FullPostStore.fromPostView(postView)
..refresh(_tryGetJwt(context)), ..refresh(_tryGetJwt(context, postView.instanceHost)),
child: FullPostPage.fromPostView(postView), child: FullPostPage.fromPostView(postView),
), ),
); );
static Route fromPostStoreRoute(PostStore postStore) => MaterialPageRoute( static Route fromPostStoreRoute(PostStore postStore) => MaterialPageRoute(
builder: (context) => Provider( builder: (context) => Provider(
create: (context) => FullPostStore.fromPostStore(postStore) create: (context) => FullPostStore.fromPostStore(postStore)
..refresh(_tryGetJwt(context)), ..refresh(_tryGetJwt(context, postStore.postView.instanceHost)),
child: FullPostPage.fromPostStore(postStore)), child: FullPostPage.fromPostStore(postStore)),
); );
} }

View File

@ -16,13 +16,14 @@ class PostBody extends StatelessWidget {
final fullPost = context.read<IsFullPost>(); final fullPost = context.read<IsFullPost>();
return ObserverBuilder<PostStore>(builder: (context, store) { return ObserverBuilder<PostStore>(builder: (context, store) {
if (store.postView.post.body == null) return const SizedBox(); final body = store.postView.post.body;
if (body == null) return const SizedBox();
if (fullPost) { if (fullPost) {
return Padding( return Padding(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: MarkdownText( child: MarkdownText(
store.postView.post.body!, body,
instanceHost: store.postView.instanceHost, instanceHost: store.postView.instanceHost,
selectable: true, selectable: true,
), ),
@ -31,7 +32,7 @@ class PostBody extends StatelessWidget {
return LayoutBuilder( return LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
final span = TextSpan( final span = TextSpan(
text: store.postView.post.body, text: body,
); );
final tp = TextPainter( final tp = TextPainter(
text: span, text: span,
@ -50,9 +51,10 @@ class PostBody extends StatelessWidget {
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
heightFactor: 0.8, heightFactor: 0.8,
child: Padding( child: Padding(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: MarkdownText(store.postView.post.body!, child: MarkdownText(body,
instanceHost: store.postView.instanceHost)), instanceHost: store.postView.instanceHost),
),
), ),
), ),
Container( Container(
@ -74,7 +76,7 @@ class PostBody extends StatelessWidget {
} else { } else {
return Padding( return Padding(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: MarkdownText(store.postView.post.body!, child: MarkdownText(body,
instanceHost: store.postView.instanceHost)); instanceHost: store.postView.instanceHost));
} }
}, },

View File

@ -1,7 +1,6 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../../l10n/l10n.dart'; import '../../l10n/l10n.dart';
@ -14,7 +13,7 @@ import 'post_more_menu.dart';
import 'post_status.dart'; import 'post_status.dart';
import 'post_store.dart'; import 'post_store.dart';
class PostInfoSection extends HookWidget { class PostInfoSection extends StatelessWidget {
const PostInfoSection(); const PostInfoSection();
@override @override
@ -31,111 +30,91 @@ class PostInfoSection extends HookWidget {
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: Row( child: Row(
children: [ children: [
Column( if (post.community.icon != null)
mainAxisSize: MainAxisSize.min, Padding(
children: [ padding: const EdgeInsets.only(right: 10),
if (post.community.icon != null) child: InkWell(
Padding( borderRadius: BorderRadius.circular(20),
padding: const EdgeInsets.only(right: 10), onTap: () => goToCommunity.byId(
child: InkWell( context, instanceHost, post.community.id),
borderRadius: BorderRadius.circular(20), child: Avatar(
onTap: () => goToCommunity.byId( url: post.community.icon,
context, instanceHost, post.community.id), noBlank: true,
child: Avatar( radius: 20,
url: post.community.icon,
noBlank: true,
radius: 20,
),
),
), ),
], ),
), ),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( RichText(
children: [ overflow: TextOverflow.ellipsis, // TODO: fix overflowing
RichText( text: TextSpan(
overflow: style: TextStyle(
TextOverflow.ellipsis, // TODO: fix overflowing fontSize: 15,
text: TextSpan( color: theme.textTheme.bodyText1?.color),
style: TextStyle( children: [
fontSize: 15, const TextSpan(
color: theme.textTheme.bodyText1?.color), text: '!',
children: [ style: TextStyle(fontWeight: FontWeight.w300)),
const TextSpan( TextSpan(
text: '!', text: post.community.name,
style: style:
TextStyle(fontWeight: FontWeight.w300)), const TextStyle(fontWeight: FontWeight.w600),
TextSpan( recognizer: TapGestureRecognizer()
text: post.community.name, ..onTap = () => goToCommunity.byId(
style: const TextStyle( context, instanceHost, post.community.id)),
fontWeight: FontWeight.w600), const TextSpan(
recognizer: TapGestureRecognizer() text: '@',
..onTap = () => goToCommunity.byId(context, style: TextStyle(fontWeight: FontWeight.w300)),
instanceHost, post.community.id)), TextSpan(
const TextSpan( text: post.post.originInstanceHost,
text: '@', style:
style: const TextStyle(fontWeight: FontWeight.w600),
TextStyle(fontWeight: FontWeight.w300)), recognizer: TapGestureRecognizer()
TextSpan( ..onTap = () => goToInstance(
text: post.post.originInstanceHost, context, post.post.originInstanceHost)),
style: const TextStyle( ],
fontWeight: FontWeight.w600), ),
recognizer: TapGestureRecognizer()
..onTap = () => goToInstance(
context, post.post.originInstanceHost)),
],
),
)
],
), ),
Row( RichText(
children: [ overflow: TextOverflow.ellipsis,
RichText( text: TextSpan(
overflow: TextOverflow.ellipsis, style: TextStyle(
text: TextSpan( fontSize: 13,
style: TextStyle( color: theme.textTheme.bodyText1?.color),
fontSize: 13, children: [
color: theme.textTheme.bodyText1?.color), TextSpan(
children: [ text: L10n.of(context)!.by,
TextSpan( style: const TextStyle(fontWeight: FontWeight.w300),
text: L10n.of(context)!.by,
style: const TextStyle(
fontWeight: FontWeight.w300),
),
TextSpan(
text: ' ${post.creator.originPreferredName}',
style: const TextStyle(
fontWeight: FontWeight.w600),
recognizer: TapGestureRecognizer()
..onTap = () => goToUser.fromPersonSafe(
context,
post.creator,
),
),
TextSpan(
text: ' · ${post.post.published.fancyShort}'),
if (post.post.locked)
const TextSpan(text: ' · 🔒'),
if (post.post.stickied)
const TextSpan(text: ' · 📌'),
if (post.post.nsfw) const TextSpan(text: ' · '),
if (post.post.nsfw)
TextSpan(
text: L10n.of(context)!.nsfw,
style: const TextStyle(color: Colors.red)),
if (store.urlDomain != null)
TextSpan(text: ' · ${store.urlDomain}'),
if (post.post.removed)
const TextSpan(text: ' · REMOVED'),
if (post.post.deleted)
const TextSpan(text: ' · DELETED'),
],
), ),
) TextSpan(
], text: ' ${post.creator.originPreferredName}',
), style: const TextStyle(fontWeight: FontWeight.w600),
recognizer: TapGestureRecognizer()
..onTap = () => goToUser.fromPersonSafe(
context,
post.creator,
),
),
TextSpan(
text: ' · ${post.post.published.fancyShort}'),
if (post.post.locked) const TextSpan(text: ' · 🔒'),
if (post.post.stickied) const TextSpan(text: ' · 📌'),
if (post.post.nsfw) const TextSpan(text: ' · '),
if (post.post.nsfw)
TextSpan(
text: L10n.of(context)!.nsfw,
style: const TextStyle(color: Colors.red)),
if (store.urlDomain != null)
TextSpan(text: ' · ${store.urlDomain}'),
if (post.post.removed)
const TextSpan(text: ' · REMOVED'),
if (post.post.deleted)
const TextSpan(text: ' · DELETED'),
],
),
)
], ],
), ),
const Spacer(), const Spacer(),

View File

@ -11,9 +11,9 @@ class PostLinkPreview extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ObserverBuilder<PostStore>( return ObserverBuilder<PostStore>(
builder: (context, store) { builder: (context, store) {
if (store.hasMedia || final url = store.postView.post.url;
store.postView.post.url == null ||
store.postView.post.url!.isEmpty) { if (store.hasMedia || url == null || url.isEmpty) {
return const SizedBox(); return const SizedBox();
} }
@ -24,7 +24,7 @@ class PostLinkPreview extends StatelessWidget {
child: InkWell( child: InkWell(
onTap: () => linkLauncher( onTap: () => linkLauncher(
context: context, context: context,
url: store.postView.post.url!, url: url,
instanceHost: store.postView.instanceHost, instanceHost: store.postView.instanceHost,
), ),
child: Container( child: Container(
@ -58,8 +58,8 @@ class PostLinkPreview extends StatelessWidget {
) )
], ],
), ),
if (store.postView.post.embedDescription != null && if (store.postView.post.embedDescription?.isNotEmpty ??
store.postView.post.embedDescription!.isNotEmpty) false)
Row( Row(
children: [ children: [
Flexible( Flexible(

View File

@ -11,19 +11,23 @@ class PostMedia extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ObserverBuilder<PostStore>(builder: (context, store) { return ObserverBuilder<PostStore>(
final post = store.postView.post; builder: (context, store) {
if (!store.hasMedia) return const SizedBox(); final post = store.postView.post;
if (!store.hasMedia) return const SizedBox();
return FullscreenableImage( final url = post.url!; // hasMedia returns false if url is null
url: post.url!,
child: CachedNetworkImage( return FullscreenableImage(
imageUrl: post.url!, url: url,
errorWidget: (_, __, ___) => const Icon(Icons.warning), child: CachedNetworkImage(
progressIndicatorBuilder: (context, url, progress) => imageUrl: url,
CircularProgressIndicator(value: progress.progress), errorWidget: (_, __, ___) => const Icon(Icons.warning),
), progressIndicatorBuilder: (context, url, progress) =>
); CircularProgressIndicator.adaptive(value: progress.progress),
}); ),
);
},
);
} }
} }

View File

@ -32,19 +32,15 @@ class PostMoreMenuButton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return IconButton(
children: [ onPressed: () => show(
IconButton( context: context,
onPressed: () => show( postStore: context.read<PostStore>(),
context: context, fullPostStore: null,
postStore: context.read<PostStore>(), ),
fullPostStore: null, icon: Icon(moreIcon),
), padding: EdgeInsets.zero,
icon: Icon(moreIcon), visualDensity: VisualDensity.compact,
padding: EdgeInsets.zero,
visualDensity: VisualDensity.compact,
)
],
); );
} }
} }
@ -108,7 +104,7 @@ class PostMoreMenu extends HookWidget {
loggedInAction(store.blockUser)(); loggedInAction(store.blockUser)();
}, },
), ),
if (fullPostStore != null && fullPostStore!.fullPostView != null) if (fullPostStore?.fullPostView != null)
ObserverBuilder<FullPostStore>( ObserverBuilder<FullPostStore>(
store: fullPostStore, store: fullPostStore,
builder: (context, store) { builder: (context, store) {

View File

@ -13,9 +13,11 @@ class PostTitle extends StatelessWidget {
return ObserverBuilder<PostStore>( return ObserverBuilder<PostStore>(
builder: (context, store) { builder: (context, store) {
final post = store.postView.post; final post = store.postView.post;
final thumbnailUrl = post.thumbnailUrl;
final url = post.url;
return Padding( return Padding(
padding: const EdgeInsets.only(left: 10, right: 10, bottom: 10), padding: const EdgeInsets.all(10).copyWith(top: 0),
child: Row( child: Row(
children: [ children: [
Expanded( Expanded(
@ -28,20 +30,20 @@ class PostTitle extends StatelessWidget {
fontSize: 18, fontWeight: FontWeight.w600), fontSize: 18, fontWeight: FontWeight.w600),
), ),
), ),
if (!store.hasMedia && post.thumbnailUrl != null) ...[ if (!store.hasMedia && thumbnailUrl != null && url != null) ...[
const Spacer(), const Spacer(),
InkWell( InkWell(
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
onTap: () => linkLauncher( onTap: () => linkLauncher(
context: context, context: context,
url: post.url!, url: url,
instanceHost: store.postView.instanceHost), instanceHost: store.postView.instanceHost),
child: Stack( child: Stack(
children: [ children: [
ClipRRect( ClipRRect(
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
child: CachedNetworkImage( child: CachedNetworkImage(
imageUrl: post.thumbnailUrl!, imageUrl: thumbnailUrl,
width: 70, width: 70,
height: 70, height: 70,
fit: BoxFit.cover, fit: BoxFit.cover,

View File

@ -34,10 +34,12 @@ class PostVoting extends HookWidget {
), ),
if (store.votingState.isLoading) if (store.votingState.isLoading)
const SizedBox( const SizedBox(
width: 20, height: 20, child: CircularProgressIndicator()) width: 20,
height: 20,
child: CircularProgressIndicator.adaptive(),
)
else if (showScores) else if (showScores)
Text(compactNumber(store.postView.counts.score + Text(compactNumber(store.postView.counts.score)),
(store.postView.myVote?.value ?? 0))),
IconButton( IconButton(
icon: Icon( icon: Icon(
Icons.arrow_downward, Icons.arrow_downward,

View File

@ -6,8 +6,6 @@ import '../../hooks/logged_in_action.dart';
import '../../util/observer_consumers.dart'; import '../../util/observer_consumers.dart';
import 'post_store.dart'; import 'post_store.dart';
// TODO: sync this button between post and fullpost. the same with voting
class SavePostButton extends HookWidget { class SavePostButton extends HookWidget {
const SavePostButton(); const SavePostButton();