Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: add desktop window option #235

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
44 changes: 44 additions & 0 deletions device_frame/lib/src/devices/generic/desktop_window/device.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import 'package:device_frame/src/devices/generic/base/draw_extensions.dart';
import 'package:device_frame/src/info/device_type.dart';
import 'package:device_frame/src/info/identifier.dart';
import 'package:device_frame/src/info/info.dart';
import 'package:flutter/material.dart';

part 'frame.dart';

/// Creates a generic desktop window device definition for the given [name], target
/// [platform] and [screenSize]. The [windowPosition] defines the position of a virtual
/// window with a window frame adapted for the given platform.
DeviceInfo buildGenericDesktopWindowDevice({
required TargetPlatform platform,
required String id,
required String name,
required Size screenSize,
required Rect windowPosition,
EdgeInsets safeAreas = EdgeInsets.zero,
double pixelRatio = 2.0,
EdgeInsets? rotatedSafeAreas,
GenericDesktopWindowFramePainter? framePainter,
}) {
final effectivePainter = framePainter ??
GenericDesktopWindowFramePainter(
platform: platform,
windowPosition: windowPosition,
);

return DeviceInfo(
identifier: DeviceIdentifier(
platform,
DeviceType.desktop,
id,
),
name: name,
pixelRatio: pixelRatio,
frameSize: effectivePainter.calculateFrameSize(screenSize),
screenSize: effectivePainter.effectiveWindowSize,
safeAreas: safeAreas,
rotatedSafeAreas: rotatedSafeAreas,
framePainter: effectivePainter,
screenPath: effectivePainter.createScreenPath(screenSize),
);
}
149 changes: 149 additions & 0 deletions device_frame/lib/src/devices/generic/desktop_window/frame.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
part of 'device.dart';

class GenericDesktopWindowFramePainter extends CustomPainter {
const GenericDesktopWindowFramePainter({
required this.platform,
required this.windowPosition,
this.outerBodyColor = defaultOuterBodyColor,
this.innerBodyColor = defaultInnerBodyColor,
this.outerBodyRadius = defaultOuterBodyRadius,
this.innerBodyRadius = defaultInnerBodyRadius,
this.innerBodyInsets = defaultInnerBodyInsets,
this.screenInsets = defaultScreenInsets,
this.screenRadius = defaultScreenRadius,
this.footSize = defaultFootSize,
this.footBarWidth = defaultFootBarWidth,
this.footBaseHeight = defaultFootBaseHeight,
this.windowRadius = defaultWindowRadius,
});

Size calculateFrameSize(Size screenSize) {
return Size(
screenSize.width + innerBodyInsets.horizontal + screenInsets.horizontal,
screenSize.height + innerBodyInsets.vertical + screenInsets.vertical,
);
}

Size get effectiveWindowSize {
return Size(
windowPosition.width,
windowPosition.height - barHeight,
);
}

double get barHeight {
switch (platform) {
case TargetPlatform.macOS:
return 30;
default:
return 40;
}
}

Offset get _windowLocation {
return Offset(
innerBodyInsets.left + screenInsets.left + windowPosition.left,
innerBodyInsets.top + screenInsets.top + windowPosition.top,
);
}

Path createScreenPath(Size screenSize) {
final result = Path();
result.addRRect(
RRect.fromRectAndCorners(
(_windowLocation + Offset(0, barHeight)) & effectiveWindowSize,
bottomLeft: windowRadius,
bottomRight: windowRadius,
),
);
return result;
}

final Rect windowPosition;
final TargetPlatform platform;
final Color outerBodyColor;
final Radius outerBodyRadius;
final Color innerBodyColor;
final Radius innerBodyRadius;
final Radius screenRadius;
final Radius windowRadius;
final EdgeInsets innerBodyInsets;
final EdgeInsets screenInsets;
final Size footSize;
final double footBarWidth;
final double footBaseHeight;

static const Color defaultOuterBodyColor = Color(0xff3A4245);
static const Radius defaultOuterBodyRadius = Radius.circular(30);
static const Color defaultInnerBodyColor = Color(0xff121515);
static const Radius defaultInnerBodyRadius = Radius.circular(20);
static const Radius defaultScreenRadius = Radius.circular(10);
static const Radius defaultWindowRadius = Radius.circular(6);
static const Size defaultFootSize = Size(920, 280);
static const double defaultFootBaseHeight = 40;
static const double defaultFootBarWidth = 60;

static const EdgeInsets defaultInnerBodyInsets = EdgeInsets.only(
left: 0,
top: 0,
right: 0,
bottom: 0,
);
static const EdgeInsets defaultScreenInsets = EdgeInsets.only(
left: 0,
top: 0,
right: 0,
bottom: 0,
);

@override
void paint(Canvas canvas, Size size) {
final bounds = Rect.fromLTWH(
0,
0,
size.width,
size.height - footSize.height,
);

final screenBounds = Rect.fromLTWH(
innerBodyInsets.left + screenInsets.left,
innerBodyInsets.top + screenInsets.top,
bounds.width - innerBodyInsets.horizontal - screenInsets.horizontal,
bounds.height - innerBodyInsets.vertical - screenInsets.vertical,
);
canvas.clipRRect(
RRect.fromRectAndRadius(
screenBounds,
screenRadius,
),
);

final windowPath = Path()
..addRRect(
RRect.fromRectAndRadius(
_windowLocation & effectiveWindowSize,
windowRadius,
),
);
canvas.drawPath(
windowPath,
Paint()
..blendMode = BlendMode.multiply
..color = const Color(0xFF3F2548).withOpacity(0.6));

canvas.drawWindowBar(
platform: platform,
bounds: _windowLocation &
Size(
windowPosition.width,
barHeight,
),
windowRadius: windowRadius,
);
}

@override
bool shouldRepaint(covariant GenericDesktopWindowFramePainter oldDelegate) {
return false;
}
}
17 changes: 17 additions & 0 deletions device_frame/lib/src/devices/linux/devices.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,22 @@ import 'package:flutter/widgets.dart';
class LinuxDevices {
const LinuxDevices();

DeviceInfo get window => _window;
static final _window = DeviceInfo.genericDesktopWindow(
platform: TargetPlatform.linux,
name: 'Window',
id: 'window',
screenSize: const Size(1920, 1080),
windowPosition: Rect.fromCenter(
center: const Offset(
1920 * 0.5,
1080 * 0.5,
),
width: 1920,
height: 1080,
),
);

DeviceInfo get wideMonitor => _wideMonitor;
static final _wideMonitor = DeviceInfo.genericDesktopMonitor(
platform: TargetPlatform.linux,
Expand Down Expand Up @@ -39,6 +55,7 @@ class LinuxDevices {

/// All devices.
List<DeviceInfo> get all => [
window,
wideMonitor,
laptop,
];
Expand Down
17 changes: 17 additions & 0 deletions device_frame/lib/src/devices/macos/devices.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,22 @@ import 'package:device_frame/src/devices/macos/macbook_pro/device.dart'
class MacOSDevices {
const MacOSDevices();

DeviceInfo get window => _window;
static final _window = DeviceInfo.genericDesktopWindow(
platform: TargetPlatform.macOS,
name: 'Window',
id: 'window',
screenSize: const Size(1920, 1080),
windowPosition: Rect.fromCenter(
center: const Offset(
1920 * 0.5,
1080 * 0.5,
),
width: 1920,
height: 1080,
),
);

DeviceInfo get macBookPro => i_macbook_pro.info;
DeviceInfo get wideMonitor => _wideMonitor;
static final _wideMonitor = DeviceInfo.genericDesktopMonitor(
Expand All @@ -26,6 +42,7 @@ class MacOSDevices {

/// All available devices.
List<DeviceInfo> get all => [
window,
macBookPro,
wideMonitor,
];
Expand Down
17 changes: 17 additions & 0 deletions device_frame/lib/src/devices/windows/devices.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,22 @@ import 'package:flutter/widgets.dart';
class WindowsDevices {
const WindowsDevices();

DeviceInfo get window => _window;
static final _window = DeviceInfo.genericDesktopWindow(
platform: TargetPlatform.windows,
name: 'Window',
id: 'window',
screenSize: const Size(1920, 1080),
windowPosition: Rect.fromCenter(
center: const Offset(
1920 * 0.5,
1080 * 0.5,
),
width: 1920,
height: 1080,
),
);

DeviceInfo get wideMonitor => _wideMonitor;
static final _wideMonitor = DeviceInfo.genericDesktopMonitor(
platform: TargetPlatform.windows,
Expand Down Expand Up @@ -40,6 +56,7 @@ class WindowsDevices {

/// All available devices.
List<DeviceInfo> get all => [
window,
wideMonitor,
laptop,
];
Expand Down
22 changes: 22 additions & 0 deletions device_frame/lib/src/info/info.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:device_frame/src/devices/generic/desktop_monitor/device.dart';
import 'package:device_frame/src/devices/generic/desktop_window/device.dart';
import 'package:device_frame/src/devices/generic/laptop/device.dart';
import 'package:device_frame/src/devices/generic/phone/device.dart';
import 'package:device_frame/src/devices/generic/tablet/device.dart';
Expand Down Expand Up @@ -86,6 +87,27 @@ abstract class DeviceInfo with _$DeviceInfo {
framePainter: framePainter,
);

factory DeviceInfo.genericDesktopWindow({
required TargetPlatform platform,
required String id,
required String name,
required Size screenSize,
required Rect windowPosition,
EdgeInsets safeAreas = EdgeInsets.zero,
double pixelRatio = 2.0,
GenericDesktopWindowFramePainter? framePainter,
}) =>
buildGenericDesktopWindowDevice(
platform: platform,
id: id,
name: name,
screenSize: screenSize,
windowPosition: windowPosition,
safeAreas: safeAreas,
pixelRatio: pixelRatio,
framePainter: framePainter,
);

factory DeviceInfo.genericDesktopMonitor({
required TargetPlatform platform,
required String id,
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.