Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kiosk Screens #274

Merged
merged 21 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading