Added double pull to exit

This commit is contained in:
JHubi1 2024-08-20 02:14:05 +02:00
parent 5d68e9893d
commit c41fb53d9c
No known key found for this signature in database
GPG Key ID: 7BF82570CBBBD050
3 changed files with 900 additions and 855 deletions

View File

@ -5,6 +5,11 @@
"description": "Title of the application",
"context": "Visible in the side bar"
},
"backToExit": "Press back again to exit",
"@backToExit": {
"description": "Text displayed when the back button is pressed to exit the app",
"context": "Visible in the chat view"
},
"optionNewChat": "New Chat",
"@optionNewChat": {
"description": "Text displayed for new chat option",

View File

@ -4,6 +4,7 @@ import 'dart:math';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@ -69,6 +70,7 @@ String hoveredChat = "";
final user = types.User(id: const Uuid().v4());
final assistant = types.User(id: const Uuid().v4());
int backPullTimestamp = 0;
bool settingsOpen = false;
bool desktopTitleVisible = true;
bool logoVisible = true;
@ -112,6 +114,16 @@ class _AppState extends State<App> {
void initState() {
super.initState();
SystemChannels.lifecycle.setMessageHandler((msg) async {
if (msg == AppLifecycleState.resumed.toString()) {
// reset back pull timestamp
setState(() {
backPullTimestamp = 0;
});
}
return null;
});
void load() async {
try {
await FlutterDisplayMode.setHighRefreshRate();
@ -971,6 +983,20 @@ class _MainAppState extends State<MainApp> {
return WindowBorder(
color: Theme.of(context).colorScheme.surface,
child: PopScope(
canPop:
DateTime.now().millisecondsSinceEpoch < (backPullTimestamp + 2000),
onPopInvoked: (didPop) {
if (!didPop) {
setState(() {
backPullTimestamp = DateTime.now().microsecondsSinceEpoch;
});
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(AppLocalizations.of(context)!.backToExit),
duration: const Duration(seconds: 2),
showCloseIcon: true));
}
},
child: Scaffold(
appBar: AppBar(
titleSpacing: 0,
@ -979,7 +1005,9 @@ class _MainAppState extends State<MainApp> {
? desktopLayoutRequired(context)
? [
SizedBox(
width: 304, height: 200, child: MoveWindow()),
width: 304,
height: 200,
child: MoveWindow()),
SizedBox(
height: 200,
child: AnimatedOpacity(
@ -1008,7 +1036,9 @@ class _MainAppState extends State<MainApp> {
]
: [
SizedBox(
width: 90, height: 200, child: MoveWindow()),
width: 90,
height: 200,
child: MoveWindow()),
Expanded(
child: SizedBox(
height: 200, child: MoveWindow())),
@ -1069,7 +1099,8 @@ class _MainAppState extends State<MainApp> {
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(AppLocalizations.of(context)!
Text(AppLocalizations.of(
context)!
.deleteDialogDescription),
]),
actions: [
@ -1078,8 +1109,8 @@ class _MainAppState extends State<MainApp> {
selectionHaptic();
Navigator.of(context).pop();
},
child: Text(
AppLocalizations.of(context)!
child: Text(AppLocalizations.of(
context)!
.deleteDialogCancel)),
TextButton(
onPressed: () {
@ -1111,8 +1142,8 @@ class _MainAppState extends State<MainApp> {
chatUuid = null;
setState(() {});
},
child: Text(
AppLocalizations.of(context)!
child: Text(AppLocalizations.of(
context)!
.deleteDialogDelete))
]);
});
@ -1201,7 +1232,8 @@ class _MainAppState extends State<MainApp> {
child: Chat(
messages: messages,
textMessageBuilder: (p0,
{required messageWidth, required showName}) {
{required messageWidth,
required showName}) {
var white =
const TextStyle(color: Colors.white);
bool greyed = false;
@ -1256,16 +1288,54 @@ class _MainAppState extends State<MainApp> {
.blockSyntaxes,
<md.InlineSyntax>[
md.EmojiSyntax(),
...md.ExtensionSet.gitHubFlavored
...md
.ExtensionSet
.gitHubFlavored
.inlineSyntaxes
],
),
imageBuilder: (uri, title, alt) {
if (uri.isAbsolute) {
return Image.network(
uri.toString(), errorBuilder:
(context, error,
stackTrace) {
uri.toString(),
errorBuilder: (context,
error, stackTrace) {
return InkWell(
onTap: () {
selectionHaptic();
ScaffoldMessenger.of(
context)
.showSnackBar(SnackBar(
content: Text(
AppLocalizations.of(
context)!
.notAValidImage),
showCloseIcon:
true));
},
child: Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius
.circular(
8),
color: Theme.of(context)
.brightness ==
Brightness
.light
? Colors.white
: Colors
.black),
padding:
const EdgeInsets.only(
left: 100,
right: 100,
top: 32),
child: const Image(
image: AssetImage(
"assets/logo512error.png"))));
});
} else {
return InkWell(
onTap: () {
selectionHaptic();
@ -1300,40 +1370,6 @@ class _MainAppState extends State<MainApp> {
child: const Image(
image: AssetImage(
"assets/logo512error.png"))));
});
} else {
return InkWell(
onTap: () {
selectionHaptic();
ScaffoldMessenger.of(
context)
.showSnackBar(SnackBar(
content: Text(
AppLocalizations.of(
context)!
.notAValidImage),
showCloseIcon:
true));
},
child: Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius
.circular(8),
color: Theme.of(context)
.brightness ==
Brightness
.light
? Colors.white
: Colors.black),
padding:
const EdgeInsets.only(
left: 100,
right: 100,
top: 32),
child: const Image(
image: AssetImage(
"assets/logo512error.png"))));
}
},
styleSheet: (p0.author == user)
@ -1354,9 +1390,11 @@ class _MainAppState extends State<MainApp> {
color: Colors.black,
backgroundColor:
Colors.white),
codeblockDecoration: BoxDecoration(
codeblockDecoration:
BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(
borderRadius:
BorderRadius.circular(
8)),
h1: white,
h2: white,
@ -1378,22 +1416,17 @@ class _MainAppState extends State<MainApp> {
Brightness.light)
? MarkdownStyleSheet(
p: TextStyle(
color: greyed
? Colors.grey
: Colors.black,
color: greyed ? Colors.grey : Colors.black,
fontSize: 16,
fontWeight:
FontWeight.w500),
blockquoteDecoration:
BoxDecoration(
color: Colors.grey[200],
fontWeight: FontWeight.w500),
blockquoteDecoration: BoxDecoration(
color:
Colors.grey[200],
borderRadius:
BorderRadius
.circular(8),
),
code: const TextStyle(
color: Colors.white,
backgroundColor: Colors.black),
code: const TextStyle(color: Colors.white, backgroundColor: Colors.black),
codeblockDecoration: BoxDecoration(color: Colors.black, borderRadius: BorderRadius.circular(8)),
horizontalRuleDecoration: BoxDecoration(border: Border(top: BorderSide(color: Colors.grey[200]!, width: 1))))
: MarkdownStyleSheet(
@ -1413,8 +1446,9 @@ class _MainAppState extends State<MainApp> {
imageMessageBuilder: (p0,
{required messageWidth}) {
return SizedBox(
width:
desktopLayout(context) ? 360.0 : 160.0,
width: desktopLayout(context)
? 360.0
: 160.0,
child: MarkdownBody(
data: "![${p0.name}](${p0.uri})"));
},
@ -1425,17 +1459,17 @@ class _MainAppState extends State<MainApp> {
onVisibilityChanged:
(VisibilityInfo info) {
if (settingsOpen) return;
logoVisible = info.visibleFraction > 0;
logoVisible =
info.visibleFraction > 0;
try {
setState(() {});
} catch (_) {}
},
child: AnimatedOpacity(
opacity: logoVisible ? 1.0 : 0.0,
duration:
const Duration(milliseconds: 500),
child: const ImageIcon(
AssetImage("assets/logo512.png"),
duration: const Duration(
milliseconds: 500),
child: const ImageIcon(AssetImage("assets/logo512.png"),
size: 44)))),
onSendPressed: (p0) {
send(p0.text, context, setState);
@ -1496,7 +1530,8 @@ class _MainAppState extends State<MainApp> {
}
var text =
(messages[index] as types.TextMessage).text;
(messages[index] as types.TextMessage)
.text;
var input = await prompt(
context,
title: AppLocalizations.of(context)!
@ -1535,7 +1570,8 @@ class _MainAppState extends State<MainApp> {
: null
: () {
selectionHaptic();
if (!chatAllowed || model == null) return;
if (!chatAllowed || model == null)
return;
if (desktopFeature()) {
FilePicker.platform
.pickFiles(type: FileType.image)
@ -1552,8 +1588,10 @@ class _MainAppState extends State<MainApp> {
types.ImageMessage(
author: user,
id: const Uuid().v4(),
name: value.files.first.name,
size: value.files.first.size,
name:
value.files.first.name,
size:
value.files.first.size,
uri:
"data:image/png;base64,$encoded"));
@ -1567,7 +1605,8 @@ class _MainAppState extends State<MainApp> {
builder: (context) {
return Container(
width: double.infinity,
padding: const EdgeInsets.only(
padding:
const EdgeInsets.only(
left: 16,
right: 16,
top: 16),
@ -1594,15 +1633,12 @@ class _MainAppState extends State<MainApp> {
true;
logoVisible =
false;
Navigator.of(context).push(MaterialPageRoute(
builder: (context) =>
const ScreenVoice()));
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => const ScreenVoice()));
},
icon: const Icon(
Icons
icon: const Icon(Icons
.headphones_rounded),
label: Text(
AppLocalizations.of(context)!
label: Text(AppLocalizations.of(context)!
.settingsTitleVoice)))
: const SizedBox
.shrink(),
@ -1628,8 +1664,8 @@ class _MainAppState extends State<MainApp> {
final result =
await ImagePicker()
.pickImage(
source: ImageSource
.camera,
source:
ImageSource.camera,
);
if (result ==
null) {
@ -1649,8 +1685,7 @@ class _MainAppState extends State<MainApp> {
author:
user,
createdAt:
DateTime.now()
.millisecondsSinceEpoch,
DateTime.now().millisecondsSinceEpoch,
height: image
.height
.toDouble(),
@ -1677,10 +1712,11 @@ class _MainAppState extends State<MainApp> {
icon: const Icon(
Icons
.photo_camera_rounded),
label: Text(AppLocalizations.of(
context)!
label: Text(
AppLocalizations.of(context)!
.takeImage))),
const SizedBox(height: 8),
const SizedBox(
height: 8),
SizedBox(
width:
double.infinity,
@ -1696,8 +1732,8 @@ class _MainAppState extends State<MainApp> {
final result =
await ImagePicker()
.pickImage(
source: ImageSource
.gallery,
source:
ImageSource.gallery,
);
if (result ==
null) {
@ -1717,8 +1753,7 @@ class _MainAppState extends State<MainApp> {
author:
user,
createdAt:
DateTime.now()
.millisecondsSinceEpoch,
DateTime.now().millisecondsSinceEpoch,
height: image
.height
.toDouble(),
@ -1745,8 +1780,8 @@ class _MainAppState extends State<MainApp> {
icon: const Icon(
Icons
.image_rounded),
label: Text(AppLocalizations.of(
context)!
label: Text(
AppLocalizations.of(context)!
.uploadImage)))
]));
});
@ -1886,6 +1921,7 @@ class _MainAppState extends State<MainApp> {
selectedIndex: 1,
children: sidebar(context, setState));
})),
),
);
}
}

View File

@ -1,5 +1,6 @@
{
"de": [
"backToExit",
"deleteChat",
"renameChat",
"settingsDescriptionBehavior",
@ -21,6 +22,7 @@
],
"it": [
"backToExit",
"deleteChat",
"renameChat",
"settingsDescriptionBehavior",
@ -42,6 +44,7 @@
],
"tr": [
"backToExit",
"deleteChat",
"renameChat",
"settingsDescriptionBehavior",
@ -63,6 +66,7 @@
],
"zh": [
"backToExit",
"deleteChat",
"renameChat",
"settingsDescriptionBehavior",