add adaptive_scaffold

This commit is contained in:
shenlong-tanwen
2024-05-24 09:42:02 +05:30
parent fb6253d2d1
commit 1631df70e9
295 changed files with 2540 additions and 44480 deletions
@@ -0,0 +1,65 @@
import 'package:flutter/material.dart';
class ImFilledButton extends StatelessWidget {
const ImFilledButton({
super.key,
this.icon,
this.onPressed,
this.isDisabled = false,
required this.label,
}) : _tonal = false;
const ImFilledButton.tonal({
super.key,
this.icon,
this.onPressed,
this.isDisabled = false,
required this.label,
}) : _tonal = true;
/// Internal flag to switch between filled and tonal variant
final bool _tonal;
/// Should disable the button
final bool isDisabled;
/// Icon to display if [withIcon] is true
final IconData? icon;
/// Action to perform on Button press
final VoidCallback? onPressed;
/// Label to be displayed in the button
final String label;
@override
Widget build(BuildContext context) {
if (_tonal) {
if (icon != null) {
return FilledButton.tonalIcon(
onPressed: isDisabled ? null : onPressed,
icon: Icon(icon),
label: Text(label),
);
}
return FilledButton.tonal(
onPressed: isDisabled ? null : onPressed,
child: Text(label),
);
}
if (icon != null) {
return FilledButton.icon(
onPressed: isDisabled ? null : onPressed,
icon: Icon(icon),
label: Text(label),
);
}
return FilledButton(
onPressed: isDisabled ? null : onPressed,
child: Text(label),
);
}
}
@@ -0,0 +1,77 @@
import 'package:flutter/material.dart';
import 'package:immich_mobile/presentation/components/input/text_form_field.widget.dart';
import 'package:material_symbols_icons/symbols.dart';
class ImPasswordFormField extends StatefulWidget {
const ImPasswordFormField({
super.key,
this.controller,
this.onChanged,
this.focusNode,
this.label,
this.hint,
this.textInputAction,
this.isDisabled = false,
});
/// The [TextEditingController] passed to the underlying [TextFormField]
final TextEditingController? controller;
/// Optional callback to receive changes
final void Function(String?)? onChanged;
/// The [FocusNode] passed to the underlying [TextFormField]
final FocusNode? focusNode;
/// Translation Key used as label
final String? label;
/// Translation key used as hint
final String? hint;
/// Type of the following action - go, next, enter, etc.
final TextInputAction? textInputAction;
/// Flag to disable the [TextFormField]
final bool isDisabled;
@override
State createState() => _ImPasswordFormFieldState();
}
class _ImPasswordFormFieldState extends State<ImPasswordFormField> {
final showPassword = ValueNotifier(false);
@override
void dispose() {
showPassword.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return ValueListenableBuilder(
valueListenable: showPassword,
builder: (_, showPass, child) => ImTextFormField(
controller: widget.controller,
onChanged: widget.onChanged,
shouldObscure: !showPass,
hint: widget.hint,
label: widget.label,
focusNode: widget.focusNode,
suffixIcon: IconButton(
onPressed: () => showPassword.value = !showPassword.value,
icon: Icon(
showPassword.value
? Symbols.visibility_off_rounded
: Symbols.visibility_rounded,
),
),
autoFillHints: const [AutofillHints.password],
keyboardType: TextInputType.visiblePassword,
textInputAction: widget.textInputAction,
isDisabled: widget.isDisabled,
),
);
}
}
@@ -0,0 +1,62 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:immich_mobile/domain/models/app_setting.model.dart';
import 'package:immich_mobile/domain/services/app_setting.service.dart';
import 'package:immich_mobile/service_locator.dart';
class ImSwitchListTile<T> extends StatefulWidget {
const ImSwitchListTile(
this.setting, {
super.key,
this.fromAppSetting,
this.toAppSetting,
}) : assert(T == bool || (fromAppSetting != null && toAppSetting != null),
"Setting is not a boolean and a from / to App setting is not provided");
final AppSetting<T> setting;
/// Converts the type T to a boolean to use in a switch
final bool Function(T value)? fromAppSetting;
/// Converts the boolean back to the type T to be stored in the app setting. Return null to not update the DB but to
/// retain the previous value
final T? Function(bool state)? toAppSetting;
@override
State createState() => _ImSwitchListTileState<T>();
}
class _ImSwitchListTileState<T> extends State<ImSwitchListTile<T>> {
// Actual switch list state
late bool isEnabled;
final AppSettingService _appSettingService = di();
Future<void> set(bool enabled) async {
if (isEnabled == enabled) return;
final value = T != bool ? widget.toAppSetting!(enabled) : enabled as T;
if (value != null &&
await _appSettingService.setSetting(widget.setting, value) &&
context.mounted) {
setState(() {
isEnabled = enabled;
});
}
}
@override
void initState() {
super.initState();
final value = _appSettingService.getSetting(widget.setting);
isEnabled = T != bool ? widget.fromAppSetting!(value) : value as bool;
}
@override
Widget build(BuildContext context) {
return SwitchListTile(
value: isEnabled,
onChanged: (value) => set(value),
);
}
}
@@ -0,0 +1,36 @@
import 'package:flutter/material.dart';
class ImTextButton extends StatelessWidget {
const ImTextButton({
super.key,
this.icon,
this.onPressed,
this.isDisabled = false,
required this.label,
});
/// Icon to display if [withIcon] is true
final IconData? icon;
/// Flag to disable the button
final bool isDisabled;
/// Action to perform on Button press
final VoidCallback? onPressed;
/// Label to be displayed in the button
final String label;
@override
Widget build(BuildContext context) {
if (icon != null) {
return TextButton.icon(
onPressed: isDisabled ? null : onPressed,
icon: Icon(icon),
label: Text(label),
);
}
return TextButton(onPressed: onPressed, child: Text(label));
}
}
@@ -0,0 +1,86 @@
import 'package:flutter/material.dart';
class ImTextFormField extends StatelessWidget {
const ImTextFormField({
super.key,
this.controller,
this.focusNode,
this.onChanged,
this.validator,
this.shouldObscure = false,
this.suffixIcon,
this.label,
this.hint,
this.autoFillHints,
this.keyboardType,
this.textInputAction,
this.isDisabled = false,
this.onSubmitted,
}) : assert(
onSubmitted == null ||
textInputAction == TextInputAction.next ||
textInputAction == TextInputAction.previous,
"onSubmitted provided when textInputAction is not next or pervious",
);
/// The [TextEditingController] passed to the underlying [TextFormField]
final TextEditingController? controller;
/// The [FocusNode] passed to the underlying [TextFormField]
final FocusNode? focusNode;
/// Optional callback to validate input
final String? Function(String?)? validator;
/// Optional callback to receive changes
final void Function(String?)? onChanged;
/// Optional flag to obscure texts
final bool shouldObscure;
/// Icon Widget to display in the suffix
final Widget? suffixIcon;
/// Translation Key used as label
final String? label;
/// Translation key used as hint
final String? hint;
/// Hints used by the auto-fill service
final List<String>? autoFillHints;
/// Type of keyboard - Numberic / Alphanum
final TextInputType? keyboardType;
/// Type of the following action - go, next, enter, etc.
final TextInputAction? textInputAction;
/// Flag to disable the [TextFormField]
final bool isDisabled;
/// Called on [TextInputAction.next] or [TextInputAction.previous]
final void Function(String)? onSubmitted;
@override
Widget build(BuildContext context) {
return TextFormField(
controller: controller,
onChanged: onChanged,
focusNode: focusNode,
obscureText: shouldObscure,
validator: validator,
decoration: InputDecoration(
labelText: label,
hintText: hint,
suffixIcon: suffixIcon,
),
autofillHints: autoFillHints,
keyboardType: keyboardType,
textInputAction: textInputAction,
readOnly: isDisabled,
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
onFieldSubmitted: onSubmitted,
);
}
}