Add a wide/compact post layout mode
This commit is contained in:
parent
fdc77d305b
commit
c22dc3107a
|
@ -17,6 +17,8 @@ class GeneralScreen extends StatelessWidget {
|
|||
final currentThemeMode = themeModeSelect.getOption(controller.themeMode);
|
||||
final currentTheme = themeSelect.getOption(controller.accentColor);
|
||||
|
||||
final currentPostLayout = postLayoutSelect.getOption(controller.postLayout);
|
||||
|
||||
final customLanguageFilterEnabled =
|
||||
!controller.useAccountLangFilter && !isLemmy;
|
||||
|
||||
|
@ -177,6 +179,26 @@ class GeneralScreen extends StatelessWidget {
|
|||
subtitle: const Text(
|
||||
'When enabled, the instance of a user/magazine will always display instead of an @ button'),
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('Post Layout'),
|
||||
leading: const Icon(Icons.view_list),
|
||||
onTap: () async {
|
||||
controller.updatePostLayout(
|
||||
await postLayoutSelect.askSelection(
|
||||
context,
|
||||
controller.postLayout,
|
||||
),
|
||||
);
|
||||
},
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(currentPostLayout.icon),
|
||||
const SizedBox(width: 4),
|
||||
Text(currentPostLayout.title),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
@ -215,3 +237,24 @@ SelectionMenu<String> themeSelect = SelectionMenu(
|
|||
))
|
||||
.toList(),
|
||||
);
|
||||
|
||||
const SelectionMenu<PostLayout> postLayoutSelect = SelectionMenu(
|
||||
'Post Layout',
|
||||
[
|
||||
SelectionMenuItem(
|
||||
value: PostLayout.auto,
|
||||
title: 'Auto',
|
||||
icon: Icons.auto_mode,
|
||||
),
|
||||
SelectionMenuItem(
|
||||
value: PostLayout.narrow,
|
||||
title: 'Narrow',
|
||||
icon: Icons.smartphone,
|
||||
),
|
||||
SelectionMenuItem(
|
||||
value: PostLayout.wide,
|
||||
title: 'Wide',
|
||||
icon: Icons.tablet,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
|
@ -17,6 +17,8 @@ import 'package:shared_preferences/shared_preferences.dart';
|
|||
|
||||
enum ServerSoftware { kbin, mbin, lemmy }
|
||||
|
||||
enum PostLayout { auto, narrow, wide }
|
||||
|
||||
class Server {
|
||||
final ServerSoftware software;
|
||||
final String? oauthIdentifier;
|
||||
|
@ -65,6 +67,8 @@ class SettingsController with ChangeNotifier {
|
|||
|
||||
late bool _alwaysShowInstance;
|
||||
bool get alwaysShowInstance => _alwaysShowInstance;
|
||||
late PostLayout _postLayout;
|
||||
PostLayout get postLayout => _postLayout;
|
||||
|
||||
late ActionLocation _feedActionBackToTop;
|
||||
ActionLocation get feedActionBackToTop => _feedActionBackToTop;
|
||||
|
@ -130,6 +134,11 @@ class SettingsController with ChangeNotifier {
|
|||
_alwaysShowInstance = prefs.getBool("alwaysShowInstance") != null
|
||||
? prefs.getBool("alwaysShowInstance")!
|
||||
: false;
|
||||
_postLayout = parseEnum(
|
||||
PostLayout.values,
|
||||
PostLayout.auto,
|
||||
prefs.getString("postLayout"),
|
||||
);
|
||||
|
||||
_feedActionBackToTop = parseEnum(
|
||||
ActionLocation.values,
|
||||
|
@ -263,6 +272,18 @@ class SettingsController with ChangeNotifier {
|
|||
await prefs.setBool('alwaysShowInstance', newShowDisplayInstance);
|
||||
}
|
||||
|
||||
Future<void> updatePostLayout(PostLayout? newPostLayout) async {
|
||||
if (newPostLayout == null) return;
|
||||
if (newPostLayout == _postLayout) return;
|
||||
|
||||
_postLayout = newPostLayout;
|
||||
|
||||
notifyListeners();
|
||||
|
||||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString('postLayout', newPostLayout.name);
|
||||
}
|
||||
|
||||
Future<void> updateDefaultFeedType(PostType? newDefaultFeedMode) async {
|
||||
if (newDefaultFeedMode == null) return;
|
||||
if (newDefaultFeedMode == _defaultFeedType) return;
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:interstellar/src/screens/explore/domain_screen.dart';
|
||||
import 'package:interstellar/src/screens/explore/magazine_screen.dart';
|
||||
import 'package:interstellar/src/screens/explore/user_screen.dart';
|
||||
import 'package:interstellar/src/screens/settings/settings_controller.dart';
|
||||
import 'package:interstellar/src/utils/utils.dart';
|
||||
import 'package:interstellar/src/widgets/display_name.dart';
|
||||
import 'package:interstellar/src/widgets/markdown.dart';
|
||||
|
@ -10,6 +11,7 @@ import 'package:interstellar/src/widgets/report_content.dart';
|
|||
import 'package:interstellar/src/widgets/text_editor.dart';
|
||||
import 'package:interstellar/src/widgets/video.dart';
|
||||
import 'package:interstellar/src/widgets/wrapper.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class ContentItem extends StatefulWidget {
|
||||
final String originInstance;
|
||||
|
@ -171,375 +173,432 @@ class _ContentItemState extends State<ContentItem> {
|
|||
)
|
||||
: null;
|
||||
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
if (widget.image != null || (!widget.isPreview && widget.video != null))
|
||||
Wrapper(
|
||||
shouldWrap: !widget.isPreview,
|
||||
parentBuilder: (child) => Container(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: MediaQuery.of(context).size.height / 2,
|
||||
),
|
||||
child: child),
|
||||
child: (!widget.isPreview && widget.video != null)
|
||||
? VideoPlayer(widget.video!)
|
||||
: Wrapper(
|
||||
shouldWrap: widget.video == null,
|
||||
parentBuilder: (child) => InkWell(
|
||||
onTap: () => _onImageClick(context),
|
||||
child: child,
|
||||
),
|
||||
child: widget.isPreview
|
||||
? Image.network(
|
||||
widget.image!,
|
||||
height: 160,
|
||||
width: double.infinity,
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: Image.network(widget.image!),
|
||||
return LayoutBuilder(builder: (context, constrains) {
|
||||
final isWide = switch (context.watch<SettingsController>().postLayout) {
|
||||
PostLayout.auto => constrains.maxWidth > 800,
|
||||
PostLayout.narrow => false,
|
||||
PostLayout.wide => true,
|
||||
};
|
||||
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
if ((!isWide && widget.image != null) ||
|
||||
(!widget.isPreview && widget.video != null))
|
||||
Wrapper(
|
||||
shouldWrap: !widget.isPreview,
|
||||
parentBuilder: (child) => Container(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: MediaQuery.of(context).size.height / 2,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
if (widget.title != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 10),
|
||||
child: widget.link != null
|
||||
? InkWell(
|
||||
child: Text(
|
||||
widget.title!,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleLarge!
|
||||
.apply(decoration: TextDecoration.underline),
|
||||
),
|
||||
onTap: () {
|
||||
openWebpage(context, widget.link!);
|
||||
},
|
||||
)
|
||||
: Text(
|
||||
widget.title!,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
if (!widget.showMagazineFirst && userWidget != null)
|
||||
userWidget,
|
||||
if (!widget.showMagazineFirst &&
|
||||
widget.opUserId == widget.userIdOnClick)
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(right: 10), child: Text("OP")),
|
||||
if (widget.showMagazineFirst && magazineWidget != null)
|
||||
magazineWidget,
|
||||
if (widget.createdAt != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 10),
|
||||
child: Text(
|
||||
timeDiffFormat(widget.createdAt!),
|
||||
style: const TextStyle(fontWeight: FontWeight.w300),
|
||||
child: child),
|
||||
child: (!widget.isPreview && widget.video != null)
|
||||
? VideoPlayer(widget.video!)
|
||||
: Wrapper(
|
||||
shouldWrap: widget.video == null,
|
||||
parentBuilder: (child) => InkWell(
|
||||
onTap: () => _onImageClick(context),
|
||||
child: child,
|
||||
),
|
||||
child: widget.isPreview
|
||||
? Image.network(
|
||||
widget.image!,
|
||||
height: 160,
|
||||
width: double.infinity,
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: Image.network(widget.image!),
|
||||
),
|
||||
if (widget.showMagazineFirst && userWidget != null)
|
||||
userWidget,
|
||||
if (widget.showMagazineFirst &&
|
||||
widget.opUserId == widget.userIdOnClick)
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(right: 10), child: Text("OP")),
|
||||
if (!widget.showMagazineFirst && magazineWidget != null)
|
||||
magazineWidget,
|
||||
if (widget.domain != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 10),
|
||||
child: IconButton(
|
||||
tooltip: widget.domain,
|
||||
onPressed: widget.domainIdOnClick != null
|
||||
? () => Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => DomainScreen(
|
||||
widget.domainIdOnClick!,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
if (widget.title != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 10),
|
||||
child: widget.link != null
|
||||
? InkWell(
|
||||
child: Text(
|
||||
widget.title!,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleLarge!
|
||||
.apply(
|
||||
decoration:
|
||||
TextDecoration.underline),
|
||||
),
|
||||
onTap: () {
|
||||
openWebpage(context, widget.link!);
|
||||
},
|
||||
)
|
||||
: null,
|
||||
icon: const Icon(Icons.public),
|
||||
iconSize: 16,
|
||||
style: const ButtonStyle(
|
||||
minimumSize:
|
||||
MaterialStatePropertyAll(Size.fromRadius(16))),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (widget.body != null) const SizedBox(height: 10),
|
||||
if (widget.body != null)
|
||||
widget.isPreview
|
||||
? Text(
|
||||
widget.body!,
|
||||
maxLines: 4,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
)
|
||||
: Markdown(widget.body!, widget.originInstance),
|
||||
const SizedBox(height: 10),
|
||||
LayoutBuilder(builder: (context, constrains) {
|
||||
final votingWidgets = [
|
||||
if (widget.boosts != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: Row(
|
||||
: Text(
|
||||
widget.title!,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.rocket_launch),
|
||||
color: widget.isBoosted
|
||||
? Colors.purple.shade400
|
||||
: null,
|
||||
onPressed: widget.onBoost,
|
||||
),
|
||||
Text(intFormat(widget.boosts!))
|
||||
],
|
||||
),
|
||||
),
|
||||
if (widget.upVotes != null || widget.downVotes != null)
|
||||
Row(
|
||||
children: [
|
||||
if (widget.upVotes != null)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.arrow_upward),
|
||||
color:
|
||||
widget.isUpVoted ? Colors.green.shade400 : null,
|
||||
onPressed: widget.onUpVote,
|
||||
),
|
||||
Text(intFormat(
|
||||
(widget.upVotes ?? 0) - (widget.downVotes ?? 0))),
|
||||
if (widget.downVotes != null)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.arrow_downward),
|
||||
color:
|
||||
widget.isDownVoted ? Colors.red.shade400 : null,
|
||||
onPressed: widget.onDownVote,
|
||||
),
|
||||
],
|
||||
),
|
||||
];
|
||||
final commentWidgets = [
|
||||
if (widget.numComments != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.comment),
|
||||
const SizedBox(width: 4),
|
||||
Text(intFormat(widget.numComments!))
|
||||
],
|
||||
),
|
||||
),
|
||||
if (widget.onReply != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.reply),
|
||||
onPressed: () => setState(() {
|
||||
_replyTextController = TextEditingController();
|
||||
}),
|
||||
),
|
||||
),
|
||||
if (widget.onCollapse != null)
|
||||
IconButton(
|
||||
tooltip: widget.isCollapsed ? 'Expand' : 'Collapse',
|
||||
onPressed: widget.onCollapse,
|
||||
icon: widget.isCollapsed
|
||||
? const Icon(Icons.expand_more)
|
||||
: const Icon(Icons.expand_less)),
|
||||
];
|
||||
final menuWidgets = [
|
||||
if (widget.openLinkUri != null ||
|
||||
widget.onReport != null ||
|
||||
widget.onEdit != null ||
|
||||
widget.onDelete != null)
|
||||
MenuAnchor(
|
||||
builder: (BuildContext context, MenuController controller,
|
||||
Widget? child) {
|
||||
return IconButton(
|
||||
icon: const Icon(Icons.more_vert),
|
||||
onPressed: () {
|
||||
if (_menuController.isOpen) {
|
||||
_menuController.close();
|
||||
} else {
|
||||
_menuController.open();
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
controller: _menuController,
|
||||
menuChildren: [
|
||||
if (widget.openLinkUri != null)
|
||||
MenuItemButton(
|
||||
onPressed: () =>
|
||||
openWebpage(context, widget.openLinkUri!),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Text("Open Link")),
|
||||
),
|
||||
if (widget.onReport != null)
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
final reportReason = await reportContent(
|
||||
context, widget.contentTypeName);
|
||||
|
||||
if (reportReason != null) {
|
||||
await widget.onReport!(reportReason);
|
||||
}
|
||||
},
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Text("Report")),
|
||||
),
|
||||
if (widget.onEdit != null)
|
||||
MenuItemButton(
|
||||
onPressed: () => setState(() {
|
||||
_editTextController =
|
||||
TextEditingController(text: widget.body);
|
||||
}),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Text("Edit")),
|
||||
),
|
||||
if (widget.onDelete != null)
|
||||
MenuItemButton(
|
||||
onPressed: () => showDialog<String>(
|
||||
context: context,
|
||||
builder: (BuildContext context) => AlertDialog(
|
||||
title: Text('Delete ${widget.contentTypeName}'),
|
||||
actions: <Widget>[
|
||||
OutlinedButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
|
||||
widget.onDelete!();
|
||||
},
|
||||
child: const Text('Delete'),
|
||||
),
|
||||
],
|
||||
actionsOverflowAlignment:
|
||||
OverflowBarAlignment.center,
|
||||
actionsOverflowButtonSpacing: 8,
|
||||
actionsOverflowDirection: VerticalDirection.up,
|
||||
if (!widget.showMagazineFirst && userWidget != null)
|
||||
userWidget,
|
||||
if (!widget.showMagazineFirst &&
|
||||
widget.opUserId == widget.userIdOnClick)
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(right: 10),
|
||||
child: Text("OP")),
|
||||
if (widget.showMagazineFirst &&
|
||||
magazineWidget != null)
|
||||
magazineWidget,
|
||||
if (widget.createdAt != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 10),
|
||||
child: Text(
|
||||
timeDiffFormat(widget.createdAt!),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w300),
|
||||
),
|
||||
),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Text("Delete")),
|
||||
),
|
||||
],
|
||||
),
|
||||
];
|
||||
if (widget.showMagazineFirst && userWidget != null)
|
||||
userWidget,
|
||||
if (widget.showMagazineFirst &&
|
||||
widget.opUserId == widget.userIdOnClick)
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(right: 10),
|
||||
child: Text("OP")),
|
||||
if (!widget.showMagazineFirst &&
|
||||
magazineWidget != null)
|
||||
magazineWidget,
|
||||
if (widget.domain != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 10),
|
||||
child: IconButton(
|
||||
tooltip: widget.domain,
|
||||
onPressed: widget.domainIdOnClick != null
|
||||
? () => Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => DomainScreen(
|
||||
widget.domainIdOnClick!,
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
icon: const Icon(Icons.public),
|
||||
iconSize: 16,
|
||||
style: const ButtonStyle(
|
||||
minimumSize: MaterialStatePropertyAll(
|
||||
Size.fromRadius(16))),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (widget.body != null) const SizedBox(height: 10),
|
||||
if (widget.body != null)
|
||||
widget.isPreview
|
||||
? Text(
|
||||
widget.body!,
|
||||
maxLines: 4,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
)
|
||||
: Markdown(widget.body!, widget.originInstance),
|
||||
const SizedBox(height: 10),
|
||||
LayoutBuilder(builder: (context, constrains) {
|
||||
final votingWidgets = [
|
||||
if (widget.boosts != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.rocket_launch),
|
||||
color: widget.isBoosted
|
||||
? Colors.purple.shade400
|
||||
: null,
|
||||
onPressed: widget.onBoost,
|
||||
),
|
||||
Text(intFormat(widget.boosts!))
|
||||
],
|
||||
),
|
||||
),
|
||||
if (widget.upVotes != null ||
|
||||
widget.downVotes != null)
|
||||
Row(
|
||||
children: [
|
||||
if (widget.upVotes != null)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.arrow_upward),
|
||||
color: widget.isUpVoted
|
||||
? Colors.green.shade400
|
||||
: null,
|
||||
onPressed: widget.onUpVote,
|
||||
),
|
||||
Text(intFormat((widget.upVotes ?? 0) -
|
||||
(widget.downVotes ?? 0))),
|
||||
if (widget.downVotes != null)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.arrow_downward),
|
||||
color: widget.isDownVoted
|
||||
? Colors.red.shade400
|
||||
: null,
|
||||
onPressed: widget.onDownVote,
|
||||
),
|
||||
],
|
||||
),
|
||||
];
|
||||
final commentWidgets = [
|
||||
if (widget.numComments != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.comment),
|
||||
const SizedBox(width: 4),
|
||||
Text(intFormat(widget.numComments!))
|
||||
],
|
||||
),
|
||||
),
|
||||
if (widget.onReply != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.reply),
|
||||
onPressed: () => setState(() {
|
||||
_replyTextController =
|
||||
TextEditingController();
|
||||
}),
|
||||
),
|
||||
),
|
||||
if (widget.onCollapse != null)
|
||||
IconButton(
|
||||
tooltip:
|
||||
widget.isCollapsed ? 'Expand' : 'Collapse',
|
||||
onPressed: widget.onCollapse,
|
||||
icon: widget.isCollapsed
|
||||
? const Icon(Icons.expand_more)
|
||||
: const Icon(Icons.expand_less)),
|
||||
];
|
||||
final menuWidgets = [
|
||||
if (widget.openLinkUri != null ||
|
||||
widget.onReport != null ||
|
||||
widget.onEdit != null ||
|
||||
widget.onDelete != null)
|
||||
MenuAnchor(
|
||||
builder: (BuildContext context,
|
||||
MenuController controller, Widget? child) {
|
||||
return IconButton(
|
||||
icon: const Icon(Icons.more_vert),
|
||||
onPressed: () {
|
||||
if (_menuController.isOpen) {
|
||||
_menuController.close();
|
||||
} else {
|
||||
_menuController.open();
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
controller: _menuController,
|
||||
menuChildren: [
|
||||
if (widget.openLinkUri != null)
|
||||
MenuItemButton(
|
||||
onPressed: () => openWebpage(
|
||||
context, widget.openLinkUri!),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Text("Open Link")),
|
||||
),
|
||||
if (widget.onReport != null)
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
final reportReason = await reportContent(
|
||||
context, widget.contentTypeName);
|
||||
|
||||
return constrains.maxWidth < 300
|
||||
? Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: votingWidgets,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
...commentWidgets,
|
||||
const Spacer(),
|
||||
...menuWidgets,
|
||||
if (reportReason != null) {
|
||||
await widget.onReport!(reportReason);
|
||||
}
|
||||
},
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Text("Report")),
|
||||
),
|
||||
if (widget.onEdit != null)
|
||||
MenuItemButton(
|
||||
onPressed: () => setState(() {
|
||||
_editTextController =
|
||||
TextEditingController(
|
||||
text: widget.body);
|
||||
}),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Text("Edit")),
|
||||
),
|
||||
if (widget.onDelete != null)
|
||||
MenuItemButton(
|
||||
onPressed: () => showDialog<String>(
|
||||
context: context,
|
||||
builder: (BuildContext context) =>
|
||||
AlertDialog(
|
||||
title: Text(
|
||||
'Delete ${widget.contentTypeName}'),
|
||||
actions: <Widget>[
|
||||
OutlinedButton(
|
||||
onPressed: () =>
|
||||
Navigator.pop(context),
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
|
||||
widget.onDelete!();
|
||||
},
|
||||
child: const Text('Delete'),
|
||||
),
|
||||
],
|
||||
actionsOverflowAlignment:
|
||||
OverflowBarAlignment.center,
|
||||
actionsOverflowButtonSpacing: 8,
|
||||
actionsOverflowDirection:
|
||||
VerticalDirection.up,
|
||||
),
|
||||
),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Text("Delete")),
|
||||
),
|
||||
],
|
||||
),
|
||||
];
|
||||
|
||||
return constrains.maxWidth < 300
|
||||
? Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: votingWidgets,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
...commentWidgets,
|
||||
const Spacer(),
|
||||
...menuWidgets,
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
children: <Widget>[
|
||||
...commentWidgets,
|
||||
const Spacer(),
|
||||
...menuWidgets,
|
||||
const SizedBox(width: 8),
|
||||
...votingWidgets,
|
||||
],
|
||||
);
|
||||
}),
|
||||
if (widget.onReply != null &&
|
||||
_replyTextController != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
TextEditor(_replyTextController!,
|
||||
isMarkdown: true),
|
||||
const SizedBox(height: 10),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
OutlinedButton(
|
||||
onPressed: () => setState(() {
|
||||
_replyTextController!.dispose();
|
||||
_replyTextController = null;
|
||||
}),
|
||||
child: const Text('Cancel')),
|
||||
const SizedBox(width: 8),
|
||||
FilledButton(
|
||||
onPressed: () async {
|
||||
// Wait in case of errors before closing
|
||||
await widget.onReply!(
|
||||
_replyTextController!.text);
|
||||
|
||||
setState(() {
|
||||
_replyTextController!.dispose();
|
||||
_replyTextController = null;
|
||||
});
|
||||
},
|
||||
child: const Text('Submit'))
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
children: <Widget>[
|
||||
...commentWidgets,
|
||||
const Spacer(),
|
||||
...menuWidgets,
|
||||
const SizedBox(width: 8),
|
||||
...votingWidgets,
|
||||
],
|
||||
);
|
||||
}),
|
||||
if (widget.onReply != null && _replyTextController != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
TextEditor(_replyTextController!, isMarkdown: true),
|
||||
const SizedBox(height: 10),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
OutlinedButton(
|
||||
onPressed: () => setState(() {
|
||||
_replyTextController!.dispose();
|
||||
_replyTextController = null;
|
||||
}),
|
||||
child: const Text('Cancel')),
|
||||
const SizedBox(width: 8),
|
||||
FilledButton(
|
||||
onPressed: () async {
|
||||
// Wait in case of errors before closing
|
||||
await widget
|
||||
.onReply!(_replyTextController!.text);
|
||||
),
|
||||
if (widget.onEdit != null && _editTextController != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
TextEditor(_editTextController!,
|
||||
isMarkdown: true),
|
||||
const SizedBox(height: 10),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
OutlinedButton(
|
||||
onPressed: () => setState(() {
|
||||
_editTextController!.dispose();
|
||||
_editTextController = null;
|
||||
}),
|
||||
child: const Text('Cancel')),
|
||||
const SizedBox(width: 8),
|
||||
FilledButton(
|
||||
onPressed: () async {
|
||||
// Wait in case of errors before closing
|
||||
await widget
|
||||
.onEdit!(_editTextController!.text);
|
||||
|
||||
setState(() {
|
||||
_replyTextController!.dispose();
|
||||
_replyTextController = null;
|
||||
});
|
||||
},
|
||||
child: const Text('Submit'))
|
||||
],
|
||||
)
|
||||
setState(() {
|
||||
_editTextController!.dispose();
|
||||
_editTextController = null;
|
||||
});
|
||||
},
|
||||
child: const Text('Submit'),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (widget.onEdit != null && _editTextController != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
TextEditor(_editTextController!, isMarkdown: true),
|
||||
const SizedBox(height: 10),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
OutlinedButton(
|
||||
onPressed: () => setState(() {
|
||||
_editTextController!.dispose();
|
||||
_editTextController = null;
|
||||
}),
|
||||
child: const Text('Cancel')),
|
||||
const SizedBox(width: 8),
|
||||
FilledButton(
|
||||
onPressed: () async {
|
||||
// Wait in case of errors before closing
|
||||
await widget.onEdit!(_editTextController!.text);
|
||||
|
||||
setState(() {
|
||||
_editTextController!.dispose();
|
||||
_editTextController = null;
|
||||
});
|
||||
},
|
||||
child: const Text('Submit'),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
if (isWide && widget.image != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 16),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Wrapper(
|
||||
shouldWrap: widget.video == null,
|
||||
parentBuilder: (child) => InkWell(
|
||||
onTap: () => _onImageClick(context),
|
||||
child: child,
|
||||
),
|
||||
child: Image.network(
|
||||
widget.image!,
|
||||
height: 128,
|
||||
width: 128,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue