diff --git a/lib/modules/export_module/provider/export_provider.dart b/lib/modules/export_module/provider/export_provider.dart index 39282848..efaf9154 100644 --- a/lib/modules/export_module/provider/export_provider.dart +++ b/lib/modules/export_module/provider/export_provider.dart @@ -43,8 +43,10 @@ class ExportApiProvider extends ChangeNotifier { progressValueColor: AppColor.primary10, msgFontWeight: FontWeight.normal, msgColor: textColor, - valueColor: textColor,elevation: 4, - msgFontSize: 16, + msgMaxLines: 2, + valueColor: textColor, + elevation: 4, + msgFontSize: 14, backgroundColor: backgroundColor, ); @@ -266,11 +268,11 @@ class ExportApiProvider extends ChangeNotifier { progressBgColor: Colors.transparent, progressValueColor: AppColor.primary10, msgFontWeight: FontWeight.normal, - msgFontSize: 18,elevation: 2, + msgFontSize: 18, + elevation: 2, valueColor: textColor, backgroundColor: backgroundColor, msgColor: textColor, - ); IOSink? sink; @@ -291,10 +293,7 @@ class ExportApiProvider extends ChangeNotifier { }), }; - final streamedResponse = await ApiManager.instance.postFormDataStreaming( - URLs.generateReport, - body: formData - ); + final streamedResponse = await ApiManager.instance.postFormDataStreaming(URLs.generateReport, body: formData); _stateCode = streamedResponse.statusCode; diff --git a/lib/views/widgets/equipment/asset_detail_page.dart b/lib/views/widgets/equipment/asset_detail_page.dart index 44b53ef7..dd94a08d 100644 --- a/lib/views/widgets/equipment/asset_detail_page.dart +++ b/lib/views/widgets/equipment/asset_detail_page.dart @@ -28,19 +28,26 @@ class AssetDetailPage extends StatefulWidget { } } -class _AssetDetailPageState extends State { +class _AssetDetailPageState extends State with SingleTickerProviderStateMixin { + late AnimationController _animationController; + int? assetId; + AssetProvider? _assetProvider; + @override void initState() { super.initState(); + _animationController = AnimationController( + duration: const Duration(milliseconds: 1400), + vsync: this, + ); } @override void dispose() { + _animationController.dispose(); super.dispose(); } - int? assetId; - AssetProvider? _assetProvider; @override Widget build(BuildContext context) { @@ -65,79 +72,245 @@ class _AssetDetailPageState extends State { } else if (snapshot.hasData) {} if (snapshot.hasData) { AssetByIdModel assetModel = snapshot.data!; + // Start animation when data is loaded + _animationController.forward(from: 0.0); + + // Image animation - fade in with scale + final imageAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.0, 0.4, curve: Curves.easeOut), + ), + ); + + final imageScaleAnimation = Tween(begin: 0.92, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.0, 0.4, curve: Curves.easeOutCubic), + ), + ); + + // Status label animation + final statusAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.15, 0.5, curve: Curves.easeOut), + ), + ); + + final statusSlideAnimation = Tween( + begin: const Offset(0.0, 0.2), + end: Offset.zero, + ).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.15, 0.5, curve: Curves.easeOutCubic), + ), + ); + + // Header animation + final headerAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.25, 0.6, curve: Curves.easeOut), + ), + ); + + final headerSlideAnimation = Tween( + begin: const Offset(0.0, 0.2), + end: Offset.zero, + ).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.25, 0.6, curve: Curves.easeOutCubic), + ), + ); + + // Details row animation + final detailsAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.35, 0.75, curve: Curves.easeOut), + ), + ); + + final detailsSlideAnimation = Tween( + begin: const Offset(0.0, 0.15), + end: Offset.zero, + ).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.35, 0.75, curve: Curves.easeOutCubic), + ), + ); + + // Dates section animation + final datesAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.50, 0.9, curve: Curves.easeOut), + ), + ); + + final datesSlideAnimation = Tween( + begin: const Offset(0.0, 0.15), + end: Offset.zero, + ).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.50, 0.9, curve: Curves.easeOutCubic), + ), + ); + + // Description animation (if exists) + final descAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.65, 1.0, curve: Curves.easeOut), + ), + ); + + final descSlideAnimation = Tween( + begin: const Offset(0.0, 0.1), + end: Offset.zero, + ).animate( + CurvedAnimation( + parent: _animationController, + curve: const Interval(0.65, 1.0, curve: Curves.easeOutCubic), + ), + ); + return SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - AspectRatio( - aspectRatio: 159 / 94, - child: Container( - width: 95, - height: 95, - decoration: ShapeDecoration( - color: AppColor.neutral30, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - image: DecorationImage( - fit: BoxFit.cover, - image: NetworkImage(assetModel.assetPhoto != null ? URLs.getFileUrl(assetModel.assetPhoto!)! : "https://www.lasteelcraft.com/images/no-image-available.png"), - )), + // Animated image + FadeTransition( + opacity: imageAnimation, + child: ScaleTransition( + scale: imageScaleAnimation, + child: AspectRatio( + aspectRatio: 159 / 94, + child: Container( + width: 95, + height: 95, + decoration: ShapeDecoration( + color: AppColor.neutral30, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + image: DecorationImage( + fit: BoxFit.cover, + image: NetworkImage(assetModel.assetPhoto != null ? URLs.getFileUrl(assetModel.assetPhoto!)! : "https://www.lasteelcraft.com/images/no-image-available.png"), + )), + ), + ), ), ), 6.height, + // Animated content column Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ + // Status label with animation if (assetModel.commissioningStatus != null) - StatusLabel( - label: assetModel.commissioningStatus!.name, - textColor: AppColor.getRequestStatusTextColorByName(context, assetModel.commissioningStatus!.name!), - backgroundColor: AppColor.getRequestStatusColorByName(context, assetModel.commissioningStatus!.name!), + FadeTransition( + opacity: statusAnimation, + child: SlideTransition( + position: statusSlideAnimation, + child: StatusLabel( + label: assetModel.commissioningStatus!.name, + textColor: AppColor.getRequestStatusTextColorByName(context, assetModel.commissioningStatus!.name!), + backgroundColor: AppColor.getRequestStatusColorByName(context, assetModel.commissioningStatus!.name!), + ), + ), ), if (assetModel.commissioningStatus != null) 8.height, - InfoHeader16Widget(assetModel.modelDefinition?.assetName?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"), + + // Header with animation + FadeTransition( + opacity: headerAnimation, + child: SlideTransition( + position: headerSlideAnimation, + child: InfoHeader16Widget(assetModel.modelDefinition?.assetName?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"), + ), + ), 8.height, - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( + + // Details row with animation + FadeTransition( + opacity: detailsAnimation, + child: SlideTransition( + position: detailsSlideAnimation, + child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - InfoTextWidget(label: context.translation.assetNo, value: assetModel.multiAssets!.first.assetNumber, showEmptyValue: true), - InfoTextWidget(label: context.translation.modelName, value: assetModel.modelDefinition!.modelName, showEmptyValue: true), - InfoTextWidget(label: context.translation.supplier, value: assetModel.supplier?.suppliername, showEmptyValue: true), - InfoTextWidget(label: context.translation.manufacture, value: assetModel.modelDefinition!.manufacturerName, showEmptyValue: true), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + InfoTextWidget(label: context.translation.assetNo, value: assetModel.multiAssets!.first.assetNumber, showEmptyValue: true), + InfoTextWidget(label: context.translation.modelName, value: assetModel.modelDefinition!.modelName, showEmptyValue: true), + InfoTextWidget(label: context.translation.supplier, value: assetModel.supplier?.suppliername, showEmptyValue: true), + InfoTextWidget(label: context.translation.manufacture, value: assetModel.modelDefinition!.manufacturerName, showEmptyValue: true), + ], + ).expanded, + 8.width, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + InfoTextWidget(label: context.translation.snNo, value: assetModel.multiAssets!.first.assetSerialNo, showEmptyValue: true), + InfoTextWidget(label: context.translation.site, value: assetModel.site?.custName?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), + InfoTextWidget(label: context.translation.building, value: assetModel.building?.name?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), + InfoTextWidget(label: context.translation.floor, value: assetModel.floor?.name?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), + InfoTextWidget(label: context.translation.md, value: assetModel.department?.departmentName?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), + InfoTextWidget(label: context.translation.room, value: assetModel.room?.name?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), + ], + ).expanded, ], - ).expanded, - 8.width, - Column( + ), + ), + ), + 8.height, + + // Divider with animation + FadeTransition( + opacity: datesAnimation, + child: const Divider(color: AppColor.neutral30, height: 1, thickness: 1), + ), + 8.height, + + // Dates section with animation + FadeTransition( + opacity: datesAnimation, + child: SlideTransition( + position: datesSlideAnimation, + child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - /// TODO: theres no [ORACLE CODE] available to preview - // "${context.translation.oracleCode}: ${"-"}".bodyText(context), - InfoTextWidget(label: context.translation.snNo, value: assetModel.multiAssets!.first.assetSerialNo, showEmptyValue: true), - InfoTextWidget(label: context.translation.site, value: assetModel.site?.custName?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), - InfoTextWidget(label: context.translation.building, value: assetModel.building?.name?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), - InfoTextWidget(label: context.translation.floor, value: assetModel.floor?.name?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), - InfoTextWidget(label: context.translation.md, value: assetModel.department?.departmentName?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), - InfoTextWidget(label: context.translation.room, value: assetModel.room?.name?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), + InfoTextWidget(label: context.translation.installationDate, value: assetModel.installationDate?.toAssetDetailsFormat, showEmptyValue: true), + InfoTextWidget(label: context.translation.nextPmDate, value: assetModel.nextPMDate?.toAssetDetailsFormat, showEmptyValue: true), + InfoTextWidget(label: context.translation.lastPmDate, value: assetModel.lastPMDate?.toAssetDetailsFormat, showEmptyValue: true), ], - ).expanded, - ], + ), + ), ), - 8.height, - const Divider(color: AppColor.neutral30, height: 1, thickness: 1), - 8.height, - InfoTextWidget(label: context.translation.installationDate, value: assetModel.installationDate?.toAssetDetailsFormat, showEmptyValue: true), - InfoTextWidget(label: context.translation.nextPmDate, value: assetModel.nextPMDate?.toAssetDetailsFormat, showEmptyValue: true), - InfoTextWidget(label: context.translation.lastPmDate, value: assetModel.lastPMDate?.toAssetDetailsFormat, showEmptyValue: true), + + // Description with animation (if exists) if ((assetModel.modelDefinition?.assetDescription ?? "").isNotEmpty) ...[ 8.height, - const Divider().defaultStyle(context), - InfoTextWidget(label: assetModel.modelDefinition!.assetDescription!, showEmptyValue: true, isMsg: true), + FadeTransition( + opacity: descAnimation, + child: const Divider().defaultStyle(context), + ), + FadeTransition( + opacity: descAnimation, + child: SlideTransition( + position: descSlideAnimation, + child: InfoTextWidget(label: assetModel.modelDefinition!.assetDescription!, showEmptyValue: true, isMsg: true), + ), + ), ] ], )