From 2ad196bde6f8adfaafd52e4f586f4002543d64fb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 29 Sep 2025 06:26:53 +0000 Subject: [PATCH 1/2] Initial plan From bc0c069adf56fef1d3fabe88159fc9880f8f4eb6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 29 Sep 2025 06:39:37 +0000 Subject: [PATCH 2/2] Implement core package refactoring: BaseLogic consolidation and new CoreButton/CoreLoadingIndicator Co-authored-by: mes71 <53784874+mes71@users.noreply.github.com> --- .../presentation/widget/base_page/logic.dart | 62 ++- .../presentation/widget/buttons/buttons.dart | 1 + .../widget/buttons/core_button.dart | 407 ++++++++++++++++++ .../indicators/core_loading_indicator.dart | 319 ++++++++++++++ .../widget/indicators/indicators.dart | 1 + .../core/lib/presentation/widget/widget.dart | 6 +- .../presentation/widget/base_page/logic.dart | 29 +- .../presentation/widgets/base_page/logic.dart | 29 +- 8 files changed, 800 insertions(+), 54 deletions(-) create mode 100644 packages/core/lib/presentation/widget/buttons/core_button.dart create mode 100644 packages/core/lib/presentation/widget/indicators/core_loading_indicator.dart create mode 100644 packages/core/lib/presentation/widget/indicators/indicators.dart diff --git a/packages/core/lib/presentation/widget/base_page/logic.dart b/packages/core/lib/presentation/widget/base_page/logic.dart index bccafe7..057fc7c 100644 --- a/packages/core/lib/presentation/widget/base_page/logic.dart +++ b/packages/core/lib/presentation/widget/base_page/logic.dart @@ -1,31 +1,81 @@ import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; -class BaseLogic extends GetxController { +/// Consolidated base logic controller that provides common functionality +/// for pages with search and filter capabilities. +/// +/// This replaces the duplicate BaseLogic classes across different packages. +class BasePageLogic extends GetxController { final RxBool isFilterSelected = false.obs; final RxBool isSearchSelected = false.obs; final RxnString searchValue = RxnString(); - final TextEditingController textEditingController = TextEditingController(); + final TextEditingController searchTextController = TextEditingController(); - void setSearchCallback(void Function(String?)? onSearchChanged) { + // Debounce time configuration + static const Duration _defaultDebounceTime = Duration(milliseconds: 600); + + /// Sets up search callback with debouncing + /// [onSearchChanged] will be called when search value changes after debounce delay + /// [debounceTime] custom debounce duration, defaults to 600ms + void setSearchCallback( + void Function(String?)? onSearchChanged, { + Duration debounceTime = _defaultDebounceTime, + }) { debounce(searchValue, (val) { if (val != null && val.trim().isNotEmpty) { onSearchChanged?.call(val); + } else { + // Call with null/empty to handle search clear + onSearchChanged?.call(null); } - }, time: const Duration(milliseconds: 600)); + }, time: debounceTime); } + /// Toggles search visibility state void toggleSearch() { isSearchSelected.value = !isSearchSelected.value; + + // Clear search when hiding + if (!isSearchSelected.value) { + clearSearch(); + } } + /// Clears search input and resets state void clearSearch() { - textEditingController.clear(); + searchTextController.clear(); searchValue.value = null; - isSearchSelected.value = false; } + /// Toggles filter selection state void toggleFilter() { isFilterSelected.value = !isFilterSelected.value; } + + /// Resets all states to initial values + void resetStates() { + isFilterSelected.value = false; + isSearchSelected.value = false; + clearSearch(); + } + + @override + void onInit() { + super.onInit(); + + // Bind search controller to reactive value + searchTextController.addListener(() { + searchValue.value = searchTextController.text; + }); + } + + @override + void onClose() { + searchTextController.dispose(); + super.onClose(); + } } + +/// Backward compatibility alias - will be deprecated +@Deprecated('Use BasePageLogic instead. This will be removed in future versions.') +typedef BaseLogic = BasePageLogic; diff --git a/packages/core/lib/presentation/widget/buttons/buttons.dart b/packages/core/lib/presentation/widget/buttons/buttons.dart index 7dd4917..c57140e 100644 --- a/packages/core/lib/presentation/widget/buttons/buttons.dart +++ b/packages/core/lib/presentation/widget/buttons/buttons.dart @@ -1,4 +1,5 @@ export 'animated_fab.dart'; +export 'core_button.dart'; export 'elevated.dart'; export 'fab.dart'; export 'fab_outlined.dart'; diff --git a/packages/core/lib/presentation/widget/buttons/core_button.dart b/packages/core/lib/presentation/widget/buttons/core_button.dart new file mode 100644 index 0000000..a8c8693 --- /dev/null +++ b/packages/core/lib/presentation/widget/buttons/core_button.dart @@ -0,0 +1,407 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; + +/// Button variant types for consistent styling +enum CoreButtonVariant { + /// Filled button with primary background color + primary, + /// Filled button with secondary background color + secondary, + /// Button with transparent background and border + outlined, + /// Button with transparent background, no border + text, + /// Destructive action button (red theme) + destructive, +} + +/// Button size presets +enum CoreButtonSize { + /// Small button - height 32 + small, + /// Medium button - height 40 (default) + medium, + /// Large button - height 56 + large, +} + +/// A unified, configurable button widget that replaces RElevated, ROutlinedElevated, etc. +/// +/// This widget provides a consistent API and theming system across the entire app. +/// It supports different variants, sizes, loading states, and full customization. +class CoreButton extends StatelessWidget { + /// Button text content + final String? text; + + /// Custom child widget (overrides text if provided) + final Widget? child; + + /// Button press callback + final VoidCallback? onPressed; + + /// Button style variant + final CoreButtonVariant variant; + + /// Button size preset + final CoreButtonSize size; + + /// Custom width (overrides size preset) + final double? width; + + /// Custom height (overrides size preset) + final double? height; + + /// Whether button should take full width + final bool isFullWidth; + + /// Loading state - shows progress indicator + final bool isLoading; + + /// Progress value for loading indicator (0.0 to 1.0, null for indeterminate) + final double? progress; + + /// Custom text style (overrides theme) + final TextStyle? textStyle; + + /// Custom background color (overrides variant theme) + final Color? backgroundColor; + + /// Custom foreground color (overrides variant theme) + final Color? foregroundColor; + + /// Custom border color for outlined variant + final Color? borderColor; + + /// Border radius (default: 8.0) + final double borderRadius; + + /// Leading icon + final Widget? icon; + + /// Icon placement + final bool iconAtEnd; + + /// Spacing between icon and text + final double iconSpacing; + + const CoreButton({ + super.key, + this.text, + this.child, + required this.onPressed, + this.variant = CoreButtonVariant.primary, + this.size = CoreButtonSize.medium, + this.width, + this.height, + this.isFullWidth = false, + this.isLoading = false, + this.progress, + this.textStyle, + this.backgroundColor, + this.foregroundColor, + this.borderColor, + this.borderRadius = 8.0, + this.icon, + this.iconAtEnd = false, + this.iconSpacing = 8.0, + }) : assert(text != null || child != null, 'Either text or child must be provided'); + + /// Creates a primary filled button + const CoreButton.primary({ + super.key, + this.text, + this.child, + required this.onPressed, + this.size = CoreButtonSize.medium, + this.width, + this.height, + this.isFullWidth = false, + this.isLoading = false, + this.progress, + this.textStyle, + this.backgroundColor, + this.foregroundColor, + this.borderRadius = 8.0, + this.icon, + this.iconAtEnd = false, + this.iconSpacing = 8.0, + }) : variant = CoreButtonVariant.primary, + borderColor = null, + assert(text != null || child != null, 'Either text or child must be provided'); + + /// Creates an outlined button + const CoreButton.outlined({ + super.key, + this.text, + this.child, + required this.onPressed, + this.size = CoreButtonSize.medium, + this.width, + this.height, + this.isFullWidth = false, + this.isLoading = false, + this.progress, + this.textStyle, + this.foregroundColor, + this.borderColor, + this.borderRadius = 8.0, + this.icon, + this.iconAtEnd = false, + this.iconSpacing = 8.0, + }) : variant = CoreButtonVariant.outlined, + backgroundColor = null, + assert(text != null || child != null, 'Either text or child must be provided'); + + /// Creates a text button with no background + const CoreButton.text({ + super.key, + this.text, + this.child, + required this.onPressed, + this.size = CoreButtonSize.medium, + this.width, + this.height, + this.isFullWidth = false, + this.isLoading = false, + this.progress, + this.textStyle, + this.foregroundColor, + this.borderRadius = 8.0, + this.icon, + this.iconAtEnd = false, + this.iconSpacing = 8.0, + }) : variant = CoreButtonVariant.text, + backgroundColor = null, + borderColor = null, + assert(text != null || child != null, 'Either text or child must be provided'); + + /// Creates a destructive action button + const CoreButton.destructive({ + super.key, + this.text, + this.child, + required this.onPressed, + this.size = CoreButtonSize.medium, + this.width, + this.height, + this.isFullWidth = false, + this.isLoading = false, + this.progress, + this.textStyle, + this.backgroundColor, + this.foregroundColor, + this.borderRadius = 8.0, + this.icon, + this.iconAtEnd = false, + this.iconSpacing = 8.0, + }) : variant = CoreButtonVariant.destructive, + borderColor = null, + assert(text != null || child != null, 'Either text or child must be provided'); + + /// Gets button dimensions based on size preset + Size get _buttonSize { + final buttonWidth = isFullWidth ? double.infinity : (width ?? _defaultWidth); + final buttonHeight = height ?? _defaultHeight; + return Size(buttonWidth, buttonHeight); + } + + double get _defaultWidth { + switch (size) { + case CoreButtonSize.small: + return 120.0; + case CoreButtonSize.medium: + return 150.0; + case CoreButtonSize.large: + return 200.0; + } + } + + double get _defaultHeight { + switch (size) { + case CoreButtonSize.small: + return 32.0; + case CoreButtonSize.medium: + return 40.0; + case CoreButtonSize.large: + return 56.0; + } + } + + /// Gets theme colors based on variant + _ButtonTheme get _theme { + switch (variant) { + case CoreButtonVariant.primary: + return _ButtonTheme( + backgroundColor: backgroundColor ?? AppColor.blueNormal, + foregroundColor: foregroundColor ?? Colors.white, + borderColor: null, + ); + case CoreButtonVariant.secondary: + return _ButtonTheme( + backgroundColor: backgroundColor ?? AppColor.greyNormal, + foregroundColor: foregroundColor ?? AppColor.textColor, + borderColor: null, + ); + case CoreButtonVariant.outlined: + return _ButtonTheme( + backgroundColor: backgroundColor ?? Colors.transparent, + foregroundColor: foregroundColor ?? (borderColor ?? AppColor.blueNormal), + borderColor: borderColor ?? AppColor.blueNormal, + ); + case CoreButtonVariant.text: + return _ButtonTheme( + backgroundColor: backgroundColor ?? Colors.transparent, + foregroundColor: foregroundColor ?? AppColor.blueNormal, + borderColor: null, + ); + case CoreButtonVariant.destructive: + return _ButtonTheme( + backgroundColor: backgroundColor ?? AppColor.error, + foregroundColor: foregroundColor ?? Colors.white, + borderColor: null, + ); + } + } + + TextStyle get _textTheme { + final baseStyle = textStyle ?? AppFonts.yekan16; + return baseStyle.copyWith(color: _theme.foregroundColor); + } + + Widget _buildContent() { + if (isLoading) { + return SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2.0, + valueColor: AlwaysStoppedAnimation(_theme.foregroundColor), + value: progress, + ), + ); + } + + final content = child ?? Text(text!, style: _textTheme); + + if (icon != null) { + final iconWidget = IconTheme( + data: IconThemeData(color: _theme.foregroundColor, size: 18), + child: icon!, + ); + + if (iconAtEnd) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + content, + SizedBox(width: iconSpacing), + iconWidget, + ], + ); + } else { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + iconWidget, + SizedBox(width: iconSpacing), + content, + ], + ); + } + } + + return content; + } + + @override + Widget build(BuildContext context) { + final isEnabled = onPressed != null && !isLoading; + final theme = _theme; + final buttonSize = _buttonSize; + + if (variant == CoreButtonVariant.outlined) { + return ConstrainedBox( + constraints: BoxConstraints.tightFor( + width: buttonSize.width, + height: buttonSize.height, + ), + child: OutlinedButton( + onPressed: isEnabled ? onPressed : null, + style: OutlinedButton.styleFrom( + backgroundColor: theme.backgroundColor, + foregroundColor: theme.foregroundColor, + side: BorderSide( + color: isEnabled ? theme.borderColor! : theme.borderColor!.withOpacity(0.38), + width: 1.5, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(borderRadius), + ), + padding: EdgeInsets.zero, + textStyle: _textTheme, + ), + child: _buildContent(), + ), + ); + } + + if (variant == CoreButtonVariant.text) { + return ConstrainedBox( + constraints: BoxConstraints.tightFor( + width: buttonSize.width, + height: buttonSize.height, + ), + child: TextButton( + onPressed: isEnabled ? onPressed : null, + style: TextButton.styleFrom( + backgroundColor: theme.backgroundColor, + foregroundColor: theme.foregroundColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(borderRadius), + ), + padding: EdgeInsets.zero, + textStyle: _textTheme, + ), + child: _buildContent(), + ), + ); + } + + // Default to ElevatedButton for primary, secondary, destructive + return ConstrainedBox( + constraints: BoxConstraints.tightFor( + width: buttonSize.width, + height: buttonSize.height, + ), + child: ElevatedButton( + onPressed: isEnabled ? onPressed : null, + style: ElevatedButton.styleFrom( + backgroundColor: theme.backgroundColor, + foregroundColor: theme.foregroundColor, + disabledBackgroundColor: theme.backgroundColor.withOpacity(0.38), + disabledForegroundColor: theme.foregroundColor.withOpacity(0.38), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(borderRadius), + ), + padding: EdgeInsets.zero, + textStyle: _textTheme, + ), + child: _buildContent(), + ), + ); + } +} + +/// Internal theme data for button variants +class _ButtonTheme { + final Color backgroundColor; + final Color foregroundColor; + final Color? borderColor; + + const _ButtonTheme({ + required this.backgroundColor, + required this.foregroundColor, + this.borderColor, + }); +} \ No newline at end of file diff --git a/packages/core/lib/presentation/widget/indicators/core_loading_indicator.dart b/packages/core/lib/presentation/widget/indicators/core_loading_indicator.dart new file mode 100644 index 0000000..a6aab99 --- /dev/null +++ b/packages/core/lib/presentation/widget/indicators/core_loading_indicator.dart @@ -0,0 +1,319 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; + +/// Loading indicator variant types +enum CoreLoadingVariant { + /// Material Design circular progress indicator + material, + /// iOS style activity indicator + cupertino, + /// Custom Lottie animation + lottie, + /// Linear progress indicator + linear, +} + +/// Loading indicator size presets +enum CoreLoadingSize { + /// Small - 16x16 + small, + /// Medium - 24x24 (default) + medium, + /// Large - 32x32 + large, + /// Extra large - 48x48 + extraLarge, +} + +/// A unified loading indicator widget that replaces inconsistent loading patterns +/// +/// This widget provides consistent loading states across the entire app with +/// support for different variants, sizes, colors, and text labels. +class CoreLoadingIndicator extends StatelessWidget { + /// Loading indicator variant + final CoreLoadingVariant variant; + + /// Size preset + final CoreLoadingSize size; + + /// Custom width (overrides size preset) + final double? width; + + /// Custom height (overrides size preset) + final double? height; + + /// Indicator color + final Color? color; + + /// Progress value for determinate indicators (0.0 to 1.0) + final double? value; + + /// Stroke width for circular indicators + final double? strokeWidth; + + /// Loading text label + final String? label; + + /// Text style for label + final TextStyle? labelStyle; + + /// Spacing between indicator and label + final double labelSpacing; + + /// Label position relative to indicator + final CrossAxisAlignment labelAlignment; + + const CoreLoadingIndicator({ + super.key, + this.variant = CoreLoadingVariant.material, + this.size = CoreLoadingSize.medium, + this.width, + this.height, + this.color, + this.value, + this.strokeWidth, + this.label, + this.labelStyle, + this.labelSpacing = 12.0, + this.labelAlignment = CrossAxisAlignment.center, + }); + + /// Creates a small Material loading indicator + const CoreLoadingIndicator.small({ + super.key, + this.color, + this.value, + this.strokeWidth, + this.label, + this.labelStyle, + this.labelSpacing = 8.0, + this.labelAlignment = CrossAxisAlignment.center, + }) : variant = CoreLoadingVariant.material, + size = CoreLoadingSize.small, + width = null, + height = null; + + /// Creates a Cupertino style activity indicator + const CoreLoadingIndicator.cupertino({ + super.key, + this.size = CoreLoadingSize.medium, + this.width, + this.height, + this.color, + this.label, + this.labelStyle, + this.labelSpacing = 12.0, + this.labelAlignment = CrossAxisAlignment.center, + }) : variant = CoreLoadingVariant.cupertino, + value = null, + strokeWidth = null; + + /// Creates a linear progress indicator + const CoreLoadingIndicator.linear({ + super.key, + this.width, + this.height = 4.0, + this.color, + this.value, + this.label, + this.labelStyle, + this.labelSpacing = 8.0, + this.labelAlignment = CrossAxisAlignment.start, + }) : variant = CoreLoadingVariant.linear, + size = CoreLoadingSize.medium, + strokeWidth = null; + + /// Creates a large Lottie animation loading indicator + const CoreLoadingIndicator.lottie({ + super.key, + this.size = CoreLoadingSize.large, + this.width, + this.height, + this.label, + this.labelStyle, + this.labelSpacing = 16.0, + this.labelAlignment = CrossAxisAlignment.center, + }) : variant = CoreLoadingVariant.lottie, + color = null, + value = null, + strokeWidth = null; + + /// Gets size dimensions based on size preset + Size get _indicatorSize { + final sizeValue = width ?? height ?? _defaultSize; + return Size(sizeValue, sizeValue); + } + + double get _defaultSize { + switch (size) { + case CoreLoadingSize.small: + return 16.0; + case CoreLoadingSize.medium: + return 24.0; + case CoreLoadingSize.large: + return 32.0; + case CoreLoadingSize.extraLarge: + return 48.0; + } + } + + Color get _indicatorColor { + return color ?? AppColor.blueNormal; + } + + Widget _buildIndicator() { + final indicatorSize = _indicatorSize; + + switch (variant) { + case CoreLoadingVariant.material: + return SizedBox( + width: indicatorSize.width, + height: indicatorSize.height, + child: CircularProgressIndicator( + value: value, + strokeWidth: strokeWidth ?? (indicatorSize.width * 0.08).clamp(1.5, 4.0), + valueColor: AlwaysStoppedAnimation(_indicatorColor), + ), + ); + + case CoreLoadingVariant.cupertino: + return SizedBox( + width: indicatorSize.width, + height: indicatorSize.height, + child: CupertinoActivityIndicator( + color: _indicatorColor, + radius: indicatorSize.width * 0.4, + ), + ); + + case CoreLoadingVariant.linear: + return SizedBox( + width: width ?? 200.0, + height: height ?? 4.0, + child: LinearProgressIndicator( + value: value, + backgroundColor: _indicatorColor.withOpacity(0.2), + valueColor: AlwaysStoppedAnimation(_indicatorColor), + ), + ); + + case CoreLoadingVariant.lottie: + try { + return Assets.anim.loading.lottie( + width: indicatorSize.width, + height: indicatorSize.height, + ); + } catch (e) { + // Fallback to Material indicator if Lottie fails + return SizedBox( + width: indicatorSize.width, + height: indicatorSize.height, + child: CircularProgressIndicator( + strokeWidth: strokeWidth ?? 3.0, + valueColor: AlwaysStoppedAnimation(_indicatorColor), + ), + ); + } + } + } + + Widget _buildLabel() { + if (label == null) return const SizedBox.shrink(); + + return Text( + label!, + style: labelStyle ?? AppFonts.yekan14.copyWith( + color: AppColor.textColor, + ), + textAlign: TextAlign.center, + ); + } + + @override + Widget build(BuildContext context) { + final indicator = _buildIndicator(); + final labelWidget = _buildLabel(); + + if (label == null) { + return indicator; + } + + if (variant == CoreLoadingVariant.linear) { + return Column( + crossAxisAlignment: labelAlignment, + mainAxisSize: MainAxisSize.min, + children: [ + labelWidget, + SizedBox(height: labelSpacing), + indicator, + ], + ); + } + + return Column( + crossAxisAlignment: labelAlignment, + mainAxisSize: MainAxisSize.min, + children: [ + indicator, + SizedBox(height: labelSpacing), + labelWidget, + ], + ); + } +} + +/// A full-screen loading overlay widget +class CoreLoadingOverlay extends StatelessWidget { + /// Loading indicator to display + final CoreLoadingIndicator indicator; + + /// Background color of the overlay + final Color backgroundColor; + + /// Whether the overlay should block user interaction + final bool barrierDismissible; + + const CoreLoadingOverlay({ + super.key, + this.indicator = const CoreLoadingIndicator.lottie( + label: 'در حال بارگذاری...', + ), + this.backgroundColor = Colors.black54, + this.barrierDismissible = false, + }); + + @override + Widget build(BuildContext context) { + return Container( + color: backgroundColor, + child: Center(child: indicator), + ); + } + + /// Shows a loading overlay on top of current screen + static void show( + BuildContext context, { + CoreLoadingIndicator? indicator, + Color backgroundColor = Colors.black54, + bool barrierDismissible = false, + }) { + showDialog( + context: context, + barrierDismissible: barrierDismissible, + barrierColor: Colors.transparent, + builder: (context) => CoreLoadingOverlay( + indicator: indicator ?? const CoreLoadingIndicator.lottie( + label: 'در حال بارگذاری...', + ), + backgroundColor: backgroundColor, + barrierDismissible: barrierDismissible, + ), + ); + } + + /// Hides the currently displayed loading overlay + static void hide(BuildContext context) { + Navigator.of(context).pop(); + } +} \ No newline at end of file diff --git a/packages/core/lib/presentation/widget/indicators/indicators.dart b/packages/core/lib/presentation/widget/indicators/indicators.dart new file mode 100644 index 0000000..89a4487 --- /dev/null +++ b/packages/core/lib/presentation/widget/indicators/indicators.dart @@ -0,0 +1 @@ +export 'core_loading_indicator.dart'; \ No newline at end of file diff --git a/packages/core/lib/presentation/widget/widget.dart b/packages/core/lib/presentation/widget/widget.dart index 293674f..cb171d7 100644 --- a/packages/core/lib/presentation/widget/widget.dart +++ b/packages/core/lib/presentation/widget/widget.dart @@ -11,8 +11,8 @@ export 'base_page/widgets/back_ground_widget.dart'; export 'base_page/widgets/breadcrumb.dart'; export 'base_page/widgets/search_widget.dart'; - -//buttons +//buttons - enhanced core widgets +export 'buttons/core_button.dart'; export 'buttons/buttons.dart'; export 'card/card_icon_widget.dart'; export 'chips/r_chips.dart'; @@ -24,6 +24,8 @@ export 'draggable_bottom_sheet/draggable_bottom_sheet.dart'; export 'draggable_bottom_sheet/draggable_bottom_sheet2.dart'; export 'draggable_bottom_sheet/draggable_bottom_sheet_controller.dart'; export 'empty_widget.dart'; +//indicators - unified loading components +export 'indicators/core_loading_indicator.dart'; //inputs export 'inputs/inputs.dart'; //list_item diff --git a/packages/inspection/lib/presentation/widget/base_page/logic.dart b/packages/inspection/lib/presentation/widget/base_page/logic.dart index 79ac095..57ae6a5 100644 --- a/packages/inspection/lib/presentation/widget/base_page/logic.dart +++ b/packages/inspection/lib/presentation/widget/base_page/logic.dart @@ -1,25 +1,8 @@ -import 'package:flutter/cupertino.dart'; -import 'package:rasadyar_core/core.dart'; +// This file now re-exports the consolidated BasePageLogic from rasadyar_core +// The BaseLogic class has been moved to the core package to eliminate duplication -class BaseLogic extends GetxController { - final RxBool isFilterSelected = false.obs; - final RxBool isSearchSelected = false.obs; - final TextEditingController searchTextController = TextEditingController(); - final RxnString searchValue = RxnString(); +export 'package:rasadyar_core/presentation/widget/base_page/logic.dart'; - void setSearchCallback(void Function(String)? onSearchChanged) { - debounce(searchValue, (val) { - if (val != null && val.trim().isNotEmpty) { - onSearchChanged?.call(val); - } - }, time: const Duration(milliseconds: 600)); - } - - void toggleFilter() { - isFilterSelected.value = !isFilterSelected.value; - } - - void toggleSearch() { - isSearchSelected.value = !isSearchSelected.value; - } -} +// Backward compatibility - can be removed in future versions +// import 'package:rasadyar_core/presentation/widget/base_page/logic.dart' as core; +// typedef BaseLogic = core.BasePageLogic; diff --git a/packages/livestock/lib/presentation/widgets/base_page/logic.dart b/packages/livestock/lib/presentation/widgets/base_page/logic.dart index 79ac095..57ae6a5 100644 --- a/packages/livestock/lib/presentation/widgets/base_page/logic.dart +++ b/packages/livestock/lib/presentation/widgets/base_page/logic.dart @@ -1,25 +1,8 @@ -import 'package:flutter/cupertino.dart'; -import 'package:rasadyar_core/core.dart'; +// This file now re-exports the consolidated BasePageLogic from rasadyar_core +// The BaseLogic class has been moved to the core package to eliminate duplication -class BaseLogic extends GetxController { - final RxBool isFilterSelected = false.obs; - final RxBool isSearchSelected = false.obs; - final TextEditingController searchTextController = TextEditingController(); - final RxnString searchValue = RxnString(); +export 'package:rasadyar_core/presentation/widget/base_page/logic.dart'; - void setSearchCallback(void Function(String)? onSearchChanged) { - debounce(searchValue, (val) { - if (val != null && val.trim().isNotEmpty) { - onSearchChanged?.call(val); - } - }, time: const Duration(milliseconds: 600)); - } - - void toggleFilter() { - isFilterSelected.value = !isFilterSelected.value; - } - - void toggleSearch() { - isSearchSelected.value = !isSearchSelected.value; - } -} +// Backward compatibility - can be removed in future versions +// import 'package:rasadyar_core/presentation/widget/base_page/logic.dart' as core; +// typedef BaseLogic = core.BasePageLogic;