added oled theme and theme presets
Android CI / Build and Test (pull_request) Failing after 11m39s
Flutter / build (BalanceFlutter/build/ios/iphoneos/*.app, macos-latest, ios) (push) Canceled after 0s
Flutter / build (BalanceFlutter/build/macos/Build/Products/Release/*.app, macos-latest, macos) (push) Canceled after 0s
Flutter / build (BalanceFlutter/build/windows/x64/runner/Release, windows-latest, windows) (push) Canceled after 0s
Flutter / watchos (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build Unsigned iOS IPA (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build macOS ZIP (push) Canceled after 0s
Flutter / checks (push) Successful in 25m8s
Flutter / build (BalanceFlutter/build/app/outputs/flutter-apk/*.apk, ubuntu-latest, android) (push) Failing after 38m6s
Flutter / build (BalanceFlutter/build/linux/x64/release/bundle, ubuntu-latest, linux) (push) Successful in 32m37s
Flutter / build (BalanceFlutter/build/web, ubuntu-latest, web) (push) Successful in 31m39s
iOS CI / Build and Test SwiftUI App (pull_request) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build Unsigned iOS IPA (pull_request) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build macOS ZIP (pull_request) Canceled after 0s
Flutter / build (BalanceFlutter/build/ios/iphoneos/*.app, macos-latest, ios) (pull_request) Canceled after 0s
Flutter / build (BalanceFlutter/build/macos/Build/Products/Release/*.app, macos-latest, macos) (pull_request) Canceled after 0s
Flutter / build (BalanceFlutter/build/windows/x64/runner/Release, windows-latest, windows) (pull_request) Canceled after 0s
Flutter / watchos (pull_request) Canceled after 0s
Flutter / checks (pull_request) Successful in 24m59s
Flutter / build (BalanceFlutter/build/app/outputs/flutter-apk/*.apk, ubuntu-latest, android) (pull_request) Failing after 31m24s
Flutter / build (BalanceFlutter/build/linux/x64/release/bundle, ubuntu-latest, linux) (pull_request) Successful in 32m34s
Flutter / build (BalanceFlutter/build/web, ubuntu-latest, web) (pull_request) Successful in 24m54s
Android CI / Build and Test (pull_request) Failing after 11m39s
Flutter / build (BalanceFlutter/build/ios/iphoneos/*.app, macos-latest, ios) (push) Canceled after 0s
Flutter / build (BalanceFlutter/build/macos/Build/Products/Release/*.app, macos-latest, macos) (push) Canceled after 0s
Flutter / build (BalanceFlutter/build/windows/x64/runner/Release, windows-latest, windows) (push) Canceled after 0s
Flutter / watchos (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build Unsigned iOS IPA (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build macOS ZIP (push) Canceled after 0s
Flutter / checks (push) Successful in 25m8s
Flutter / build (BalanceFlutter/build/app/outputs/flutter-apk/*.apk, ubuntu-latest, android) (push) Failing after 38m6s
Flutter / build (BalanceFlutter/build/linux/x64/release/bundle, ubuntu-latest, linux) (push) Successful in 32m37s
Flutter / build (BalanceFlutter/build/web, ubuntu-latest, web) (push) Successful in 31m39s
iOS CI / Build and Test SwiftUI App (pull_request) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build Unsigned iOS IPA (pull_request) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build macOS ZIP (pull_request) Canceled after 0s
Flutter / build (BalanceFlutter/build/ios/iphoneos/*.app, macos-latest, ios) (pull_request) Canceled after 0s
Flutter / build (BalanceFlutter/build/macos/Build/Products/Release/*.app, macos-latest, macos) (pull_request) Canceled after 0s
Flutter / build (BalanceFlutter/build/windows/x64/runner/Release, windows-latest, windows) (pull_request) Canceled after 0s
Flutter / watchos (pull_request) Canceled after 0s
Flutter / checks (pull_request) Successful in 24m59s
Flutter / build (BalanceFlutter/build/app/outputs/flutter-apk/*.apk, ubuntu-latest, android) (pull_request) Failing after 31m24s
Flutter / build (BalanceFlutter/build/linux/x64/release/bundle, ubuntu-latest, linux) (pull_request) Successful in 32m34s
Flutter / build (BalanceFlutter/build/web, ubuntu-latest, web) (pull_request) Successful in 24m54s
This commit is contained in:
1 parent
2c278044bb
commit
a2aa714a83
16 files changed
+436
-42
No files matched your search
@@ -0,0 +1,140 @@
|
||||
import 'package:balance_flutter/domain/appearance.dart';
|
||||
import 'package:balance_flutter/services/app_store.dart';
|
||||
import 'package:balance_flutter/services/storage.dart';
|
||||
import 'package:balance_flutter/ui/app_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'widget_test.dart' as fixtures;
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
setUp(fixtures.mockStorage);
|
||||
|
||||
test('OLED uses pure black for surfaces, cards, navigation and dialogs', () {
|
||||
final theme = BalanceThemes.build(Brightness.dark, ColorPreset.oled);
|
||||
final scheme = theme.colorScheme;
|
||||
expect(theme.brightness, Brightness.dark);
|
||||
for (final surface in [
|
||||
theme.scaffoldBackgroundColor,
|
||||
theme.canvasColor,
|
||||
scheme.surface,
|
||||
scheme.surfaceDim,
|
||||
scheme.surfaceBright,
|
||||
scheme.surfaceContainerLowest,
|
||||
scheme.surfaceContainerLow,
|
||||
scheme.surfaceContainer,
|
||||
scheme.surfaceContainerHigh,
|
||||
scheme.surfaceContainerHighest,
|
||||
scheme.primaryContainer,
|
||||
theme.appBarTheme.backgroundColor,
|
||||
theme.navigationBarTheme.backgroundColor,
|
||||
theme.navigationRailTheme.backgroundColor,
|
||||
theme.dialogTheme.backgroundColor,
|
||||
]) {
|
||||
expect(surface, Colors.black);
|
||||
}
|
||||
expect(theme.cardTheme.surfaceTintColor, Colors.transparent);
|
||||
expect(theme.applyElevationOverlayColor, isFalse);
|
||||
expect(scheme.onSurface.computeLuminance(), greaterThan(.6));
|
||||
expect(scheme.primary.computeLuminance(), greaterThan(.3));
|
||||
});
|
||||
|
||||
test('presets have distinct accents and preserve light/dark mode', () {
|
||||
final accents = <Color>{};
|
||||
for (final preset in ColorPreset.values) {
|
||||
final light = BalanceThemes.build(Brightness.light, preset);
|
||||
final dark = BalanceThemes.build(Brightness.dark, preset);
|
||||
expect(light.brightness, Brightness.light);
|
||||
expect(dark.brightness, Brightness.dark);
|
||||
expect(light.scaffoldBackgroundColor, isNot(Colors.black));
|
||||
accents.add(light.colorScheme.primary);
|
||||
}
|
||||
expect(accents.length, ColorPreset.values.length);
|
||||
});
|
||||
|
||||
test(
|
||||
'preset and mode survive restart; OLED initially selects dark',
|
||||
() async {
|
||||
final storage = MemorySnapshotStorage();
|
||||
final store = AppStore(storage: storage, background: true);
|
||||
await store.initialize();
|
||||
expect(store.themePreset, 'forest');
|
||||
expect(store.theme, 'system');
|
||||
await store.setTheme('light');
|
||||
await store.setThemePreset('oled');
|
||||
expect(store.theme, 'dark');
|
||||
await store.setTheme('system');
|
||||
final reopened = AppStore(storage: storage, background: true);
|
||||
await reopened.initialize();
|
||||
expect(reopened.themePreset, 'oled');
|
||||
expect(reopened.theme, 'system');
|
||||
await reopened.setThemePreset('rose');
|
||||
expect(reopened.theme, 'system');
|
||||
await expectLater(
|
||||
reopened.setThemePreset('unknown'),
|
||||
throwsArgumentError,
|
||||
);
|
||||
await store.close();
|
||||
await reopened.close();
|
||||
store.dispose();
|
||||
reopened.dispose();
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets('system mode responds to OS brightness with OLED selected', (
|
||||
tester,
|
||||
) async {
|
||||
final store = (await tester.runAsync(
|
||||
() => fixtures.createStore(seeded: false),
|
||||
))!;
|
||||
await tester.runAsync(() async {
|
||||
await store.setThemePreset('oled');
|
||||
await store.setTheme('system');
|
||||
});
|
||||
tester.platformDispatcher.platformBrightnessTestValue = Brightness.dark;
|
||||
addTearDown(tester.platformDispatcher.clearPlatformBrightnessTestValue);
|
||||
await fixtures.boot(tester, store, const Size(390, 844));
|
||||
ThemeData theme() => Theme.of(tester.element(find.byType(Scaffold).first));
|
||||
expect(theme().scaffoldBackgroundColor, Colors.black);
|
||||
tester.platformDispatcher.platformBrightnessTestValue = Brightness.light;
|
||||
await tester.pumpAndSettle();
|
||||
expect(theme().brightness, Brightness.light);
|
||||
expect(theme().scaffoldBackgroundColor, isNot(Colors.black));
|
||||
await tester.runAsync(() => store.setTheme('dark'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(theme().scaffoldBackgroundColor, Colors.black);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'OLED can be selected in narrow settings and updates mode control',
|
||||
(tester) async {
|
||||
await fixtures.loadReadableFont();
|
||||
final store = (await tester.runAsync(
|
||||
() => fixtures.createStore(seeded: false),
|
||||
))!;
|
||||
await fixtures.boot(tester, store, const Size(320, 568));
|
||||
await fixtures.navigate(tester, 4);
|
||||
final oled = find.widgetWithText(ChoiceChip, 'OLED — чёрный');
|
||||
await tester.ensureVisible(oled);
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(oled);
|
||||
await tester.runAsync(() async {
|
||||
await Future<void>.delayed(const Duration(milliseconds: 50));
|
||||
});
|
||||
await tester.pumpAndSettle();
|
||||
expect(store.themePreset, 'oled');
|
||||
expect(store.theme, 'dark');
|
||||
expect(
|
||||
tester.widget<MaterialApp>(find.byType(MaterialApp)).themeMode,
|
||||
ThemeMode.dark,
|
||||
);
|
||||
expect(
|
||||
Theme.of(
|
||||
tester.element(find.byType(Scaffold).first),
|
||||
).scaffoldBackgroundColor,
|
||||
Colors.black,
|
||||
);
|
||||
expect(tester.takeException(), isNull);
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import 'dart:io';
|
||||
import 'dart:ui' as ui;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'widget_test.dart' as fixtures;
|
||||
|
||||
void main() {
|
||||
setUpAll(fixtures.loadReadableFont);
|
||||
setUp(fixtures.mockStorage);
|
||||
for (final size in [const Size(390, 844), const Size(1280, 900)]) {
|
||||
testWidgets('OLED renders black pixels at $size', (tester) async {
|
||||
final store = (await tester.runAsync(() => fixtures.createStore()))!;
|
||||
await tester.runAsync(() => store.setThemePreset('oled'));
|
||||
final key = GlobalKey();
|
||||
await fixtures.boot(tester, store, size, boundaryKey: key);
|
||||
for (final page in [0, 4]) {
|
||||
await fixtures.navigate(tester, page);
|
||||
await tester.runAsync(() async {
|
||||
final boundary =
|
||||
key.currentContext!.findRenderObject()! as RenderRepaintBoundary;
|
||||
final image = await boundary.toImage(pixelRatio: 1);
|
||||
final rgba = await image.toByteData(
|
||||
format: ui.ImageByteFormat.rawRgba,
|
||||
);
|
||||
// Left edge of the scaffold/rail below the app bar, away from text.
|
||||
final pixel = (110 * image.width) * 4;
|
||||
expect(rgba!.getUint8(pixel), 0);
|
||||
expect(rgba.getUint8(pixel + 1), 0);
|
||||
expect(rgba.getUint8(pixel + 2), 0);
|
||||
expect(rgba.getUint8(pixel + 3), 255);
|
||||
final png = await image.toByteData(format: ui.ImageByteFormat.png);
|
||||
final dir = Directory('/tmp/balance-oled-preview')
|
||||
..createSync(recursive: true);
|
||||
File(
|
||||
'${dir.path}/${size.width.toInt()}-${page == 0 ? 'overview' : 'settings'}.png',
|
||||
).writeAsBytesSync(png!.buffer.asUint8List());
|
||||
image.dispose();
|
||||
});
|
||||
expect(tester.takeException(), isNull);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user