home logic added

This commit is contained in:
amirrezaghabeli
2025-08-09 14:15:02 +03:30
parent 99b6bbb13f
commit 1fdfc52297
22 changed files with 1627 additions and 112 deletions
+49 -29
View File
@@ -1,8 +1,11 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:tm_app/core/constants/strings.dart';
import 'package:tm_app/core/routes/app_routes.dart';
import 'package:tm_app/core/theme/colors.dart';
import 'package:tm_app/core/utils/size_config.dart';
import 'package:tm_app/data/services/model/home/home_response/home_response_model.dart';
import 'package:tm_app/view_models/home_view_model.dart';
import '../widgets.dart';
@@ -12,49 +15,63 @@ class DesktopHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 55),
_progressBarsRow(),
SizedBox(height: 32.0.h()),
_firstTenderCardsRow(context),
SizedBox(height: 32.0.h()),
_yourTenderText(),
SizedBox(height: 8.0.h()),
_bottomListView(),
],
),
body: Consumer<HomeViewModel>(
builder: (context, homeViewModel, child) {
if (homeViewModel.isLoading) {
return const Center(
child: CircularProgressIndicator(color: AppColors.secondary50),
);
}
if (homeViewModel.errorMessage != null) {
return Center(child: Text(homeViewModel.errorMessage!));
}
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 55),
_progressBarsRow(homeViewModel.homeResponse!),
SizedBox(height: 32.0.h()),
_firstTenderCardsRow(context, homeViewModel.homeResponse!),
SizedBox(height: 32.0.h()),
_yourTenderText(),
SizedBox(height: 8.0.h()),
_bottomListView(homeViewModel.homeResponse!),
],
),
);
},
),
);
}
Widget _progressBarsRow() {
Widget _progressBarsRow(HomeResponseModel homeResponse) {
return Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.center,
children: [
ProgressBarColumn(
text: AppStrings.partnership,
value: 0.75,
amount: '75%',
value: double.parse(homeResponse.partnership ?? '0'),
amount: homeResponse.partnership ?? '0',
circularProgressIndicatorWidth: 176,
circularProgressIndicatorHeight: 176,
),
SizedBox(width: 106),
ProgressBarColumn(
text: AppStrings.selfApply,
value: 0.88,
amount: '12',
value: double.parse(homeResponse.selfApply ?? '0'),
amount: homeResponse.selfApply ?? '0',
circularProgressIndicatorWidth: 176,
circularProgressIndicatorHeight: 176,
),
SizedBox(width: 106),
ProgressBarColumn(
text: AppStrings.contracting,
value: 0.36,
amount: '36',
value: double.parse(homeResponse.contracting ?? '0'),
amount: homeResponse.contracting ?? '0',
circularProgressIndicatorWidth: 176,
circularProgressIndicatorHeight: 176,
),
@@ -62,7 +79,10 @@ class DesktopHomePage extends StatelessWidget {
);
}
Widget _firstTenderCardsRow(BuildContext context) {
Widget _firstTenderCardsRow(
BuildContext context,
HomeResponseModel homeResponse,
) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
@@ -70,7 +90,7 @@ class DesktopHomePage extends StatelessWidget {
backgroundColor: AppColors.primary20,
iconPath: 'assets/icons/arrows.svg',
title: AppStrings.tenderSubmitted,
amount: '12',
amount: homeResponse.tenderSubmitted ?? '0',
textColor: Color(0xFF0164FF),
enableTap: true,
width: 178,
@@ -84,7 +104,7 @@ class DesktopHomePage extends StatelessWidget {
backgroundColor: AppColors.primary10,
iconPath: 'assets/icons/thumb.svg',
title: AppStrings.approvedTenders,
amount: '03',
amount: homeResponse.approvedTenders ?? '0',
textColor: Color(0xFF24848E),
enableTap: true,
width: 178,
@@ -98,7 +118,7 @@ class DesktopHomePage extends StatelessWidget {
backgroundColor: AppColors.orange10,
iconPath: 'assets/icons/shield.svg',
title: AppStrings.tenderValue,
amount: '\$250,000',
amount: homeResponse.tenderValue ?? '0',
textColor: Color(0xFFE5821E),
enableTap: true,
width: 178,
@@ -110,7 +130,7 @@ class DesktopHomePage extends StatelessWidget {
backgroundColor: AppColors.grey10,
iconPath: 'assets/icons/edit.svg',
title: AppStrings.thunderStatus,
amount: '23',
amount: homeResponse.thunderStatus ?? '0',
textColor: Color(0xFF9E9E9E),
enableTap: false,
width: 178,
@@ -138,15 +158,15 @@ class DesktopHomePage extends StatelessWidget {
);
}
Widget _bottomListView() {
Widget _bottomListView(HomeResponseModel homeResponse) {
return SizedBox(
width: 740,
height: 310.0.h(),
child: ListView.builder(
itemCount: 10,
itemCount: homeResponse.yourTenders?.length ?? 0,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return TendersListItem();
return TendersListItem(tender: homeResponse.yourTenders![index]);
},
),
);
+82 -34
View File
@@ -1,9 +1,12 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:tm_app/core/constants/assets.dart';
import 'package:tm_app/core/constants/strings.dart';
import 'package:tm_app/core/routes/app_routes.dart';
import 'package:tm_app/core/theme/colors.dart';
import 'package:tm_app/core/utils/size_config.dart';
import 'package:tm_app/data/services/model/home/home_response/home_response_model.dart';
import 'package:tm_app/view_models/home_view_model.dart';
import 'package:tm_app/views/shared/tender_app_bar.dart';
import '../widgets.dart';
@@ -15,27 +18,69 @@ class MobileHomePage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: tenderMobileAppBar(title: AppStrings.home),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 18.0.h()),
_progressBarsRow(),
SizedBox(height: 32.0.h()),
_firstTenderCardsRow(context),
SizedBox(height: 8.0.h()),
_secondTenderCardsRow(),
SizedBox(height: 32.0.h()),
_yourTenderText(),
SizedBox(height: 8.0.h()),
_bottomListView(),
],
),
body: Consumer<HomeViewModel>(
builder: (context, homeViewModel, child) {
if (homeViewModel.isLoading) {
return const Center(
child: CircularProgressIndicator(color: AppColors.secondary50),
);
}
if (homeViewModel.errorMessage != null) {
return Center(
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.error_outline,
size: 64,
color: Colors.red,
),
const SizedBox(height: 16),
Text(
homeViewModel.errorMessage!,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
color: Colors.grey.shade700,
),
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () => homeViewModel.getHome(),
child: const Text('Try Again'),
),
],
),
),
);
}
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 18.0.h()),
_progressBarsRow(homeViewModel.homeResponse!),
SizedBox(height: 32.0.h()),
_firstTenderCardsRow(context, homeViewModel.homeResponse!),
SizedBox(height: 8.0.h()),
_secondTenderCardsRow(homeViewModel.homeResponse!),
SizedBox(height: 32.0.h()),
_yourTenderText(),
SizedBox(height: 8.0.h()),
_bottomListView(homeViewModel.homeResponse!),
],
),
);
},
),
);
}
Widget _progressBarsRow() {
Widget _progressBarsRow(HomeResponseModel homeResponse) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 24.0.w()),
child: Row(
@@ -43,25 +88,28 @@ class MobileHomePage extends StatelessWidget {
children: [
ProgressBarColumn(
text: AppStrings.partnership,
value: 0.75,
amount: '75%',
value: double.parse(homeResponse.partnership ?? '0'),
amount: '${homeResponse.partnership}%',
),
ProgressBarColumn(
text: AppStrings.selfApply,
value: 0.88,
amount: '12',
value: double.parse(homeResponse.selfApply ?? '0'),
amount: homeResponse.selfApply ?? '0',
),
ProgressBarColumn(
text: AppStrings.contracting,
value: 0.36,
amount: '36',
value: double.parse(homeResponse.contracting ?? '0'),
amount: homeResponse.contracting ?? '0',
),
],
),
);
}
Widget _firstTenderCardsRow(BuildContext context) {
Widget _firstTenderCardsRow(
BuildContext context,
HomeResponseModel homeResponse,
) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 24.0.w()),
child: Row(
@@ -71,7 +119,7 @@ class MobileHomePage extends StatelessWidget {
backgroundColor: AppColors.primary20,
iconPath: AssetsManager.arrows,
title: AppStrings.tenderSubmitted,
amount: '12',
amount: homeResponse.tenderSubmitted ?? '0',
textColor: Color(0xFF0164FF),
enableTap: true,
onTap: () {
@@ -82,7 +130,7 @@ class MobileHomePage extends StatelessWidget {
backgroundColor: AppColors.primary10,
iconPath: AssetsManager.thumb,
title: AppStrings.approvedTenders,
amount: '03',
amount: homeResponse.approvedTenders ?? '0',
textColor: Color(0xFF24848E),
enableTap: true,
onTap: () {
@@ -94,7 +142,7 @@ class MobileHomePage extends StatelessWidget {
);
}
Widget _secondTenderCardsRow() {
Widget _secondTenderCardsRow(HomeResponseModel homeResponse) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 24.0.w()),
child: Row(
@@ -104,7 +152,7 @@ class MobileHomePage extends StatelessWidget {
backgroundColor: AppColors.orange10,
iconPath: AssetsManager.shield,
title: AppStrings.tenderValue,
amount: '\$250,000',
amount: homeResponse.tenderValue ?? '0',
textColor: Color(0xFFE5821E),
enableTap: true,
onTap: () {},
@@ -113,7 +161,7 @@ class MobileHomePage extends StatelessWidget {
backgroundColor: AppColors.grey10,
iconPath: AssetsManager.edit,
title: AppStrings.thunderStatus,
amount: '23',
amount: homeResponse.thunderStatus ?? '0',
textColor: Color(0xFF9E9E9E),
enableTap: false,
onTap: () {},
@@ -137,16 +185,16 @@ class MobileHomePage extends StatelessWidget {
);
}
Widget _bottomListView() {
Widget _bottomListView(HomeResponseModel homeResponse) {
return SizedBox(
width: double.infinity,
height: 310.0.h(),
height: 286.0.h(),
child: ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 24.0.w()),
itemCount: 10,
padding: EdgeInsets.symmetric(horizontal: 24.0.w(), vertical: 16.0.h()),
itemCount: homeResponse.yourTenders?.length ?? 0,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return TendersListItem();
return TendersListItem(tender: homeResponse.yourTenders![index]);
},
),
);
+59 -39
View File
@@ -1,8 +1,11 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:tm_app/core/constants/strings.dart';
import 'package:tm_app/core/routes/app_routes.dart';
import 'package:tm_app/core/theme/colors.dart';
import 'package:tm_app/core/utils/size_config.dart';
import 'package:tm_app/data/services/model/home/home_response/home_response_model.dart';
import 'package:tm_app/view_models/home_view_model.dart';
import '../widgets.dart';
@@ -12,57 +15,71 @@ class TabletHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
24.0.w(),
120.0.h(),
24.0.w(),
24.0.h(),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_progressBarsRow(),
SizedBox(height: 32.0.h()),
_firstTenderCardsRow(context),
SizedBox(height: 8.0.h()),
_secondTenderCardsRow(),
SizedBox(height: 32.0.h()),
_yourTenderText(),
SizedBox(height: 8.0.h()),
_bottomListView(),
],
),
),
body: Consumer<HomeViewModel>(
builder: (context, homeViewModel, child) {
if (homeViewModel.isLoading) {
return const Center(
child: CircularProgressIndicator(color: AppColors.secondary50),
);
}
if (homeViewModel.errorMessage != null) {
return Center(child: Text(homeViewModel.errorMessage!));
}
return SingleChildScrollView(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
24.0.w(),
120.0.h(),
24.0.w(),
24.0.h(),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_progressBarsRow(homeViewModel.homeResponse!),
SizedBox(height: 32.0.h()),
_firstTenderCardsRow(context, homeViewModel.homeResponse!),
SizedBox(height: 8.0.h()),
_secondTenderCardsRow(homeViewModel.homeResponse!),
SizedBox(height: 32.0.h()),
_yourTenderText(),
SizedBox(height: 8.0.h()),
_bottomListView(homeViewModel.homeResponse!),
],
),
),
);
},
),
);
}
Widget _progressBarsRow() {
Widget _progressBarsRow(HomeResponseModel homeResponse) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ProgressBarColumn(
text: AppStrings.partnership,
value: 0.75,
amount: '75%',
value: double.parse(homeResponse.partnership ?? '0'),
amount: homeResponse.partnership ?? '0',
circularProgressIndicatorWidth: 176.0,
circularProgressIndicatorHeight: 176.0,
strokeWidth: 8.0,
),
ProgressBarColumn(
text: AppStrings.selfApply,
value: 0.88,
amount: '12',
value: double.parse(homeResponse.selfApply ?? '0'),
amount: homeResponse.selfApply ?? '0',
circularProgressIndicatorWidth: 176.0,
circularProgressIndicatorHeight: 176.0,
strokeWidth: 8.0,
),
ProgressBarColumn(
text: AppStrings.contracting,
value: 0.36,
amount: '36',
value: double.parse(homeResponse.contracting ?? '0'),
amount: homeResponse.contracting ?? '0',
circularProgressIndicatorWidth: 176.0,
circularProgressIndicatorHeight: 176.0,
strokeWidth: 8.0,
@@ -71,7 +88,10 @@ class TabletHomePage extends StatelessWidget {
);
}
Widget _firstTenderCardsRow(BuildContext context) {
Widget _firstTenderCardsRow(
BuildContext context,
HomeResponseModel homeResponse,
) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@@ -80,7 +100,7 @@ class TabletHomePage extends StatelessWidget {
backgroundColor: AppColors.primary20,
iconPath: 'assets/icons/arrows.svg',
title: AppStrings.tenderSubmitted,
amount: '12',
amount: homeResponse.tenderSubmitted ?? '0',
textColor: Color(0xFF0164FF),
enableTap: true,
width: double.infinity,
@@ -96,7 +116,7 @@ class TabletHomePage extends StatelessWidget {
backgroundColor: AppColors.primary10,
iconPath: 'assets/icons/thumb.svg',
title: AppStrings.approvedTenders,
amount: '03',
amount: homeResponse.approvedTenders ?? '0',
textColor: Color(0xFF24848E),
enableTap: true,
width: double.infinity,
@@ -110,7 +130,7 @@ class TabletHomePage extends StatelessWidget {
);
}
Widget _secondTenderCardsRow() {
Widget _secondTenderCardsRow(HomeResponseModel homeResponse) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@@ -119,7 +139,7 @@ class TabletHomePage extends StatelessWidget {
backgroundColor: AppColors.orange10,
iconPath: 'assets/icons/shield.svg',
title: AppStrings.tenderValue,
amount: '\$250,000',
amount: homeResponse.tenderValue ?? '0',
textColor: Color(0xFFE5821E),
enableTap: true,
width: double.infinity,
@@ -133,7 +153,7 @@ class TabletHomePage extends StatelessWidget {
backgroundColor: AppColors.grey10,
iconPath: 'assets/icons/edit.svg',
title: AppStrings.thunderStatus,
amount: '23',
amount: homeResponse.thunderStatus ?? '0',
textColor: Color(0xFF9E9E9E),
enableTap: false,
width: double.infinity,
@@ -156,15 +176,15 @@ class TabletHomePage extends StatelessWidget {
);
}
Widget _bottomListView() {
Widget _bottomListView(HomeResponseModel homeResponse) {
return SizedBox(
width: double.infinity,
height: 310.0.h(),
child: ListView.builder(
itemCount: 10,
itemCount: homeResponse.yourTenders?.length ?? 0,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return TendersListItem();
return TendersListItem(tender: homeResponse.yourTenders![index]);
},
),
);
+1 -1
View File
@@ -43,7 +43,7 @@ class _ProgressBarColumnState extends State<ProgressBarColumn>
// Create a Tween animation from 0.0 to 0.75
_animation = Tween<double>(
begin: 0.0,
end: widget.value,
end: widget.value / 100,
).animate(CurvedAnimation(parent: _controller, curve: Curves.easeOut));
// Start the animation
+12 -8
View File
@@ -1,12 +1,14 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:tm_app/data/services/model/home/tender/tender_model.dart';
import '../../core/constants/assets.dart';
import '../../core/theme/colors.dart';
import '../../core/utils/size_config.dart';
class TendersListItem extends StatelessWidget {
const TendersListItem({super.key});
const TendersListItem({required this.tender, super.key});
final TenderModel tender;
@override
Widget build(BuildContext context) {
@@ -17,7 +19,7 @@ class TendersListItem extends StatelessWidget {
),
margin: EdgeInsetsDirectional.only(end: 16.0.w()),
width: 320.0.w(),
height: 309.0.h(),
height: 280.0.h(),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0.w(), vertical: 16.0.h()),
child: Column(
@@ -26,7 +28,7 @@ class TendersListItem extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'2025-05-21',
tender.createdTime ?? '',
style: TextStyle(
fontSize: 12.0.sp(),
fontWeight: FontWeight.w400,
@@ -42,7 +44,7 @@ class TendersListItem extends StatelessWidget {
),
alignment: Alignment.center,
child: Text(
'Completed',
tender.status ?? '',
style: TextStyle(
fontSize: 12.0.sp(),
fontWeight: FontWeight.w500,
@@ -54,7 +56,7 @@ class TendersListItem extends StatelessWidget {
),
SizedBox(height: 12.0.h()),
Text(
'Lorem ipsum dolor sit amet consectetur. Sed mi tortor eu purus senectus.',
tender.title ?? '',
style: TextStyle(
fontSize: 16.0.sp(),
fontWeight: FontWeight.w600,
@@ -63,7 +65,9 @@ class TendersListItem extends StatelessWidget {
),
SizedBox(height: 8.0.h()),
Text(
'Lorem ipsum dolor sit amet consectetur. Volutpat velit tincidunt amet diam. Placerat congue ut Sed facilisis faucibus porttitor. Proin suspendisse eu euismod sit lorem quis. Suscipit ...',
tender.description ?? '',
maxLines: 3,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 14.0.sp(),
fontWeight: FontWeight.w400,
@@ -76,7 +80,7 @@ class TendersListItem extends StatelessWidget {
SvgPicture.asset(AssetsManager.location),
SizedBox(width: 1.0.w()),
Text(
'Location',
tender.location ?? '',
style: TextStyle(
fontSize: 12.0.sp(),
fontWeight: FontWeight.w400,
@@ -99,7 +103,7 @@ class TendersListItem extends StatelessWidget {
),
alignment: Alignment.center,
child: Text(
'Self Control',
tender.type ?? '',
style: TextStyle(
fontSize: 12.0.sp(),
fontWeight: FontWeight.w500,