added request successful page and add animation for feedback of tenders
This commit is contained in:
@@ -8,7 +8,7 @@ class AppConfig {
|
||||
|
||||
// این متد بر اساس محیط فعال، URL مناسب را برمیگرداند.
|
||||
static String get apiBaseUrl {
|
||||
return 'http://10.0.2.2:8081';
|
||||
return 'http://10.0.2.2:8081';
|
||||
// return '192.168.1.103:8081';
|
||||
// if (isDevelopment) {
|
||||
// // Handle different platforms for local development
|
||||
|
||||
@@ -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(
|
||||
padding: EdgeInsets.symmetric(vertical: 24.0.h()),
|
||||
padding: EdgeInsets.symmetric(vertical: 18.0.h()),
|
||||
child: MainTendersSlider(
|
||||
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_svg/svg.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tm_app/data/services/model/tender_data/tender_data.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_dialog.dart';
|
||||
import '../strings/tenders_strings.dart';
|
||||
import '../widgets/animated_feedback_button.dart';
|
||||
|
||||
class TenderActionButtonsRow extends StatelessWidget {
|
||||
final TenderData tender;
|
||||
@@ -200,7 +200,6 @@ class TenderActionButtonsRow extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget _dislikeButton(TendersViewModel viewModel) {
|
||||
// Find feedback for this specific tender
|
||||
if (tender.id == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
@@ -208,46 +207,36 @@ class TenderActionButtonsRow extends StatelessWidget {
|
||||
final feedback = viewModel.getFeedbackForTender(tender.id!);
|
||||
final isDisliked = feedback?.feedbackType == TenderFeedback.disliked.value;
|
||||
|
||||
return Tooltip(
|
||||
message: TendersStrings.dislike,
|
||||
child: InkWell(
|
||||
splashColor: Colors.transparent,
|
||||
onTap: () {
|
||||
viewModel.toogleFeedback(
|
||||
tenderId: tender.id!,
|
||||
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()),
|
||||
if (!isDesktop)
|
||||
Text(
|
||||
TendersStrings.dislike,
|
||||
style: TextStyle(
|
||||
fontSize: 12.0.sp(),
|
||||
fontWeight: FontWeight.w400,
|
||||
color: isDisliked ? AppColors.errorColor : AppColors.grey50,
|
||||
),
|
||||
),
|
||||
],
|
||||
return Column(
|
||||
children: [
|
||||
AnimatedFeedbackButton(
|
||||
iconPath: AssetsManager.dislike,
|
||||
activeColor: AppColors.errorColor,
|
||||
inactiveColor: AppColors.grey50,
|
||||
isActive: isDisliked,
|
||||
tooltip: TendersStrings.dislike,
|
||||
onTap: () {
|
||||
viewModel.toogleFeedback(
|
||||
tenderId: tender.id!,
|
||||
feedbackType: TenderFeedback.disliked.value,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8.0.h()),
|
||||
if (!isDesktop)
|
||||
Text(
|
||||
TendersStrings.dislike,
|
||||
style: TextStyle(
|
||||
fontSize: 12.0.sp(),
|
||||
fontWeight: FontWeight.w400,
|
||||
color: isDisliked ? AppColors.errorColor : AppColors.grey50,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _likeButton(TendersViewModel viewModel) {
|
||||
// Find feedback for this specific tender
|
||||
if (tender.id == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
@@ -255,41 +244,32 @@ class TenderActionButtonsRow extends StatelessWidget {
|
||||
final feedback = viewModel.getFeedbackForTender(tender.id!);
|
||||
final isLiked = feedback?.feedbackType == TenderFeedback.liked.value;
|
||||
|
||||
return Tooltip(
|
||||
message: TendersStrings.like,
|
||||
child: InkWell(
|
||||
splashColor: Colors.transparent,
|
||||
onTap: () {
|
||||
viewModel.toogleFeedback(
|
||||
tenderId: tender.id!,
|
||||
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()),
|
||||
if (!isDesktop)
|
||||
Text(
|
||||
TendersStrings.like,
|
||||
style: TextStyle(
|
||||
fontSize: 12.0.sp(),
|
||||
fontWeight: FontWeight.w400,
|
||||
color: isLiked ? AppColors.successColor : AppColors.grey50,
|
||||
),
|
||||
),
|
||||
],
|
||||
return Column(
|
||||
children: [
|
||||
AnimatedFeedbackButton(
|
||||
iconPath: AssetsManager.like,
|
||||
activeColor: AppColors.successColor,
|
||||
inactiveColor: AppColors.grey50,
|
||||
isActive: isLiked,
|
||||
tooltip: TendersStrings.like,
|
||||
onTap: () {
|
||||
viewModel.toogleFeedback(
|
||||
tenderId: tender.id!,
|
||||
feedbackType: TenderFeedback.liked.value,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8.0.h()),
|
||||
if (!isDesktop)
|
||||
Text(
|
||||
TendersStrings.like,
|
||||
style: TextStyle(
|
||||
fontSize: 12.0.sp(),
|
||||
fontWeight: FontWeight.w400,
|
||||
color: isLiked ? AppColors.successColor : AppColors.grey50,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user