Skip to content

Commit

Permalink
Kiosk Screens (#274)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdlukaa authored Oct 11, 2024
2 parents c310337 + 691dbfe commit f0dce5c
Show file tree
Hide file tree
Showing 9 changed files with 414 additions and 56 deletions.
3 changes: 3 additions & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ Future<void> main(List<String> args) async {
// can run the [SplashScreen] widget as the app.
if (isDesktopPlatform) {
await configureWindow();
if (canLaunchAtStartup) setupLaunchAtStartup();
if (canUseSystemTray) setupSystemTray();

runApp(const SplashScreen());
}

Expand Down
8 changes: 5 additions & 3 deletions lib/providers/home_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ class HomeProvider extends ChangeNotifier {
/// they come back.
Map<String, double> volumes = {};

Future<void> setTab(UnityTab tab, BuildContext context) async {
Future<void> setTab(UnityTab tab, [BuildContext? context]) async {
if (tab == this.tab) return;

final currentTab = this.tab;
Expand Down Expand Up @@ -159,8 +159,10 @@ class HomeProvider extends ChangeNotifier {
volumes.clear();
}

refreshDeviceOrientation(context);
updateWakelock(context);
if (context != null) {
refreshDeviceOrientation(context);
updateWakelock(context);
}
notifyListeners();
}

Expand Down
60 changes: 54 additions & 6 deletions lib/providers/settings_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,19 @@ import 'package:bluecherry_client/providers/update_provider.dart';
import 'package:bluecherry_client/screens/events_timeline/desktop/timeline.dart';
import 'package:bluecherry_client/screens/settings/shared/options_chooser_tile.dart';
import 'package:bluecherry_client/utils/logging.dart';
import 'package:bluecherry_client/utils/methods.dart';
import 'package:bluecherry_client/utils/storage.dart';
import 'package:bluecherry_client/utils/video_player.dart';
import 'package:bluecherry_client/widgets/hover_button.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:intl/intl.dart';
import 'package:launch_at_startup/launch_at_startup.dart';
import 'package:unity_video_player/unity_video_player.dart';
import 'package:unity_video_player_main/unity_video_player_main.dart';
import 'package:window_manager/window_manager.dart';

enum NetworkUsage {
auto,
Expand Down Expand Up @@ -97,16 +101,16 @@ class _SettingsOption<T> {

late final String Function(dynamic value) saveAs;
late final T Function(String value) loadFrom;
final ValueChanged<T>? onChanged;
final Future<void> Function(T)? onChanged;
final T Function(dynamic value)? valueOverrider;

late T _value;

T get value => valueOverrider?.call(_value) ?? _value;
set value(T newValue) {
SettingsProvider.instance.updateProperty(() {
SettingsProvider.instance.updateProperty(() async {
_value = newValue;
onChanged?.call(value);
await onChanged?.call(value);
});
}

Expand Down Expand Up @@ -453,6 +457,48 @@ class SettingsProvider extends UnityProvider {
final kLaunchAppOnStartup = _SettingsOption<bool>(
def: false,
key: 'window.launch_app_on_startup',
getDefault: kIsWeb ? null : launchAtStartup.isEnabled,
onChanged: (value) async {
if (kIsWeb) {
return;
}
if (value) {
await launchAtStartup.enable();
} else {
await launchAtStartup.disable();
}
},
);
final kFullscreen = _SettingsOption<bool>(
def: false,
key: 'window.fullscreen',
getDefault: () async {
if (!isDesktopPlatform) return false;
return windowManager.isFullScreen();
},
onChanged: (value) async {
if (!isDesktopPlatform) return;
await windowManager.setFullScreen(value);
},
);
final kImmersiveMode = _SettingsOption<bool>(
def: false,
key: 'window.immersive_mode',
onChanged: (value) async {
if (isMobilePlatform) {
if (value) {
await SystemChrome.setEnabledSystemUIMode(
SystemUiMode.immersive,
overlays: [],
);
} else {
await SystemChrome.setEnabledSystemUIMode(
SystemUiMode.manual,
overlays: SystemUiOverlay.values,
);
}
}
},
);
final kMinimizeToTray = _SettingsOption<bool>(
def: false,
Expand Down Expand Up @@ -528,7 +574,7 @@ class SettingsProvider extends UnityProvider {
final kSoftwareZooming = _SettingsOption<bool>(
def: isHardwareZoomSupported ? true : false,
key: 'other.software_zoom',
onChanged: (value) {
onChanged: (value) async {
for (final player in UnityPlayers.players.values) {
player
..resetCrop()
Expand Down Expand Up @@ -592,6 +638,8 @@ class SettingsProvider extends UnityProvider {
kTimeFormat,
kConvertTimeToLocalTimezone,
kLaunchAppOnStartup,
kFullscreen,
kImmersiveMode,
kMinimizeToTray,
kAnimationsEnabled,
kHighContrast,
Expand Down Expand Up @@ -659,8 +707,8 @@ class SettingsProvider extends UnityProvider {
super.save(notifyListeners: notifyListeners);
}

void updateProperty(VoidCallback update) {
update();
Future<void> updateProperty(Future Function() update) async {
await update();
save();
}

Expand Down
113 changes: 85 additions & 28 deletions lib/screens/settings/application.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import 'package:bluecherry_client/providers/settings_provider.dart';
import 'package:bluecherry_client/screens/settings/settings_desktop.dart';
import 'package:bluecherry_client/screens/settings/shared/options_chooser_tile.dart';
import 'package:bluecherry_client/utils/extensions.dart';
import 'package:bluecherry_client/utils/methods.dart';
import 'package:bluecherry_client/utils/window.dart';
import 'package:bluecherry_client/widgets/misc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
Expand Down Expand Up @@ -69,6 +71,7 @@ class ApplicationSettings extends StatelessWidget {
settings.kThemeMode.value = v;
},
),
if (isMobilePlatform) _buildImmersiveModeTile(),
const LanguageSection(),
SubHeader(
loc.dateAndTime,
Expand All @@ -93,45 +96,64 @@ class ApplicationSettings extends StatelessWidget {
subtitle: Text(loc.convertToLocalTimeDescription),
isThreeLine: true,
),
if (settings.kShowDebugInfo.value) ...[
if (isDesktopPlatform) ...[
const SubHeader('Window'),
CheckboxListTile.adaptive(
value: settings.kLaunchAppOnStartup.value,
onChanged: (v) {
if (v != null) {
settings.kLaunchAppOnStartup.value = v;
}
},
contentPadding: DesktopSettings.horizontalPadding,
secondary: CircleAvatar(
backgroundColor: Colors.transparent,
foregroundColor: theme.iconTheme.color,
child: const Icon(Icons.launch),
),
title: const Text('Launch app on startup'),
subtitle: const Text(
'Whether to launchthe app when the system starts',
if (canLaunchAtStartup)
CheckboxListTile.adaptive(
value: settings.kLaunchAppOnStartup.value,
onChanged: (v) {
if (v != null) {
settings.kLaunchAppOnStartup.value = v;
}
},
contentPadding: DesktopSettings.horizontalPadding,
secondary: CircleAvatar(
backgroundColor: Colors.transparent,
foregroundColor: theme.iconTheme.color,
child: const Icon(Icons.launch),
),
title: const Text('Launch app on startup'),
subtitle: const Text(
'Whether to launch the app when the system starts',
),
),
),
CheckboxListTile.adaptive(
value: settings.kMinimizeToTray.value,
value: settings.kFullscreen.value,
onChanged: (v) {
if (v != null) {
settings.kMinimizeToTray.value = v;
}
if (v != null) settings.kFullscreen.value = v;
},
contentPadding: DesktopSettings.horizontalPadding,
secondary: CircleAvatar(
backgroundColor: Colors.transparent,
foregroundColor: theme.iconTheme.color,
child: const Icon(Icons.sensor_door),
),
title: const Text('Minimize to tray'),
subtitle: const Text(
'Whether to minimize app to the system tray when the window is closed. '
'This will keep the app running in the background.',
child: const Icon(Icons.fullscreen),
),
title: const Text('Fullscreen Mode'),
subtitle: const Text('Whether the app is in fullscreen mode or not.'),
),
_buildImmersiveModeTile(),
if (canUseSystemTray)
CheckboxListTile.adaptive(
value: settings.kMinimizeToTray.value,
onChanged: (v) {
if (v != null) {
settings.kMinimizeToTray.value = v;
}
},
contentPadding: DesktopSettings.horizontalPadding,
secondary: CircleAvatar(
backgroundColor: Colors.transparent,
foregroundColor: theme.iconTheme.color,
child: const Icon(Icons.sensor_door),
),
title: const Text('Minimize to tray'),
subtitle: const Text(
'Whether to minimize app to the system tray when the window is '
'closed. This will keep the app running in the background.',
),
),
],
if (settings.kShowDebugInfo.value) ...[
const SubHeader('Acessibility'),
CheckboxListTile.adaptive(
value: settings.kAnimationsEnabled.value,
Expand Down Expand Up @@ -191,6 +213,41 @@ class ApplicationSettings extends StatelessWidget {
],
]);
}

/// Creates the Immersive Mode tile.
///
/// On Desktop, this is used alonside the Fullscreen mode tile. When in
/// fullscreen, the immersive mode hides the top bar and only shows it when
/// the user hovers over the top of the window.
///
/// On Mobile, this makes the app full-screen and hides the system UI.
Widget _buildImmersiveModeTile() {
return Builder(builder: (context) {
final theme = Theme.of(context);
final settings = context.watch<SettingsProvider>();

return CheckboxListTile.adaptive(
value: settings.kImmersiveMode.value,
onChanged: settings.kFullscreen.value || isMobilePlatform
? (v) {
if (v != null) settings.kImmersiveMode.value = v;
}
: null,
contentPadding: DesktopSettings.horizontalPadding,
secondary: CircleAvatar(
backgroundColor: Colors.transparent,
foregroundColor: theme.iconTheme.color,
child: const Icon(Icons.web_asset),
),
title: const Text('Immersive Mode'),
subtitle: const Text(
'This will hide the title bar and window controls. '
'To show the top bar, hover over the top of the window. '
'This only works in fullscreen mode.',
),
);
});
}
}

class LanguageSection extends StatelessWidget {
Expand Down
Loading

0 comments on commit f0dce5c

Please sign in to comment.