Skip to content

Instantly share code, notes, and snippets.

@Nidal-Bakir
Last active March 9, 2025 13:30
Show Gist options
  • Save Nidal-Bakir/b02ce3ac55ec583cf3b73b233b88ae2c to your computer and use it in GitHub Desktop.
Save Nidal-Bakir/b02ce3ac55ec583cf3b73b233b88ae2c to your computer and use it in GitHub Desktop.
Device type (phone/tablet) and orientation (landscape/portrait)
// MIT License
//
// Copyright (c) 2025 Nidal Bakir
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import 'dart:ui' as ui;
import 'package:flutter/widgets.dart';
import 'package:wow_shopping/backend/backend.dart';
enum DeviceType {
unknown,
phone,
tablet,
}
enum DeviceOrientation {
unknown,
portrait,
landscape,
}
@immutable
class DeviceTypeOrientationState {
const DeviceTypeOrientationState({
required this.deviceType,
required this.orientation,
});
const DeviceTypeOrientationState.unknown()
: deviceType = DeviceType.unknown,
orientation = DeviceOrientation.unknown;
final DeviceType deviceType;
final DeviceOrientation orientation;
bool get isTablet => deviceType == DeviceType.tablet;
bool get isPhone => deviceType == DeviceType.phone;
bool get isLandscape => orientation == DeviceOrientation.landscape;
bool get isPortrait => orientation == DeviceOrientation.portrait;
DeviceTypeOrientationState copyWith({
DeviceType? deviceType,
DeviceOrientation? orientation,
}) {
return DeviceTypeOrientationState(
deviceType: deviceType ?? this.deviceType,
orientation: orientation ?? this.orientation,
);
}
}
class DeviceTypeOrientationNotifier extends ChangeNotifier with WidgetsBindingObserver {
DeviceTypeOrientationNotifier();
var _state = const DeviceTypeOrientationState.unknown();
bool get isTablet => _state.isTablet;
bool get isPhone => _state.isPhone;
bool get isLandscape => _state.isLandscape;
bool get isPortrait => _state.isPortrait;
void init() {
WidgetsBinding.instance.addObserver(this);
updateDeviceType();
}
@override
void didChangeMetrics() {
super.didChangeMetrics();
updateDeviceType();
}
void updateDeviceType() {
final view = ui.PlatformDispatcher.instance.implicitView!;
final size = view.physicalSize / view.devicePixelRatio;
bool updated = false;
final deviceType = (size.shortestSide < 600) //
? DeviceType.phone
: DeviceType.tablet;
if (deviceType != _state.deviceType) {
debugPrint('Device Type changed to: $deviceType');
_state = _state.copyWith(deviceType: deviceType);
updated = true;
}
final orientation = (size.width < size.height) //
? DeviceOrientation.portrait
: DeviceOrientation.landscape;
if (orientation != _state.orientation) {
debugPrint('Orientation changed to: $orientation');
_state = _state.copyWith(orientation: orientation);
updated = true;
}
if (updated) {
notifyListeners();
}
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
}
class DeviceTypeBuilder extends StatelessWidget {
const DeviceTypeBuilder({
super.key,
required this.builder,
this.child,
});
final Widget Function(
BuildContext context,
DeviceTypeOrientationState state,
Widget? child,
) builder;
final Widget? child;
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: context.deviceType,
builder: (BuildContext context, Widget? child) {
return builder(context, context.deviceType._state, child);
},
child: child,
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment