check and fix in ui

This commit is contained in:
amirrezaghabeli
2025-08-10 16:05:03 +03:30
parent 55d7d96baf
commit 9ea9480818
35 changed files with 1066 additions and 416 deletions
@@ -0,0 +1,29 @@
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/tenders/widgets/main_tenders_slider.dart';
class DesktopTendersPage extends StatelessWidget {
const DesktopTendersPage({super.key});
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: AppColors.backgroundColor,
body: Center(
child: SingleChildScrollView(
child: SizedBox(
width: 740,
height: 800,
child: Padding(
padding: EdgeInsets.symmetric(vertical: 24.0.h()),
child: MainTendersSlider(isDesktop: true),
),
),
),
),
),
);
}
}
@@ -1,13 +1,13 @@
import 'package:flutter/material.dart';
import 'package:tm_app/core/constants/strings.dart';
import 'package:tm_app/views/shared/tender_app_bar.dart';
import 'package:tm_app/core/utils/size_config.dart';
import 'package:tm_app/views/tenders/widgets/main_tenders_slider.dart';
import '../../core/theme/colors.dart';
import '../../core/utils/size_config.dart';
import 'widgets/main_tenders_slider.dart';
import '../../../core/constants/strings.dart';
import '../../../core/theme/colors.dart';
import '../../shared/tender_app_bar.dart';
class TendersScreen extends StatelessWidget {
const TendersScreen({super.key});
class MobileTendersPage extends StatelessWidget {
const MobileTendersPage({super.key});
@override
Widget build(BuildContext context) {
@@ -0,0 +1,24 @@
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/tenders/widgets/main_tenders_slider.dart';
class TabletTendersPage extends StatelessWidget {
const TabletTendersPage({super.key});
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: AppColors.backgroundColor,
body: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 24.0.h()),
child: MainTendersSlider(),
),
),
),
);
}
}
@@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
import 'package:tm_app/views/shared/responsive_builder.dart';
import 'd_tenders_page.dart';
import 'm_tenders_page.dart';
import 't_tenders_page.dart';
class TendersScreen extends StatelessWidget {
const TendersScreen({super.key});
@override
Widget build(BuildContext context) {
return ResponsiveBuilder(
mobile: MobileTendersPage(),
tablet: TabletTendersPage(),
desktop: DesktopTendersPage(),
);
}
}
@@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:tm_app/core/routes/app_routes.dart';
import 'package:tm_app/core/theme/colors.dart';
import '../../../core/constants/assets.dart';
@@ -9,7 +8,8 @@ import '../models/tender_model.dart';
import 'tender_card.dart';
class MainTendersSlider extends StatefulWidget {
const MainTendersSlider({super.key});
const MainTendersSlider({super.key, this.isDesktop = false});
final bool isDesktop;
@override
State<MainTendersSlider> createState() => _MainTendersSliderState();
@@ -18,37 +18,7 @@ class MainTendersSlider extends StatefulWidget {
class _MainTendersSliderState extends State<MainTendersSlider> {
final PageController pageController = PageController(initialPage: 0);
List<Tender> likedTenders = [];
List<Tender> dislikedTenders = [];
int currentPage = 1;
List<Tender> rejectedTenders = [];
List<Tender> submittedTenders = [];
void _onDislike(Tender tender) {
if (likedTenders.contains(tender)) {
likedTenders.remove(tender);
}
if (!dislikedTenders.contains(tender)) {
dislikedTenders.add(tender);
} else {
dislikedTenders.remove(tender);
}
setState(() {});
}
void _onLike(Tender tender) {
if (dislikedTenders.contains(tender)) {
dislikedTenders.remove(tender);
}
if (!likedTenders.contains(tender)) {
likedTenders.add(tender);
} else {
likedTenders.remove(tender);
}
setState(() {});
}
void _goToPreviousPage() {
pageController.previousPage(
@@ -76,25 +46,6 @@ class _MainTendersSliderState extends State<MainTendersSlider> {
});
}
void _onReject(Tender tender) {
if (rejectedTenders.contains(tender)) {
rejectedTenders.remove(tender);
} else {
rejectedTenders.add(tender);
}
setState(() {});
}
void _onSubmit(Tender tender) {
if (submittedTenders.contains(tender)) {
submittedTenders.remove(tender);
} else {
submittedTenders.add(tender);
}
setState(() {});
}
@override
void dispose() {
pageController.dispose();
@@ -119,25 +70,7 @@ class _MainTendersSliderState extends State<MainTendersSlider> {
},
itemBuilder: (context, index) {
final tender = sampleTenders[index];
return TenderCard(
date: tender.date,
deadline: tender.deadline,
title: tender.title,
description: tender.description,
tenderId: tender.tenderId,
location: tender.location,
country: tender.country,
matchPercentage: tender.matchPercentage,
isLiked: likedTenders.contains(tender),
isDisliked: dislikedTenders.contains(tender),
onDislike: () => _onDislike(tender),
onLike: () => _onLike(tender),
onApply: () => TenderDetailRouteData().push(context),
onReject: () => _onReject(tender),
onSubmit: () => _onSubmit(tender),
rejected: rejectedTenders.contains(tender),
submitted: submittedTenders.contains(tender),
);
return TenderCard(tender: tender, isDesktop: widget.isDesktop);
},
),
),
@@ -1,167 +1,207 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:provider/provider.dart';
import 'package:tm_app/view_models/tenders_view_model.dart';
import 'package:tm_app/views/tenders/models/tender_model.dart';
import '../../../core/constants/assets.dart';
import '../../../core/theme/colors.dart';
import '../../../core/utils/size_config.dart';
class TenderActionButtons extends StatelessWidget {
final VoidCallback? onLike;
final VoidCallback? onDislike;
final VoidCallback? onClose;
final VoidCallback? onReject;
final VoidCallback? onSubmit;
final bool isLiked;
final bool isDisliked;
final bool rejected;
final bool submitted;
final Tender tender;
final bool isDesktop;
const TenderActionButtons({
required this.tender,
this.isDesktop = false,
super.key,
this.onLike,
this.onDislike,
this.onClose,
this.onReject,
this.onSubmit,
this.isLiked = false,
this.isDisliked = false,
this.rejected = false,
this.submitted = false,
});
@override
Widget build(BuildContext context) {
final viewModel = context.watch<TendersViewModel>();
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(width: 16.0.w()),
// Dislike button
GestureDetector(
onTap: onDislike,
child: Column(
children: [
SvgPicture.asset(
width: 32.0.w(),
height: 32.0.w(),
fit: BoxFit.cover,
AssetsManager.dislike,
colorFilter: ColorFilter.mode(
isDisliked ? AppColors.errorColor : AppColors.grey50,
BlendMode.srcATop,
Tooltip(
message: 'Dislike',
child: InkWell(
onTap: () {
viewModel.onDislike(tender);
},
child: Column(
children: [
SvgPicture.asset(
width: 32.0.w(),
height: 32.0.w(),
fit: BoxFit.cover,
AssetsManager.dislike,
colorFilter: ColorFilter.mode(
viewModel.dislikedTenders.contains(tender)
? AppColors.errorColor
: AppColors.grey50,
BlendMode.srcATop,
),
),
),
SizedBox(height: 8.0.h()),
Text(
'Like',
style: TextStyle(
fontSize: 12.0.sp(),
fontWeight: FontWeight.w400,
color: isDisliked ? AppColors.errorColor : AppColors.grey50,
),
),
],
SizedBox(height: 8.0.h()),
if (!isDesktop)
Text(
'Like',
style: TextStyle(
fontSize: 12.0.sp(),
fontWeight: FontWeight.w400,
color:
viewModel.dislikedTenders.contains(tender)
? AppColors.errorColor
: AppColors.grey50,
),
),
],
),
),
),
SizedBox(width: 32.0.w()),
//reject button
GestureDetector(
onTap: onReject,
child: Column(
children: [
Container(
width: 32.0.w(),
height: 32.0.w(),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: rejected ? AppColors.errorColor : AppColors.grey60,
width: 1.5.w(),
Tooltip(
message: 'Reject',
child: InkWell(
onTap: () {
viewModel.onReject(tender);
},
child: Column(
children: [
Container(
width: 32.0.w(),
height: 32.0.w(),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color:
viewModel.rejectedTenders.contains(tender)
? AppColors.errorColor
: AppColors.grey60,
width: 1.5.w(),
),
),
alignment: Alignment.center,
child: Icon(
Icons.close,
color:
viewModel.rejectedTenders.contains(tender)
? AppColors.errorColor
: AppColors.grey60,
size: 16,
),
),
alignment: Alignment.center,
child: Icon(
Icons.close,
color: rejected ? AppColors.errorColor : AppColors.grey60,
size: 16,
),
),
SizedBox(height: 8.0.h()),
Text(
'Reject',
style: TextStyle(
fontSize: 12.0.sp(),
fontWeight: FontWeight.w400,
color: rejected ? AppColors.errorColor : AppColors.grey60,
),
),
],
SizedBox(height: 8.0.h()),
if (!isDesktop)
Text(
'Reject',
style: TextStyle(
fontSize: 12.0.sp(),
fontWeight: FontWeight.w400,
color:
viewModel.rejectedTenders.contains(tender)
? AppColors.errorColor
: AppColors.grey60,
),
),
],
),
),
),
SizedBox(width: 32.0.w()),
//submit button
GestureDetector(
onTap: onSubmit,
child: Column(
children: [
Container(
width: 32.0.w(),
height: 32.0.w(),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color:
submitted ? AppColors.successColor : AppColors.grey60,
width: 1.5.w(),
Tooltip(
message: 'Submit',
child: InkWell(
onTap: () {
viewModel.onSubmit(tender);
},
child: Column(
children: [
Container(
width: 32.0.w(),
height: 32.0.w(),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color:
viewModel.submittedTenders.contains(tender)
? AppColors.successColor
: AppColors.grey60,
width: 1.5.w(),
),
),
alignment: Alignment.center,
child: SvgPicture.asset(
AssetsManager.tick,
colorFilter: ColorFilter.mode(
viewModel.submittedTenders.contains(tender)
? AppColors.successColor
: AppColors.grey60,
BlendMode.srcATop,
),
),
),
alignment: Alignment.center,
child: SvgPicture.asset(
AssetsManager.tick,
colorFilter: ColorFilter.mode(
submitted ? AppColors.successColor : AppColors.grey60,
BlendMode.srcATop,
SizedBox(height: 8.0.h()),
if (!isDesktop)
Text(
'Submit',
style: TextStyle(
fontSize: 12.0.sp(),
fontWeight: FontWeight.w400,
color:
viewModel.submittedTenders.contains(tender)
? AppColors.successColor
: AppColors.grey60,
),
),
),
),
SizedBox(height: 8.0.h()),
Text(
'Submit',
style: TextStyle(
fontSize: 12.0.sp(),
fontWeight: FontWeight.w400,
color: submitted ? AppColors.successColor : AppColors.grey60,
),
),
],
],
),
),
),
SizedBox(width: 32.0.w()),
// Like button
GestureDetector(
onTap: onLike,
child: Column(
children: [
SvgPicture.asset(
width: 32.0.w(),
height: 32.0.w(),
fit: BoxFit.cover,
AssetsManager.like,
colorFilter: ColorFilter.mode(
isLiked ? AppColors.successColor : AppColors.grey50,
BlendMode.srcATop,
Tooltip(
message: 'Like',
child: InkWell(
onTap: () {
viewModel.onLike(tender);
},
child: Column(
children: [
SvgPicture.asset(
width: 32.0.w(),
height: 32.0.w(),
fit: BoxFit.cover,
AssetsManager.like,
colorFilter: ColorFilter.mode(
viewModel.likedTenders.contains(tender)
? AppColors.successColor
: AppColors.grey50,
BlendMode.srcATop,
),
),
),
SizedBox(height: 8.0.h()),
Text(
'Like',
style: TextStyle(
fontSize: 12.0.sp(),
fontWeight: FontWeight.w400,
color: isLiked ? AppColors.successColor : AppColors.grey50,
),
),
],
SizedBox(height: 8.0.h()),
if (!isDesktop)
Text(
'Like',
style: TextStyle(
fontSize: 12.0.sp(),
fontWeight: FontWeight.w400,
color:
viewModel.likedTenders.contains(tender)
? AppColors.successColor
: AppColors.grey50,
),
),
],
),
),
),
],
+33 -65
View File
@@ -1,52 +1,18 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:tm_app/core/constants/strings.dart';
import 'package:tm_app/core/routes/app_routes.dart';
import '../../../core/constants/assets.dart';
import '../../../core/theme/colors.dart';
import '../../../core/utils/size_config.dart';
import '../models/tender_model.dart';
import 'tender_action_buttons.dart';
class TenderCard extends StatelessWidget {
final String date;
final String deadline;
final String title;
final String description;
final String tenderId;
final String location;
final String country;
final double matchPercentage;
final VoidCallback? onApply;
final VoidCallback? onLike;
final VoidCallback? onDislike;
final VoidCallback? onClose;
final bool isLiked;
final bool isDisliked;
final VoidCallback? onReject;
final VoidCallback? onSubmit;
final bool rejected;
final bool submitted;
const TenderCard({
required this.date,
required this.deadline,
required this.title,
required this.description,
required this.tenderId,
required this.location,
required this.country,
required this.matchPercentage,
this.onApply,
this.onLike,
this.onDislike,
this.onClose,
this.isLiked = false,
this.isDisliked = false,
this.onReject,
this.onSubmit,
this.rejected = false,
this.submitted = false,
super.key,
});
final Tender tender;
final bool isDesktop;
const TenderCard({required this.tender, super.key, this.isDesktop = false});
@override
Widget build(BuildContext context) {
@@ -71,13 +37,23 @@ class TenderCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Date
Text(
date,
style: TextStyle(
color: AppColors.grey60,
fontSize: 12.0.sp(),
fontWeight: FontWeight.w400,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
tender.date,
style: TextStyle(
color: AppColors.grey60,
fontSize: 12.0.sp(),
fontWeight: FontWeight.w400,
),
),
if (isDesktop)
TenderActionButtons(
tender: tender,
isDesktop: isDesktop,
),
],
),
SizedBox(height: 12.0.h()),
@@ -102,7 +78,7 @@ class TenderCard extends StatelessWidget {
),
),
Text(
deadline,
tender.deadline,
style: TextStyle(
color: AppColors.grey80,
fontSize: 14.0.sp(),
@@ -116,7 +92,7 @@ class TenderCard extends StatelessWidget {
// Title
Text(
title,
tender.title,
style: TextStyle(
color: AppColors.grey80,
fontSize: 16.0.sp(),
@@ -127,7 +103,7 @@ class TenderCard extends StatelessWidget {
// Description
Text(
description,
tender.description,
style: TextStyle(
color: AppColors.grey70,
fontSize: 16.0.sp(),
@@ -139,7 +115,7 @@ class TenderCard extends StatelessWidget {
// Tender ID
Text(
tenderId,
tender.tenderId,
style: TextStyle(
color: AppColors.grey,
fontSize: 14.0.sp(),
@@ -168,7 +144,7 @@ class TenderCard extends StatelessWidget {
),
),
Text(
'${matchPercentage.toInt()}%',
'${tender.matchPercentage.toInt()}%',
style: TextStyle(
color: AppColors.secondaryTextColor,
fontSize: 16.0.sp(),
@@ -189,7 +165,7 @@ class TenderCard extends StatelessWidget {
),
child: FractionallySizedBox(
alignment: Alignment.centerLeft,
widthFactor: matchPercentage / 100,
widthFactor: tender.matchPercentage / 100,
child: Container(
decoration: BoxDecoration(
color: AppColors.secondary50,
@@ -210,7 +186,7 @@ class TenderCard extends StatelessWidget {
SvgPicture.asset(AssetsManager.location),
SizedBox(width: 4.0.w()),
Text(
location,
tender.location,
style: TextStyle(
color: AppColors.grey80,
fontSize: 14.0.sp(),
@@ -230,7 +206,9 @@ class TenderCard extends StatelessWidget {
// See More button
GestureDetector(
onTap: onApply,
onTap: () {
TenderDetailRouteData().push(context);
},
child: Container(
width: 108.0.w(),
height: 40.0.h(),
@@ -258,17 +236,7 @@ class TenderCard extends StatelessWidget {
),
),
SizedBox(height: 72.0.h()),
TenderActionButtons(
isDisliked: isDisliked,
isLiked: isLiked,
onDislike: onDislike,
onLike: onLike,
onClose: onClose,
onReject: onReject,
onSubmit: onSubmit,
rejected: rejected,
submitted: submitted,
),
if (!isDesktop) TenderActionButtons(tender: tender),
],
);
}