Initial commit
This commit is contained in:
313
lib/widgets/widget_buttons.dart
Normal file
313
lib/widgets/widget_buttons.dart
Normal file
@@ -0,0 +1,313 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:hum/core/constants/app_theme.dart';
|
||||
import 'package:phosphor_flutter/phosphor_flutter.dart';
|
||||
|
||||
class BTNSquareBG extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final VoidCallback action;
|
||||
|
||||
const BTNSquareBG({super.key, required this.icon, required this.action});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CupertinoButton(
|
||||
color: CupertinoDynamicColor.resolve(colorBarButton, context),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
padding: EdgeInsets.zero,
|
||||
onPressed: action,
|
||||
child: Icon(
|
||||
size: 18,
|
||||
color: CupertinoDynamicColor.resolve(
|
||||
colorAccentSecondary, // 👈 define as dynamic in your theme
|
||||
context,
|
||||
),
|
||||
icon,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BTNRoundBG extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final VoidCallback action;
|
||||
|
||||
const BTNRoundBG({super.key, required this.icon, required this.action});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CupertinoButton(
|
||||
color: CupertinoDynamicColor.resolve(colorBarButton, context),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
padding: EdgeInsets.zero,
|
||||
onPressed: action,
|
||||
child: Icon(
|
||||
size: 18,
|
||||
color: CupertinoDynamicColor.resolve(
|
||||
colorAccentSecondary, // 👈 define as dynamic in your theme
|
||||
context,
|
||||
),
|
||||
icon,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BTNFilled extends StatelessWidget {
|
||||
const BTNFilled({
|
||||
super.key,
|
||||
this.text = '',
|
||||
this.width = double.infinity,
|
||||
this.color = colorAccentSecondary,
|
||||
required this.action,
|
||||
});
|
||||
|
||||
final String text;
|
||||
final double width;
|
||||
final VoidCallback action;
|
||||
final Color color;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
width: width,
|
||||
child: CupertinoButton.filled(
|
||||
color: color,
|
||||
borderRadius: BorderRadius.circular(roundLarge),
|
||||
onPressed: action,
|
||||
child: Text(text),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BTNFilledIcon extends StatelessWidget {
|
||||
const BTNFilledIcon({
|
||||
super.key,
|
||||
this.text = '',
|
||||
this.width = double.infinity,
|
||||
this.color = colorAccentSecondary,
|
||||
this.alignment = MainAxisAlignment.start,
|
||||
required this.icon,
|
||||
required this.action,
|
||||
});
|
||||
|
||||
final String text;
|
||||
final double width;
|
||||
final VoidCallback action;
|
||||
final Color color;
|
||||
final IconData icon;
|
||||
final MainAxisAlignment alignment;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
width: width,
|
||||
child: CupertinoButton.filled(
|
||||
color: color,
|
||||
borderRadius: BorderRadius.circular(roundLarge),
|
||||
onPressed: action,
|
||||
child: Row(
|
||||
spacing: 14,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
mainAxisAlignment: alignment,
|
||||
children: [PhosphorIcon(icon), Text(text)],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BTNComplex extends StatelessWidget {
|
||||
const BTNComplex({
|
||||
super.key,
|
||||
this.text = 'text',
|
||||
this.label = 'label',
|
||||
this.width = double.infinity,
|
||||
this.color = colorAccentSecondary,
|
||||
this.alignment = MainAxisAlignment.start,
|
||||
this.trailingIcon = CupertinoIcons.right_chevron,
|
||||
this.textColor = CupertinoColors.white,
|
||||
required this.iconLeading,
|
||||
required this.action,
|
||||
});
|
||||
|
||||
final String label;
|
||||
final String text;
|
||||
final double width;
|
||||
final VoidCallback action;
|
||||
final Color color;
|
||||
final IconData iconLeading;
|
||||
final IconData trailingIcon;
|
||||
final MainAxisAlignment alignment;
|
||||
final Color textColor;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
width: width,
|
||||
child: CupertinoButton.filled(
|
||||
color: color,
|
||||
borderRadius: BorderRadius.circular(roundLarge),
|
||||
onPressed: action,
|
||||
child: Row(
|
||||
spacing: 14,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: alignment,
|
||||
children: [
|
||||
Icon(iconLeading),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Opacity(opacity: .6, child: Text(label, style: TextStyle(fontSize: 14))),
|
||||
Text(text, style: TextStyle(color: textColor)),
|
||||
],
|
||||
),
|
||||
Spacer(),
|
||||
Opacity(opacity: .4, child: Icon(trailingIcon, size: 18)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BTNFilledAnimated extends StatelessWidget {
|
||||
const BTNFilledAnimated({
|
||||
super.key,
|
||||
this.text = '',
|
||||
this.width = double.infinity,
|
||||
this.color = colorAccentSecondary,
|
||||
this.working = false,
|
||||
required this.action,
|
||||
});
|
||||
|
||||
final String text;
|
||||
final double width;
|
||||
final Color color;
|
||||
final bool working;
|
||||
final VoidCallback action;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
const double spinnerSize = 16;
|
||||
const double gap = 8;
|
||||
const double slotWidth = spinnerSize + gap; // space reserved on both sides
|
||||
|
||||
return SizedBox(
|
||||
width: width,
|
||||
child: CupertinoButton.filled(
|
||||
color: color,
|
||||
borderRadius: BorderRadius.circular(roundLarge),
|
||||
// Disable tap while working (optional UX)
|
||||
onPressed: working ? null : action,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
// right slot shows spinner when working, otherwise keeps same width
|
||||
SizedBox(
|
||||
width: slotWidth,
|
||||
child: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
transitionBuilder: (child, anim) => FadeTransition(opacity: anim, child: child),
|
||||
child: working
|
||||
? Align(
|
||||
alignment: Alignment.centerRight,
|
||||
key: const ValueKey('spinner'),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: gap),
|
||||
child: CupertinoActivityIndicator(radius: spinnerSize / 2),
|
||||
),
|
||||
)
|
||||
: const SizedBox(key: ValueKey('no-spinner')),
|
||||
),
|
||||
),
|
||||
|
||||
// centered label
|
||||
Expanded(child: Center(child: Text(text))),
|
||||
|
||||
// left spacer to keep text perfectly centered
|
||||
const SizedBox(width: slotWidth),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BTNText extends StatelessWidget {
|
||||
const BTNText({super.key, this.text = '', required this.action});
|
||||
|
||||
final VoidCallback action;
|
||||
final String text;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CupertinoButton(onPressed: action, child: Text(text));
|
||||
}
|
||||
}
|
||||
|
||||
// CONTEXT MENU BUTTON
|
||||
class MenuAction {
|
||||
final String label;
|
||||
final IconData? icon;
|
||||
final VoidCallback onPressed;
|
||||
final bool destructive;
|
||||
const MenuAction({
|
||||
required this.label,
|
||||
required this.onPressed,
|
||||
this.icon,
|
||||
this.destructive = false,
|
||||
});
|
||||
}
|
||||
|
||||
class CupertinoMoreButton extends StatelessWidget {
|
||||
final List<MenuAction> actions;
|
||||
final double iconSize;
|
||||
final EdgeInsetsGeometry padding;
|
||||
|
||||
const CupertinoMoreButton({
|
||||
super.key,
|
||||
required this.actions,
|
||||
this.iconSize = 22,
|
||||
this.padding = EdgeInsets.zero,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CupertinoButton(
|
||||
padding: padding,
|
||||
child: Icon(CupertinoIcons.ellipsis_vertical, size: iconSize),
|
||||
onPressed: () => _showMenu(context),
|
||||
);
|
||||
}
|
||||
|
||||
void _showMenu(BuildContext context) {
|
||||
showCupertinoModalPopup<void>(
|
||||
context: context,
|
||||
builder: (ctx) => CupertinoActionSheet(
|
||||
actions: actions.map((a) {
|
||||
final text = Text(a.label);
|
||||
final row = a.icon == null
|
||||
? text
|
||||
: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [Icon(a.icon, size: 18), const SizedBox(width: 8), text],
|
||||
);
|
||||
return CupertinoActionSheetAction(
|
||||
isDestructiveAction: a.destructive,
|
||||
onPressed: () {
|
||||
Navigator.of(ctx).pop();
|
||||
a.onPressed();
|
||||
},
|
||||
child: row,
|
||||
);
|
||||
}).toList(),
|
||||
cancelButton: CupertinoActionSheetAction(
|
||||
onPressed: () => Navigator.of(ctx).pop(),
|
||||
isDefaultAction: true,
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
82
lib/widgets/widget_text_fields.dart
Normal file
82
lib/widgets/widget_text_fields.dart
Normal file
@@ -0,0 +1,82 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:hum/core/constants/app_theme.dart';
|
||||
|
||||
class TXTFieldInput
|
||||
extends
|
||||
StatefulWidget {
|
||||
const TXTFieldInput({
|
||||
super.key,
|
||||
this.placeholder = '',
|
||||
this.inputType = TextInputType.text,
|
||||
this.password = false,
|
||||
required this.controller,
|
||||
});
|
||||
|
||||
final String placeholder;
|
||||
final TextInputType inputType;
|
||||
final bool password;
|
||||
final TextEditingController controller;
|
||||
// final ValueKey fieldId;
|
||||
|
||||
@override
|
||||
State<
|
||||
TXTFieldInput
|
||||
>
|
||||
createState() => _TXTFieldInputState();
|
||||
}
|
||||
|
||||
class _TXTFieldInputState
|
||||
extends
|
||||
State<
|
||||
TXTFieldInput
|
||||
> {
|
||||
bool _obscure = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_obscure = widget.password
|
||||
? true
|
||||
: false;
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(
|
||||
BuildContext context,
|
||||
) {
|
||||
return CupertinoTextField(
|
||||
controller: widget.controller,
|
||||
key: widget.key,
|
||||
placeholder: widget.placeholder,
|
||||
keyboardType: widget.inputType,
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 12,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: CupertinoDynamicColor.resolve(
|
||||
colorBackground,
|
||||
context,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(
|
||||
roundLarge,
|
||||
),
|
||||
),
|
||||
|
||||
obscureText: _obscure,
|
||||
suffix: widget.password
|
||||
? CupertinoButton(
|
||||
padding: EdgeInsets.zero,
|
||||
onPressed: () => setState(
|
||||
() => _obscure = !_obscure,
|
||||
),
|
||||
child: Icon(
|
||||
_obscure
|
||||
? CupertinoIcons.eye
|
||||
: CupertinoIcons.eye_slash,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user