160 lines
3.6 KiB
Dart
160 lines
3.6 KiB
Dart
import 'dart:async';
|
|
import 'dart:io';
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:quasar_jet/models/storage_model.dart';
|
|
import 'package:quasar_jet/quick_tile_dispatcher.dart' show quickTileDispatcher;
|
|
import 'package:quasar_jet/services/tray_service.dart';
|
|
import 'package:quasar_jet/services/vpn_service.dart';
|
|
import 'package:quasar_jet/views/main_view.dart';
|
|
import 'package:quasar_jet/theme.dart';
|
|
import 'package:window_manager/window_manager.dart';
|
|
|
|
@pragma('vm:entry-point')
|
|
void _keepQuickTileDispatcher() {
|
|
quickTileDispatcher;
|
|
}
|
|
|
|
@pragma('vm:entry-point')
|
|
Future<void> quickTileMain() async {
|
|
await quickTileDispatcher();
|
|
}
|
|
|
|
Future<void> main() async {
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
|
|
if (_isLinuxDesktop) {
|
|
await windowManager.ensureInitialized();
|
|
await windowManager.waitUntilReadyToShow(
|
|
const WindowOptions(
|
|
size: Size(980, 720),
|
|
center: true,
|
|
title: 'Quasar Jet',
|
|
),
|
|
() async {
|
|
await windowManager.setPreventClose(true);
|
|
await windowManager.show();
|
|
await windowManager.focus();
|
|
},
|
|
);
|
|
}
|
|
|
|
final model = StorageModel();
|
|
await model.init();
|
|
|
|
final vpnService = VpnService();
|
|
|
|
runApp(MyApp(model: model, vpnService: vpnService));
|
|
}
|
|
|
|
// ignore: must_be_immutable
|
|
class MyApp extends StatefulWidget {
|
|
MyApp({super.key, required this.model, required this.vpnService});
|
|
|
|
StorageModel model;
|
|
VpnService vpnService;
|
|
|
|
static _MyAppState of(BuildContext context) {
|
|
return context.findAncestorStateOfType<_MyAppState>()!;
|
|
}
|
|
|
|
@override
|
|
State<MyApp> createState() => _MyAppState();
|
|
}
|
|
|
|
class _MyAppState extends State<MyApp> {
|
|
ThemeMode _themeMode = ThemeMode.system;
|
|
late final WindowListener _windowListener = _LinuxWindowListener(this);
|
|
TrayService? _trayService;
|
|
bool _isQuitting = false;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
if (_isLinuxDesktop) {
|
|
windowManager.addListener(_windowListener);
|
|
unawaited(_initTray());
|
|
}
|
|
}
|
|
|
|
void changeTheme(ThemeMode mode) {
|
|
setState(() {
|
|
_themeMode = mode;
|
|
});
|
|
}
|
|
|
|
Future<void> _initTray() async {
|
|
_trayService = TrayService(
|
|
onShow: _showWindow,
|
|
onHide: _hideWindow,
|
|
onQuit: _quitFromTray,
|
|
);
|
|
await _trayService!.init();
|
|
}
|
|
|
|
Future<void> _showWindow() async {
|
|
await windowManager.show();
|
|
await windowManager.focus();
|
|
}
|
|
|
|
Future<void> _hideWindow() async {
|
|
await windowManager.hide();
|
|
}
|
|
|
|
Future<void> _quitFromTray() async {
|
|
if (_isQuitting) {
|
|
return;
|
|
}
|
|
_isQuitting = true;
|
|
|
|
await widget.vpnService.stop();
|
|
await windowManager.setPreventClose(false);
|
|
await windowManager.close();
|
|
}
|
|
|
|
Future<void> _handleWindowClose() async {
|
|
if (_isQuitting) {
|
|
await windowManager.setPreventClose(false);
|
|
return;
|
|
}
|
|
|
|
await _hideWindow();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
if (_isLinuxDesktop) {
|
|
windowManager.removeListener(_windowListener);
|
|
unawaited(_trayService?.dispose());
|
|
}
|
|
widget.vpnService.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return MaterialApp(
|
|
theme: AppTheme.light,
|
|
darkTheme: AppTheme.dark,
|
|
themeMode: _themeMode,
|
|
home: MainView(model: widget.model, vpnService: widget.vpnService),
|
|
);
|
|
}
|
|
}
|
|
|
|
bool get _isLinuxDesktop {
|
|
return !kIsWeb && Platform.isLinux;
|
|
}
|
|
|
|
final class _LinuxWindowListener with WindowListener {
|
|
_LinuxWindowListener(this._state);
|
|
|
|
final _MyAppState _state;
|
|
|
|
@override
|
|
void onWindowClose() {
|
|
unawaited(_state._handleWindowClose());
|
|
}
|
|
}
|