Skip to content

Commit

Permalink
[gui] remember window size per each resolution
Browse files Browse the repository at this point in the history
  • Loading branch information
andrei-toterman committed Dec 16, 2024
1 parent f023f60 commit 8055fc1
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 78 deletions.
80 changes: 2 additions & 78 deletions src/client/gui/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
import 'package:async/async.dart';
import 'package:basics/int_basics.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hotkey_manager/hotkey_manager.dart';
import 'package:local_notifier/local_notifier.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:window_manager/window_manager.dart';
import 'package:window_size/window_size.dart';

import 'before_quit_dialog.dart';
import 'catalogue/catalogue.dart';
import 'daemon_unavailable.dart';
import 'extensions.dart';
import 'help.dart';
import 'logger.dart';
import 'notifications.dart';
import 'platform/platform.dart';
import 'providers.dart';
import 'settings/hotkey.dart';
import 'settings/settings.dart';
Expand All @@ -24,6 +19,7 @@ import 'tray_menu.dart';
import 'vm_details/mapping_slider.dart';
import 'vm_details/vm_details.dart';
import 'vm_table/vm_table_screen.dart';
import 'window_size.dart';

void main() async {
WidgetsFlutterBinding.ensureInitialized();
Expand All @@ -36,12 +32,11 @@ void main() async {
);

final sharedPreferences = await SharedPreferences.getInstance();
final screenSize = await getCurrentScreenSize();
await windowManager.ensureInitialized();
final windowOptions = WindowOptions(
center: true,
minimumSize: const Size(750, 450),
size: deriveWindowSize(sharedPreferences, screenSize),
size: await deriveWindowSize(sharedPreferences),
title: 'Multipass',
);

Expand Down Expand Up @@ -160,14 +155,6 @@ class _AppState extends ConsumerState<App> with WindowListener {
super.dispose();
}

final saveWindowSizeTimer = RestartableTimer(1.seconds, () async {
final currentSize = await windowManager.getSize();
final sharedPreferences = await SharedPreferences.getInstance();
logger.d('Saving screen size: ${currentSize.s()}');
sharedPreferences.setDouble(windowWidthKey, currentSize.width);
sharedPreferences.setDouble(windowHeightKey, currentSize.height);
});

// this event handler is called continuously during a window resizing operation
// so we want to save the data to the disk only after the resizing stops
@override
Expand Down Expand Up @@ -224,69 +211,6 @@ class _AppState extends ConsumerState<App> with WindowListener {
}
}

const windowWidthKey = 'windowWidth';
const windowHeightKey = 'windowHeight';

Future<Size?> getCurrentScreenSize() async {
try {
final screen = await getCurrentScreen();
if (screen == null) throw Exception('Screen instance is null');

final scaleFactor = screen.scaleFactor;
final visibleFrameSize = screen.visibleFrame.size;
final size = mpPlatform.multiplyScreenScaleFactor
? visibleFrameSize * scaleFactor
: visibleFrameSize;

logger.d(
'Got Screen{frame: ${screen.frame.s()}, scaleFactor: $scaleFactor, visibleFrame: ${screen.visibleFrame.s()}, scaledSize: ${size.s()}}',
);

return size;
} catch (e) {
logger.w('Failed to get current screen information: $e');
return null;
}
}

Size deriveWindowSize(SharedPreferences sharedPreferences, Size? screenSize) {
final lastWindowWidth = sharedPreferences.getDouble(windowWidthKey);
final lastWindowHeight = sharedPreferences.getDouble(windowHeightKey);
final size = lastWindowWidth != null && lastWindowHeight != null
? Size(lastWindowWidth, lastWindowHeight)
: null;
logger.d('Got last window size: ${size?.s()}');
final clampedSize = size != null && screenSize != null && size < screenSize
? size
: computeDefaultWindowSize(screenSize);
logger.d('Using clamped window size: ${clampedSize.s()}');
return clampedSize;
}

Size computeDefaultWindowSize(Size? screenSize) {
const windowSizeFactor = 0.8;
final (screenWidth, screenHeight) = (screenSize?.width, screenSize?.height);
final aspectRatioFactor = screenSize?.flipped.aspectRatio;

final defaultWidth = switch (screenWidth) {
null || <= 1024 => 750.0,
>= 1600 => 1400.0,
_ => screenWidth * windowSizeFactor,
};

final defaultHeight = switch (screenHeight) {
null || <= 576 => 450.0,
>= 900 => 822.0,
_ => aspectRatioFactor != null
? defaultWidth * aspectRatioFactor
: screenHeight * windowSizeFactor,
};

final size = Size(defaultWidth, defaultHeight);
logger.d('Computed default window size: ${size.s()}');
return size;
}

final theme = ThemeData(
useMaterial3: false,
fontFamily: 'Ubuntu',
Expand Down
81 changes: 81 additions & 0 deletions src/client/gui/lib/window_size.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import 'dart:ui';

import 'package:async/async.dart';
import 'package:basics/basics.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:window_manager/window_manager.dart';
import 'package:window_size/window_size.dart';

import 'extensions.dart';
import 'logger.dart';

const windowWidthKey = 'windowWidth';
const windowHeightKey = 'windowHeight';

String resolutionString(Size? size) {
return size != null ? '${size.width}x${size.height}' : '';
}

final saveWindowSizeTimer = RestartableTimer(1.seconds, () async {
final currentSize = await windowManager.getSize();
final sharedPreferences = await SharedPreferences.getInstance();
final screenSize = await getCurrentScreenSize();
logger.d(
'Saving window size ${currentSize.s()} for screen size ${screenSize?.s()}',
);
final prefix = resolutionString(screenSize);
sharedPreferences.setDouble('$prefix$windowWidthKey', currentSize.width);
sharedPreferences.setDouble('$prefix$windowHeightKey', currentSize.height);
});

Future<Size?> getCurrentScreenSize() async {
try {
final screen = await getCurrentScreen();
if (screen == null) throw Exception('Screen instance is null');

logger.d(
'Got Screen{frame: ${screen.frame.s()}, scaleFactor: ${screen.scaleFactor}, visibleFrame: ${screen.visibleFrame.s()}}',
);

return screen.visibleFrame.size;
} catch (e) {
logger.w('Failed to get current screen information: $e');
return null;
}
}

Future<Size> deriveWindowSize(SharedPreferences sharedPreferences) async {
final screenSize = await getCurrentScreenSize();
final prefix = resolutionString(screenSize);
final lastWidth = sharedPreferences.getDouble('$prefix$windowWidthKey');
final lastHeight = sharedPreferences.getDouble('$prefix$windowHeightKey');
final size = lastWidth != null && lastHeight != null
? Size(lastWidth, lastHeight)
: null;
logger.d('Got last window size: ${size?.s()}');
return size ?? computeDefaultWindowSize(screenSize);
}

Size computeDefaultWindowSize(Size? screenSize) {
const windowSizeFactor = 0.8;
final (screenWidth, screenHeight) = (screenSize?.width, screenSize?.height);
final aspectRatioFactor = screenSize?.flipped.aspectRatio;

final defaultWidth = switch (screenWidth) {
null || <= 1024 => 750.0,
>= 1600 => 1400.0,
_ => screenWidth * windowSizeFactor,
};

final defaultHeight = switch (screenHeight) {
null || <= 576 => 450.0,
>= 900 => 822.0,
_ => aspectRatioFactor != null
? defaultWidth * aspectRatioFactor
: screenHeight * windowSizeFactor,
};

final size = Size(defaultWidth, defaultHeight);
logger.d('Computed default window size: ${size.s()}');
return size;
}

0 comments on commit 8055fc1

Please sign in to comment.