mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2024-11-21 23:10:40 +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 }
|
||||
|
||||
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 {
|
||||
final String name;
|
||||
final ScreenshotDevicePlatform platform;
|
||||
final ({int dx, int dy}) screenshotFrameOffset;
|
||||
|
||||
const ScreenshotDevice({
|
||||
required this.name,
|
||||
required this.platform,
|
||||
this.screenshotFrameOffset = (dx: 0, dy: 0),
|
||||
});
|
||||
|
||||
ScreenshotDevice.fromDisplayName({
|
||||
required String displayName,
|
||||
required this.platform,
|
||||
this.screenshotFrameOffset = (dx: 0, dy: 0),
|
||||
}) : name = displayName.replaceAll(' ', '_').toLowerCase();
|
||||
|
||||
String get systemOverlayPathLight =>
|
||||
'screenshots/assets/system_overlays/${platform.name}/${name}_system_overlay_light.png';
|
||||
String get systemOverlayPathDark =>
|
||||
'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/utils/widget_tester_actions.dart';
|
||||
import 'screenshot_args.dart';
|
||||
|
||||
//https://stackoverflow.com/a/67186625/13167574
|
||||
|
||||
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.
|
||||
void main() {
|
||||
final binding = IntegrationTestWidgetsFlutterBinding();
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
final Color lightThemeColor = primaryColorsList[5];
|
||||
final Color darkThemeColor = primaryColorsList[3];
|
||||
|
||||
void mockSharedPrefs(ThemeType theme, Color color) {
|
||||
// ignore: invalid_use_of_visible_for_testing_member
|
||||
|
@ -70,7 +73,7 @@ void main() {
|
|||
|
||||
/// Generates several screenshots with the light theme
|
||||
testWidgets('Generate light theme screenshots', (tester) async {
|
||||
mockSharedPrefs(ThemeType.light, lightThemeColor);
|
||||
mockSharedPrefs(ThemeType.light, _lightThemeColor);
|
||||
await tester.pumpApplication(
|
||||
availableFilms: [_mockFilm],
|
||||
filmsInUse: [_mockFilm],
|
||||
|
@ -114,7 +117,7 @@ void main() {
|
|||
testWidgets(
|
||||
'Generate dark theme screenshots',
|
||||
(tester) async {
|
||||
mockSharedPrefs(ThemeType.dark, darkThemeColor);
|
||||
mockSharedPrefs(ThemeType.dark, _darkThemeColor);
|
||||
await tester.pumpApplication(
|
||||
availableFilms: [_mockFilm],
|
||||
filmsInUse: [_mockFilm],
|
||||
|
@ -138,8 +141,21 @@ final String _platformFolder = Platform.isAndroid ? 'android' : 'ios';
|
|||
|
||||
extension on WidgetTester {
|
||||
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(
|
||||
"$_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();
|
||||
}
|
||||
|
|
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:typed_data';
|
||||
|
||||
import 'package:image/image.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';
|
||||
|
||||
Future<void> main() async {
|
||||
await grantCameraPermission();
|
||||
await integrationDriver(
|
||||
onScreenshot: (name, bytes, [args]) async {
|
||||
final File image = await File('screenshots/generated/$name.png').create(recursive: true);
|
||||
image.writeAsBytesSync(bytes);
|
||||
onScreenshot: (name, bytes, [_]) async {
|
||||
final screenshotArgs = ScreenshotArgs.fromString(name);
|
||||
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;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
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