mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2024-11-22 07:20:39 +00:00
add device frame (wip)
This commit is contained in:
parent
41b7730f82
commit
0c6519efa1
5 changed files with 163 additions and 13 deletions
BIN
screenshots/assets/frames/ios/iphone_13_pro_frame.png
Normal file
BIN
screenshots/assets/frames/ios/iphone_13_pro_frame.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 219 KiB |
|
@ -1,26 +1,37 @@
|
||||||
enum ScreenshotDevicePlatform { android, ios }
|
enum ScreenshotDevicePlatform { android, ios }
|
||||||
|
|
||||||
|
final screenshotDevicesIos = [
|
||||||
|
ScreenshotDevice.fromDisplayName(
|
||||||
|
displayName: 'iPhone 8 Plus',
|
||||||
|
platform: ScreenshotDevicePlatform.ios,
|
||||||
|
),
|
||||||
|
ScreenshotDevice.fromDisplayName(
|
||||||
|
displayName: 'iPhone 13 Pro',
|
||||||
|
platform: ScreenshotDevicePlatform.ios,
|
||||||
|
screenshotFrameOffset: (dx: 72, dy: 60),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
class ScreenshotDevice {
|
class ScreenshotDevice {
|
||||||
final String name;
|
final String name;
|
||||||
final ScreenshotDevicePlatform platform;
|
final ScreenshotDevicePlatform platform;
|
||||||
|
final ({int dx, int dy}) screenshotFrameOffset;
|
||||||
|
|
||||||
const ScreenshotDevice({
|
const ScreenshotDevice({
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.platform,
|
required this.platform,
|
||||||
|
this.screenshotFrameOffset = (dx: 0, dy: 0),
|
||||||
});
|
});
|
||||||
|
|
||||||
ScreenshotDevice.fromDisplayName({
|
ScreenshotDevice.fromDisplayName({
|
||||||
required String displayName,
|
required String displayName,
|
||||||
required this.platform,
|
required this.platform,
|
||||||
|
this.screenshotFrameOffset = (dx: 0, dy: 0),
|
||||||
}) : name = displayName.replaceAll(' ', '_').toLowerCase();
|
}) : name = displayName.replaceAll(' ', '_').toLowerCase();
|
||||||
|
|
||||||
String get systemOverlayPathLight =>
|
String get systemOverlayPathLight =>
|
||||||
'screenshots/assets/system_overlays/${platform.name}/${name}_system_overlay_light.png';
|
'screenshots/assets/system_overlays/${platform.name}/${name}_system_overlay_light.png';
|
||||||
String get systemOverlayPathDark =>
|
String get systemOverlayPathDark =>
|
||||||
'screenshots/assets/system_overlays/${platform.name}/${name}_system_overlay_dark.png';
|
'screenshots/assets/system_overlays/${platform.name}/${name}_system_overlay_dark.png';
|
||||||
|
String get deviceFramePath => 'screenshots/assets/frames/${platform.name}/${name}_frame.png';
|
||||||
}
|
}
|
||||||
|
|
||||||
final screenshotDevicesIos = [
|
|
||||||
ScreenshotDevice.fromDisplayName(displayName: 'iPhone 8 Plus', platform: ScreenshotDevicePlatform.ios),
|
|
||||||
ScreenshotDevice.fromDisplayName(displayName: 'iPhone 13 Pro', platform: ScreenshotDevicePlatform.ios),
|
|
||||||
];
|
|
||||||
|
|
|
@ -19,17 +19,20 @@ import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
import '../integration_test/mocks/paid_features_mock.dart';
|
import '../integration_test/mocks/paid_features_mock.dart';
|
||||||
import '../integration_test/utils/widget_tester_actions.dart';
|
import '../integration_test/utils/widget_tester_actions.dart';
|
||||||
|
import 'screenshot_args.dart';
|
||||||
|
|
||||||
//https://stackoverflow.com/a/67186625/13167574
|
//https://stackoverflow.com/a/67186625/13167574
|
||||||
|
|
||||||
const _mockFilm = Film('Ilford HP5+', 400);
|
const _mockFilm = Film('Ilford HP5+', 400);
|
||||||
|
final Color _lightThemeColor = primaryColorsList[5];
|
||||||
|
final Color _darkThemeColor = primaryColorsList[3];
|
||||||
|
final ThemeData _themeLight = themeFrom(_lightThemeColor, Brightness.light);
|
||||||
|
final ThemeData _themeDark = themeFrom(_darkThemeColor, Brightness.dark);
|
||||||
|
|
||||||
/// Just a screenshot generator. No expectations here.
|
/// Just a screenshot generator. No expectations here.
|
||||||
void main() {
|
void main() {
|
||||||
final binding = IntegrationTestWidgetsFlutterBinding();
|
final binding = IntegrationTestWidgetsFlutterBinding();
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
final Color lightThemeColor = primaryColorsList[5];
|
|
||||||
final Color darkThemeColor = primaryColorsList[3];
|
|
||||||
|
|
||||||
void mockSharedPrefs(ThemeType theme, Color color) {
|
void mockSharedPrefs(ThemeType theme, Color color) {
|
||||||
// ignore: invalid_use_of_visible_for_testing_member
|
// ignore: invalid_use_of_visible_for_testing_member
|
||||||
|
@ -70,7 +73,7 @@ void main() {
|
||||||
|
|
||||||
/// Generates several screenshots with the light theme
|
/// Generates several screenshots with the light theme
|
||||||
testWidgets('Generate light theme screenshots', (tester) async {
|
testWidgets('Generate light theme screenshots', (tester) async {
|
||||||
mockSharedPrefs(ThemeType.light, lightThemeColor);
|
mockSharedPrefs(ThemeType.light, _lightThemeColor);
|
||||||
await tester.pumpApplication(
|
await tester.pumpApplication(
|
||||||
availableFilms: [_mockFilm],
|
availableFilms: [_mockFilm],
|
||||||
filmsInUse: [_mockFilm],
|
filmsInUse: [_mockFilm],
|
||||||
|
@ -114,7 +117,7 @@ void main() {
|
||||||
testWidgets(
|
testWidgets(
|
||||||
'Generate dark theme screenshots',
|
'Generate dark theme screenshots',
|
||||||
(tester) async {
|
(tester) async {
|
||||||
mockSharedPrefs(ThemeType.dark, darkThemeColor);
|
mockSharedPrefs(ThemeType.dark, _darkThemeColor);
|
||||||
await tester.pumpApplication(
|
await tester.pumpApplication(
|
||||||
availableFilms: [_mockFilm],
|
availableFilms: [_mockFilm],
|
||||||
filmsInUse: [_mockFilm],
|
filmsInUse: [_mockFilm],
|
||||||
|
@ -138,8 +141,21 @@ final String _platformFolder = Platform.isAndroid ? 'android' : 'ios';
|
||||||
|
|
||||||
extension on WidgetTester {
|
extension on WidgetTester {
|
||||||
Future<void> takeScreenshot(IntegrationTestWidgetsFlutterBinding binding, String name) async {
|
Future<void> takeScreenshot(IntegrationTestWidgetsFlutterBinding binding, String name) async {
|
||||||
|
final bool isDark = name.contains('dark-');
|
||||||
|
final Color backgroundColor = (isDark ? _themeDark : _themeLight).colorScheme.surface;
|
||||||
await binding.takeScreenshot(
|
await binding.takeScreenshot(
|
||||||
"$_platformFolder/${const String.fromEnvironment('deviceName').replaceAll(' ', '_').toLowerCase()}/$name",
|
ScreenshotArgs(
|
||||||
|
name: name,
|
||||||
|
deviceName: const String.fromEnvironment('deviceName').replaceAll(' ', '_').toLowerCase(),
|
||||||
|
platformFolder: _platformFolder,
|
||||||
|
backgroundColor: (
|
||||||
|
r: backgroundColor.red,
|
||||||
|
g: backgroundColor.green,
|
||||||
|
b: backgroundColor.blue,
|
||||||
|
a: backgroundColor.alpha,
|
||||||
|
),
|
||||||
|
isDark: isDark,
|
||||||
|
).toString(),
|
||||||
);
|
);
|
||||||
await pumpAndSettle();
|
await pumpAndSettle();
|
||||||
}
|
}
|
||||||
|
|
55
screenshots/screenshot_args.dart
Normal file
55
screenshots/screenshot_args.dart
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
class ScreenshotArgs {
|
||||||
|
final String name;
|
||||||
|
final String deviceName;
|
||||||
|
final String platformFolder;
|
||||||
|
final ({int r, int g, int b, int a}) backgroundColor;
|
||||||
|
final bool isDark;
|
||||||
|
|
||||||
|
const ScreenshotArgs({
|
||||||
|
required this.name,
|
||||||
|
required this.deviceName,
|
||||||
|
required this.platformFolder,
|
||||||
|
required this.backgroundColor,
|
||||||
|
required this.isDark,
|
||||||
|
});
|
||||||
|
|
||||||
|
String toPath() => 'screenshots/generated/$platformFolder/$deviceName/$name.png';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => jsonEncode(_toJson());
|
||||||
|
|
||||||
|
factory ScreenshotArgs.fromString(String data) => ScreenshotArgs._fromJson(jsonDecode(data) as Map<String, dynamic>);
|
||||||
|
|
||||||
|
factory ScreenshotArgs._fromJson(Map<String, dynamic> data) {
|
||||||
|
final colorChannels = data['backgroundColor'] as List;
|
||||||
|
return ScreenshotArgs(
|
||||||
|
name: data['name'] as String,
|
||||||
|
deviceName: data['deviceName'] as String,
|
||||||
|
platformFolder: data['platformFolder'] as String,
|
||||||
|
backgroundColor: (
|
||||||
|
r: colorChannels[0] as int,
|
||||||
|
g: colorChannels[1] as int,
|
||||||
|
b: colorChannels[2] as int,
|
||||||
|
a: colorChannels[3] as int,
|
||||||
|
),
|
||||||
|
isDark: data['isDark'] as bool,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> _toJson() {
|
||||||
|
return {
|
||||||
|
"name": name,
|
||||||
|
"deviceName": deviceName,
|
||||||
|
"platformFolder": platformFolder,
|
||||||
|
"backgroundColor": [
|
||||||
|
backgroundColor.r,
|
||||||
|
backgroundColor.g,
|
||||||
|
backgroundColor.b,
|
||||||
|
backgroundColor.a,
|
||||||
|
],
|
||||||
|
"isDark": isDark,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,83 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:image/image.dart';
|
||||||
import 'package:integration_test/integration_test_driver_extended.dart';
|
import 'package:integration_test/integration_test_driver_extended.dart';
|
||||||
|
|
||||||
|
import '../screenshots/devices_config.dart';
|
||||||
|
import '../screenshots/screenshot_args.dart';
|
||||||
import 'utils/grant_camera_permission.dart';
|
import 'utils/grant_camera_permission.dart';
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
await grantCameraPermission();
|
await grantCameraPermission();
|
||||||
await integrationDriver(
|
await integrationDriver(
|
||||||
onScreenshot: (name, bytes, [args]) async {
|
onScreenshot: (name, bytes, [_]) async {
|
||||||
final File image = await File('screenshots/generated/$name.png').create(recursive: true);
|
final screenshotArgs = ScreenshotArgs.fromString(name);
|
||||||
image.writeAsBytesSync(bytes);
|
final backgroundColor = ColorRgba8(
|
||||||
|
screenshotArgs.backgroundColor.r,
|
||||||
|
screenshotArgs.backgroundColor.g,
|
||||||
|
screenshotArgs.backgroundColor.b,
|
||||||
|
screenshotArgs.backgroundColor.a,
|
||||||
|
);
|
||||||
|
final platform =
|
||||||
|
screenshotArgs.platformFolder == 'ios' ? ScreenshotDevicePlatform.ios : ScreenshotDevicePlatform.ios;
|
||||||
|
final deviceName = screenshotArgs.deviceName;
|
||||||
|
final file = await File(screenshotArgs.toPath()).create(recursive: true);
|
||||||
|
|
||||||
|
// switch (platform) {
|
||||||
|
// case ScreenshotDevicePlatform.ios:
|
||||||
|
// final device = screenshotDevicesIos.firstWhere(
|
||||||
|
// (device) => device.name == deviceName,
|
||||||
|
// orElse: () => ScreenshotDevice(name: '', platform: platform),
|
||||||
|
// );
|
||||||
|
// Image screenshot = decodePng(Uint8List.fromList(bytes))!;
|
||||||
|
// screenshot = screenshot.addSystemOverlay(device, isDark: screenshotArgs.isDark);
|
||||||
|
// screenshot = screenshot.addDeviceFrame(device, backgroundColor);
|
||||||
|
// file.writeAsBytesSync(encodePng(screenshot));
|
||||||
|
// case ScreenshotDevicePlatform.android:
|
||||||
|
// file.writeAsBytesSync(bytes);
|
||||||
|
// }
|
||||||
|
|
||||||
|
file.writeAsBytesSync(bytes);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension ScreenshotImage on Image {
|
||||||
|
Image addSystemOverlay(ScreenshotDevice device, {required bool isDark}) {
|
||||||
|
final path = isDark ? device.systemOverlayPathDark : device.systemOverlayPathLight;
|
||||||
|
final statusBar = copyResize(
|
||||||
|
decodePng(File(path).readAsBytesSync())!,
|
||||||
|
width: width,
|
||||||
|
);
|
||||||
|
return compositeImage(this, statusBar);
|
||||||
|
}
|
||||||
|
|
||||||
|
Image addDeviceFrame(ScreenshotDevice device, Color backgroundColor) {
|
||||||
|
final screenshotRounded = copyCrop(
|
||||||
|
this,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
);
|
||||||
|
|
||||||
|
final frame = decodePng(File(device.deviceFramePath).readAsBytesSync())!;
|
||||||
|
final expandedScreenshot = copyExpandCanvas(
|
||||||
|
copyExpandCanvas(
|
||||||
|
screenshotRounded,
|
||||||
|
newWidth: screenshotRounded.width + device.screenshotFrameOffset.dx,
|
||||||
|
newHeight: screenshotRounded.height + device.screenshotFrameOffset.dy,
|
||||||
|
position: ExpandCanvasPosition.bottomRight,
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
),
|
||||||
|
newWidth: frame.width,
|
||||||
|
newHeight: frame.height,
|
||||||
|
position: ExpandCanvasPosition.topLeft,
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
);
|
||||||
|
|
||||||
|
return compositeImage(expandedScreenshot, frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue