Restrict width of chat view on desktop
This commit is contained in:
parent
36eaf42d1d
commit
443acf8a81
377
lib/main.dart
377
lib/main.dart
|
@ -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: ""));
|
child: MarkdownBody(
|
||||||
|
data: ""));
|
||||||
},
|
},
|
||||||
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:
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue