Files
iiEsaywebUIapp/lib/shared/utils/platform_utils.dart
2025-08-10 01:20:45 +05:30

488 lines
12 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/cupertino.dart';
import 'dart:io' show Platform;
import '../theme/theme_extensions.dart';
/// Platform-specific utilities for enhanced user experience
class PlatformUtils {
PlatformUtils._();
/// Check if device supports haptic feedback
static bool get supportsHaptics => Platform.isIOS || Platform.isAndroid;
/// Trigger light haptic feedback
static void lightHaptic() {
if (supportsHaptics) {
HapticFeedback.lightImpact();
}
}
/// Trigger medium haptic feedback
static void mediumHaptic() {
if (supportsHaptics && Platform.isIOS) {
HapticFeedback.mediumImpact();
} else if (Platform.isAndroid) {
HapticFeedback.lightImpact();
}
}
/// Trigger heavy haptic feedback
static void heavyHaptic() {
if (supportsHaptics && Platform.isIOS) {
HapticFeedback.heavyImpact();
} else if (Platform.isAndroid) {
HapticFeedback.vibrate();
}
}
/// Trigger selection haptic feedback
static void selectionHaptic() {
if (supportsHaptics) {
HapticFeedback.selectionClick();
}
}
/// Get platform-appropriate icon
static IconData getIcon({required IconData ios, required IconData android}) {
return Platform.isIOS ? ios : android;
}
/// Get platform-appropriate text style
static TextStyle getPlatformTextStyle(BuildContext context) {
if (Platform.isIOS) {
return CupertinoTheme.of(context).textTheme.textStyle;
}
return Theme.of(context).textTheme.bodyMedium ?? const TextStyle();
}
/// Create platform-specific button
static Widget createButton({
required String text,
required VoidCallback? onPressed,
bool isPrimary = true,
Color? color,
}) {
if (Platform.isIOS) {
return Builder(
builder: (context) => CupertinoButton(
onPressed: onPressed,
color: isPrimary
? (color ?? context.conduitTheme.buttonPrimary)
: null,
child: Text(text),
),
);
}
return isPrimary
? FilledButton(
onPressed: onPressed,
style: color != null
? FilledButton.styleFrom(backgroundColor: color)
: null,
child: Text(text),
)
: OutlinedButton(onPressed: onPressed, child: Text(text));
}
/// Create platform-specific switch
static Widget createSwitch({
required bool value,
required ValueChanged<bool>? onChanged,
Color? activeColor,
}) {
if (Platform.isIOS) {
return Builder(
builder: (context) => CupertinoSwitch(
value: value,
onChanged: onChanged,
thumbColor: activeColor ?? context.conduitTheme.buttonPrimary,
),
);
}
return Switch(
value: value,
onChanged: onChanged,
activeTrackColor: activeColor,
);
}
/// Create platform-specific slider
static Widget createSlider({
required double value,
required ValueChanged<double>? onChanged,
double min = 0.0,
double max = 1.0,
int? divisions,
Color? activeColor,
}) {
if (Platform.isIOS) {
return Builder(
builder: (context) => CupertinoSlider(
value: value,
onChanged: onChanged,
min: min,
max: max,
divisions: divisions,
activeColor: activeColor ?? context.conduitTheme.buttonPrimary,
),
);
}
return Slider(
value: value,
onChanged: onChanged,
min: min,
max: max,
divisions: divisions,
activeColor: activeColor,
);
}
}
/// iOS-specific enhancements
class IOSEnhancements {
/// Create iOS-style navigation bar
static PreferredSizeWidget createNavigationBar({
required String title,
VoidCallback? onBack,
List<Widget>? actions,
Color? backgroundColor,
}) {
return CupertinoNavigationBar(
middle: Text(title),
leading: onBack != null
? CupertinoNavigationBarBackButton(onPressed: onBack)
: null,
trailing: actions != null && actions.isNotEmpty
? Row(mainAxisSize: MainAxisSize.min, children: actions)
: null,
backgroundColor: backgroundColor,
);
}
/// Create iOS-style context menu
static Widget createContextMenu({
required Widget child,
required List<ContextMenuAction> actions,
}) {
return CupertinoContextMenu(
actions: actions
.map(
(action) => CupertinoContextMenuAction(
onPressed: action.onPressed,
isDefaultAction: action.isDefault,
isDestructiveAction: action.isDestructive,
child: Text(action.title),
),
)
.toList(),
child: child,
);
}
/// Create iOS-style action sheet
static void showActionSheet({
required BuildContext context,
required String title,
String? message,
required List<ActionSheetAction> actions,
}) {
showCupertinoModalPopup(
context: context,
builder: (context) => CupertinoActionSheet(
title: Text(title),
message: message != null ? Text(message) : null,
actions: actions
.map(
(action) => CupertinoActionSheetAction(
onPressed: () {
Navigator.pop(context);
action.onPressed();
},
isDefaultAction: action.isDefault,
isDestructiveAction: action.isDestructive,
child: Text(action.title),
),
)
.toList(),
cancelButton: CupertinoActionSheetAction(
onPressed: () => Navigator.pop(context),
child: const Text('Cancel'),
),
),
);
}
}
/// Android-specific enhancements
class AndroidEnhancements {
/// Create Material You themed button
static Widget createMaterial3Button({
required String text,
required VoidCallback? onPressed,
ButtonType type = ButtonType.filled,
IconData? icon,
}) {
Widget button;
switch (type) {
case ButtonType.filled:
button = icon != null
? FilledButton.icon(
onPressed: onPressed,
icon: Icon(icon),
label: Text(text),
)
: FilledButton(onPressed: onPressed, child: Text(text));
break;
case ButtonType.outlined:
button = icon != null
? OutlinedButton.icon(
onPressed: onPressed,
icon: Icon(icon),
label: Text(text),
)
: OutlinedButton(onPressed: onPressed, child: Text(text));
break;
case ButtonType.text:
button = icon != null
? TextButton.icon(
onPressed: onPressed,
icon: Icon(icon),
label: Text(text),
)
: TextButton(onPressed: onPressed, child: Text(text));
break;
}
return button;
}
/// Create Material 3 card
static Widget createCard({
required Widget child,
VoidCallback? onTap,
EdgeInsetsGeometry? padding,
CardType type = CardType.filled,
}) {
Widget card;
switch (type) {
case CardType.filled:
card = Card.filled(
child: padding != null
? Padding(padding: padding, child: child)
: child,
);
break;
case CardType.outlined:
card = Card.outlined(
child: padding != null
? Padding(padding: padding, child: child)
: child,
);
break;
case CardType.elevated:
card = Card(
child: padding != null
? Padding(padding: padding, child: child)
: child,
);
break;
}
if (onTap != null) {
return InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(AppBorderRadius.md),
child: card,
);
}
return card;
}
/// Create floating action button with Material 3 styling
static Widget createFAB({
required VoidCallback onPressed,
required Widget child,
bool isExtended = false,
String? label,
}) {
if (isExtended && label != null) {
return FloatingActionButton.extended(
onPressed: onPressed,
icon: child,
label: Text(label),
);
}
return FloatingActionButton(onPressed: onPressed, child: child);
}
}
/// Platform-aware widget that provides different implementations
class PlatformWidget extends StatelessWidget {
final Widget ios;
final Widget android;
final Widget? fallback;
const PlatformWidget({
super.key,
required this.ios,
required this.android,
this.fallback,
});
@override
Widget build(BuildContext context) {
if (Platform.isIOS) {
return ios;
} else if (Platform.isAndroid) {
return android;
} else {
return fallback ?? android;
}
}
}
/// Enhanced button with platform-specific haptics
class HapticButton extends StatelessWidget {
final Widget child;
final VoidCallback? onPressed;
final HapticType hapticType;
final ButtonStyle? style;
const HapticButton({
super.key,
required this.child,
required this.onPressed,
this.hapticType = HapticType.light,
this.style,
});
@override
Widget build(BuildContext context) {
return FilledButton(
onPressed: onPressed != null
? () {
_triggerHaptic();
onPressed!();
}
: null,
style: style,
child: child,
);
}
void _triggerHaptic() {
switch (hapticType) {
case HapticType.light:
PlatformUtils.lightHaptic();
break;
case HapticType.medium:
PlatformUtils.mediumHaptic();
break;
case HapticType.heavy:
PlatformUtils.heavyHaptic();
break;
case HapticType.selection:
PlatformUtils.selectionHaptic();
break;
}
}
}
/// Enhanced list tile with platform-specific styling
class PlatformListTile extends StatelessWidget {
final Widget? leading;
final Widget? title;
final Widget? subtitle;
final Widget? trailing;
final VoidCallback? onTap;
final bool enableHaptic;
const PlatformListTile({
super.key,
this.leading,
this.title,
this.subtitle,
this.trailing,
this.onTap,
this.enableHaptic = true,
});
@override
Widget build(BuildContext context) {
final tile = ListTile(
leading: leading,
title: title,
subtitle: subtitle,
trailing: trailing,
onTap: onTap != null && enableHaptic
? () {
PlatformUtils.selectionHaptic();
onTap!();
}
: onTap,
);
if (Platform.isIOS) {
return Builder(
builder: (context) => Container(
decoration: BoxDecoration(
color: context.conduitTheme.surfaceBackground,
border: Border(
bottom: BorderSide(
color: context.conduitTheme.dividerColor,
width: 0.5,
),
),
),
child: tile,
),
);
}
return tile;
}
}
// Enums and supporting classes
enum HapticType { light, medium, heavy, selection }
enum ButtonType { filled, outlined, text }
enum CardType { filled, outlined, elevated }
class ContextMenuAction {
final String title;
final VoidCallback onPressed;
final bool isDefault;
final bool isDestructive;
const ContextMenuAction({
required this.title,
required this.onPressed,
this.isDefault = false,
this.isDestructive = false,
});
}
class ActionSheetAction {
final String title;
final VoidCallback onPressed;
final bool isDefault;
final bool isDestructive;
const ActionSheetAction({
required this.title,
required this.onPressed,
this.isDefault = false,
this.isDestructive = false,
});
}