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

View File

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

View File

@ -1,7 +1,6 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:provider/provider.dart';
import '../../l10n/l10n.dart';
@ -14,7 +13,7 @@ import 'post_more_menu.dart';
import 'post_status.dart';
import 'post_store.dart';
class PostInfoSection extends HookWidget {
class PostInfoSection extends StatelessWidget {
const PostInfoSection();
@override
@ -31,111 +30,91 @@ class PostInfoSection extends HookWidget {
padding: const EdgeInsets.all(10),
child: Row(
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
if (post.community.icon != null)
Padding(
padding: const EdgeInsets.only(right: 10),
child: InkWell(
borderRadius: BorderRadius.circular(20),
onTap: () => goToCommunity.byId(
context, instanceHost, post.community.id),
child: Avatar(
url: post.community.icon,
noBlank: true,
radius: 20,
),
),
if (post.community.icon != null)
Padding(
padding: const EdgeInsets.only(right: 10),
child: InkWell(
borderRadius: BorderRadius.circular(20),
onTap: () => goToCommunity.byId(
context, instanceHost, post.community.id),
child: Avatar(
url: post.community.icon,
noBlank: true,
radius: 20,
),
],
),
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
RichText(
overflow:
TextOverflow.ellipsis, // TODO: fix overflowing
text: TextSpan(
style: TextStyle(
fontSize: 15,
color: theme.textTheme.bodyText1?.color),
children: [
const TextSpan(
text: '!',
style:
TextStyle(fontWeight: FontWeight.w300)),
TextSpan(
text: post.community.name,
style: const TextStyle(
fontWeight: FontWeight.w600),
recognizer: TapGestureRecognizer()
..onTap = () => goToCommunity.byId(context,
instanceHost, post.community.id)),
const TextSpan(
text: '@',
style:
TextStyle(fontWeight: FontWeight.w300)),
TextSpan(
text: post.post.originInstanceHost,
style: const TextStyle(
fontWeight: FontWeight.w600),
recognizer: TapGestureRecognizer()
..onTap = () => goToInstance(
context, post.post.originInstanceHost)),
],
),
)
],
RichText(
overflow: TextOverflow.ellipsis, // TODO: fix overflowing
text: TextSpan(
style: TextStyle(
fontSize: 15,
color: theme.textTheme.bodyText1?.color),
children: [
const TextSpan(
text: '!',
style: TextStyle(fontWeight: FontWeight.w300)),
TextSpan(
text: post.community.name,
style:
const TextStyle(fontWeight: FontWeight.w600),
recognizer: TapGestureRecognizer()
..onTap = () => goToCommunity.byId(
context, instanceHost, post.community.id)),
const TextSpan(
text: '@',
style: TextStyle(fontWeight: FontWeight.w300)),
TextSpan(
text: post.post.originInstanceHost,
style:
const TextStyle(fontWeight: FontWeight.w600),
recognizer: TapGestureRecognizer()
..onTap = () => goToInstance(
context, post.post.originInstanceHost)),
],
),
),
Row(
children: [
RichText(
overflow: TextOverflow.ellipsis,
text: TextSpan(
style: TextStyle(
fontSize: 13,
color: theme.textTheme.bodyText1?.color),
children: [
TextSpan(
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'),
],
RichText(
overflow: TextOverflow.ellipsis,
text: TextSpan(
style: TextStyle(
fontSize: 13,
color: theme.textTheme.bodyText1?.color),
children: [
TextSpan(
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'),
],
),
)
],
),
const Spacer(),

View File

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

View File

@ -11,19 +11,23 @@ class PostMedia extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ObserverBuilder<PostStore>(builder: (context, store) {
final post = store.postView.post;
if (!store.hasMedia) return const SizedBox();
return ObserverBuilder<PostStore>(
builder: (context, store) {
final post = store.postView.post;
if (!store.hasMedia) return const SizedBox();
return FullscreenableImage(
url: post.url!,
child: CachedNetworkImage(
imageUrl: post.url!,
errorWidget: (_, __, ___) => const Icon(Icons.warning),
progressIndicatorBuilder: (context, url, progress) =>
CircularProgressIndicator(value: progress.progress),
),
);
});
final url = post.url!; // hasMedia returns false if url is null
return FullscreenableImage(
url: url,
child: CachedNetworkImage(
imageUrl: url,
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
Widget build(BuildContext context) {
return Column(
children: [
IconButton(
onPressed: () => show(
context: context,
postStore: context.read<PostStore>(),
fullPostStore: null,
),
icon: Icon(moreIcon),
padding: EdgeInsets.zero,
visualDensity: VisualDensity.compact,
)
],
return IconButton(
onPressed: () => show(
context: context,
postStore: context.read<PostStore>(),
fullPostStore: null,
),
icon: Icon(moreIcon),
padding: EdgeInsets.zero,
visualDensity: VisualDensity.compact,
);
}
}
@ -108,7 +104,7 @@ class PostMoreMenu extends HookWidget {
loggedInAction(store.blockUser)();
},
),
if (fullPostStore != null && fullPostStore!.fullPostView != null)
if (fullPostStore?.fullPostView != null)
ObserverBuilder<FullPostStore>(
store: fullPostStore,
builder: (context, store) {

View File

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

View File

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

View File

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