Skip to content
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
2 changes: 2 additions & 0 deletions doc/Skins.md
Original file line number Diff line number Diff line change
Expand Up @@ -1444,6 +1444,8 @@ Returns to auto-managed wake-lock behavior based on machine state.
**Wake-Lock Auto-Management:**
- When no override is active, wake-lock is automatically enabled when the machine is connected and not sleeping, and disabled when the machine sleeps or disconnects.
- Brightness is automatically restored to its pre-sleep value when the machine transitions from sleeping to idle.
- When the embedded skin view closes, native UI becomes authoritative and the host resets brightness to 100 (OS-managed), overriding any active REST or WebSocket brightness request.
- Clients that still require fixed brightness must request it again after the skin closes.

**Low Battery Brightness Cap:**
- When the `lowBatteryBrightnessLimit` setting is enabled (via `POST /api/v1/settings`) and battery drops below 30%, screen brightness is capped at 20.
Expand Down
4 changes: 4 additions & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,7 @@ void main(List<String> args) async {
decentAccountService: decentAccountService,
accountTokensController: accountTokensController,
batteryController: batteryController,
displayController: displayController,
),
),
);
Expand Down Expand Up @@ -841,6 +842,7 @@ class AppRoot extends StatefulWidget {
final DecentAccountService? decentAccountService;
final AccountTokensController? accountTokensController;
final BatteryController? batteryController;
final DisplayController displayController;

const AppRoot({
super.key,
Expand All @@ -866,6 +868,7 @@ class AppRoot extends StatefulWidget {
this.decentAccountService,
this.accountTokensController,
this.batteryController,
required this.displayController,
});

static void restart(BuildContext context) {
Expand Down Expand Up @@ -924,6 +927,7 @@ class _AppRootState extends State<AppRoot> {
decentAccountService: widget.decentAccountService,
accountTokensController: widget.accountTokensController,
batteryController: widget.batteryController,
displayController: widget.displayController,
),
);

Expand Down
4 changes: 4 additions & 0 deletions lib/src/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:reaprime/main.dart';
import 'package:reaprime/src/controllers/account_tokens_controller.dart';
import 'package:reaprime/src/controllers/connection_manager.dart';
import 'package:reaprime/src/controllers/de1_state_manager.dart';
import 'package:reaprime/src/controllers/display_controller.dart';
import 'package:reaprime/src/controllers/persistence_controller.dart';
import 'package:reaprime/src/controllers/presence_controller.dart';
import 'package:reaprime/src/controllers/presence_navigator_observer.dart';
Expand Down Expand Up @@ -87,6 +88,7 @@ class MyApp extends StatefulWidget {
required this.webUIStorage,
required this.webViewLogService,
required this.presenceController,
required this.displayController,
required this.connectionManager,
required this.scanStateGuardian,
this.updateCheckService,
Expand All @@ -111,6 +113,7 @@ class MyApp extends StatefulWidget {
final WebUIStorage webUIStorage;
final WebViewLogService webViewLogService;
final PresenceController presenceController;
final DisplayController displayController;
final ConnectionManager connectionManager;
final ScanStateGuardian scanStateGuardian;
final UpdateCheckService? updateCheckService;
Expand Down Expand Up @@ -492,6 +495,7 @@ class _MyAppState extends State<MyApp> {
settingsController: widget.settingsController,
webViewLogService: widget.webViewLogService,
deviceIp: widget.webUIService.deviceIp(),
displayController: widget.displayController,
);
default:
return OnboardingView(
Expand Down
4 changes: 4 additions & 0 deletions lib/src/skin_feature/skin_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:logging/logging.dart';
import 'package:reaprime/build_info.dart';
import 'package:reaprime/src/controllers/display_controller.dart';
import 'package:reaprime/src/home_feature/widgets/quick_settings_widget.dart';
import 'package:reaprime/src/services/telemetry/boot_timing.dart';
import 'package:reaprime/src/services/webview_compatibility_checker.dart';
Expand Down Expand Up @@ -69,11 +70,13 @@ class SkinView extends StatefulWidget {
required this.settingsController,
required this.webViewLogService,
required this.deviceIp,
required this.displayController,
});

final SettingsController settingsController;
final WebViewLogService webViewLogService;
final String deviceIp;
final DisplayController displayController;

static const routeName = '/skin';

Expand Down Expand Up @@ -113,6 +116,7 @@ class _SkinViewState extends State<SkinView> with WidgetsBindingObserver {
@override
void dispose() {
_log.fine("disposing");
unawaited(widget.displayController.setBrightness(100));
_blankPageTimer?.cancel();
_blankPageTimer = null;
final controller = _webViewController;
Expand Down
61 changes: 61 additions & 0 deletions test/unit/skin_feature/skin_view_brightness_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:reaprime/src/controllers/device_controller.dart';
import 'package:reaprime/src/controllers/display_controller.dart';
import 'package:reaprime/src/services/webview_log_service.dart';
import 'package:reaprime/src/settings/settings_controller.dart';
import 'package:reaprime/src/skin_feature/skin_view.dart';

import '../../helpers/mock_de1_controller.dart';
import '../../helpers/mock_settings_service.dart';

void main() {
testWidgets(
'native UI overrides other brightness requests when skin closes',
(tester) async {
final logs = WebViewLogService(logDirectoryPath: '.');
final de1Controller = MockDe1Controller(
controller: DeviceController(const []),
);
final settingsController = SettingsController(MockSettingsService());
var resetCalls = 0;
final displayController = DisplayController(
de1Controller: de1Controller,
settingsController: settingsController,
setBrightness: (_) async {},
resetBrightness: () async {
resetCalls++;
},
enableWakeLock: () async {},
disableWakeLock: () async {},
platformSupport: const DisplayPlatformSupport(
brightness: true,
wakeLock: false,
),
);
addTearDown(() {
displayController.dispose();
logs.dispose();
});

await displayController.setBrightness(40);
expect(displayController.currentState.requestedBrightness, 40);

await tester.pumpWidget(
MaterialApp(
home: SkinView(
settingsController: settingsController,
webViewLogService: logs,
deviceIp: '127.0.0.1',
displayController: displayController,
),
),
);
await tester.pumpWidget(const SizedBox.shrink());
await tester.pump();

expect(displayController.currentState.requestedBrightness, 100);
expect(resetCalls, 1);
},
);
}
Loading