Skip to content
Merged
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
1 change: 0 additions & 1 deletion .pubignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
build/
example/
coverage/
.github/
.vscode/
Expand Down
8 changes: 8 additions & 0 deletions lib/responsive_builder2.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
/// The responsive_builder2 library provides widgets and utilities for building
/// responsive UIs in Flutter.
///
/// This package allows you to easily adapt your UI to different screen sizes
/// and device types (watch, phone, tablet, desktop).
/// It includes builder widgets such as [ResponsiveBuilder] and
/// [ScreenTypeLayout.builder2] that provide detailed sizing information,
/// as well as helpers for custom breakpoints and refined size categories.
library responsive_builder2;

export 'src/device_screen_type.dart';
Expand Down
47 changes: 47 additions & 0 deletions lib/src/device_screen_type.dart
Original file line number Diff line number Diff line change
@@ -1,45 +1,92 @@
/// Represents the type of device screen, used for responsive layout decisions.
///
/// The enum values are ordered by increasing screen size:
/// - [watch]: Smallest screens, such as smartwatches.
/// - [phone]: Phones and small mobile devices.
/// - [tablet]: Tablets and medium-sized devices.
/// - [desktop]: Large screens, such as desktops and laptops.
///
/// Deprecated values (capitalized) are kept for backward compatibility.
enum DeviceScreenType {
/// Deprecated: Use [watch] instead.
@Deprecated('Use lowercase version')
Watch(0),

/// Deprecated: Use [phone] instead.
@Deprecated('Use lowercase or phoneversion')
Mobile(1),

/// Deprecated: Use [tablet] instead.
@Deprecated('Use lowercase version')
Tablet(2),

/// Deprecated: Use [desktop] instead.
@Deprecated('Use lowercase version')
Desktop(3),

/// Deprecated: Use [phone] instead.
@Deprecated('Use phone version')
mobile(1),

/// Smallest screens, such as smartwatches.
watch(0),

/// Phones and small mobile devices.
phone(1),

/// Tablets and medium-sized devices.
tablet(2),

/// Large screens, such as desktops and laptops.
desktop(3);

/// The ordinal value representing the order of the device type.
const DeviceScreenType(this.ordinal);

final int ordinal;

/// Returns true if this device type is greater (larger) than [other].
bool operator >(DeviceScreenType other) => ordinal > other.ordinal;

/// Returns true if this device type is greater than or equal to [other].
bool operator >=(DeviceScreenType other) => ordinal >= other.ordinal;

/// Returns true if this device type is less (smaller) than [other].
bool operator <(DeviceScreenType other) => ordinal < other.ordinal;

/// Returns true if this device type is less than or equal to [other].
bool operator <=(DeviceScreenType other) => ordinal <= other.ordinal;
}

/// Represents a more granular size classification for responsive layouts.
///
/// The enum values are ordered by increasing size:
/// - [small]: Smallest refined size.
/// - [normal]: Default or typical size.
/// - [large]: Larger than normal.
/// - [extraLarge]: Largest refined size.
enum RefinedSize {
/// Smallest refined size.
small,

/// Default or typical size.
normal,

/// Larger than normal.
large,

/// Largest refined size.
extraLarge;

/// Returns true if this refined size is greater (larger) than [other].
bool operator >(RefinedSize other) => index > other.index;

/// Returns true if this refined size is greater than or equal to [other].
bool operator >=(RefinedSize other) => index >= other.index;

/// Returns true if this refined size is less (smaller) than [other].
bool operator <(RefinedSize other) => index < other.index;

/// Returns true if this refined size is less than or equal to [other].
bool operator <=(RefinedSize other) => index <= other.index;
}
11 changes: 11 additions & 0 deletions lib/src/helpers/device_width.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
import 'dart:ui';

/// Calculates the effective device width based on the platform and screen size.
///
/// For web or desktop platforms, returns the full width of the screen.
/// For mobile platforms, returns the shortest side of the screen
/// (width or height).
///
/// Parameters:
/// * [size]: The physical size of the screen
/// * [isWebOrDesktop]: Whether the app is running on web or desktop platform
///
/// Returns the effective width in logical pixels.
double deviceWidth(Size size, bool isWebOrDesktop) =>
isWebOrDesktop ? size.width : size.shortestSide;
3 changes: 0 additions & 3 deletions lib/src/helpers/device_width_web.dart

This file was deleted.

92 changes: 77 additions & 15 deletions lib/src/helpers/helpers.dart
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
import 'dart:io';
// Removed import 'dart:io' for WASM compatibility.

import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:responsive_builder2/responsive_builder2.dart';
import 'package:universal_platform/universal_platform.dart';

// Author: https://github.com/fastogt/responsive_builder/tree/master
import 'device_width.dart' if (dart.library.js_interop) 'device_width_web.dart'
as width;
import 'device_width.dart' as width;

final _isWebOrDesktop =
kIsWeb || Platform.isWindows || Platform.isLinux || Platform.isMacOS;
/// Determines if the current platform is web or desktop (WASM compatible)
final _isWebOrDesktop = kIsWeb ||
UniversalPlatform.isWindows ||
UniversalPlatform.isLinux ||
UniversalPlatform.isMacOS;

/// Returns the [DeviceScreenType] that the application is currently running on
///
/// This function determines the device type based on the screen size and
/// optional breakpoints.
///
/// Parameters:
/// * [size] - The current screen size
/// * [breakpoint] - Optional custom breakpoints to override defaults
/// * [isWebOrDesktop] - Optional flag to force web/desktop behavior
///
/// Returns [DeviceScreenType] representing the current device type (desktop,
/// tablet, phone, or watch)
DeviceScreenType getDeviceType(Size size,
[ScreenBreakpoints? breakpoint = null, bool? isWebOrDesktop]) {
isWebOrDesktop = isWebOrDesktop ??= _isWebOrDesktop;
Expand Down Expand Up @@ -39,14 +52,28 @@ DeviceScreenType getDeviceType(Size size,
return DeviceScreenType.phone;
}

// coverage:ignore-start
/// Helper function to determine if a large screen should be treated as desktop
/// or tablet
///
/// Returns [DeviceScreenType.desktop] if [isWebOrDesktop] is true, otherwise
/// returns [DeviceScreenType.tablet]
DeviceScreenType _desktopOrTablet(bool? isWebOrDesktop) =>
(isWebOrDesktop ?? _isWebOrDesktop)
? DeviceScreenType.desktop
: DeviceScreenType.tablet;
// coverage:ignore-end

/// Returns the [RefindedSize] for each device that the application is currently running on
/// Returns the [RefinedSize] for the current device based on screen dimensions
///
/// This function provides more granular size categories (extraLarge, large,
/// normal, small)
/// within each device type (desktop, tablet, phone, watch).
///
/// Parameters:
/// * [size] - The current screen size
/// * [refinedBreakpoint] - Optional custom breakpoints for refined sizes
/// * [isWebOrDesktop] - Optional flag to force web/desktop behavior
///
/// Returns [RefinedSize] representing the current refined size category
RefinedSize getRefinedSize(
Size size, {
RefinedBreakpoints? refinedBreakpoint,
Expand Down Expand Up @@ -160,7 +187,22 @@ RefinedSize getRefinedSize(
return RefinedSize.small;
}

/// Will return one of the values passed in for the device it's running on
/// Returns a value based on the current device screen type
///
/// This function selects the appropriate value from the provided options based
/// on the current device type (desktop, tablet, phone, watch). It follows a
/// fallback pattern where if a value for the current device type isn't provided,
/// it will use the next best option.
///
/// Parameters:
/// * [context] - The build context
/// * [isWebOrDesktop] - Optional flag to force web/desktop behavior
/// * [mobile] - Required value for mobile devices
/// * [tablet] - Optional value for tablet devices
/// * [desktop] - Optional value for desktop devices
/// * [watch] - Optional value for watch devices
///
/// Returns the appropriate value for the current device type
T getValueForScreenType<T>({
required BuildContext context,
bool? isWebOrDesktop,
Expand All @@ -175,7 +217,8 @@ T getValueForScreenType<T>({
if (deviceScreenType == DeviceScreenType.desktop) {
// If we have supplied the desktop layout then display that
if (desktop != null) return desktop;
// If no desktop layout is supplied we want to check if we have the size below it and display that
// If no desktop layout is supplied we want to check if we have the size
// below it and display that
if (tablet != null) return tablet;
}

Expand All @@ -191,12 +234,28 @@ T getValueForScreenType<T>({
if (mobile != null) return mobile;
}

// If none of the layouts above are supplied we use the prefered layout based on the flag
// If none of the layouts above are supplied we use the prefered layout based
// on the flag
final buildDesktopLayout = ResponsiveAppUtil.preferDesktop && desktop != null;

return buildDesktopLayout ? desktop : mobile;
}

/// Returns a value based on the current refined screen size
///
/// This function selects the appropriate value from the provided options based
/// on the current refined size (extraLarge, large, normal, small). It follows a
/// fallback pattern where if a value for the current size isn't provided, it
/// will use the next best option.
///
/// Parameters:
/// * [context] - The build context
/// * [small] - Optional value for small screens
/// * [normal] - Required value for normal screens
/// * [large] - Optional value for large screens
/// * [extraLarge] - Optional value for extra large screens
///
/// Returns the appropriate value for the current refined size
/// Will return one of the values passed in for the refined size
T getValueForRefinedSize<T>({
required BuildContext context,
Expand All @@ -210,14 +269,16 @@ T getValueForRefinedSize<T>({
if (refinedSize == RefinedSize.extraLarge) {
// If we have supplied the extra large layout then display that
if (extraLarge != null) return extraLarge;
// If no extra large layout is supplied we want to check if we have the size below it and display that
// If no extra large layout is supplied we want to check if we have the
// size below it and display that
if (large != null) return large;
}

if (refinedSize == RefinedSize.large) {
// If we have supplied the large layout then display that
if (large != null) return large;
// If no large layout is supplied we want to check if we have the size below it and display that
// If no large layout is supplied we want to check if we have the size
// below it and display that
if (normal != null) return normal;
}

Expand All @@ -232,7 +293,8 @@ T getValueForRefinedSize<T>({
if (small != null) return small;
}

// If none of the layouts above are supplied or we're on the normal size layout then we show the normal layout
// If none of the layouts above are supplied or we're on the normal size
// layout then we show the normal layout
return normal;
}

Expand Down
Loading