Skip to content

Commit

Permalink
Add settings page and proxy configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
ActiveChooN committed Jan 22, 2025
1 parent 59919f5 commit a08faff
Show file tree
Hide file tree
Showing 7 changed files with 293 additions and 69 deletions.
59 changes: 56 additions & 3 deletions lib/config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
//
// SPDX-License-Identifier: Apache-2.0

import 'package:fluent_ui/fluent_ui.dart';
import 'package:inference/utils.dart';
import 'dart:convert';
import 'dart:io';
import 'package:path_provider/path_provider.dart';

enum HintsEnum { intelCoreLLMPerformanceSuggestion }

class Hints {
Expand All @@ -12,7 +18,54 @@ class Hints {
}

class Config {
static bool geti = false;
static Hints hints = Hints();
static bool proxyDirect = false;
}
static String _proxy = '';
static bool _proxyEnabled = false;
static ThemeMode _mode = ThemeMode.system;

Check warning on line 24 in lib/config.dart

View check run for this annotation

Codecov / codecov/patch

lib/config.dart#L24

Added line #L24 was not covered by tests

static String get proxy => _proxy;
static set proxy(String value) {

Check warning on line 27 in lib/config.dart

View check run for this annotation

Codecov / codecov/patch

lib/config.dart#L26-L27

Added lines #L26 - L27 were not covered by tests
_proxy = value;
_save('proxy', value);

Check warning on line 29 in lib/config.dart

View check run for this annotation

Codecov / codecov/patch

lib/config.dart#L29

Added line #L29 was not covered by tests
}

static bool get proxyEnabled => _proxyEnabled;
static set proxyEnabled(bool value) {

Check warning on line 33 in lib/config.dart

View check run for this annotation

Codecov / codecov/patch

lib/config.dart#L32-L33

Added lines #L32 - L33 were not covered by tests
_proxyEnabled = value;
_save('proxyEnabled', value);

Check warning on line 35 in lib/config.dart

View check run for this annotation

Codecov / codecov/patch

lib/config.dart#L35

Added line #L35 was not covered by tests
}

static ThemeMode get themeMode => _mode;
static set themeMode(ThemeMode value) {

Check warning on line 39 in lib/config.dart

View check run for this annotation

Codecov / codecov/patch

lib/config.dart#L38-L39

Added lines #L38 - L39 were not covered by tests
_mode = value;
_save('mode', value.index);

Check warning on line 41 in lib/config.dart

View check run for this annotation

Codecov / codecov/patch

lib/config.dart#L41

Added line #L41 was not covered by tests
}

static Future<void> loadFromFile() async {
final directory = await getApplicationSupportDirectory();
final file = File('${directory.path}/config.json');
if (await file.exists()) {
final contents = await file.readAsString();
final json = jsonDecode(contents);
_proxyEnabled = json['proxyEnabled'] ?? false;
if (json['proxy'] is String && json['proxy'].isNotEmpty) {
_proxy = json['proxy'];

Check warning on line 52 in lib/config.dart

View check run for this annotation

Codecov / codecov/patch

lib/config.dart#L44-L52

Added lines #L44 - L52 were not covered by tests
} else if (_proxyEnabled) {
_proxy = await getProxy();

Check warning on line 54 in lib/config.dart

View check run for this annotation

Codecov / codecov/patch

lib/config.dart#L54

Added line #L54 was not covered by tests
}
_mode = ThemeMode.values[json['mode'] ?? 0];

Check warning on line 56 in lib/config.dart

View check run for this annotation

Codecov / codecov/patch

lib/config.dart#L56

Added line #L56 was not covered by tests
}
}

static Future<void> _save(String key, dynamic value) async {
final directory = await getApplicationSupportDirectory();
final file = File('${directory.path}/config.json');
Map<String, dynamic> json = {};
if (await file.exists()) {
final contents = await file.readAsString();
json = jsonDecode(contents);

Check warning on line 66 in lib/config.dart

View check run for this annotation

Codecov / codecov/patch

lib/config.dart#L60-L66

Added lines #L60 - L66 were not covered by tests
}
json[key] = value;
await file.writeAsString(jsonEncode(json));

Check warning on line 69 in lib/config.dart

View check run for this annotation

Codecov / codecov/patch

lib/config.dart#L68-L69

Added lines #L68 - L69 were not covered by tests
}
}
17 changes: 1 addition & 16 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,22 @@
// SPDX-License-Identifier: Apache-2.0
import 'dart:io';

import 'package:dio/dio.dart';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:inference/config.dart';
import 'package:inference/router.dart';
import 'package:inference/theme_fluent.dart';
import 'package:inference/providers/preference_provider.dart';
import 'package:inference/providers/project_provider.dart';
import 'package:inference/public_models.dart';
import 'package:provider/provider.dart';
import 'package:window_manager/window_manager.dart';

const String title = 'OpenVINO TestDrive';

void testConnection() async {
final dio = Dio(BaseOptions(connectTimeout: const Duration(seconds: 10)));

try {
await dio.get(collections[0].path);
} on DioException catch(ex) {
if (ex.type == DioExceptionType.connectionError) {
// Perhaps proxy issue, disable proxy in future requests.
Config.proxyDirect = true;
}
}
}

void main() async {
WidgetsFlutterBinding.ensureInitialized();
testConnection();
await windowManager.ensureInitialized();

await Config.loadFromFile();
WindowOptions windowOptions = WindowOptions(
size: const Size(1400, 1024),
center: true,
Expand Down
32 changes: 15 additions & 17 deletions lib/openvino_console_app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -97,35 +97,33 @@ class _OpenVINOTestDriveAppState extends State<OpenVINOTestDriveApp> {

late final List<NavigationPaneItem> footerNavigationItems = [
PaneItem(
title: const Text('Dark mode'),
icon: Builder(builder: (context) {
final appTheme = context.watch<AppTheme>();
if (appTheme.mode == ThemeMode.dark) {
return const Icon(FluentIcons.clear_night);
} else if (appTheme.mode == ThemeMode.light) {
return const Icon(FluentIcons.brightness);
} else {
return const Icon(FluentIcons.half_alpha);
}
}),
key: const ValueKey('/settings'),
title: const Text('Settings'),
icon: const Icon(FluentIcons.settings),
body: const SizedBox.shrink(),
onTap: () {
final appTheme = context.read<AppTheme>();
appTheme.toggleTheme();
if (GoRouterState.of(context).uri.toString() != '/settings') {
GoRouter.of(context).go('/settings');
}
},
),
];

int? _calculateSelectedIndex(BuildContext context) {
final uri = GoRouterState.of(context).uri.toString();
int? index = originalNavigationItems
int? indexOriginal = originalNavigationItems
.indexWhere((item) {
return uri.startsWith((item.key as ValueKey).value);
});
if (index == -1) {
index = null;
if (indexOriginal == -1) {
int indexFooter = footerNavigationItems
.indexWhere((element) => element.key == Key(uri));
if (indexFooter == -1) {
return 0;
}
return originalNavigationItems.length + indexFooter;
}
return index;
return indexOriginal;
}

void toggleMaximize() {
Expand Down
153 changes: 153 additions & 0 deletions lib/pages/settings/settings.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
// Copyright 2025 Intel Corporation.
// SPDX-License-Identifier: Apache-2.0

import 'package:fluent_ui/fluent_ui.dart';
import 'package:inference/config.dart';
import 'package:inference/theme_fluent.dart';
import 'package:inference/utils.dart';
import 'package:provider/provider.dart';

class SettingsPage extends StatefulWidget {
const SettingsPage({Key? key}) : super(key: key);

@override
_SettingsPageState createState() => _SettingsPageState();
}

class _SettingsPageState extends State<SettingsPage> {
late TextEditingController _proxyController;

@override
void initState() {
super.initState();
_proxyController = TextEditingController(text: Config.proxy);
}

@override
void dispose() {
_proxyController.dispose();
super.dispose();
}

Widget buildSettingSection({
required String title,
required String description,
required Widget child,
bool isWide = false,
}) {
return isWide
? Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: const TextStyle(fontWeight: FontWeight.bold)),
const SizedBox(height: 12),
Text(
description,
style: TextStyle(color: subtleTextColor.of(FluentTheme.of(context)), fontSize: 12),
overflow: TextOverflow.visible,
),
],
),
),
child,
],
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: const TextStyle(fontWeight: FontWeight.bold)),
const SizedBox(height: 12),
Text(
description,
style: TextStyle(color: subtleTextColor.of(FluentTheme.of(context)), fontSize: 12),
overflow: TextOverflow.visible,
),
const SizedBox(height: 8),
child,
],
);
}

@override
Widget build(BuildContext context) {
final theme = Provider.of<AppTheme>(context);
return ScaffoldPage(
header: const PageHeader(title: Text('Settings')),
content: LayoutBuilder(
builder: (context, constraints) {
final isWide = constraints.maxWidth > 589;
return Padding(
padding: EdgeInsets.symmetric(horizontal: isWide ? 32 : 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildSettingSection(
title: 'Appearance',
description: 'Select the color theme for the application.',
child: ComboBox<ThemeMode>(
value: theme.mode,
items: ThemeMode.values.map((mode) {
return ComboBoxItem<ThemeMode>(
value: mode,
child: Text(mode.toString().split('.').last.capitalize()),
);
}).toList(),
onChanged: (mode) {
if (mode != null) {
setState(() {
theme.mode = mode;
});
}
},
),
isWide: isWide,
),
const Padding(
padding: EdgeInsets.symmetric(vertical: 20),
child: Divider(),
),
buildSettingSection(
title: 'HTTPS Proxy',
description: 'Configure the proxy settings for network connections. Leave empty to auto-configure.',
child: Column(
crossAxisAlignment: isWide ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: [
const SizedBox(height: 8),
ToggleSwitch(
checked: Config.proxyEnabled,
onChanged: (value) {
setState(() {
Config.proxyEnabled = value;
});
},
),
const SizedBox(height: 8),
ConstrainedBox(
constraints: BoxConstraints(maxWidth: isWide ? 300 : double.infinity),
child: TextBox(
controller: _proxyController,
placeholder: '<username>:<password>@<proxy>:<port>',
onChanged: (value) {
Config.proxy = value;
},
),
),
],
),
isWide: isWide,
),
const SizedBox(height: 4),
],
),
);
},
),
);
}
}

2 changes: 2 additions & 0 deletions lib/router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import 'package:inference/pages/import/import.dart';
import 'package:inference/pages/models/models.dart';
import 'package:inference/project.dart';
import 'package:inference/pages/models/inference.dart';
import 'package:inference/pages/settings/settings.dart';

final rootNavigatorKey = GlobalKey<NavigatorState>();
final _shellNavigatorKey = GlobalKey<NavigatorState>();
Expand All @@ -26,6 +27,7 @@ final router = GoRouter(navigatorKey: rootNavigatorKey,
),
routes: [
GoRoute(path: '/home', builder: (context, state) => const HomePage()),
GoRoute(path: '/settings', builder: (context, state) => const SettingsPage()),
GoRoute(path: '/models', builder: (context, state) => const ModelsPage()),
GoRoute(path: '/models/import', builder: (context, state) => const ImportPage()),
GoRoute(path: '/models/download', builder: (context, state) => DownloadPage(project: state.extra as PublicProject)),
Expand Down
28 changes: 7 additions & 21 deletions lib/theme_fluent.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter_acrylic/flutter_acrylic.dart';
import 'package:inference/config.dart';

enum NavigationIndicators { sticky, end }

Expand All @@ -25,27 +26,6 @@ class AppTheme extends ChangeNotifier {
notifyListeners();
}

ThemeMode _mode = ThemeMode.system;
ThemeMode get mode => _mode;
set mode(ThemeMode value) {
_mode = value;
notifyListeners();
}

void toggleTheme() {
switch (mode) {
case ThemeMode.system:
mode = ThemeMode.light;
break;
case ThemeMode.light:
mode = ThemeMode.dark;
break;
case ThemeMode.dark:
mode = ThemeMode.system;
break;
}
}

PaneDisplayMode _paneMode = PaneDisplayMode.auto;
PaneDisplayMode get paneMode => _paneMode;
set paneMode(PaneDisplayMode value) {
Expand All @@ -67,6 +47,12 @@ class AppTheme extends ChangeNotifier {
notifyListeners();
}

ThemeMode get mode => Config.themeMode;
set mode(ThemeMode value) {
Config.themeMode = value;
notifyListeners();

Check warning on line 53 in lib/theme_fluent.dart

View check run for this annotation

Codecov / codecov/patch

lib/theme_fluent.dart#L50-L53

Added lines #L50 - L53 were not covered by tests
}

void setEffect(WindowEffect effect, BuildContext context) {
Window.setEffect(
effect: effect,
Expand Down
Loading

0 comments on commit a08faff

Please sign in to comment.