Skip to content

Commit fb0049a

Browse files
committed
Merge branch 'main' into rhecker/fluent-ui-rag
2 parents d9762b5 + ce2f1ff commit fb0049a

File tree

14 files changed

+585
-69
lines changed

14 files changed

+585
-69
lines changed

lib/config.dart

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
//
33
// SPDX-License-Identifier: Apache-2.0
44

5+
import 'package:dio/dio.dart';
6+
import 'package:dio/io.dart';
7+
import 'package:fluent_ui/fluent_ui.dart';
8+
import 'package:inference/utils.dart';
9+
import 'dart:convert';
10+
import 'dart:io';
11+
import 'package:path_provider/path_provider.dart';
12+
513
enum HintsEnum { intelCoreLLMPerformanceSuggestion }
614

715
class Hints {
@@ -12,7 +20,91 @@ class Hints {
1220
}
1321

1422
class Config {
15-
static bool geti = false;
1623
static Hints hints = Hints();
17-
static bool proxyDirect = false;
24+
static String _proxy = '';
25+
static bool _proxyEnabled = false;
26+
static ThemeMode _mode = ThemeMode.system;
27+
static Envvars envvars = Envvars();
28+
29+
static String get proxy => _proxy;
30+
static setProxy(String value) async {
31+
_proxy = value;
32+
await _save('proxy', value);
33+
}
34+
35+
static bool get proxyEnabled => _proxyEnabled;
36+
static setProxyEnabled(bool value) async {
37+
_proxyEnabled = value;
38+
await _save('proxyEnabled', value);
39+
}
40+
41+
static ThemeMode get themeMode => _mode;
42+
static setThemeMode(ThemeMode value) async {
43+
_mode = value;
44+
await _save('mode', value.index);
45+
}
46+
47+
static void reset() {
48+
hints = Hints();
49+
_proxy = '';
50+
_proxyEnabled = false;
51+
_mode = ThemeMode.system;
52+
envvars = Envvars();
53+
}
54+
55+
static Future<String> _getProxy() async {
56+
final dio = Dio(BaseOptions(connectTimeout: const Duration(seconds: 10)));
57+
dio.httpClientAdapter = IOHttpClientAdapter(
58+
createHttpClient: () {
59+
final client = HttpClient();
60+
client.findProxy = (uri) {
61+
return "DIRECT";
62+
};
63+
return client;
64+
},
65+
);
66+
try {
67+
final response = await dio.get('http://wpad/wpad.dat');
68+
if (response.statusCode == 200) {
69+
return parseWpad(response.data);
70+
}
71+
} catch (e) {
72+
print(e.toString());
73+
}
74+
75+
final proxyEnv = envvars.proxy;
76+
if (proxyEnv.isNotEmpty) {
77+
return proxyEnv;
78+
}
79+
return '';
80+
}
81+
82+
static Future<void> loadFromFile() async {
83+
final directory = await getApplicationSupportDirectory();
84+
final file = File('${directory.path}/config.json');
85+
if (await file.exists()) {
86+
final contents = await file.readAsString();
87+
final json = jsonDecode(contents);
88+
_proxyEnabled = json['proxyEnabled'] ?? false;
89+
if (json['proxy'] is String && json['proxy'].isNotEmpty) {
90+
_proxy = json['proxy'];
91+
} else if (_proxyEnabled) {
92+
_proxy = await _getProxy();
93+
}
94+
_mode = ThemeMode.values[json['mode'] ?? 0];
95+
}
96+
}
97+
98+
static Future<void> _save(String key, dynamic value) async {
99+
final directory = await getApplicationSupportDirectory();
100+
final file = File('${directory.path}/config.json');
101+
Map<String, dynamic> json = {};
102+
if (await file.exists()) {
103+
final contents = await file.readAsString();
104+
json = jsonDecode(contents);
105+
}
106+
json[key] = value;
107+
await file.writeAsString(jsonEncode(json));
108+
}
109+
18110
}

lib/main.dart

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// SPDX-License-Identifier: Apache-2.0
44
import 'dart:io';
55

6-
import 'package:dio/dio.dart';
76
import 'package:fluent_ui/fluent_ui.dart';
87
import 'package:inference/config.dart';
98
import 'package:inference/langchain/object_box/object_box.dart';
@@ -12,31 +11,17 @@ import 'package:inference/router.dart';
1211
import 'package:inference/theme_fluent.dart';
1312
import 'package:inference/providers/preference_provider.dart';
1413
import 'package:inference/providers/project_provider.dart';
15-
import 'package:inference/public_models.dart';
1614
import 'package:provider/provider.dart';
1715
import 'package:window_manager/window_manager.dart';
1816

1917
const String title = 'OpenVINO TestDrive';
2018

21-
void testConnection() async {
22-
final dio = Dio(BaseOptions(connectTimeout: const Duration(seconds: 10)));
23-
24-
try {
25-
await dio.get(collections[0].path);
26-
} on DioException catch(ex) {
27-
if (ex.type == DioExceptionType.connectionError) {
28-
// Perhaps proxy issue, disable proxy in future requests.
29-
Config.proxyDirect = true;
30-
}
31-
}
32-
}
3319

3420
void main() async {
3521
WidgetsFlutterBinding.ensureInitialized();
36-
testConnection();
3722
await windowManager.ensureInitialized();
3823
await ObjectBox.create();
39-
24+
await Config.loadFromFile();
4025
WindowOptions windowOptions = WindowOptions(
4126
size: const Size(1400, 1024),
4227
center: true,

lib/openvino_console_app.dart

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import 'package:inference/interop/device.dart';
99
import 'package:inference/interop/image_inference.dart';
1010
import 'package:inference/providers/preference_provider.dart';
1111
import 'package:inference/providers/project_provider.dart';
12-
import 'package:inference/theme_fluent.dart';
1312
import 'package:inference/utils.dart';
1413
import 'package:inference/widgets/feedback_button.dart';
1514
import 'package:provider/provider.dart';
@@ -96,35 +95,33 @@ class _OpenVINOTestDriveAppState extends State<OpenVINOTestDriveApp> {
9695

9796
late final List<NavigationPaneItem> footerNavigationItems = [
9897
PaneItem(
99-
title: const Text('Dark mode'),
100-
icon: Builder(builder: (context) {
101-
final appTheme = context.watch<AppTheme>();
102-
if (appTheme.mode == ThemeMode.dark) {
103-
return const Icon(FluentIcons.clear_night);
104-
} else if (appTheme.mode == ThemeMode.light) {
105-
return const Icon(FluentIcons.brightness);
106-
} else {
107-
return const Icon(FluentIcons.half_alpha);
108-
}
109-
}),
98+
key: const ValueKey('/settings'),
99+
title: const Text('Settings'),
100+
icon: const Icon(FluentIcons.settings),
110101
body: const SizedBox.shrink(),
111102
onTap: () {
112-
final appTheme = context.read<AppTheme>();
113-
appTheme.toggleTheme();
103+
if (GoRouterState.of(context).uri.toString() != '/settings') {
104+
GoRouter.of(context).go('/settings');
105+
}
114106
},
115107
),
116108
];
117109

118110
int? _calculateSelectedIndex(BuildContext context) {
119111
final uri = GoRouterState.of(context).uri.toString();
120-
int? index = originalNavigationItems
112+
int? indexOriginal = originalNavigationItems
121113
.indexWhere((item) {
122114
return uri.startsWith((item.key as ValueKey).value);
123115
});
124-
if (index == -1) {
125-
index = null;
116+
if (indexOriginal == -1) {
117+
int indexFooter = footerNavigationItems
118+
.indexWhere((element) => element.key == Key(uri));
119+
if (indexFooter == -1) {
120+
return 0;
121+
}
122+
return originalNavigationItems.length + indexFooter;
126123
}
127-
return index;
124+
return indexOriginal;
128125
}
129126

130127
void toggleMaximize() {

lib/pages/settings/settings.dart

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// Copyright (c) 2024 Intel Corporation
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
import 'package:fluent_ui/fluent_ui.dart';
6+
import 'package:inference/config.dart';
7+
import 'package:inference/theme_fluent.dart';
8+
import 'package:inference/utils.dart';
9+
import 'package:provider/provider.dart';
10+
11+
class SettingsPage extends StatefulWidget {
12+
const SettingsPage({super.key});
13+
14+
@override
15+
_SettingsPageState createState() => _SettingsPageState();
16+
}
17+
18+
class _SettingsPageState extends State<SettingsPage> {
19+
late TextEditingController _proxyController;
20+
21+
@override
22+
void initState() {
23+
super.initState();
24+
_proxyController = TextEditingController(text: Config.proxy);
25+
}
26+
27+
@override
28+
void dispose() {
29+
_proxyController.dispose();
30+
super.dispose();
31+
}
32+
33+
Widget buildSettingSection({
34+
required String title,
35+
required String description,
36+
required Widget child,
37+
bool isWide = false,
38+
}) {
39+
return isWide
40+
? Row(
41+
mainAxisAlignment: MainAxisAlignment.spaceBetween,
42+
crossAxisAlignment: CrossAxisAlignment.start,
43+
children: [
44+
Expanded(
45+
child: Column(
46+
crossAxisAlignment: CrossAxisAlignment.start,
47+
children: [
48+
Text(title, style: const TextStyle(fontWeight: FontWeight.bold)),
49+
const SizedBox(height: 12),
50+
Text(
51+
description,
52+
style: TextStyle(color: subtleTextColor.of(FluentTheme.of(context)), fontSize: 12),
53+
overflow: TextOverflow.visible,
54+
),
55+
],
56+
),
57+
),
58+
child,
59+
],
60+
)
61+
: Column(
62+
crossAxisAlignment: CrossAxisAlignment.start,
63+
children: [
64+
Text(title, style: const TextStyle(fontWeight: FontWeight.bold)),
65+
const SizedBox(height: 12),
66+
Text(
67+
description,
68+
style: TextStyle(color: subtleTextColor.of(FluentTheme.of(context)), fontSize: 12),
69+
overflow: TextOverflow.visible,
70+
),
71+
const SizedBox(height: 8),
72+
child,
73+
],
74+
);
75+
}
76+
77+
@override
78+
Widget build(BuildContext context) {
79+
final theme = Provider.of<AppTheme>(context);
80+
return ScaffoldPage(
81+
header: const PageHeader(title: Text('Settings')),
82+
content: LayoutBuilder(
83+
builder: (context, constraints) {
84+
final isWide = constraints.maxWidth > 589;
85+
return Padding(
86+
padding: EdgeInsets.symmetric(horizontal: isWide ? 32 : 12),
87+
child: Column(
88+
crossAxisAlignment: CrossAxisAlignment.start,
89+
children: [
90+
buildSettingSection(
91+
title: 'Appearance',
92+
description: 'Select the color theme for the application.',
93+
child: ComboBox<ThemeMode>(
94+
value: theme.mode,
95+
items: ThemeMode.values.map((mode) {
96+
return ComboBoxItem<ThemeMode>(
97+
value: mode,
98+
child: Text(mode.toString().split('.').last.capitalize()),
99+
);
100+
}).toList(),
101+
onChanged: (mode) {
102+
if (mode != null) {
103+
setState(() {
104+
theme.mode = mode;
105+
});
106+
}
107+
},
108+
),
109+
isWide: isWide,
110+
),
111+
const Padding(
112+
padding: EdgeInsets.symmetric(vertical: 20),
113+
child: Divider(),
114+
),
115+
buildSettingSection(
116+
title: 'HTTPS Proxy',
117+
description: 'Configure the proxy settings for network connections. Leave empty to auto-configure.',
118+
child: Column(
119+
crossAxisAlignment: isWide ? CrossAxisAlignment.end : CrossAxisAlignment.start,
120+
children: [
121+
const SizedBox(height: 8),
122+
ToggleSwitch(
123+
checked: Config.proxyEnabled,
124+
onChanged: (value) async {
125+
await Config.setProxyEnabled(value);
126+
setState(() { });
127+
},
128+
),
129+
const SizedBox(height: 8),
130+
ConstrainedBox(
131+
constraints: BoxConstraints(maxWidth: isWide ? 300 : double.infinity),
132+
child: TextBox(
133+
controller: _proxyController,
134+
placeholder: '<username>:<password>@<proxy>:<port>',
135+
onChanged: (value) async {
136+
Config.setProxy(value);
137+
setState(() { });
138+
},
139+
),
140+
),
141+
],
142+
),
143+
isWide: isWide,
144+
),
145+
const SizedBox(height: 4),
146+
],
147+
),
148+
);
149+
},
150+
),
151+
);
152+
}
153+
}
154+

lib/router.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import 'package:inference/pages/knowledge_base/knowledge_base.dart';
1313
import 'package:inference/pages/models/models.dart';
1414
import 'package:inference/project.dart';
1515
import 'package:inference/pages/models/inference.dart';
16+
import 'package:inference/pages/settings/settings.dart';
1617

1718
final rootNavigatorKey = GlobalKey<NavigatorState>();
1819
final _shellNavigatorKey = GlobalKey<NavigatorState>();
@@ -27,6 +28,7 @@ final router = GoRouter(navigatorKey: rootNavigatorKey,
2728
),
2829
routes: [
2930
GoRoute(path: '/home', builder: (context, state) => const HomePage()),
31+
GoRoute(path: '/settings', builder: (context, state) => const SettingsPage()),
3032
GoRoute(path: '/models', builder: (context, state) => const ModelsPage()),
3133
GoRoute(path: '/models/import', builder: (context, state) => const ImportPage()),
3234
GoRoute(path: '/models/download', builder: (context, state) => DownloadPage(project: state.extra as PublicProject)),

0 commit comments

Comments
 (0)