Skip to content

Commit

Permalink
v1.24.1-beat.3 (#49)
Browse files Browse the repository at this point in the history
* refactor: implement single instance with window_manager

* style: format code

* refactor(App): move WebViewDashboard

* refactor(App): Home

* refactor(Home): bind WindowListener

* feat(App): dispose webview when window is hidden

* feat(App): show progress indicator when window is reopen

* chore: update .gitignore

* feat: override applicationSupportsSecureRestorableState

* chore: resolve merge conflict

* chore: v1.24.1-beat.3

* ci: upgrade flutter
  • Loading branch information
igoogolx authored Dec 28, 2024
1 parent c07a135 commit e7a5980
Show file tree
Hide file tree
Showing 11 changed files with 228 additions and 99 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
python-version: '3.11'
- uses: subosito/flutter-action@v2
with:
flutter-version: '3.24.0'
flutter-version: '3.27.1'
channel: 'stable'
- run: dart pub global activate flutter_distributor
- run: flutter pub get
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
*.swp
.DS_Store
.atom/
.build/
.buildlog/
.history
.svn/
.swiftpm/
migrate_working_dir/

# IntelliJ related
Expand Down
80 changes: 80 additions & 0 deletions lib/dashboard.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
import 'package:webview_win_floating/webview_plugin.dart';
import 'package:window_manager/window_manager.dart';
import 'package:path/path.dart' as path;

class WebViewDashboard extends StatefulWidget {
final String baseUrl;
final String urlStr;
final String homeDir;
final ValueChanged<String> onUrlChanged;

const WebViewDashboard(this.homeDir, this.baseUrl, this.urlStr, this.onUrlChanged, {super.key});

@override
State<WebViewDashboard> createState() => _WebViewDashboardState();
}

class _WebViewDashboardState extends State<WebViewDashboard> {
late WebViewController? _controller;

_WebViewDashboardState();

@override
void dispose() async {
super.dispose();
var curUrl = await _controller?.currentUrl();
if(curUrl!=null){
widget.onUrlChanged(curUrl);
}
_controller=null;
}


@override
void initState() {
super.initState();
late final PlatformWebViewControllerCreationParams params;
if (WebViewPlatform.instance is WebKitWebViewPlatform) {
params = WebKitWebViewControllerCreationParams();
} else {
String cacheDir = path.join(widget.homeDir, 'cache_webview');
params = WindowsPlatformWebViewControllerCreationParams(
userDataFolder: cacheDir);
}
final WebViewController controller =
WebViewController.fromPlatformCreationParams(params);

controller.setNavigationDelegate(
NavigationDelegate(onNavigationRequest: (NavigationRequest request) {
if (request.url.startsWith(widget.baseUrl)) {
widget.onUrlChanged(request.url);
return NavigationDecision.navigate;
}
launchUrl(Uri.parse(request.url));
return NavigationDecision.prevent;
}, onPageFinished: (String url) async {
await windowManager.show();
await windowManager.focus();
}),
);

controller.loadRequest(Uri.parse(widget.urlStr));
_controller = controller;
}

@override
Widget build(BuildContext context) {
if(_controller !=null){
return Scaffold(
body: WebViewWidget(controller: _controller as WebViewController),
);
}
return Text("Disposed");
}
}
73 changes: 73 additions & 0 deletions lib/home.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:lux/dashboard.dart';
import 'package:lux/progress_indicator.dart';
import 'package:window_manager/window_manager.dart';

class Home extends StatefulWidget {
final String baseUrl;
final String urlStr;
final String homeDir;

const Home(this.homeDir, this.baseUrl, this.urlStr, {super.key});
@override
State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> with WindowListener {

bool isWebviewHidden = false;

String? dashboardUrl;

void onChanged(String newUrl){
dashboardUrl= newUrl;
}

void _init() async {
windowManager.addListener(this);
await windowManager.setPreventClose(true);
setState(() {});
}

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

@override
void onWindowClose() async {
setState(() {
isWebviewHidden= true;
});
if (Platform.isMacOS) {
if (await windowManager.isFullScreen()) {
await windowManager.setFullScreen(false);
//FIXME: remove delay
await Future.delayed(const Duration(seconds: 1));
await windowManager.minimize();
} else {
await windowManager.minimize();
}
} else {
await windowManager.hide();
}
}

@override
void onWindowFocus() async {
setState(() {
isWebviewHidden= false;
});
}

@override
Widget build(BuildContext context) {
var preUrl = dashboardUrl ?? widget.urlStr;
return Scaffold(
body: isWebviewHidden ? AppProgressIndicator() : WebViewDashboard(widget.homeDir, widget.baseUrl,preUrl,onChanged)
);
}
}
98 changes: 11 additions & 87 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:lux/const/const.dart';
import 'package:lux/core_manager.dart';
import 'package:lux/elevate.dart';
import 'package:lux/home.dart';
import 'package:lux/notifier.dart';
import 'package:lux/process_manager.dart';
import 'package:lux/tray.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';
import 'package:url_launcher/url_launcher.dart';
import 'package:lux/const/const.dart';
import 'package:path/path.dart' as path;
import 'package:package_info_plus/package_info_plus.dart';
import 'package:window_manager/window_manager.dart';
import 'package:version/version.dart';
import 'package:flutter_single_instance/flutter_single_instance.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
import 'package:webview_win_floating/webview_win_floating.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';
import 'package:uuid/uuid.dart';
import 'package:version/version.dart';
import 'package:window_manager/window_manager.dart';


var uuid = Uuid();

Expand All @@ -36,11 +34,7 @@ void main(args) async {

try {
await windowManager.ensureInitialized();
if (Platform.isWindows &&
!await FlutterSingleInstance.platform.isFirstInstance()) {
await notifier.show("App is already running");
exitApp();
}


PackageInfo packageInfo = await PackageInfo.fromPlatform();
final port = await findAvailablePort(8000, 9000);
Expand Down Expand Up @@ -82,82 +76,12 @@ void main(args) async {
});
}

runApp(const MaterialApp(home: WebViewDashboard()));
runApp(MaterialApp(home: Home(homeDir,baseUrl,urlStr)));
} catch (e) {
await notifier.show("$e");
exitApp();
}
}

class WebViewDashboard extends StatefulWidget {
const WebViewDashboard({super.key});

@override
State<WebViewDashboard> createState() => _WebViewDashboardState();
}

class _WebViewDashboardState extends State<WebViewDashboard>
with WindowListener {
late final WebViewController _controller;

void _init() async {
windowManager.addListener(this);
await windowManager.setPreventClose(true);
setState(() {});
}

@override
void onWindowClose() async {
if (Platform.isMacOS) {
if (await windowManager.isFullScreen()) {
await windowManager.setFullScreen(false);
//FIXME: remove delay
await Future.delayed(const Duration(seconds: 1));
await windowManager.minimize();
} else {
await windowManager.minimize();
}
} else {
await windowManager.hide();
}
}

@override
void initState() {
super.initState();
_init();
late final PlatformWebViewControllerCreationParams params;
if (WebViewPlatform.instance is WebKitWebViewPlatform) {
params = WebKitWebViewControllerCreationParams();
} else {
String cacheDir = path.join(homeDir, 'cache_webview');
params = WindowsPlatformWebViewControllerCreationParams(
userDataFolder: cacheDir);
}
final WebViewController controller =
WebViewController.fromPlatformCreationParams(params);

controller.setNavigationDelegate(
NavigationDelegate(onNavigationRequest: (NavigationRequest request) {
if (request.url.startsWith(baseUrl)) {
return NavigationDecision.navigate;
}
launchUrl(Uri.parse(request.url));
return NavigationDecision.prevent;
}, onPageFinished: (String url) async {
await windowManager.show();
await windowManager.focus();
}),
);

controller.loadRequest(Uri.parse(urlStr));
_controller = controller;
}

@override
Widget build(BuildContext context) {
return Scaffold(
body: WebViewWidget(controller: _controller),
);
}
}
43 changes: 43 additions & 0 deletions lib/progress_indicator.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import 'package:flutter/material.dart';


class AppProgressIndicator extends StatefulWidget {
const AppProgressIndicator({super.key});

@override
State<AppProgressIndicator> createState() =>
_AppProgressIndicatorState();
}

class _AppProgressIndicatorState extends State<AppProgressIndicator>
with TickerProviderStateMixin {
late AnimationController controller;

@override
void initState() {
controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 500),
)..addListener(() {
setState(() {});
});
controller.repeat(reverse: false);
super.initState();
}

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

@override
Widget build(BuildContext context) {
return Center(
child: CircularProgressIndicator(
value: controller.value,
semanticsLabel: 'Circular progress indicator',
),
);
}
}
4 changes: 4 additions & 0 deletions macos/Runner/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ class AppDelegate: FlutterAppDelegate {
let controller : FlutterViewController = mainFlutterWindow?.contentViewController as! FlutterViewController
return _windowManager.applicationShouldTerminate(controller);
}

override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
return true
}
}
8 changes: 0 additions & 8 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -174,14 +174,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.0.0"
flutter_single_instance:
dependency: "direct main"
description:
name: flutter_single_instance
sha256: fda1cc378b0ef61f50eb92fc41e3a7dba8b0e1564ade3a0ea7f4c3ff59b1b4cd
url: "https://pub.dev"
source: hosted
version: "0.0.1"
flutter_test:
dependency: "direct dev"
description: flutter
Expand Down
3 changes: 1 addition & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.24.1-beat.2
version: 1.24.1-beat.3

environment:
sdk: '>=3.0.6 <4.0.0'
Expand Down Expand Up @@ -51,7 +51,6 @@ dependencies:
url: https://github.com/igoogolx/flutter_window_close.git
ref: main # branch name
version: ^3.0.2
flutter_single_instance: ^0.0.1
webview_flutter: ^4.9.0
webview_flutter_wkwebview: ^3.15.0
webview_win_floating: ^2.2.8
Expand Down
Loading

0 comments on commit e7a5980

Please sign in to comment.