Add device preview

This commit is contained in:
Foti Dim
2025-12-21 09:11:57 +01:00
parent f6eb5dd4e3
commit dad326ccff
9 changed files with 256 additions and 47 deletions
+7
View File
@@ -40,5 +40,12 @@
"--web-port=8080" "--web-port=8080"
], ],
}, },
{
"name": "device_preview",
"cwd": "example",
"request": "launch",
"type": "dart",
"program": "lib/main_device_preview.dart"
},
], ],
} }
+2
View File
@@ -21,6 +21,7 @@
"LPOSVERSIONINFO", "LPOSVERSIONINFO",
"lpsz", "lpsz",
"LRESULT", "LRESULT",
"LTWH",
"MAXIMIZEBOX", "MAXIMIZEBOX",
"microtask", "microtask",
"MINIMIZEBOX", "MINIMIZEBOX",
@@ -52,6 +53,7 @@
"Unpair", "Unpair",
"Unpairing", "Unpairing",
"unwatch", "unwatch",
"USERPROFILE",
"uuidstr", "uuidstr",
"winrt", "winrt",
"WNDCLASS", "WNDCLASS",
+3 -43
View File
@@ -1,47 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:universal_ble/universal_ble.dart'; import 'package:universal_ble_example/universal_ble_app.dart';
import 'package:universal_ble_example/data/storage_service.dart';
import 'package:universal_ble_example/home/permission_screen.dart';
import 'package:universal_ble_example/home/scanner_screen.dart';
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized(); bool hasPermission = await initializeApp();
await StorageService.instance.init(); runApp(UniversalBleApp(hasPermission: hasPermission));
// await UniversalBle.setLogLevel(BleLogLevel.verbose);
bool hasPermission = await UniversalBle.hasPermissions(
withAndroidFineLocation: false,
);
runApp(MyApp(
hasPermission: hasPermission,
));
}
class MyApp extends StatelessWidget {
final bool hasPermission;
const MyApp({super.key, required this.hasPermission});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Universal BLE',
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.light,
),
),
darkTheme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.dark,
),
),
themeMode: ThemeMode.system,
home: hasPermission ? ScannerScreen() : const PermissionScreen(),
);
}
} }
+88
View File
@@ -0,0 +1,88 @@
import 'dart:io';
import 'package:device_preview_screenshot/device_preview_screenshot.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:universal_ble_example/universal_ble_app.dart';
void main() async {
bool hasPermission = await initializeApp();
// On macOS: ~/Library/Containers/com.navideck.universalble/Data/Documents/screenshots
final screenshotsDir = await getScreenshotsDirectory();
debugPrint('Screenshots will be saved to: ${screenshotsDir.path}');
runApp(
DevicePreview(
enabled: true,
builder: (context) => UniversalBleApp(
hasPermission: hasPermission,
locale: DevicePreview.locale(context),
builder: DevicePreview.appBuilder,
),
devices: [
createCustomDevice(
name: 'App Store 1242x2688',
physicalWidth: 1242,
physicalHeight: 2688,
),
],
tools: [
...DevicePreview.defaultTools,
DevicePreviewScreenshot(
onScreenshot: screenshotAsFiles(screenshotsDir),
),
],
),
);
}
/// Gets or creates the screenshots directory in the app's documents directory.
Future<Directory> getScreenshotsDirectory() async {
final appDocumentsDir = await getApplicationDocumentsDirectory();
final screenshotsDir = Directory('${appDocumentsDir.path}/screenshots');
if (!await screenshotsDir.exists()) {
await screenshotsDir.create(recursive: true);
}
return screenshotsDir;
}
/// Creates a custom device with the specified physical pixel dimensions.
DeviceInfo createCustomDevice({
required String name,
required double physicalWidth,
required double physicalHeight,
double pixelRatio = 3.0,
}) {
final logicalWidth = physicalWidth / pixelRatio;
final logicalHeight = physicalHeight / pixelRatio;
return DeviceInfo(
identifier: DeviceIdentifier(
TargetPlatform.iOS,
DeviceType.phone,
name,
),
name: name,
pixelRatio: pixelRatio,
safeAreas: EdgeInsets.zero,
rotatedSafeAreas: EdgeInsets.zero,
screenPath: Path()
..addRect(Rect.fromLTWH(0.0, 0.0, logicalWidth, logicalHeight)),
frameSize: Size(logicalWidth, logicalHeight),
screenSize: Size(logicalWidth, logicalHeight),
framePainter: const _EmptyFramePainter(),
);
}
class _EmptyFramePainter extends CustomPainter {
const _EmptyFramePainter();
@override
void paint(Canvas canvas, Size size) {}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
+55
View File
@@ -0,0 +1,55 @@
import 'package:flutter/material.dart';
import 'package:universal_ble/universal_ble.dart';
import 'package:universal_ble_example/data/storage_service.dart';
import 'package:universal_ble_example/home/permission_screen.dart';
import 'package:universal_ble_example/home/scanner_screen.dart';
/// Initializes the app services and checks permissions.
/// Returns whether the app has the required permissions.
Future<bool> initializeApp() async {
WidgetsFlutterBinding.ensureInitialized();
await StorageService.instance.init();
// await UniversalBle.setLogLevel(BleLogLevel.verbose);
return await UniversalBle.hasPermissions(
withAndroidFineLocation: false,
);
}
class UniversalBleApp extends StatelessWidget {
final bool hasPermission;
final Locale? locale;
final Widget Function(BuildContext, Widget?)? builder;
const UniversalBleApp({
super.key,
required this.hasPermission,
this.locale,
this.builder,
});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Universal BLE',
debugShowCheckedModeBanner: false,
locale: locale,
builder: builder,
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.light,
),
),
darkTheme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.dark,
),
),
themeMode: ThemeMode.system,
home: hasPermission ? ScannerScreen() : const PermissionScreen(),
);
}
}
@@ -6,12 +6,14 @@ import FlutterMacOS
import Foundation import Foundation
import package_info_plus import package_info_plus
import path_provider_foundation
import shared_preferences_foundation import shared_preferences_foundation
import universal_ble import universal_ble
import url_launcher_macos import url_launcher_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
UniversalBlePlugin.register(with: registry.registrar(forPlugin: "UniversalBlePlugin")) UniversalBlePlugin.register(with: registry.registrar(forPlugin: "UniversalBlePlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
+11 -4
View File
@@ -2,6 +2,9 @@ PODS:
- FlutterMacOS (1.0.0) - FlutterMacOS (1.0.0)
- package_info_plus (0.0.1): - package_info_plus (0.0.1):
- FlutterMacOS - FlutterMacOS
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- shared_preferences_foundation (0.0.1): - shared_preferences_foundation (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
@@ -14,6 +17,7 @@ PODS:
DEPENDENCIES: DEPENDENCIES:
- FlutterMacOS (from `Flutter/ephemeral`) - FlutterMacOS (from `Flutter/ephemeral`)
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
- universal_ble (from `Flutter/ephemeral/.symlinks/plugins/universal_ble/darwin`) - universal_ble (from `Flutter/ephemeral/.symlinks/plugins/universal_ble/darwin`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
@@ -23,6 +27,8 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral :path: Flutter/ephemeral
package_info_plus: package_info_plus:
:path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos
path_provider_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
shared_preferences_foundation: shared_preferences_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
universal_ble: universal_ble:
@@ -32,10 +38,11 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS: SPEC CHECKSUMS:
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
package_info_plus: 12f1c5c2cfe8727ca46cbd0b26677728972d9a5b package_info_plus: f0052d280d17aa382b932f399edf32507174e870
shared_preferences_foundation: 5086985c1d43c5ba4d5e69a4e8083a389e2909e6 path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
universal_ble: 65e1257dffc557cc7991a93d253beeddc7c1dc92 shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
url_launcher_macos: 175a54c831f4375a6cf895875f716ee5af3888ce universal_ble: 45519b2aeafe62761e2c6309f8927edb5288b914
url_launcher_macos: f87a979182d112f911de6820aefddaf56ee9fbfd
PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3 PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3
+85
View File
@@ -121,6 +121,30 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.11" version: "0.7.11"
device_frame:
dependency: transitive
description:
name: device_frame
sha256: "7b2ebb2a09d6cc0f086b51bd1412d7be83e0170056a7290349169be41164c86a"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
device_preview:
dependency: "direct main"
description:
name: device_preview
sha256: "88aa1cc73ee9a8ec771b309dcbc4000cc66b5d8456b825980997640ab1195bf5"
url: "https://pub.dev"
source: hosted
version: "1.3.1"
device_preview_screenshot:
dependency: "direct main"
description:
name: device_preview_screenshot
sha256: c79f185e155c0ed5d97b4e1afff6df181c2045fe28c7414c95f0b46307c549e6
url: "https://pub.dev"
source: hosted
version: "1.0.0"
expandable: expandable:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -180,6 +204,11 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.0" version: "6.0.0"
flutter_localizations:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@@ -198,6 +227,14 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
freezed_annotation:
dependency: transitive
description:
name: freezed_annotation
sha256: "7294967ff0a6d98638e7acb774aac3af2550777accd8149c90af5b014e6d44d8"
url: "https://pub.dev"
source: hosted
version: "3.1.0"
fuchsia_remote_debug_protocol: fuchsia_remote_debug_protocol:
dependency: transitive dependency: transitive
description: flutter description: flutter
@@ -240,6 +277,14 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
intl:
dependency: transitive
description:
name: intl
sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5"
url: "https://pub.dev"
source: hosted
version: "0.20.2"
json_annotation: json_annotation:
dependency: transitive dependency: transitive
description: description:
@@ -320,6 +365,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.17.0" version: "1.17.0"
nested:
dependency: transitive
description:
name: nested
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
package_info_plus: package_info_plus:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -352,6 +405,30 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.9.1" version: "1.9.1"
path_provider:
dependency: "direct main"
description:
name: path_provider
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
url: "https://pub.dev"
source: hosted
version: "2.1.5"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e
url: "https://pub.dev"
source: hosted
version: "2.2.22"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: "6d13aece7b3f5c5a9731eaf553ff9dcbc2eff41087fd2df587fd0fed9a3eb0c4"
url: "https://pub.dev"
source: hosted
version: "2.5.1"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
@@ -416,6 +493,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.0.5" version: "5.0.5"
provider:
dependency: transitive
description:
name: provider
sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272"
url: "https://pub.dev"
source: hosted
version: "6.1.5+1"
shared_preferences: shared_preferences:
dependency: "direct main" dependency: "direct main"
description: description:
+3
View File
@@ -15,8 +15,11 @@ dependencies:
shared_preferences: ^2.5.4 shared_preferences: ^2.5.4
package_info_plus: ^9.0.0 package_info_plus: ^9.0.0
url_launcher: ^6.3.2 url_launcher: ^6.3.2
path_provider: ^2.1.1
universal_ble: universal_ble:
path: ../ path: ../
device_preview: ^1.3.1
device_preview_screenshot: ^1.0.0
dev_dependencies: dev_dependencies:
integration_test: integration_test: