Restrict width of chat view on desktop

This commit is contained in:
JHubi1 2024-06-21 20:23:55 +02:00
parent 36eaf42d1d
commit 443acf8a81
No known key found for this signature in database
GPG Key ID: 7BF82570CBBBD050
2 changed files with 648 additions and 582 deletions

View File

@ -823,14 +823,26 @@ class _MainAppState extends State<MainApp> {
: Colors.grey[900])) : Colors.grey[900]))
: const SizedBox.shrink(), : const SizedBox.shrink(),
Expanded( Expanded(
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Flexible(
child: Container(
constraints: const BoxConstraints(maxWidth: 1000),
child: Chat( child: Chat(
messages: messages, messages: messages,
textMessageBuilder: (p0, textMessageBuilder: (p0,
{required messageWidth, required showName}) { {required messageWidth, required showName}) {
var white = const TextStyle(color: Colors.white); var white =
const TextStyle(color: Colors.white);
return Padding( return Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
left: 20, right: 23, top: 17, bottom: 17), left: 20,
right: 23,
top: 17,
bottom: 17),
child: MarkdownBody( child: MarkdownBody(
data: p0.text, data: p0.text,
onTapLink: (text, href, title) async { onTapLink: (text, href, title) async {
@ -839,25 +851,28 @@ class _MainAppState extends State<MainApp> {
var url = Uri.parse(href!); var url = Uri.parse(href!);
if (await canLaunchUrl(url)) { if (await canLaunchUrl(url)) {
launchUrl( launchUrl(
mode: LaunchMode.inAppBrowserView, mode: LaunchMode
.inAppBrowserView,
url); url);
} else { } else {
throw Exception(); throw Exception();
} }
} catch (_) { } catch (_) {
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context)
SnackBar( .showSnackBar(SnackBar(
content: Text( content: Text(
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
AppLocalizations.of(context)! AppLocalizations.of(
context)!
.settingsHostInvalid( .settingsHostInvalid(
"url")), "url")),
showCloseIcon: true)); showCloseIcon: true));
} }
}, },
extensionSet: md.ExtensionSet( extensionSet: md.ExtensionSet(
md.ExtensionSet.gitHubFlavored.blockSyntaxes, md.ExtensionSet.gitHubFlavored
.blockSyntaxes,
<md.InlineSyntax>[ <md.InlineSyntax>[
md.EmojiSyntax(), md.EmojiSyntax(),
...md.ExtensionSet.gitHubFlavored ...md.ExtensionSet.gitHubFlavored
@ -867,29 +882,34 @@ class _MainAppState extends State<MainApp> {
imageBuilder: (uri, title, alt) { imageBuilder: (uri, title, alt) {
if (uri.isAbsolute) { if (uri.isAbsolute) {
return Image.network(uri.toString(), return Image.network(uri.toString(),
errorBuilder: errorBuilder: (context, error,
(context, error, stackTrace) { stackTrace) {
return InkWell( return InkWell(
onTap: () { onTap: () {
selectionHaptic(); selectionHaptic();
ScaffoldMessenger.of(context) ScaffoldMessenger.of(
context)
.showSnackBar(SnackBar( .showSnackBar(SnackBar(
content: Text( content: Text(
AppLocalizations.of( AppLocalizations.of(
context)! context)!
.notAValidImage), .notAValidImage),
showCloseIcon: true)); showCloseIcon:
true));
}, },
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: borderRadius:
BorderRadius.circular(8), BorderRadius
.circular(8),
color: Theme.of(context) color: Theme.of(context)
.brightness == .brightness ==
Brightness.light Brightness
.light
? Colors.white ? Colors.white
: Colors.black), : Colors.black),
padding: const EdgeInsets.only( padding:
const EdgeInsets.only(
left: 100, left: 100,
right: 100, right: 100,
top: 32), top: 32),
@ -912,14 +932,18 @@ class _MainAppState extends State<MainApp> {
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: borderRadius:
BorderRadius.circular(8), BorderRadius
.circular(8),
color: Theme.of(context) color: Theme.of(context)
.brightness == .brightness ==
Brightness.light Brightness.light
? Colors.white ? Colors.white
: Colors.black), : Colors.black),
padding: const EdgeInsets.only( padding:
left: 100, right: 100, top: 32), const EdgeInsets.only(
left: 100,
right: 100,
top: 32),
child: const Image( child: const Image(
image: AssetImage( image: AssetImage(
"assets/logo512error.png")))); "assets/logo512error.png"))));
@ -930,19 +954,22 @@ class _MainAppState extends State<MainApp> {
p: const TextStyle( p: const TextStyle(
color: Colors.white, color: Colors.white,
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w500), fontWeight:
blockquoteDecoration: BoxDecoration( FontWeight.w500),
blockquoteDecoration:
BoxDecoration(
color: Colors.grey[800], color: Colors.grey[800],
borderRadius: borderRadius:
BorderRadius.circular(8), BorderRadius.circular(8),
), ),
code: const TextStyle( code: const TextStyle(
color: Colors.black, color: Colors.black,
backgroundColor: Colors.white), backgroundColor:
Colors.white),
codeblockDecoration: BoxDecoration( codeblockDecoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: borderRadius: BorderRadius.circular(
BorderRadius.circular(8)), 8)),
h1: white, h1: white,
h2: white, h2: white,
h3: white, h3: white,
@ -950,10 +977,12 @@ class _MainAppState extends State<MainApp> {
h5: white, h5: white,
h6: white, h6: white,
listBullet: white, listBullet: white,
horizontalRuleDecoration: BoxDecoration( horizontalRuleDecoration:
BoxDecoration(
border: Border( border: Border(
top: BorderSide( top: BorderSide(
color: Colors.grey[800]!, color: Colors
.grey[800]!,
width: 1))), width: 1))),
tableBorder: TableBorder.all( tableBorder: TableBorder.all(
color: Colors.white), color: Colors.white),
@ -964,47 +993,39 @@ class _MainAppState extends State<MainApp> {
p: const TextStyle( p: const TextStyle(
color: Colors.black, color: Colors.black,
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w500), fontWeight:
blockquoteDecoration: BoxDecoration( FontWeight.w500),
blockquoteDecoration:
BoxDecoration(
color: Colors.grey[200], color: Colors.grey[200],
borderRadius: borderRadius:
BorderRadius.circular(8), BorderRadius.circular(
8),
), ),
code: const TextStyle( code: const TextStyle(
color: Colors.white, color: Colors.white,
backgroundColor: Colors.black), backgroundColor: Colors.black),
codeblockDecoration: BoxDecoration( codeblockDecoration: BoxDecoration(color: Colors.black, borderRadius: BorderRadius.circular(8)),
color: Colors.black, horizontalRuleDecoration: BoxDecoration(border: Border(top: BorderSide(color: Colors.grey[200]!, width: 1))))
borderRadius:
BorderRadius.circular(8)),
horizontalRuleDecoration: BoxDecoration(
border: Border(
top: BorderSide(
color:
Colors.grey[200]!,
width: 1))))
: MarkdownStyleSheet( : MarkdownStyleSheet(
p: const TextStyle( p: const TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500),
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w500),
blockquoteDecoration: BoxDecoration( blockquoteDecoration: BoxDecoration(
color: Colors.grey[800]!, color: Colors.grey[800]!,
borderRadius: borderRadius:
BorderRadius.circular(8), BorderRadius.circular(
8),
), ),
code: const TextStyle( code: const TextStyle(color: Colors.black, backgroundColor: Colors.white),
color: Colors.black, codeblockDecoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8)),
backgroundColor: Colors.white),
codeblockDecoration:
BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8)),
horizontalRuleDecoration: BoxDecoration(border: Border(top: BorderSide(color: Colors.grey[200]!, width: 1)))))); horizontalRuleDecoration: BoxDecoration(border: Border(top: BorderSide(color: Colors.grey[200]!, width: 1))))));
}, },
imageMessageBuilder: (p0, {required messageWidth}) { imageMessageBuilder: (p0,
{required messageWidth}) {
return SizedBox( return SizedBox(
width: desktopLayout(context) ? 360.0 : 160.0, width:
child: desktopLayout(context) ? 360.0 : 160.0,
MarkdownBody(data: "![${p0.name}](${p0.uri})")); child: MarkdownBody(
data: "![${p0.name}](${p0.uri})"));
}, },
disableImageGallery: true, disableImageGallery: true,
// keyboardDismissBehavior: // keyboardDismissBehavior:
@ -1012,7 +1033,8 @@ class _MainAppState extends State<MainApp> {
emptyState: Center( emptyState: Center(
child: VisibilityDetector( child: VisibilityDetector(
key: const Key("logoVisible"), key: const Key("logoVisible"),
onVisibilityChanged: (VisibilityInfo info) { onVisibilityChanged:
(VisibilityInfo info) {
if (settingsOpen) return; if (settingsOpen) return;
logoVisible = info.visibleFraction > 0; logoVisible = info.visibleFraction > 0;
try { try {
@ -1021,8 +1043,10 @@ class _MainAppState extends State<MainApp> {
}, },
child: AnimatedOpacity( child: AnimatedOpacity(
opacity: logoVisible ? 1.0 : 0.0, opacity: logoVisible ? 1.0 : 0.0,
duration: const Duration(milliseconds: 500), duration:
child: const ImageIcon(AssetImage("assets/logo512.png"), const Duration(milliseconds: 500),
child: const ImageIcon(
AssetImage("assets/logo512.png"),
size: 44)))), size: 44)))),
onSendPressed: (p0) { onSendPressed: (p0) {
send(p0.text, context, setState); send(p0.text, context, setState);
@ -1034,12 +1058,15 @@ class _MainAppState extends State<MainApp> {
for (var i = 0; i < messages.length; i++) { for (var i = 0; i < messages.length; i++) {
if (messages[i].id == p1.id) { if (messages[i].id == p1.id) {
List messageList = List messageList =
(jsonDecode(jsonEncode(messages)) as List) (jsonDecode(jsonEncode(messages))
as List)
.reversed .reversed
.toList(); .toList();
bool found = false; bool found = false;
List index = []; List index = [];
for (var j = 0; j < messageList.length; j++) { for (var j = 0;
j < messageList.length;
j++) {
if (messageList[j]["id"] == p1.id) { if (messageList[j]["id"] == p1.id) {
found = true; found = true;
} }
@ -1048,7 +1075,9 @@ class _MainAppState extends State<MainApp> {
} }
} }
for (var j = 0; j < index.length; j++) { for (var j = 0; j < index.length; j++) {
for (var k = 0; k < messages.length; k++) { for (var k = 0;
k < messages.length;
k++) {
if (messages[k].id == index[j]) { if (messages[k].id == index[j]) {
messages.removeAt(k); messages.removeAt(k);
} }
@ -1063,7 +1092,8 @@ class _MainAppState extends State<MainApp> {
onMessageLongPress: (context, p1) async { onMessageLongPress: (context, p1) async {
selectionHaptic(); selectionHaptic();
if (!(prefs!.getBool("enableEditing") ?? true)) { if (!(prefs!.getBool("enableEditing") ??
true)) {
return; return;
} }
@ -1076,7 +1106,8 @@ class _MainAppState extends State<MainApp> {
} }
} }
var text = (messages[index] as types.TextMessage).text; var text =
(messages[index] as types.TextMessage).text;
var input = await prompt( var input = await prompt(
context, context,
title: AppLocalizations.of(context)! title: AppLocalizations.of(context)!
@ -1098,7 +1129,8 @@ class _MainAppState extends State<MainApp> {
setState(() {}); setState(() {});
}, },
onAttachmentPressed: (!multimodal) onAttachmentPressed: (!multimodal)
? (prefs?.getBool("voiceModeEnabled") ?? false) ? (prefs?.getBool("voiceModeEnabled") ??
false)
? (model != null) ? (model != null)
? () { ? () {
selectionHaptic(); selectionHaptic();
@ -1123,7 +1155,8 @@ class _MainAppState extends State<MainApp> {
if (!multimodal) return; if (!multimodal) return;
var encoded = base64.encode( var encoded = base64.encode(
await File(value.files.first.path!) await File(
value.files.first.path!)
.readAsBytes()); .readAsBytes());
messages.insert( messages.insert(
0, 0,
@ -1146,22 +1179,25 @@ class _MainAppState extends State<MainApp> {
return Container( return Container(
width: double.infinity, width: double.infinity,
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
left: 16, right: 16, top: 16), left: 16,
right: 16,
top: 16),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize:
MainAxisSize.min,
children: [ children: [
(prefs?.getBool( (prefs?.getBool(
"voiceModeEnabled") ?? "voiceModeEnabled") ??
false) false)
? SizedBox( ? SizedBox(
width: double.infinity, width: double
child: .infinity,
OutlinedButton.icon( child: OutlinedButton
.icon(
onPressed: onPressed:
() async { () async {
selectionHaptic(); selectionHaptic();
Navigator.of( Navigator.of(context)
context)
.pop(); .pop();
setMainState = setMainState =
setState; setState;
@ -1169,32 +1205,36 @@ class _MainAppState extends State<MainApp> {
true; true;
logoVisible = logoVisible =
false; false;
Navigator.of( Navigator.of(context).push(MaterialPageRoute(
context) builder: (context) =>
.push(MaterialPageRoute(
builder:
(context) =>
const ScreenVoice())); const ScreenVoice()));
}, },
icon: const Icon(Icons icon: const Icon(
Icons
.headphones_rounded), .headphones_rounded),
label: Text( label: Text(
AppLocalizations.of( AppLocalizations.of(context)!
context)!
.settingsTitleVoice))) .settingsTitleVoice)))
: const SizedBox.shrink(), : const SizedBox
.shrink(),
(prefs?.getBool( (prefs?.getBool(
"voiceModeEnabled") ?? "voiceModeEnabled") ??
false) false)
? const SizedBox(height: 8) ? const SizedBox(
: const SizedBox.shrink(), height: 8)
: const SizedBox
.shrink(),
SizedBox( SizedBox(
width: double.infinity, width:
child: OutlinedButton.icon( double.infinity,
onPressed: () async { child: OutlinedButton
.icon(
onPressed:
() async {
selectionHaptic(); selectionHaptic();
Navigator.of(context) Navigator.of(
context)
.pop(); .pop();
final result = final result =
await ImagePicker() await ImagePicker()
@ -1202,7 +1242,8 @@ class _MainAppState extends State<MainApp> {
source: ImageSource source: ImageSource
.camera, .camera,
); );
if (result == null) { if (result ==
null) {
return; return;
} }
@ -1214,40 +1255,54 @@ class _MainAppState extends State<MainApp> {
bytes); bytes);
final message = final message =
types.ImageMessage( types
author: user, .ImageMessage(
createdAt: DateTime author:
.now() user,
createdAt:
DateTime.now()
.millisecondsSinceEpoch, .millisecondsSinceEpoch,
height: image.height height: image
.height
.toDouble(), .toDouble(),
id: const Uuid().v4(), id: const Uuid()
name: result.name, .v4(),
size: bytes.length, name: result
uri: result.path, .name,
width: image.width size: bytes
.length,
uri: result
.path,
width: image
.width
.toDouble(), .toDouble(),
); );
messages.insert( messages.insert(
0, message); 0,
setState(() {}); message);
setState(
() {});
selectionHaptic(); selectionHaptic();
}, },
icon: const Icon(Icons icon: const Icon(
Icons
.photo_camera_rounded), .photo_camera_rounded),
label: Text( label: Text(AppLocalizations.of(
AppLocalizations.of(
context)! context)!
.takeImage))), .takeImage))),
const SizedBox(height: 8), const SizedBox(height: 8),
SizedBox( SizedBox(
width: double.infinity, width:
child: OutlinedButton.icon( double.infinity,
onPressed: () async { child: OutlinedButton
.icon(
onPressed:
() async {
selectionHaptic(); selectionHaptic();
Navigator.of(context) Navigator.of(
context)
.pop(); .pop();
final result = final result =
await ImagePicker() await ImagePicker()
@ -1255,7 +1310,8 @@ class _MainAppState extends State<MainApp> {
source: ImageSource source: ImageSource
.gallery, .gallery,
); );
if (result == null) { if (result ==
null) {
return; return;
} }
@ -1267,42 +1323,55 @@ class _MainAppState extends State<MainApp> {
bytes); bytes);
final message = final message =
types.ImageMessage( types
author: user, .ImageMessage(
createdAt: DateTime author:
.now() user,
createdAt:
DateTime.now()
.millisecondsSinceEpoch, .millisecondsSinceEpoch,
height: image.height height: image
.height
.toDouble(), .toDouble(),
id: const Uuid().v4(), id: const Uuid()
name: result.name, .v4(),
size: bytes.length, name: result
uri: result.path, .name,
width: image.width size: bytes
.length,
uri: result
.path,
width: image
.width
.toDouble(), .toDouble(),
); );
messages.insert( messages.insert(
0, message); 0,
setState(() {}); message);
setState(
() {});
selectionHaptic(); selectionHaptic();
}, },
icon: const Icon( icon: const Icon(
Icons.image_rounded), Icons
label: Text( .image_rounded),
AppLocalizations.of( label: Text(AppLocalizations.of(
context)! context)!
.uploadImage))) .uploadImage)))
])); ]));
}); });
}, },
l10n: ChatL10nEn( l10n: ChatL10nEn(
inputPlaceholder: AppLocalizations.of(context)! inputPlaceholder:
AppLocalizations.of(context)!
.messageInputPlaceholder, .messageInputPlaceholder,
attachmentButtonAccessibilityLabel: attachmentButtonAccessibilityLabel:
AppLocalizations.of(context)!.tooltipAttachment, AppLocalizations.of(context)!
.tooltipAttachment,
sendButtonAccessibilityLabel: sendButtonAccessibilityLabel:
AppLocalizations.of(context)!.tooltipSend), AppLocalizations.of(context)!
.tooltipSend),
inputOptions: InputOptions( inputOptions: InputOptions(
keyboardType: TextInputType.multiline, keyboardType: TextInputType.multiline,
onTextChanged: (p0) { onTextChanged: (p0) {
@ -1317,30 +1386,29 @@ class _MainAppState extends State<MainApp> {
: SendButtonVisibilityMode.hidden), : SendButtonVisibilityMode.hidden),
user: user, user: user,
hideBackgroundOnEmojiMessages: false, hideBackgroundOnEmojiMessages: false,
theme: (Theme.of(context).brightness == Brightness.light) theme: (Theme.of(context).brightness ==
Brightness.light)
? DefaultChatTheme( ? DefaultChatTheme(
backgroundColor: backgroundColor: (theme ?? ThemeData())
(theme ?? ThemeData()).colorScheme.surface, .colorScheme
primaryColor: .surface,
(theme ?? ThemeData()).colorScheme.primary, primaryColor: (theme ?? ThemeData()).colorScheme.primary,
attachmentButtonIcon: !multimodal attachmentButtonIcon: !multimodal
? (prefs?.getBool("voiceModeEnabled") ?? ? (prefs?.getBool("voiceModeEnabled") ?? false)
false) ? Icon(Icons.headphones_rounded, color: Theme.of(context).iconTheme.color)
? Icon(Icons.headphones_rounded,
color:
Theme.of(context).iconTheme.color)
: null : null
: Icon(Icons.add_a_photo_rounded, : Icon(Icons.add_a_photo_rounded, color: Theme.of(context).iconTheme.color),
color: Theme.of(context).iconTheme.color),
sendButtonIcon: SizedBox( sendButtonIcon: SizedBox(
height: 24, height: 24,
child: CircleAvatar( child: CircleAvatar(
backgroundColor: backgroundColor: Theme.of(context)
Theme.of(context).iconTheme.color, .iconTheme
.color,
radius: 12, radius: 12,
child: Icon(Icons.arrow_upward_rounded, child: Icon(
color: Icons.arrow_upward_rounded,
(prefs?.getBool("useDeviceTheme") ?? color: (prefs?.getBool(
"useDeviceTheme") ??
false) false)
? Theme.of(context) ? Theme.of(context)
.colorScheme .colorScheme
@ -1349,14 +1417,9 @@ class _MainAppState extends State<MainApp> {
), ),
sendButtonMargin: EdgeInsets.zero, sendButtonMargin: EdgeInsets.zero,
attachmentButtonMargin: EdgeInsets.zero, attachmentButtonMargin: EdgeInsets.zero,
inputBackgroundColor: (theme ?? ThemeData()) inputBackgroundColor: (theme ?? ThemeData()).colorScheme.onSurface.withAlpha(10),
.colorScheme inputTextColor: (theme ?? ThemeData()).colorScheme.onSurface,
.onSurface inputBorderRadius: const BorderRadius.all(Radius.circular(64)),
.withAlpha(10),
inputTextColor:
(theme ?? ThemeData()).colorScheme.onSurface,
inputBorderRadius:
const BorderRadius.all(Radius.circular(64)),
inputPadding: const EdgeInsets.all(16), inputPadding: const EdgeInsets.all(16),
inputMargin: EdgeInsets.only(left: 8, right: 8, bottom: (MediaQuery.of(context).viewInsets.bottom == 0.0 && !desktopFeature()) ? 0 : 8), inputMargin: EdgeInsets.only(left: 8, right: 8, bottom: (MediaQuery.of(context).viewInsets.bottom == 0.0 && !desktopFeature()) ? 0 : 8),
messageMaxWidth: (MediaQuery.of(context).size.width >= 1000) messageMaxWidth: (MediaQuery.of(context).size.width >= 1000)
@ -1378,12 +1441,14 @@ class _MainAppState extends State<MainApp> {
sendButtonIcon: SizedBox( sendButtonIcon: SizedBox(
height: 24, height: 24,
child: CircleAvatar( child: CircleAvatar(
backgroundColor: backgroundColor: Theme.of(context)
Theme.of(context).iconTheme.color, .iconTheme
.color,
radius: 12, radius: 12,
child: Icon(Icons.arrow_upward_rounded, child: Icon(
color: Icons.arrow_upward_rounded,
(prefs?.getBool("useDeviceTheme") ?? color: (prefs?.getBool(
"useDeviceTheme") ??
false) false)
? Theme.of(context) ? Theme.of(context)
.colorScheme .colorScheme
@ -1403,7 +1468,13 @@ class _MainAppState extends State<MainApp> {
? 1900 ? 1900
: 1300 : 1300
: 700 : 700
: 440))), : 440)),
),
),
],
),
),
),
], ],
), ),
drawerEdgeDragWidth: drawerEdgeDragWidth:

View File

@ -5,28 +5,23 @@ import 'package:flutter/foundation.dart';
import 'package:bitsdojo_window/bitsdojo_window.dart'; import 'package:bitsdojo_window/bitsdojo_window.dart';
bool desktopFeature() { bool desktopFeature({bool web = false}) {
return (Platform.isWindows || Platform.isLinux || Platform.isMacOS); return (Platform.isWindows ||
Platform.isLinux ||
Platform.isMacOS ||
(web ? kIsWeb : false));
} }
bool desktopWebFeature() { bool desktopLayout(BuildContext context,
return (Platform.isWindows || Platform.isLinux || Platform.isMacOS || kIsWeb); {bool web = false, double? value, double valueCap = 1000}) {
value ??= MediaQuery.of(context).size.width;
return (desktopFeature(web: web) || value >= valueCap);
} }
bool desktopLayout(BuildContext context) { bool desktopLayoutRequired(BuildContext context,
return (desktopFeature() || MediaQuery.of(context).size.width >= 1000); {bool web = false, double? value, double valueCap = 1000}) {
} value ??= MediaQuery.of(context).size.width;
return (desktopFeature(web: web) && value >= valueCap);
bool desktopLayoutRequired(BuildContext context) {
return (desktopFeature() && MediaQuery.of(context).size.width >= 1000);
}
bool desktopWebLayout(BuildContext context) {
return (desktopWebFeature() || MediaQuery.of(context).size.width >= 1000);
}
bool desktopWebLayoutRequired(BuildContext context) {
return (desktopWebFeature() && MediaQuery.of(context).size.width >= 1000);
} }
Widget desktopControls(BuildContext context) { Widget desktopControls(BuildContext context) {