Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quality of life changes #4

Merged
merged 1 commit into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions confichat/analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
analyzer:
errors:
unused_field: ignore
include: package:flutter_lints/flutter.yaml

linter:
Expand Down
5 changes: 4 additions & 1 deletion confichat/lib/app_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import 'dart:io';

import 'package:confichat/ui_widgets.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

Expand Down Expand Up @@ -42,9 +43,11 @@ class AppData {
LlmApi api = LlmApiFactory.create(AiProvider.ollama.name);
bool clearMessagesOnModelSwitch = true;
bool filterHistoryByModel = false;
bool haveUnsavedMessages = false;
int appScrollDurationInms = 100;
double windowWidth = 1024;
double windowHeight = 1024;
AiProvider defaultProvider = AiProvider.ollama;
String rootPath = '';

void defaultCallback(AiProvider? provider) {
Expand Down Expand Up @@ -161,7 +164,7 @@ class ShowErrorDialog extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(title),
title: DialogTitle(title: title),
content: Text(content),
actions: <Widget>[
TextButton(
Expand Down
87 changes: 81 additions & 6 deletions confichat/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@
* SPDX-License-Identifier: Apache-2.0
*/

import 'dart:ui';

import 'package:confichat/ui_widgets.dart';
import 'package:flutter/material.dart';
import 'package:confichat/themes.dart';
import 'package:flutter/scheduler.dart';
import 'package:provider/provider.dart';
import 'package:path_provider/path_provider.dart';
import 'package:desktop_window/desktop_window.dart';
Expand Down Expand Up @@ -60,9 +64,33 @@ class ConfiChat extends StatelessWidget {
// Set theme
if (context.mounted) {
final themeProvider = Provider.of<ThemeProvider>(context, listen: false);
final selectedTheme = jsonContent['app']['selectedTheme'] ?? 'Light';
final selectedTheme = jsonContent['app']['selectedTheme'] ?? 'Onyx';
themeProvider.setTheme(selectedTheme);
}

// Set default provider
if(context.mounted){
final defaultProvider = jsonContent['app']['selectedDefaultProvider'] ?? 'Ollama';

AiProvider selectedProvider;
switch (defaultProvider.toLowerCase()) {
case 'ollama':
selectedProvider = AiProvider.ollama;
break;
case 'openai':
selectedProvider = AiProvider.openai;
break;
case 'llamacpp':
selectedProvider = AiProvider.llamacpp;
break;
default:
selectedProvider = AiProvider.ollama; // Fallback to Ollama if the string doesn't match
break;
}

AppData.instance.defaultProvider = selectedProvider;
}

}
}
}
Expand Down Expand Up @@ -117,21 +145,68 @@ class HomePage extends StatefulWidget {
State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
class _HomePageState extends State<HomePage> {
final ChatSessionSelectedNotifier chatSessionSelectedNotifier = ChatSessionSelectedNotifier();
TextEditingController providerController = TextEditingController();
AiProvider? selectedProvider;

TextEditingController providerModel = TextEditingController();
ModelItem? selectedModel;

late final AppLifecycleListener _lifecycleListener;
late AppLifecycleState? _lifecycleState;

@override
void initState() {
super.initState();
super.initState();

if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
DesktopWindow.setWindowSize(Size(widget.appData.windowWidth, widget.appData.windowHeight));
}
if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
DesktopWindow.setWindowSize(Size(widget.appData.windowWidth, widget.appData.windowHeight));
}

_lifecycleState = SchedulerBinding.instance.lifecycleState;
_lifecycleListener = AppLifecycleListener(
onExitRequested: _checkForUnsavedChat
);
}

Future<AppExitResponse> _checkForUnsavedChat() async {

// If there are no unsaved changes, proceed to exit
if(!widget.appData.haveUnsavedMessages) { return AppExitResponse.exit;}

bool shouldExit = false;
await showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const DialogTitle(title: 'Warning', isError: true),
content: Text(
'There are unsaved messages in the current chat window - they will be lost. Proceed?',
style: Theme.of(context).textTheme.bodyLarge,
),
actions: [
ElevatedButton(
child: const Text('Yes'),
onPressed: () {
shouldExit = true;
Navigator.of(context).pop();
},
),
ElevatedButton(
child: const Text('Cancel'),
onPressed: () {
shouldExit = false;
Navigator.of(context).pop();
},
),
],
);
},
);

return shouldExit ? AppExitResponse.exit : AppExitResponse.cancel;

}

@override
Expand Down
4 changes: 2 additions & 2 deletions confichat/lib/ui_advanced_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,8 @@ class AdvancedOptionsState extends State<AdvancedOptions> {
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Unsaved changes'),
content: const Text('You have unsaved changes to the advanced options. Are you sure you want to exit?'),
title: const DialogTitle(title: 'Unsaved changes', isError: true),
content: Text('You have unsaved changes to the advanced options. Are you sure you want to exit?', style: Theme.of(context).textTheme.bodyLarge,),
actions: [
ElevatedButton(
onPressed: () {
Expand Down
32 changes: 20 additions & 12 deletions confichat/lib/ui_app_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class CCAppBarState extends State<CCAppBar> {
@override
void initState() {
super.initState();
_switchProvider(AiProvider.ollama);
_switchProvider(widget.appData.defaultProvider);
_populateModelList(true);

widget.appData.callbackSwitchProvider = _switchProvider;
Expand Down Expand Up @@ -78,7 +78,7 @@ class CCAppBarState extends State<CCAppBar> {
},
),
actions: [
_buildModelProviderDropdown(context, isPhone),
_buildModelProviderDropdown(context, isPhone, selectedProvider ?? AiProvider.ollama),
_buildModelDropdown(context, isPhone),
if (!isPhone) _buildConfigButton(context),
if (!isPhone) _buildAddButton(context),
Expand All @@ -88,11 +88,11 @@ class CCAppBarState extends State<CCAppBar> {
);
}

Widget _buildModelProviderDropdown(BuildContext context, bool isPhone) {
Widget _buildModelProviderDropdown(BuildContext context, bool isPhone, AiProvider selectedProvider) {
return Container(
margin: const EdgeInsets.all(10),
child: DropdownMenu<AiProvider>(
initialSelection: AiProvider.ollama,
initialSelection: selectedProvider,
controller: widget.providerController,
requestFocusOnTap: true,
textStyle: TextStyle(
Expand Down Expand Up @@ -292,26 +292,35 @@ class CCAppBarState extends State<CCAppBar> {
}
}

void _showModelChangeWarning(BuildContext context, ModelItem newModel) {
showDialog(
Future<void> _showModelChangeWarning(BuildContext context, ModelItem newModel) async {

if(!widget.appData.haveUnsavedMessages) {
_setModelItem(newModel);
return;
}

await showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Warning'),
content: const Text(
'Any messages in the current chat window will be lost. Proceed?',
title: const DialogTitle(title: 'Warning', isError: true),
content: Text(
'There are unsaved messages in the current chat window - they will be lost. Proceed?',
style: Theme.of(context).textTheme.bodyLarge,
),
actions: <Widget>[
actions: [
ElevatedButton(
child: const Text('Yes'),
onPressed: () {
widget.appData.haveUnsavedMessages = false;
_setModelItem(newModel);
Navigator.of(context).pop();
},
),
ElevatedButton(
child: const Text('Cancel'),
onPressed: () {
if(mounted && selectedModel != null) {_setModelItem(selectedModel!);}
Navigator.of(context).pop();
},
),
Expand Down Expand Up @@ -339,9 +348,8 @@ class CCAppBarState extends State<CCAppBar> {
if(mounted) {
setState(() {
selectedProvider = provider;
_populateModelList(true);
});

_populateModelList(true);
}
}

Expand Down
Loading