added request successful page and add animation for feedback of tenders
This commit is contained in:
@@ -0,0 +1,45 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tm_app/core/theme/colors.dart';
|
||||||
|
import 'package:tm_app/core/utils/size_config.dart';
|
||||||
|
import 'package:tm_app/views/request_successful/strings/request_successful_strings.dart';
|
||||||
|
|
||||||
|
import '../../shared/base_button.dart';
|
||||||
|
|
||||||
|
class RequestSuccessfulPage extends StatelessWidget {
|
||||||
|
const RequestSuccessfulPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 124.0.h()),
|
||||||
|
Container(
|
||||||
|
width: 64.0.w(),
|
||||||
|
height: 64.0.h(),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.green30,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
RequestSuccessfulStrings.requestSuccessfulTitle,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 22.0.sp(),
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: AppColors.grey80,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 124.0.h()),
|
||||||
|
BaseButton(
|
||||||
|
text: RequestSuccessfulStrings.backToTendersButton,
|
||||||
|
textColor: AppColors.white,
|
||||||
|
borderColor: AppColors.mainBlue,
|
||||||
|
isEnabled: true,
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
class RequestSuccessfulStrings {
|
||||||
|
static const String requestSuccessfulTitle =
|
||||||
|
'Your request has been successfully registered.';
|
||||||
|
static const String backToTendersButton = 'Back to Tenders';
|
||||||
|
}
|
||||||
@@ -64,7 +64,7 @@ class _MobileTendersPageState extends State<MobileTendersPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.symmetric(vertical: 24.0.h()),
|
padding: EdgeInsets.symmetric(vertical: 18.0.h()),
|
||||||
child: MainTendersSlider(
|
child: MainTendersSlider(
|
||||||
tenders: viewModel.tendersResponse?.data?.tenders ?? [],
|
tenders: viewModel.tendersResponse?.data?.tenders ?? [],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -0,0 +1,116 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
|
||||||
|
import '../../../core/utils/size_config.dart';
|
||||||
|
|
||||||
|
class AnimatedFeedbackButton extends StatefulWidget {
|
||||||
|
final String iconPath;
|
||||||
|
final Color activeColor;
|
||||||
|
final Color inactiveColor;
|
||||||
|
final bool isActive;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
final String tooltip;
|
||||||
|
|
||||||
|
const AnimatedFeedbackButton({
|
||||||
|
required this.iconPath,
|
||||||
|
required this.activeColor,
|
||||||
|
required this.inactiveColor,
|
||||||
|
required this.isActive,
|
||||||
|
required this.onTap,
|
||||||
|
required this.tooltip,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<AnimatedFeedbackButton> createState() => _AnimatedFeedbackButtonState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AnimatedFeedbackButtonState extends State<AnimatedFeedbackButton>
|
||||||
|
with TickerProviderStateMixin {
|
||||||
|
late AnimationController _clickController;
|
||||||
|
late Animation<double> _scaleAnimation;
|
||||||
|
late Animation<double> _rotationAnimation;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_clickController = AnimationController(
|
||||||
|
duration: const Duration(milliseconds: 250),
|
||||||
|
vsync: this,
|
||||||
|
);
|
||||||
|
|
||||||
|
_scaleAnimation = Tween<double>(begin: 1.0, end: 1.2).animate(
|
||||||
|
CurvedAnimation(
|
||||||
|
parent: _clickController,
|
||||||
|
curve: const Interval(0.0, 0.3, curve: Curves.elasticOut),
|
||||||
|
reverseCurve: const Interval(0.0, 0.3, curve: Curves.elasticOut),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
_rotationAnimation = Tween<double>(begin: 0.0, end: -0.15).animate(
|
||||||
|
CurvedAnimation(
|
||||||
|
parent: _clickController,
|
||||||
|
curve: const Interval(0.0, 0.1, curve: Curves.elasticOut),
|
||||||
|
reverseCurve: const Interval(0.0, 0.1, curve: Curves.elasticOut),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_clickController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleTap() {
|
||||||
|
_clickController.forward().then((_) {
|
||||||
|
_clickController.reverse();
|
||||||
|
});
|
||||||
|
widget.onTap();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Tooltip(
|
||||||
|
message: widget.tooltip,
|
||||||
|
child: InkWell(
|
||||||
|
splashColor: Colors.transparent,
|
||||||
|
onTap: _handleTap,
|
||||||
|
child: AnimatedBuilder(
|
||||||
|
animation: _clickController,
|
||||||
|
builder: (context, child) {
|
||||||
|
return Transform.scale(
|
||||||
|
scale: _scaleAnimation.value,
|
||||||
|
child: Transform.rotate(
|
||||||
|
angle: _rotationAnimation.value,
|
||||||
|
child: TweenAnimationBuilder<Color?>(
|
||||||
|
tween: ColorTween(
|
||||||
|
begin: widget.inactiveColor,
|
||||||
|
end:
|
||||||
|
widget.isActive
|
||||||
|
? widget.activeColor
|
||||||
|
: widget.inactiveColor,
|
||||||
|
),
|
||||||
|
duration: const Duration(milliseconds: 100),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
builder: (context, color, child) {
|
||||||
|
return SvgPicture.asset(
|
||||||
|
width: 24.0.w(),
|
||||||
|
height: 24.0.w(),
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
widget.iconPath,
|
||||||
|
colorFilter: ColorFilter.mode(
|
||||||
|
color ?? widget.inactiveColor,
|
||||||
|
BlendMode.srcATop,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:tm_app/data/services/model/tender_data/tender_data.dart';
|
import 'package:tm_app/data/services/model/tender_data/tender_data.dart';
|
||||||
import 'package:tm_app/view_models/tenders_view_model.dart';
|
import 'package:tm_app/view_models/tenders_view_model.dart';
|
||||||
@@ -13,6 +12,7 @@ import '../../../core/utils/size_config.dart';
|
|||||||
import '../../shared/select_submission_bottom_sheet.dart';
|
import '../../shared/select_submission_bottom_sheet.dart';
|
||||||
import '../../shared/select_submission_dialog.dart';
|
import '../../shared/select_submission_dialog.dart';
|
||||||
import '../strings/tenders_strings.dart';
|
import '../strings/tenders_strings.dart';
|
||||||
|
import '../widgets/animated_feedback_button.dart';
|
||||||
|
|
||||||
class TenderActionButtonsRow extends StatelessWidget {
|
class TenderActionButtonsRow extends StatelessWidget {
|
||||||
final TenderData tender;
|
final TenderData tender;
|
||||||
@@ -200,7 +200,6 @@ class TenderActionButtonsRow extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _dislikeButton(TendersViewModel viewModel) {
|
Widget _dislikeButton(TendersViewModel viewModel) {
|
||||||
// Find feedback for this specific tender
|
|
||||||
if (tender.id == null) {
|
if (tender.id == null) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
@@ -208,27 +207,20 @@ class TenderActionButtonsRow extends StatelessWidget {
|
|||||||
final feedback = viewModel.getFeedbackForTender(tender.id!);
|
final feedback = viewModel.getFeedbackForTender(tender.id!);
|
||||||
final isDisliked = feedback?.feedbackType == TenderFeedback.disliked.value;
|
final isDisliked = feedback?.feedbackType == TenderFeedback.disliked.value;
|
||||||
|
|
||||||
return Tooltip(
|
return Column(
|
||||||
message: TendersStrings.dislike,
|
children: [
|
||||||
child: InkWell(
|
AnimatedFeedbackButton(
|
||||||
splashColor: Colors.transparent,
|
iconPath: AssetsManager.dislike,
|
||||||
|
activeColor: AppColors.errorColor,
|
||||||
|
inactiveColor: AppColors.grey50,
|
||||||
|
isActive: isDisliked,
|
||||||
|
tooltip: TendersStrings.dislike,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
viewModel.toogleFeedback(
|
viewModel.toogleFeedback(
|
||||||
tenderId: tender.id!,
|
tenderId: tender.id!,
|
||||||
feedbackType: TenderFeedback.disliked.value,
|
feedbackType: TenderFeedback.disliked.value,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
SvgPicture.asset(
|
|
||||||
width: 24.0.w(),
|
|
||||||
height: 24.0.w(),
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
AssetsManager.dislike,
|
|
||||||
colorFilter: ColorFilter.mode(
|
|
||||||
isDisliked ? AppColors.errorColor : AppColors.grey50,
|
|
||||||
BlendMode.srcATop,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
SizedBox(height: 8.0.h()),
|
SizedBox(height: 8.0.h()),
|
||||||
if (!isDesktop)
|
if (!isDesktop)
|
||||||
@@ -241,13 +233,10 @@ class TenderActionButtonsRow extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _likeButton(TendersViewModel viewModel) {
|
Widget _likeButton(TendersViewModel viewModel) {
|
||||||
// Find feedback for this specific tender
|
|
||||||
if (tender.id == null) {
|
if (tender.id == null) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
@@ -255,27 +244,20 @@ class TenderActionButtonsRow extends StatelessWidget {
|
|||||||
final feedback = viewModel.getFeedbackForTender(tender.id!);
|
final feedback = viewModel.getFeedbackForTender(tender.id!);
|
||||||
final isLiked = feedback?.feedbackType == TenderFeedback.liked.value;
|
final isLiked = feedback?.feedbackType == TenderFeedback.liked.value;
|
||||||
|
|
||||||
return Tooltip(
|
return Column(
|
||||||
message: TendersStrings.like,
|
children: [
|
||||||
child: InkWell(
|
AnimatedFeedbackButton(
|
||||||
splashColor: Colors.transparent,
|
iconPath: AssetsManager.like,
|
||||||
|
activeColor: AppColors.successColor,
|
||||||
|
inactiveColor: AppColors.grey50,
|
||||||
|
isActive: isLiked,
|
||||||
|
tooltip: TendersStrings.like,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
viewModel.toogleFeedback(
|
viewModel.toogleFeedback(
|
||||||
tenderId: tender.id!,
|
tenderId: tender.id!,
|
||||||
feedbackType: TenderFeedback.liked.value,
|
feedbackType: TenderFeedback.liked.value,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
SvgPicture.asset(
|
|
||||||
width: 24.0.w(),
|
|
||||||
height: 24.0.w(),
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
AssetsManager.like,
|
|
||||||
colorFilter: ColorFilter.mode(
|
|
||||||
isLiked ? AppColors.successColor : AppColors.grey50,
|
|
||||||
BlendMode.srcATop,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
SizedBox(height: 8.0.h()),
|
SizedBox(height: 8.0.h()),
|
||||||
if (!isDesktop)
|
if (!isDesktop)
|
||||||
@@ -288,8 +270,6 @@ class TenderActionButtonsRow extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user