From 4f07facbb890b56be3071ef7f17d6f4a5f36b969 Mon Sep 17 00:00:00 2001 From: amirrezaghabeli Date: Tue, 26 Aug 2025 14:58:06 +0330 Subject: [PATCH] tablet navigation bar fixed --- lib/core/constants/strings.dart | 2 + .../routes/app_shell/tablet_shell_page.dart | 107 +------ lib/core/utils/breakpoints.dart | 2 +- .../model/tender_data/tender_data.dart | 2 +- .../tender_data/tender_data.freezed.dart | 42 +-- .../model/tender_data/tender_data.g.dart | 4 +- .../detail/widgets/tender_detail_header.dart | 2 +- .../widgets/tender_detail_info_section.dart | 28 +- lib/views/home/pages/t_home_page.dart | 56 +++- lib/views/login/pages/login_mobile_page.dart | 4 +- lib/views/login/pages/login_tablet_page.dart | 21 +- lib/views/profile/pages/d_profile_page.dart | 270 +++++++++--------- lib/views/profile/pages/t_profile_page.dart | 46 +++ .../shared/tablet_navigation_widget.dart | 98 +++++++ lib/views/tenders/pages/d_tenders_page.dart | 108 ++++--- lib/views/tenders/pages/t_tenders_page.dart | 91 ++++-- .../pages/your_tenders_desktop_page.dart | 134 +++++---- .../pages/your_tenders_tablet_page.dart | 90 +++--- 18 files changed, 628 insertions(+), 479 deletions(-) create mode 100644 lib/views/shared/tablet_navigation_widget.dart diff --git a/lib/core/constants/strings.dart b/lib/core/constants/strings.dart index c5a735e..0c6e24c 100644 --- a/lib/core/constants/strings.dart +++ b/lib/core/constants/strings.dart @@ -87,4 +87,6 @@ class AppStrings { static const String tenderMatchPercentageExample = '75%'; static const String locationDescription = 'Luleå Municipality is procuring on behalf of Norrbotten’s e-board (all municipalities in Norrbotten).

The procurement includes operation, support, and further development of the existing open e-platform.

No additional information, amendments, or answers to questions will be provided after June 16.o additional information, amendments, or answers to questions will be provided after June 16.o additional information, amendments, or answers to questions will be provided after June 16.website: www.tenders.com Lorem ipsum is amet Luleå Municipality is procuring on behalf of Norrbotten’s e-board (all municipalities in Norrbotten).

The procurement includes operation, support, and further development of the existing open e-platform.

No additional information, amendments, or answers to questions will be provided after June 16. o additional information, amendments, or answers to questions will be provided after June 16. o additional information, amendments, or answers to questions will be provided after June 16.website: www.tenders.com'; + static const String estimatedValue = 'Estimated Value '; + static const String duration = 'Duration'; } diff --git a/lib/core/routes/app_shell/tablet_shell_page.dart b/lib/core/routes/app_shell/tablet_shell_page.dart index e2c9841..bd45e7e 100644 --- a/lib/core/routes/app_shell/tablet_shell_page.dart +++ b/lib/core/routes/app_shell/tablet_shell_page.dart @@ -1,13 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.dart'; import 'package:go_router/go_router.dart'; -import 'package:tm_app/core/constants/assets.dart'; -import 'package:tm_app/core/constants/strings.dart'; -import 'package:tm_app/core/theme/colors.dart'; -import 'package:tm_app/core/utils/size_config.dart'; class TabletShellPage extends StatelessWidget { - TabletShellPage({ + const TabletShellPage({ required this.navigationShell, required this.onTap, super.key, @@ -16,106 +11,8 @@ class TabletShellPage extends StatelessWidget { final StatefulNavigationShell navigationShell; final ValueChanged onTap; - final GlobalKey _key = GlobalKey(); - @override Widget build(BuildContext context) { - return Scaffold( - key: _key, - body: Stack( - children: [ - navigationShell, - Container( - width: double.infinity, - height: 64.0.h(), - padding: EdgeInsets.symmetric(horizontal: 24.0.w()), - decoration: BoxDecoration( - color: AppColors.backgroundColor, - border: Border( - bottom: BorderSide(color: AppColors.grey30, width: 1), - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SvgPicture.asset(AssetsManager.logoSmall), - InkWell( - onTap: () => _key.currentState!.openDrawer(), - child: SvgPicture.asset(AssetsManager.menu), - ), - ], - ), - ), - ], - ), - drawer: Container( - width: 200.0.w(), - height: double.infinity, - color: AppColors.backgroundColor, - child: Column( - children: [ - SizedBox(height: 48.0.h()), - _drawerItem( - context: context, - text: AppStrings.home, - isActive: navigationShell.currentIndex == 0, - onTap: () => onTap(0), - iconPath: AssetsManager.home, - activeIconPath: AssetsManager.homeActive, - ), - _drawerItem( - context: context, - text: AppStrings.tendersTitle, - isActive: navigationShell.currentIndex == 1, - onTap: () => onTap(1), - iconPath: AssetsManager.tenders, - activeIconPath: AssetsManager.tendersActive, - ), - _drawerItem( - context: context, - text: AppStrings.profile, - isActive: navigationShell.currentIndex == 2, - onTap: () => onTap(2), - iconPath: AssetsManager.profile, - activeIconPath: AssetsManager.profileActive, - ), - ], - ), - ), - ); - } - - Widget _drawerItem({ - required BuildContext context, - required String text, - required bool isActive, - required VoidCallback onTap, - required String iconPath, - required String activeIconPath, - }) { - return InkWell( - onTap: onTap, - child: SizedBox( - width: 200.0.w(), - height: 64.0.h(), - child: Padding( - padding: EdgeInsetsDirectional.only(start: 24.0.w()), - child: Row( - children: [ - SvgPicture.asset(isActive ? activeIconPath : iconPath), - SizedBox(width: 8.0.w()), - Text( - text, - style: TextStyle( - fontSize: 12.0.sp(), - fontWeight: FontWeight.w400, - color: isActive ? AppColors.primaryColor : AppColors.grey60, - ), - ), - ], - ), - ), - ), - ); + return Scaffold(body: navigationShell); } } diff --git a/lib/core/utils/breakpoints.dart b/lib/core/utils/breakpoints.dart index abf1087..04794ea 100644 --- a/lib/core/utils/breakpoints.dart +++ b/lib/core/utils/breakpoints.dart @@ -11,7 +11,7 @@ extension DisplaySizeDetector on Size { DisplaySize get displaySize { if (width < 600) { return DisplaySize.extraSmall; - } else if (width < 1024) { + } else if (width <= 1024) { return DisplaySize.small; } else if (width < 1440) { return DisplaySize.medium; diff --git a/lib/data/services/model/tender_data/tender_data.dart b/lib/data/services/model/tender_data/tender_data.dart index 40fed2e..6556da9 100644 --- a/lib/data/services/model/tender_data/tender_data.dart +++ b/lib/data/services/model/tender_data/tender_data.dart @@ -24,12 +24,12 @@ abstract class TenderData with _$TenderData { @JsonKey(name: 'estimated_value') required int? estimatedValue, required String? currency, required String? duration, - required String? durationUnit, @JsonKey(name: 'tender_deadline') required int? tenderDeadline, @JsonKey(name: 'submission_deadline') required int? submissionDeadline, @JsonKey(name: 'application_deadline') required int? applicationDeadline, @JsonKey(name: 'submission_url') required String? submissionUrl, @JsonKey(name: 'country_code') required String? countryCode, + @JsonKey(name: 'duration_unit') required String? durationUnit, @JsonKey(name: 'buyer_organization') required Organization? buyerOrganization, required String? status, diff --git a/lib/data/services/model/tender_data/tender_data.freezed.dart b/lib/data/services/model/tender_data/tender_data.freezed.dart index 60c295d..e46222a 100644 --- a/lib/data/services/model/tender_data/tender_data.freezed.dart +++ b/lib/data/services/model/tender_data/tender_data.freezed.dart @@ -15,7 +15,7 @@ T _$identity(T value) => value; /// @nodoc mixin _$TenderData { - bool? get success; String? get message; String? get id;@JsonKey(name: 'tender_id') String? get tenderId;@JsonKey(name: 'notice_publication_id') String? get noticePublicationId;@JsonKey(name: 'publication_date') int? get publicationDate; String? get title; String? get description;@JsonKey(name: 'procurement_type_code') String? get procurementTypeCode;@JsonKey(name: 'procedure_code') String? get procedureCode;@JsonKey(name: 'estimated_value') int? get estimatedValue; String? get currency; String? get duration; String? get durationUnit;@JsonKey(name: 'tender_deadline') int? get tenderDeadline;@JsonKey(name: 'submission_deadline') int? get submissionDeadline;@JsonKey(name: 'application_deadline') int? get applicationDeadline;@JsonKey(name: 'submission_url') String? get submissionUrl;@JsonKey(name: 'country_code') String? get countryCode;@JsonKey(name: 'buyer_organization') Organization? get buyerOrganization; String? get status; + bool? get success; String? get message; String? get id;@JsonKey(name: 'tender_id') String? get tenderId;@JsonKey(name: 'notice_publication_id') String? get noticePublicationId;@JsonKey(name: 'publication_date') int? get publicationDate; String? get title; String? get description;@JsonKey(name: 'procurement_type_code') String? get procurementTypeCode;@JsonKey(name: 'procedure_code') String? get procedureCode;@JsonKey(name: 'estimated_value') int? get estimatedValue; String? get currency; String? get duration;@JsonKey(name: 'tender_deadline') int? get tenderDeadline;@JsonKey(name: 'submission_deadline') int? get submissionDeadline;@JsonKey(name: 'application_deadline') int? get applicationDeadline;@JsonKey(name: 'submission_url') String? get submissionUrl;@JsonKey(name: 'country_code') String? get countryCode;@JsonKey(name: 'duration_unit') String? get durationUnit;@JsonKey(name: 'buyer_organization') Organization? get buyerOrganization; String? get status; /// Create a copy of TenderData /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -28,16 +28,16 @@ $TenderDataCopyWith get copyWith => _$TenderDataCopyWithImpl Object.hashAll([runtimeType,success,message,id,tenderId,noticePublicationId,publicationDate,title,description,procurementTypeCode,procedureCode,estimatedValue,currency,duration,durationUnit,tenderDeadline,submissionDeadline,applicationDeadline,submissionUrl,countryCode,buyerOrganization,status]); +int get hashCode => Object.hashAll([runtimeType,success,message,id,tenderId,noticePublicationId,publicationDate,title,description,procurementTypeCode,procedureCode,estimatedValue,currency,duration,tenderDeadline,submissionDeadline,applicationDeadline,submissionUrl,countryCode,durationUnit,buyerOrganization,status]); @override String toString() { - return 'TenderData(success: $success, message: $message, id: $id, tenderId: $tenderId, noticePublicationId: $noticePublicationId, publicationDate: $publicationDate, title: $title, description: $description, procurementTypeCode: $procurementTypeCode, procedureCode: $procedureCode, estimatedValue: $estimatedValue, currency: $currency, duration: $duration, durationUnit: $durationUnit, tenderDeadline: $tenderDeadline, submissionDeadline: $submissionDeadline, applicationDeadline: $applicationDeadline, submissionUrl: $submissionUrl, countryCode: $countryCode, buyerOrganization: $buyerOrganization, status: $status)'; + return 'TenderData(success: $success, message: $message, id: $id, tenderId: $tenderId, noticePublicationId: $noticePublicationId, publicationDate: $publicationDate, title: $title, description: $description, procurementTypeCode: $procurementTypeCode, procedureCode: $procedureCode, estimatedValue: $estimatedValue, currency: $currency, duration: $duration, tenderDeadline: $tenderDeadline, submissionDeadline: $submissionDeadline, applicationDeadline: $applicationDeadline, submissionUrl: $submissionUrl, countryCode: $countryCode, durationUnit: $durationUnit, buyerOrganization: $buyerOrganization, status: $status)'; } @@ -48,7 +48,7 @@ abstract mixin class $TenderDataCopyWith<$Res> { factory $TenderDataCopyWith(TenderData value, $Res Function(TenderData) _then) = _$TenderDataCopyWithImpl; @useResult $Res call({ - bool? success, String? message, String? id,@JsonKey(name: 'tender_id') String? tenderId,@JsonKey(name: 'notice_publication_id') String? noticePublicationId,@JsonKey(name: 'publication_date') int? publicationDate, String? title, String? description,@JsonKey(name: 'procurement_type_code') String? procurementTypeCode,@JsonKey(name: 'procedure_code') String? procedureCode,@JsonKey(name: 'estimated_value') int? estimatedValue, String? currency, String? duration, String? durationUnit,@JsonKey(name: 'tender_deadline') int? tenderDeadline,@JsonKey(name: 'submission_deadline') int? submissionDeadline,@JsonKey(name: 'application_deadline') int? applicationDeadline,@JsonKey(name: 'submission_url') String? submissionUrl,@JsonKey(name: 'country_code') String? countryCode,@JsonKey(name: 'buyer_organization') Organization? buyerOrganization, String? status + bool? success, String? message, String? id,@JsonKey(name: 'tender_id') String? tenderId,@JsonKey(name: 'notice_publication_id') String? noticePublicationId,@JsonKey(name: 'publication_date') int? publicationDate, String? title, String? description,@JsonKey(name: 'procurement_type_code') String? procurementTypeCode,@JsonKey(name: 'procedure_code') String? procedureCode,@JsonKey(name: 'estimated_value') int? estimatedValue, String? currency, String? duration,@JsonKey(name: 'tender_deadline') int? tenderDeadline,@JsonKey(name: 'submission_deadline') int? submissionDeadline,@JsonKey(name: 'application_deadline') int? applicationDeadline,@JsonKey(name: 'submission_url') String? submissionUrl,@JsonKey(name: 'country_code') String? countryCode,@JsonKey(name: 'duration_unit') String? durationUnit,@JsonKey(name: 'buyer_organization') Organization? buyerOrganization, String? status }); @@ -65,7 +65,7 @@ class _$TenderDataCopyWithImpl<$Res> /// Create a copy of TenderData /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? success = freezed,Object? message = freezed,Object? id = freezed,Object? tenderId = freezed,Object? noticePublicationId = freezed,Object? publicationDate = freezed,Object? title = freezed,Object? description = freezed,Object? procurementTypeCode = freezed,Object? procedureCode = freezed,Object? estimatedValue = freezed,Object? currency = freezed,Object? duration = freezed,Object? durationUnit = freezed,Object? tenderDeadline = freezed,Object? submissionDeadline = freezed,Object? applicationDeadline = freezed,Object? submissionUrl = freezed,Object? countryCode = freezed,Object? buyerOrganization = freezed,Object? status = freezed,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? success = freezed,Object? message = freezed,Object? id = freezed,Object? tenderId = freezed,Object? noticePublicationId = freezed,Object? publicationDate = freezed,Object? title = freezed,Object? description = freezed,Object? procurementTypeCode = freezed,Object? procedureCode = freezed,Object? estimatedValue = freezed,Object? currency = freezed,Object? duration = freezed,Object? tenderDeadline = freezed,Object? submissionDeadline = freezed,Object? applicationDeadline = freezed,Object? submissionUrl = freezed,Object? countryCode = freezed,Object? durationUnit = freezed,Object? buyerOrganization = freezed,Object? status = freezed,}) { return _then(_self.copyWith( success: freezed == success ? _self.success : success // ignore: cast_nullable_to_non_nullable as bool?,message: freezed == message ? _self.message : message // ignore: cast_nullable_to_non_nullable @@ -80,12 +80,12 @@ as String?,procedureCode: freezed == procedureCode ? _self.procedureCode : proce as String?,estimatedValue: freezed == estimatedValue ? _self.estimatedValue : estimatedValue // ignore: cast_nullable_to_non_nullable as int?,currency: freezed == currency ? _self.currency : currency // ignore: cast_nullable_to_non_nullable as String?,duration: freezed == duration ? _self.duration : duration // ignore: cast_nullable_to_non_nullable -as String?,durationUnit: freezed == durationUnit ? _self.durationUnit : durationUnit // ignore: cast_nullable_to_non_nullable as String?,tenderDeadline: freezed == tenderDeadline ? _self.tenderDeadline : tenderDeadline // ignore: cast_nullable_to_non_nullable as int?,submissionDeadline: freezed == submissionDeadline ? _self.submissionDeadline : submissionDeadline // ignore: cast_nullable_to_non_nullable as int?,applicationDeadline: freezed == applicationDeadline ? _self.applicationDeadline : applicationDeadline // ignore: cast_nullable_to_non_nullable as int?,submissionUrl: freezed == submissionUrl ? _self.submissionUrl : submissionUrl // ignore: cast_nullable_to_non_nullable as String?,countryCode: freezed == countryCode ? _self.countryCode : countryCode // ignore: cast_nullable_to_non_nullable +as String?,durationUnit: freezed == durationUnit ? _self.durationUnit : durationUnit // ignore: cast_nullable_to_non_nullable as String?,buyerOrganization: freezed == buyerOrganization ? _self.buyerOrganization : buyerOrganization // ignore: cast_nullable_to_non_nullable as Organization?,status: freezed == status ? _self.status : status // ignore: cast_nullable_to_non_nullable as String?, @@ -185,10 +185,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen(TResult Function( bool? success, String? message, String? id, @JsonKey(name: 'tender_id') String? tenderId, @JsonKey(name: 'notice_publication_id') String? noticePublicationId, @JsonKey(name: 'publication_date') int? publicationDate, String? title, String? description, @JsonKey(name: 'procurement_type_code') String? procurementTypeCode, @JsonKey(name: 'procedure_code') String? procedureCode, @JsonKey(name: 'estimated_value') int? estimatedValue, String? currency, String? duration, String? durationUnit, @JsonKey(name: 'tender_deadline') int? tenderDeadline, @JsonKey(name: 'submission_deadline') int? submissionDeadline, @JsonKey(name: 'application_deadline') int? applicationDeadline, @JsonKey(name: 'submission_url') String? submissionUrl, @JsonKey(name: 'country_code') String? countryCode, @JsonKey(name: 'buyer_organization') Organization? buyerOrganization, String? status)? $default,{required TResult orElse(),}) {final _that = this; +@optionalTypeArgs TResult maybeWhen(TResult Function( bool? success, String? message, String? id, @JsonKey(name: 'tender_id') String? tenderId, @JsonKey(name: 'notice_publication_id') String? noticePublicationId, @JsonKey(name: 'publication_date') int? publicationDate, String? title, String? description, @JsonKey(name: 'procurement_type_code') String? procurementTypeCode, @JsonKey(name: 'procedure_code') String? procedureCode, @JsonKey(name: 'estimated_value') int? estimatedValue, String? currency, String? duration, @JsonKey(name: 'tender_deadline') int? tenderDeadline, @JsonKey(name: 'submission_deadline') int? submissionDeadline, @JsonKey(name: 'application_deadline') int? applicationDeadline, @JsonKey(name: 'submission_url') String? submissionUrl, @JsonKey(name: 'country_code') String? countryCode, @JsonKey(name: 'duration_unit') String? durationUnit, @JsonKey(name: 'buyer_organization') Organization? buyerOrganization, String? status)? $default,{required TResult orElse(),}) {final _that = this; switch (_that) { case _TenderData() when $default != null: -return $default(_that.success,_that.message,_that.id,_that.tenderId,_that.noticePublicationId,_that.publicationDate,_that.title,_that.description,_that.procurementTypeCode,_that.procedureCode,_that.estimatedValue,_that.currency,_that.duration,_that.durationUnit,_that.tenderDeadline,_that.submissionDeadline,_that.applicationDeadline,_that.submissionUrl,_that.countryCode,_that.buyerOrganization,_that.status);case _: +return $default(_that.success,_that.message,_that.id,_that.tenderId,_that.noticePublicationId,_that.publicationDate,_that.title,_that.description,_that.procurementTypeCode,_that.procedureCode,_that.estimatedValue,_that.currency,_that.duration,_that.tenderDeadline,_that.submissionDeadline,_that.applicationDeadline,_that.submissionUrl,_that.countryCode,_that.durationUnit,_that.buyerOrganization,_that.status);case _: return orElse(); } @@ -206,10 +206,10 @@ return $default(_that.success,_that.message,_that.id,_that.tenderId,_that.notice /// } /// ``` -@optionalTypeArgs TResult when(TResult Function( bool? success, String? message, String? id, @JsonKey(name: 'tender_id') String? tenderId, @JsonKey(name: 'notice_publication_id') String? noticePublicationId, @JsonKey(name: 'publication_date') int? publicationDate, String? title, String? description, @JsonKey(name: 'procurement_type_code') String? procurementTypeCode, @JsonKey(name: 'procedure_code') String? procedureCode, @JsonKey(name: 'estimated_value') int? estimatedValue, String? currency, String? duration, String? durationUnit, @JsonKey(name: 'tender_deadline') int? tenderDeadline, @JsonKey(name: 'submission_deadline') int? submissionDeadline, @JsonKey(name: 'application_deadline') int? applicationDeadline, @JsonKey(name: 'submission_url') String? submissionUrl, @JsonKey(name: 'country_code') String? countryCode, @JsonKey(name: 'buyer_organization') Organization? buyerOrganization, String? status) $default,) {final _that = this; +@optionalTypeArgs TResult when(TResult Function( bool? success, String? message, String? id, @JsonKey(name: 'tender_id') String? tenderId, @JsonKey(name: 'notice_publication_id') String? noticePublicationId, @JsonKey(name: 'publication_date') int? publicationDate, String? title, String? description, @JsonKey(name: 'procurement_type_code') String? procurementTypeCode, @JsonKey(name: 'procedure_code') String? procedureCode, @JsonKey(name: 'estimated_value') int? estimatedValue, String? currency, String? duration, @JsonKey(name: 'tender_deadline') int? tenderDeadline, @JsonKey(name: 'submission_deadline') int? submissionDeadline, @JsonKey(name: 'application_deadline') int? applicationDeadline, @JsonKey(name: 'submission_url') String? submissionUrl, @JsonKey(name: 'country_code') String? countryCode, @JsonKey(name: 'duration_unit') String? durationUnit, @JsonKey(name: 'buyer_organization') Organization? buyerOrganization, String? status) $default,) {final _that = this; switch (_that) { case _TenderData(): -return $default(_that.success,_that.message,_that.id,_that.tenderId,_that.noticePublicationId,_that.publicationDate,_that.title,_that.description,_that.procurementTypeCode,_that.procedureCode,_that.estimatedValue,_that.currency,_that.duration,_that.durationUnit,_that.tenderDeadline,_that.submissionDeadline,_that.applicationDeadline,_that.submissionUrl,_that.countryCode,_that.buyerOrganization,_that.status);case _: +return $default(_that.success,_that.message,_that.id,_that.tenderId,_that.noticePublicationId,_that.publicationDate,_that.title,_that.description,_that.procurementTypeCode,_that.procedureCode,_that.estimatedValue,_that.currency,_that.duration,_that.tenderDeadline,_that.submissionDeadline,_that.applicationDeadline,_that.submissionUrl,_that.countryCode,_that.durationUnit,_that.buyerOrganization,_that.status);case _: throw StateError('Unexpected subclass'); } @@ -226,10 +226,10 @@ return $default(_that.success,_that.message,_that.id,_that.tenderId,_that.notice /// } /// ``` -@optionalTypeArgs TResult? whenOrNull(TResult? Function( bool? success, String? message, String? id, @JsonKey(name: 'tender_id') String? tenderId, @JsonKey(name: 'notice_publication_id') String? noticePublicationId, @JsonKey(name: 'publication_date') int? publicationDate, String? title, String? description, @JsonKey(name: 'procurement_type_code') String? procurementTypeCode, @JsonKey(name: 'procedure_code') String? procedureCode, @JsonKey(name: 'estimated_value') int? estimatedValue, String? currency, String? duration, String? durationUnit, @JsonKey(name: 'tender_deadline') int? tenderDeadline, @JsonKey(name: 'submission_deadline') int? submissionDeadline, @JsonKey(name: 'application_deadline') int? applicationDeadline, @JsonKey(name: 'submission_url') String? submissionUrl, @JsonKey(name: 'country_code') String? countryCode, @JsonKey(name: 'buyer_organization') Organization? buyerOrganization, String? status)? $default,) {final _that = this; +@optionalTypeArgs TResult? whenOrNull(TResult? Function( bool? success, String? message, String? id, @JsonKey(name: 'tender_id') String? tenderId, @JsonKey(name: 'notice_publication_id') String? noticePublicationId, @JsonKey(name: 'publication_date') int? publicationDate, String? title, String? description, @JsonKey(name: 'procurement_type_code') String? procurementTypeCode, @JsonKey(name: 'procedure_code') String? procedureCode, @JsonKey(name: 'estimated_value') int? estimatedValue, String? currency, String? duration, @JsonKey(name: 'tender_deadline') int? tenderDeadline, @JsonKey(name: 'submission_deadline') int? submissionDeadline, @JsonKey(name: 'application_deadline') int? applicationDeadline, @JsonKey(name: 'submission_url') String? submissionUrl, @JsonKey(name: 'country_code') String? countryCode, @JsonKey(name: 'duration_unit') String? durationUnit, @JsonKey(name: 'buyer_organization') Organization? buyerOrganization, String? status)? $default,) {final _that = this; switch (_that) { case _TenderData() when $default != null: -return $default(_that.success,_that.message,_that.id,_that.tenderId,_that.noticePublicationId,_that.publicationDate,_that.title,_that.description,_that.procurementTypeCode,_that.procedureCode,_that.estimatedValue,_that.currency,_that.duration,_that.durationUnit,_that.tenderDeadline,_that.submissionDeadline,_that.applicationDeadline,_that.submissionUrl,_that.countryCode,_that.buyerOrganization,_that.status);case _: +return $default(_that.success,_that.message,_that.id,_that.tenderId,_that.noticePublicationId,_that.publicationDate,_that.title,_that.description,_that.procurementTypeCode,_that.procedureCode,_that.estimatedValue,_that.currency,_that.duration,_that.tenderDeadline,_that.submissionDeadline,_that.applicationDeadline,_that.submissionUrl,_that.countryCode,_that.durationUnit,_that.buyerOrganization,_that.status);case _: return null; } @@ -241,7 +241,7 @@ return $default(_that.success,_that.message,_that.id,_that.tenderId,_that.notice @JsonSerializable() class _TenderData implements TenderData { - const _TenderData({required this.success, required this.message, required this.id, @JsonKey(name: 'tender_id') required this.tenderId, @JsonKey(name: 'notice_publication_id') required this.noticePublicationId, @JsonKey(name: 'publication_date') required this.publicationDate, required this.title, required this.description, @JsonKey(name: 'procurement_type_code') required this.procurementTypeCode, @JsonKey(name: 'procedure_code') required this.procedureCode, @JsonKey(name: 'estimated_value') required this.estimatedValue, required this.currency, required this.duration, required this.durationUnit, @JsonKey(name: 'tender_deadline') required this.tenderDeadline, @JsonKey(name: 'submission_deadline') required this.submissionDeadline, @JsonKey(name: 'application_deadline') required this.applicationDeadline, @JsonKey(name: 'submission_url') required this.submissionUrl, @JsonKey(name: 'country_code') required this.countryCode, @JsonKey(name: 'buyer_organization') required this.buyerOrganization, required this.status}); + const _TenderData({required this.success, required this.message, required this.id, @JsonKey(name: 'tender_id') required this.tenderId, @JsonKey(name: 'notice_publication_id') required this.noticePublicationId, @JsonKey(name: 'publication_date') required this.publicationDate, required this.title, required this.description, @JsonKey(name: 'procurement_type_code') required this.procurementTypeCode, @JsonKey(name: 'procedure_code') required this.procedureCode, @JsonKey(name: 'estimated_value') required this.estimatedValue, required this.currency, required this.duration, @JsonKey(name: 'tender_deadline') required this.tenderDeadline, @JsonKey(name: 'submission_deadline') required this.submissionDeadline, @JsonKey(name: 'application_deadline') required this.applicationDeadline, @JsonKey(name: 'submission_url') required this.submissionUrl, @JsonKey(name: 'country_code') required this.countryCode, @JsonKey(name: 'duration_unit') required this.durationUnit, @JsonKey(name: 'buyer_organization') required this.buyerOrganization, required this.status}); factory _TenderData.fromJson(Map json) => _$TenderDataFromJson(json); @override final bool? success; @@ -257,12 +257,12 @@ class _TenderData implements TenderData { @override@JsonKey(name: 'estimated_value') final int? estimatedValue; @override final String? currency; @override final String? duration; -@override final String? durationUnit; @override@JsonKey(name: 'tender_deadline') final int? tenderDeadline; @override@JsonKey(name: 'submission_deadline') final int? submissionDeadline; @override@JsonKey(name: 'application_deadline') final int? applicationDeadline; @override@JsonKey(name: 'submission_url') final String? submissionUrl; @override@JsonKey(name: 'country_code') final String? countryCode; +@override@JsonKey(name: 'duration_unit') final String? durationUnit; @override@JsonKey(name: 'buyer_organization') final Organization? buyerOrganization; @override final String? status; @@ -279,16 +279,16 @@ Map toJson() { @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _TenderData&&(identical(other.success, success) || other.success == success)&&(identical(other.message, message) || other.message == message)&&(identical(other.id, id) || other.id == id)&&(identical(other.tenderId, tenderId) || other.tenderId == tenderId)&&(identical(other.noticePublicationId, noticePublicationId) || other.noticePublicationId == noticePublicationId)&&(identical(other.publicationDate, publicationDate) || other.publicationDate == publicationDate)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.procurementTypeCode, procurementTypeCode) || other.procurementTypeCode == procurementTypeCode)&&(identical(other.procedureCode, procedureCode) || other.procedureCode == procedureCode)&&(identical(other.estimatedValue, estimatedValue) || other.estimatedValue == estimatedValue)&&(identical(other.currency, currency) || other.currency == currency)&&(identical(other.duration, duration) || other.duration == duration)&&(identical(other.durationUnit, durationUnit) || other.durationUnit == durationUnit)&&(identical(other.tenderDeadline, tenderDeadline) || other.tenderDeadline == tenderDeadline)&&(identical(other.submissionDeadline, submissionDeadline) || other.submissionDeadline == submissionDeadline)&&(identical(other.applicationDeadline, applicationDeadline) || other.applicationDeadline == applicationDeadline)&&(identical(other.submissionUrl, submissionUrl) || other.submissionUrl == submissionUrl)&&(identical(other.countryCode, countryCode) || other.countryCode == countryCode)&&(identical(other.buyerOrganization, buyerOrganization) || other.buyerOrganization == buyerOrganization)&&(identical(other.status, status) || other.status == status)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _TenderData&&(identical(other.success, success) || other.success == success)&&(identical(other.message, message) || other.message == message)&&(identical(other.id, id) || other.id == id)&&(identical(other.tenderId, tenderId) || other.tenderId == tenderId)&&(identical(other.noticePublicationId, noticePublicationId) || other.noticePublicationId == noticePublicationId)&&(identical(other.publicationDate, publicationDate) || other.publicationDate == publicationDate)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.procurementTypeCode, procurementTypeCode) || other.procurementTypeCode == procurementTypeCode)&&(identical(other.procedureCode, procedureCode) || other.procedureCode == procedureCode)&&(identical(other.estimatedValue, estimatedValue) || other.estimatedValue == estimatedValue)&&(identical(other.currency, currency) || other.currency == currency)&&(identical(other.duration, duration) || other.duration == duration)&&(identical(other.tenderDeadline, tenderDeadline) || other.tenderDeadline == tenderDeadline)&&(identical(other.submissionDeadline, submissionDeadline) || other.submissionDeadline == submissionDeadline)&&(identical(other.applicationDeadline, applicationDeadline) || other.applicationDeadline == applicationDeadline)&&(identical(other.submissionUrl, submissionUrl) || other.submissionUrl == submissionUrl)&&(identical(other.countryCode, countryCode) || other.countryCode == countryCode)&&(identical(other.durationUnit, durationUnit) || other.durationUnit == durationUnit)&&(identical(other.buyerOrganization, buyerOrganization) || other.buyerOrganization == buyerOrganization)&&(identical(other.status, status) || other.status == status)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hashAll([runtimeType,success,message,id,tenderId,noticePublicationId,publicationDate,title,description,procurementTypeCode,procedureCode,estimatedValue,currency,duration,durationUnit,tenderDeadline,submissionDeadline,applicationDeadline,submissionUrl,countryCode,buyerOrganization,status]); +int get hashCode => Object.hashAll([runtimeType,success,message,id,tenderId,noticePublicationId,publicationDate,title,description,procurementTypeCode,procedureCode,estimatedValue,currency,duration,tenderDeadline,submissionDeadline,applicationDeadline,submissionUrl,countryCode,durationUnit,buyerOrganization,status]); @override String toString() { - return 'TenderData(success: $success, message: $message, id: $id, tenderId: $tenderId, noticePublicationId: $noticePublicationId, publicationDate: $publicationDate, title: $title, description: $description, procurementTypeCode: $procurementTypeCode, procedureCode: $procedureCode, estimatedValue: $estimatedValue, currency: $currency, duration: $duration, durationUnit: $durationUnit, tenderDeadline: $tenderDeadline, submissionDeadline: $submissionDeadline, applicationDeadline: $applicationDeadline, submissionUrl: $submissionUrl, countryCode: $countryCode, buyerOrganization: $buyerOrganization, status: $status)'; + return 'TenderData(success: $success, message: $message, id: $id, tenderId: $tenderId, noticePublicationId: $noticePublicationId, publicationDate: $publicationDate, title: $title, description: $description, procurementTypeCode: $procurementTypeCode, procedureCode: $procedureCode, estimatedValue: $estimatedValue, currency: $currency, duration: $duration, tenderDeadline: $tenderDeadline, submissionDeadline: $submissionDeadline, applicationDeadline: $applicationDeadline, submissionUrl: $submissionUrl, countryCode: $countryCode, durationUnit: $durationUnit, buyerOrganization: $buyerOrganization, status: $status)'; } @@ -299,7 +299,7 @@ abstract mixin class _$TenderDataCopyWith<$Res> implements $TenderDataCopyWith<$ factory _$TenderDataCopyWith(_TenderData value, $Res Function(_TenderData) _then) = __$TenderDataCopyWithImpl; @override @useResult $Res call({ - bool? success, String? message, String? id,@JsonKey(name: 'tender_id') String? tenderId,@JsonKey(name: 'notice_publication_id') String? noticePublicationId,@JsonKey(name: 'publication_date') int? publicationDate, String? title, String? description,@JsonKey(name: 'procurement_type_code') String? procurementTypeCode,@JsonKey(name: 'procedure_code') String? procedureCode,@JsonKey(name: 'estimated_value') int? estimatedValue, String? currency, String? duration, String? durationUnit,@JsonKey(name: 'tender_deadline') int? tenderDeadline,@JsonKey(name: 'submission_deadline') int? submissionDeadline,@JsonKey(name: 'application_deadline') int? applicationDeadline,@JsonKey(name: 'submission_url') String? submissionUrl,@JsonKey(name: 'country_code') String? countryCode,@JsonKey(name: 'buyer_organization') Organization? buyerOrganization, String? status + bool? success, String? message, String? id,@JsonKey(name: 'tender_id') String? tenderId,@JsonKey(name: 'notice_publication_id') String? noticePublicationId,@JsonKey(name: 'publication_date') int? publicationDate, String? title, String? description,@JsonKey(name: 'procurement_type_code') String? procurementTypeCode,@JsonKey(name: 'procedure_code') String? procedureCode,@JsonKey(name: 'estimated_value') int? estimatedValue, String? currency, String? duration,@JsonKey(name: 'tender_deadline') int? tenderDeadline,@JsonKey(name: 'submission_deadline') int? submissionDeadline,@JsonKey(name: 'application_deadline') int? applicationDeadline,@JsonKey(name: 'submission_url') String? submissionUrl,@JsonKey(name: 'country_code') String? countryCode,@JsonKey(name: 'duration_unit') String? durationUnit,@JsonKey(name: 'buyer_organization') Organization? buyerOrganization, String? status }); @@ -316,7 +316,7 @@ class __$TenderDataCopyWithImpl<$Res> /// Create a copy of TenderData /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? success = freezed,Object? message = freezed,Object? id = freezed,Object? tenderId = freezed,Object? noticePublicationId = freezed,Object? publicationDate = freezed,Object? title = freezed,Object? description = freezed,Object? procurementTypeCode = freezed,Object? procedureCode = freezed,Object? estimatedValue = freezed,Object? currency = freezed,Object? duration = freezed,Object? durationUnit = freezed,Object? tenderDeadline = freezed,Object? submissionDeadline = freezed,Object? applicationDeadline = freezed,Object? submissionUrl = freezed,Object? countryCode = freezed,Object? buyerOrganization = freezed,Object? status = freezed,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? success = freezed,Object? message = freezed,Object? id = freezed,Object? tenderId = freezed,Object? noticePublicationId = freezed,Object? publicationDate = freezed,Object? title = freezed,Object? description = freezed,Object? procurementTypeCode = freezed,Object? procedureCode = freezed,Object? estimatedValue = freezed,Object? currency = freezed,Object? duration = freezed,Object? tenderDeadline = freezed,Object? submissionDeadline = freezed,Object? applicationDeadline = freezed,Object? submissionUrl = freezed,Object? countryCode = freezed,Object? durationUnit = freezed,Object? buyerOrganization = freezed,Object? status = freezed,}) { return _then(_TenderData( success: freezed == success ? _self.success : success // ignore: cast_nullable_to_non_nullable as bool?,message: freezed == message ? _self.message : message // ignore: cast_nullable_to_non_nullable @@ -331,12 +331,12 @@ as String?,procedureCode: freezed == procedureCode ? _self.procedureCode : proce as String?,estimatedValue: freezed == estimatedValue ? _self.estimatedValue : estimatedValue // ignore: cast_nullable_to_non_nullable as int?,currency: freezed == currency ? _self.currency : currency // ignore: cast_nullable_to_non_nullable as String?,duration: freezed == duration ? _self.duration : duration // ignore: cast_nullable_to_non_nullable -as String?,durationUnit: freezed == durationUnit ? _self.durationUnit : durationUnit // ignore: cast_nullable_to_non_nullable as String?,tenderDeadline: freezed == tenderDeadline ? _self.tenderDeadline : tenderDeadline // ignore: cast_nullable_to_non_nullable as int?,submissionDeadline: freezed == submissionDeadline ? _self.submissionDeadline : submissionDeadline // ignore: cast_nullable_to_non_nullable as int?,applicationDeadline: freezed == applicationDeadline ? _self.applicationDeadline : applicationDeadline // ignore: cast_nullable_to_non_nullable as int?,submissionUrl: freezed == submissionUrl ? _self.submissionUrl : submissionUrl // ignore: cast_nullable_to_non_nullable as String?,countryCode: freezed == countryCode ? _self.countryCode : countryCode // ignore: cast_nullable_to_non_nullable +as String?,durationUnit: freezed == durationUnit ? _self.durationUnit : durationUnit // ignore: cast_nullable_to_non_nullable as String?,buyerOrganization: freezed == buyerOrganization ? _self.buyerOrganization : buyerOrganization // ignore: cast_nullable_to_non_nullable as Organization?,status: freezed == status ? _self.status : status // ignore: cast_nullable_to_non_nullable as String?, diff --git a/lib/data/services/model/tender_data/tender_data.g.dart b/lib/data/services/model/tender_data/tender_data.g.dart index 5b59940..68b9b62 100644 --- a/lib/data/services/model/tender_data/tender_data.g.dart +++ b/lib/data/services/model/tender_data/tender_data.g.dart @@ -20,12 +20,12 @@ _TenderData _$TenderDataFromJson(Map json) => _TenderData( estimatedValue: (json['estimated_value'] as num?)?.toInt(), currency: json['currency'] as String?, duration: json['duration'] as String?, - durationUnit: json['durationUnit'] as String?, tenderDeadline: (json['tender_deadline'] as num?)?.toInt(), submissionDeadline: (json['submission_deadline'] as num?)?.toInt(), applicationDeadline: (json['application_deadline'] as num?)?.toInt(), submissionUrl: json['submission_url'] as String?, countryCode: json['country_code'] as String?, + durationUnit: json['duration_unit'] as String?, buyerOrganization: json['buyer_organization'] == null ? null @@ -50,12 +50,12 @@ Map _$TenderDataToJson(_TenderData instance) => 'estimated_value': instance.estimatedValue, 'currency': instance.currency, 'duration': instance.duration, - 'durationUnit': instance.durationUnit, 'tender_deadline': instance.tenderDeadline, 'submission_deadline': instance.submissionDeadline, 'application_deadline': instance.applicationDeadline, 'submission_url': instance.submissionUrl, 'country_code': instance.countryCode, + 'duration_unit': instance.durationUnit, 'buyer_organization': instance.buyerOrganization, 'status': instance.status, }; diff --git a/lib/views/detail/widgets/tender_detail_header.dart b/lib/views/detail/widgets/tender_detail_header.dart index 6f2945a..a216068 100644 --- a/lib/views/detail/widgets/tender_detail_header.dart +++ b/lib/views/detail/widgets/tender_detail_header.dart @@ -57,7 +57,7 @@ class TenderDetailHeader extends StatelessWidget { ), ), StatusTag( - text: detail.status ?? '', + text: detail.procurementTypeCode ?? '', textColor: AppColors.cyanTeal, backgroundColor: AppColors.cyanAqua, ), diff --git a/lib/views/detail/widgets/tender_detail_info_section.dart b/lib/views/detail/widgets/tender_detail_info_section.dart index cebcc4a..7dee5e4 100644 --- a/lib/views/detail/widgets/tender_detail_info_section.dart +++ b/lib/views/detail/widgets/tender_detail_info_section.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; import 'package:tm_app/core/constants/strings.dart'; import 'package:tm_app/data/services/model/tender_data/tender_data.dart'; import 'package:tm_app/views/detail/widgets/deadline_item.dart'; @@ -19,13 +20,13 @@ class TenderDetailInfoSection extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - InfoItem(title: AppStrings.tenderIdLabel, value: detail.id ?? ''), + InfoItem(title: AppStrings.tenderIdLabel, value: detail.tenderId ?? ''), DeadlineItem( title: AppStrings.tenderDeadlineLabel, approvalText: AppStrings.tenderApprovalText, - approvalDate: '', + approvalDate: unixToDate(detail.submissionDeadline), submissionText: AppStrings.tenderSubmissionText, - submissionDate: '', + submissionDate: unixToDate(detail.applicationDeadline), isScreenBig: isScreenBig, ), InfoItem( @@ -33,8 +34,12 @@ class TenderDetailInfoSection extends StatelessWidget { value: detail.buyerOrganization!.name ?? '', ), InfoItem( - title: AppStrings.tenderDeliveryLocationsLabel, - value: detail.countryCode ?? '', + title: AppStrings.estimatedValue, + value: '${detail.estimatedValue} ${detail.currency ?? ''}', + ), + InfoItem( + title: AppStrings.duration, + value: '${detail.duration} ${detail.durationUnit ?? ''}', ), InfoItem( title: AppStrings.tenderReferenceNumberLabel, @@ -44,3 +49,16 @@ class TenderDetailInfoSection extends StatelessWidget { ); } } + +String unixToDate(int? unixTimestamp, {String format = 'yyyy-MM-dd'}) { + if (unixTimestamp == null) { + return ''; + } + + // Convert seconds to milliseconds if needed + int timestampInMs = + unixTimestamp > 1000000000000 ? unixTimestamp : unixTimestamp * 1000; + + final DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(timestampInMs); + return DateFormat(format).format(dateTime); +} diff --git a/lib/views/home/pages/t_home_page.dart b/lib/views/home/pages/t_home_page.dart index 6ff7415..d76a7dd 100644 --- a/lib/views/home/pages/t_home_page.dart +++ b/lib/views/home/pages/t_home_page.dart @@ -1,4 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import 'package:tm_app/core/constants/strings.dart'; import 'package:tm_app/core/routes/app_routes.dart'; @@ -7,7 +9,9 @@ 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/data/services/model/tender_approvals_state_response/tender_approvals_state_response.dart'; import 'package:tm_app/view_models/home_view_model.dart'; +import 'package:tm_app/views/shared/tablet_navigation_widget.dart'; +import '../../../core/constants/assets.dart'; import '../widgets.dart'; class TabletHomePage extends StatelessWidget { @@ -15,7 +19,57 @@ class TabletHomePage extends StatelessWidget { @override Widget build(BuildContext context) { + final GlobalKey key = GlobalKey(); + return Scaffold( + key: key, + + appBar: PreferredSize( + preferredSize: const Size.fromHeight(64), + child: AppBar( + backgroundColor: AppColors.backgroundColor, + elevation: 0, + titleSpacing: 0, + leading: Padding( + padding: EdgeInsetsDirectional.only(start: 24.0.w()), + child: SvgPicture.asset(AssetsManager.logoSmall), + ), + actions: [ + IconButton( + icon: Padding( + padding: EdgeInsetsDirectional.only(end: 24.0.w()), + child: SvgPicture.asset( + AssetsManager.menu, + height: 32.0.w(), + width: 32.0.w(), + ), + ), + onPressed: () => key.currentState!.openDrawer(), + ), + ], + ), + ), + drawer: TabletNavigationWidget( + currentIndex: 0, // Home is index 0 + onTabChanged: (index) { + // Handle navigation to other tabs + switch (index) { + case 0: + // Already on home + break; + case 1: + // Navigate to tenders + context.pop(); + Router.neglect(context, () => context.go('/tenders')); + break; + case 2: + // Navigate to profile + context.pop(); + Router.neglect(context, () => context.go('/profile')); + break; + } + }, + ), body: Consumer( builder: (context, homeViewModel, child) { if (homeViewModel.isLoading) { @@ -32,7 +86,7 @@ class TabletHomePage extends StatelessWidget { child: Padding( padding: EdgeInsetsDirectional.fromSTEB( 24.0.w(), - 120.0.h(), + 24.0.h(), 24.0.w(), 24.0.h(), ), diff --git a/lib/views/login/pages/login_mobile_page.dart b/lib/views/login/pages/login_mobile_page.dart index 5234bc5..0981c1d 100644 --- a/lib/views/login/pages/login_mobile_page.dart +++ b/lib/views/login/pages/login_mobile_page.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; -import 'package:tm_app/core/routes/app_routes.dart'; import 'package:tm_app/core/theme/colors.dart'; import '../../../core/constants/assets.dart'; @@ -28,7 +28,7 @@ class _LoginMobilePageState extends State { void _viewModelListener() { if (viewModel.loggedInUser != null) { - HomeRouteData().go(context); + Router.neglect(context, () => context.go('/home')); } if (viewModel.errorMessage != null) { ScaffoldMessenger.of( diff --git a/lib/views/login/pages/login_tablet_page.dart b/lib/views/login/pages/login_tablet_page.dart index 2c32465..ca37a9d 100644 --- a/lib/views/login/pages/login_tablet_page.dart +++ b/lib/views/login/pages/login_tablet_page.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; -import 'package:tm_app/core/routes/app_routes.dart'; import 'package:tm_app/core/theme/colors.dart'; import '../../../core/constants/assets.dart'; @@ -28,12 +28,12 @@ class _LoginTabletPageState extends State { void _viewModelListener() { if (viewModel.loggedInUser != null) { - HomeRouteData().go(context); + Router.neglect(context, () => context.go('/home')); } if (viewModel.errorMessage != null) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(viewModel.errorMessage!)), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(viewModel.errorMessage!))); } } @@ -94,11 +94,12 @@ class _LoginTabletPageState extends State { else BaseButton( isEnabled: viewModel.isLoginEnabled, - onPressed: viewModel.isLoginEnabled - ? () async { - await viewModel.login(); - } - : null, + onPressed: + viewModel.isLoginEnabled + ? () async { + await viewModel.login(); + } + : null, ), ], ); diff --git a/lib/views/profile/pages/d_profile_page.dart b/lib/views/profile/pages/d_profile_page.dart index 965d66b..85192c2 100644 --- a/lib/views/profile/pages/d_profile_page.dart +++ b/lib/views/profile/pages/d_profile_page.dart @@ -51,145 +51,139 @@ class _DesktopProfilePageState extends State { @override Widget build(BuildContext context) { - return SafeArea( - child: Scaffold( - backgroundColor: AppColors.backgroundColor, - body: Consumer( - builder: (context, viewModel, child) { - if (viewModel.isLoading) { - return Center( - child: CircularProgressIndicator(color: AppColors.secondary50), - ); - } - if (viewModel.errorMessage != null) { - return Center(child: Text(viewModel.errorMessage!)); - } - - return Column( - children: [ - DesktopNavigationWidget( - currentIndex: 2, // Tenders index - onTabChanged: (index) { - // Navigate to different screens based on index - switch (index) { - case 0: - // Navigate to home - Router.neglect(context, () => context.go('/home')); - break; - case 1: - // Navigate to profile - Router.neglect(context, () => context.go('/tenders')); - break; - case 2: - // Already on profile - - break; - } - }, - ), - SizedBox( - // color: Colors.amber.shade100, - width: 740, - // height: 662, - child: Column( - children: [ - SizedBox(height: 36.0.h()), - TitleDescription( - title: 'Company Name', - description: viewModel.companyProfileData!.name!, - ), - TitleDescription( - title: 'National ID', - description: viewModel.companyProfileData!.id!, - ), - TitleDescription( - title: 'Registration No.', - description: - viewModel.companyProfileData!.registrationNumber!, - ), - TitleDescription( - title: 'Business Type', - description: '-', - ), - TitleDescription( - title: 'Founded', - description: - viewModel.companyProfileData!.foundedYear! - .toString(), - ), - SizedBox(height: 24.0.h()), - // Theme Toggle - Align( - alignment: AlignmentDirectional.centerStart, - child: Text( - AppStrings.settings, - style: TextStyle( - fontSize: 20.0.sp(), - fontWeight: FontWeight.w600, - color: AppColors.grey70, - ), - ), - ), - SizedBox(height: 36.0.h()), - Padding( - padding: EdgeInsets.symmetric(horizontal: 8.0.w()), - child: Row( - children: [ - Text( - AppStrings.appTheme, - style: TextStyle( - fontSize: 16.0.sp(), - fontWeight: FontWeight.w400, - color: AppColors.grey70, - ), - ), - Spacer(), - SvgPicture.asset(AssetsManager.sun), - SizedBox(width: 12.0.w()), - SizedBox( - width: 52.0.w(), - height: 32.0.h(), - child: ThemeToggle(), - ), - SizedBox(width: 12.0.w()), - SvgPicture.asset(AssetsManager.moon), - ], - ), - ), - SizedBox(height: 24.0.h()), - Divider(color: AppColors.dividerColor, thickness: 1), - SizedBox(height: 24.0.h()), - // Spacer(), - Align( - alignment: Alignment.centerRight, - child: InkWell( - onTap: () => viewModel.logout(), - child: Container( - width: 156, - height: 56.0.h(), - decoration: BoxDecoration( - color: AppColors.primary20, - borderRadius: BorderRadius.circular(100), - ), - alignment: Alignment.center, - child: Text( - 'Logout', - style: TextStyle( - fontSize: 14.0.sp(), - fontWeight: FontWeight.w500, - color: AppColors.primaryColor, - ), - ), - ), - ), - ), - ], - ), - ), - ], + return Scaffold( + backgroundColor: AppColors.backgroundColor, + body: Consumer( + builder: (context, viewModel, child) { + if (viewModel.isLoading) { + return Center( + child: CircularProgressIndicator(color: AppColors.secondary50), ); - }, - ), + } + if (viewModel.errorMessage != null) { + return Center(child: Text(viewModel.errorMessage!)); + } + + return Column( + children: [ + DesktopNavigationWidget( + currentIndex: 2, // Tenders index + onTabChanged: (index) { + // Navigate to different screens based on index + switch (index) { + case 0: + // Navigate to home + Router.neglect(context, () => context.go('/home')); + break; + case 1: + // Navigate to profile + Router.neglect(context, () => context.go('/tenders')); + break; + case 2: + // Already on profile + + break; + } + }, + ), + SizedBox( + // color: Colors.amber.shade100, + width: 740, + // height: 662, + child: Column( + children: [ + SizedBox(height: 36.0.h()), + TitleDescription( + title: 'Company Name', + description: viewModel.companyProfileData!.name!, + ), + TitleDescription( + title: 'National ID', + description: viewModel.companyProfileData!.id!, + ), + TitleDescription( + title: 'Registration No.', + description: + viewModel.companyProfileData!.registrationNumber!, + ), + TitleDescription(title: 'Business Type', description: '-'), + TitleDescription( + title: 'Founded', + description: + viewModel.companyProfileData!.foundedYear!.toString(), + ), + SizedBox(height: 24.0.h()), + // Theme Toggle + Align( + alignment: AlignmentDirectional.centerStart, + child: Text( + AppStrings.settings, + style: TextStyle( + fontSize: 20.0.sp(), + fontWeight: FontWeight.w600, + color: AppColors.grey70, + ), + ), + ), + SizedBox(height: 36.0.h()), + Padding( + padding: EdgeInsets.symmetric(horizontal: 8.0.w()), + child: Row( + children: [ + Text( + AppStrings.appTheme, + style: TextStyle( + fontSize: 16.0.sp(), + fontWeight: FontWeight.w400, + color: AppColors.grey70, + ), + ), + Spacer(), + SvgPicture.asset(AssetsManager.sun), + SizedBox(width: 12.0.w()), + SizedBox( + width: 52.0.w(), + height: 32.0.h(), + child: ThemeToggle(), + ), + SizedBox(width: 12.0.w()), + SvgPicture.asset(AssetsManager.moon), + ], + ), + ), + SizedBox(height: 24.0.h()), + Divider(color: AppColors.dividerColor, thickness: 1), + SizedBox(height: 24.0.h()), + // Spacer(), + Align( + alignment: Alignment.centerRight, + child: InkWell( + onTap: () => viewModel.logout(), + child: Container( + width: 156, + height: 56.0.h(), + decoration: BoxDecoration( + color: AppColors.primary20, + borderRadius: BorderRadius.circular(100), + ), + alignment: Alignment.center, + child: Text( + 'Logout', + style: TextStyle( + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + color: AppColors.primaryColor, + ), + ), + ), + ), + ), + ], + ), + ), + ], + ); + }, ), ); } diff --git a/lib/views/profile/pages/t_profile_page.dart b/lib/views/profile/pages/t_profile_page.dart index 90fa97e..1759a41 100644 --- a/lib/views/profile/pages/t_profile_page.dart +++ b/lib/views/profile/pages/t_profile_page.dart @@ -1,13 +1,16 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:go_router/go_router.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/view_models/home_view_model.dart'; import 'package:tm_app/view_models/profile_view_model.dart'; import '../../../core/theme/colors.dart'; import '../../../core/utils/size_config.dart'; +import '../../shared/tablet_navigation_widget.dart'; import '../widgets/theme_toggle.dart'; import '../widgets/title_description.dart'; @@ -49,6 +52,7 @@ class _TabletProfilePageState extends State { @override Widget build(BuildContext context) { + final GlobalKey key = GlobalKey(); return Consumer( builder: (context, viewModel, child) { if (viewModel.isLoading) { @@ -62,7 +66,49 @@ class _TabletProfilePageState extends State { return SafeArea( child: Scaffold( + key: key, backgroundColor: AppColors.backgroundColor, + appBar: PreferredSize( + preferredSize: const Size.fromHeight(64), + child: AppBar( + backgroundColor: AppColors.backgroundColor, + elevation: 0, + titleSpacing: 0, + leading: Padding( + padding: EdgeInsetsDirectional.only(start: 24.0.w()), + child: SvgPicture.asset(AssetsManager.logoSmall), + ), + actions: [ + IconButton( + icon: Padding( + padding: EdgeInsetsDirectional.only(end: 24.0.w()), + child: SvgPicture.asset( + AssetsManager.menu, + height: 32.0.w(), + width: 32.0.w(), + ), + ), + onPressed: () => key.currentState!.openDrawer(), + ), + ], + ), + ), + drawer: TabletNavigationWidget( + currentIndex: 2, + onTabChanged: (index) { + switch (index) { + case 0: + context.pop(); + Router.neglect(context, () => context.go('/home')); + context.read().init(); + break; + case 1: + context.pop(); + Router.neglect(context, () => context.go('/tenders')); + break; + } + }, + ), body: Padding( padding: EdgeInsets.symmetric( horizontal: 24.0.w(), diff --git a/lib/views/shared/tablet_navigation_widget.dart b/lib/views/shared/tablet_navigation_widget.dart new file mode 100644 index 0000000..ef733ba --- /dev/null +++ b/lib/views/shared/tablet_navigation_widget.dart @@ -0,0 +1,98 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:tm_app/core/constants/assets.dart'; +import 'package:tm_app/core/constants/strings.dart'; +import 'package:tm_app/core/theme/colors.dart'; +import 'package:tm_app/core/utils/size_config.dart'; + +class TabletNavigationWidget extends StatelessWidget { + const TabletNavigationWidget({ + required this.currentIndex, + required this.onTabChanged, + super.key, + }); + + final int currentIndex; + final ValueChanged onTabChanged; + + @override + Widget build(BuildContext context) { + return Container( + width: 200.0.w(), + height: double.infinity, + color: AppColors.backgroundColor, + child: Column( + children: [ + SizedBox(height: 48.0.h()), + _navigationItem( + context: context, + text: AppStrings.home, + isActive: currentIndex == 0, + onTap: () => onTabChanged(0), + iconPath: AssetsManager.home, + activeIconPath: AssetsManager.homeActive, + ), + _navigationItem( + context: context, + text: AppStrings.tendersTitle, + isActive: currentIndex == 1, + onTap: () => onTabChanged(1), + iconPath: AssetsManager.tenders, + activeIconPath: AssetsManager.tendersActive, + ), + _navigationItem( + context: context, + text: AppStrings.profile, + isActive: currentIndex == 2, + onTap: () => onTabChanged(2), + iconPath: AssetsManager.profile, + activeIconPath: AssetsManager.profileActive, + ), + ], + ), + ); + } + + Widget _navigationItem({ + required BuildContext context, + required String text, + required bool isActive, + required VoidCallback onTap, + required String iconPath, + required String activeIconPath, + }) { + return InkWell( + onTap: onTap, + child: Container( + width: 200.0.w(), + height: 64.0.h(), + decoration: BoxDecoration(color: AppColors.backgroundColor), + child: Padding( + padding: EdgeInsetsDirectional.only(start: 24.0.w()), + child: Row( + children: [ + SvgPicture.asset(isActive ? activeIconPath : iconPath), + SizedBox(width: 12.0.w()), + Text( + text, + style: TextStyle( + fontSize: 14.0.sp(), + fontWeight: isActive ? FontWeight.w600 : FontWeight.w400, + color: isActive ? AppColors.primaryColor : AppColors.grey60, + ), + ), + Spacer(), + Container( + width: 4.0.w(), + height: 64.0.h(), + decoration: BoxDecoration( + color: isActive ? AppColors.primaryColor : Colors.transparent, + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/views/tenders/pages/d_tenders_page.dart b/lib/views/tenders/pages/d_tenders_page.dart index 9b3fee8..d6d17a4 100644 --- a/lib/views/tenders/pages/d_tenders_page.dart +++ b/lib/views/tenders/pages/d_tenders_page.dart @@ -51,66 +51,64 @@ class _DesktopTendersPageState extends State { @override Widget build(BuildContext context) { - return SafeArea( - child: Scaffold( - backgroundColor: AppColors.backgroundColor, - body: Column( - children: [ - DesktopNavigationWidget( - currentIndex: 1, // Tenders index - onTabChanged: (index) { - // Navigate to different screens based on index - switch (index) { - case 0: - // Navigate to home - Router.neglect(context, () => context.go('/home')); - context.read().init(); - break; - case 1: - // Already on tenders - break; - case 2: - // Navigate to profile - // context.go('/profile'); - Router.neglect(context, () => context.go('/profile')); - break; - } - }, - ), - Expanded( - child: Center( - child: SingleChildScrollView( - child: Consumer( - builder: (context, viewModel, child) { - if (viewModel.isLoading) { - return Center( - child: CircularProgressIndicator( - color: AppColors.jellyBean, - ), - ); - } - if (viewModel.errorMessage != null) { - return Center(child: Text(viewModel.errorMessage!)); - } - return SizedBox( - width: 740, - height: 800, - child: Padding( - padding: EdgeInsets.symmetric(vertical: 24.0.h()), - child: MainTendersSlider( - tenders: - viewModel.tendersResponse?.data?.tenders ?? [], - isDesktop: true, - ), + return Scaffold( + backgroundColor: AppColors.backgroundColor, + body: Column( + children: [ + DesktopNavigationWidget( + currentIndex: 1, // Tenders index + onTabChanged: (index) { + // Navigate to different screens based on index + switch (index) { + case 0: + // Navigate to home + Router.neglect(context, () => context.go('/home')); + context.read().init(); + break; + case 1: + // Already on tenders + break; + case 2: + // Navigate to profile + // context.go('/profile'); + Router.neglect(context, () => context.go('/profile')); + break; + } + }, + ), + Expanded( + child: Center( + child: SingleChildScrollView( + child: Consumer( + builder: (context, viewModel, child) { + if (viewModel.isLoading) { + return Center( + child: CircularProgressIndicator( + color: AppColors.jellyBean, ), ); - }, - ), + } + if (viewModel.errorMessage != null) { + return Center(child: Text(viewModel.errorMessage!)); + } + return SizedBox( + width: 740, + height: 800, + child: Padding( + padding: EdgeInsets.symmetric(vertical: 24.0.h()), + child: MainTendersSlider( + tenders: + viewModel.tendersResponse?.data?.tenders ?? [], + isDesktop: true, + ), + ), + ); + }, ), ), ), - ], - ), + ), + ], ), ); } diff --git a/lib/views/tenders/pages/t_tenders_page.dart b/lib/views/tenders/pages/t_tenders_page.dart index 5006c24..fe9c734 100644 --- a/lib/views/tenders/pages/t_tenders_page.dart +++ b/lib/views/tenders/pages/t_tenders_page.dart @@ -1,38 +1,85 @@ import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import 'package:tm_app/core/theme/colors.dart'; import 'package:tm_app/core/utils/size_config.dart'; +import 'package:tm_app/view_models/home_view_model.dart'; import 'package:tm_app/view_models/tenders_view_model.dart'; +import 'package:tm_app/views/shared/tablet_navigation_widget.dart'; import 'package:tm_app/views/tenders/widgets/main_tenders_slider.dart'; +import '../../../core/constants/assets.dart'; + class TabletTendersPage extends StatelessWidget { const TabletTendersPage({super.key}); @override Widget build(BuildContext context) { - return SafeArea( - child: Scaffold( - backgroundColor: AppColors.backgroundColor, - - body: SingleChildScrollView( - child: Consumer( - builder: (context, viewModel, child) { - if (viewModel.isLoading) { - return Center( - child: CircularProgressIndicator(color: AppColors.jellyBean), - ); - } - if (viewModel.errorMessage != null) { - return Center(child: Text(viewModel.errorMessage!)); - } - return Padding( - padding: EdgeInsets.only(right: 24.0.w(), top: 128.0.h()), - child: MainTendersSlider( - tenders: viewModel.tendersResponse?.data?.tenders ?? [], - ), - ); - }, + final GlobalKey key = GlobalKey(); + return Scaffold( + key: key, + backgroundColor: AppColors.backgroundColor, + appBar: PreferredSize( + preferredSize: const Size.fromHeight(64), + child: AppBar( + backgroundColor: AppColors.backgroundColor, + elevation: 0, + titleSpacing: 0, + leading: Padding( + padding: EdgeInsetsDirectional.only(start: 24.0.w()), + child: SvgPicture.asset(AssetsManager.logoSmall), ), + actions: [ + IconButton( + icon: Padding( + padding: EdgeInsetsDirectional.only(end: 24.0.w()), + child: SvgPicture.asset( + AssetsManager.menu, + height: 32.0.w(), + width: 32.0.w(), + ), + ), + onPressed: () => key.currentState!.openDrawer(), + ), + ], + ), + ), + drawer: TabletNavigationWidget( + currentIndex: 1, + onTabChanged: (index) { + switch (index) { + case 0: + context.pop(); + Router.neglect(context, () => context.go('/home')); + context.read().init(); + break; + case 2: + context.pop(); + Router.neglect(context, () => context.go('/profile')); + + break; + } + }, + ), + body: SingleChildScrollView( + child: Consumer( + builder: (context, viewModel, child) { + if (viewModel.isLoading) { + return Center( + child: CircularProgressIndicator(color: AppColors.jellyBean), + ); + } + if (viewModel.errorMessage != null) { + return Center(child: Text(viewModel.errorMessage!)); + } + return Padding( + padding: EdgeInsets.only(right: 24.0.w(), top: 128.0.h()), + child: MainTendersSlider( + tenders: viewModel.tendersResponse?.data?.tenders ?? [], + ), + ); + }, ), ), ); diff --git a/lib/views/your_tenders/pages/your_tenders_desktop_page.dart b/lib/views/your_tenders/pages/your_tenders_desktop_page.dart index 272af18..562d807 100644 --- a/lib/views/your_tenders/pages/your_tenders_desktop_page.dart +++ b/lib/views/your_tenders/pages/your_tenders_desktop_page.dart @@ -40,80 +40,76 @@ class _YourTendersDesktopPageState extends State @override Widget build(BuildContext context) { - return SafeArea( - child: Scaffold( - backgroundColor: AppColors.backgroundColor, + return Scaffold( + backgroundColor: AppColors.backgroundColor, - body: Column( - children: [ - DesktopNavigationWidget( - currentIndex: 1, // Tenders index - onTabChanged: (index) { - // Navigate to different screens based on index - switch (index) { - case 0: - // Navigate to home - Router.neglect(context, () => context.go('/home')); - break; - case 1: - // Already on tenders - break; - case 2: - // Navigate to profile - // context.go('/profile'); - Router.neglect(context, () => context.go('/profile')); - break; - } - }, - ), - Expanded( - child: SizedBox( - width: 740, - child: Column( - children: [ - SizedBox(height: 64.0), - TabletDesktopAppbar(), - SizedBox(height: 20.0), - MainTabBar( - controller: controller, - titles: [ - AppStrings.approvedTenders, - AppStrings.tenderSubmitted, - ], - ), - Expanded( - child: Consumer( - builder: (context, viewModel, child) { - if (viewModel.isLoading) { - return const Center( - child: CircularProgressIndicator( - color: AppColors.secondary50, - ), - ); - } - - if (viewModel.errorMessage != null) { - return Center(child: Text(viewModel.errorMessage!)); - } - - return TabBarView( - controller: controller, - children: [ - ApprovedTenders(tendersSubmitted: []), - TendersSubmitted( - approvedTenders: viewModel.data!, - ), - ], + body: Column( + children: [ + DesktopNavigationWidget( + currentIndex: 1, // Tenders index + onTabChanged: (index) { + // Navigate to different screens based on index + switch (index) { + case 0: + // Navigate to home + Router.neglect(context, () => context.go('/home')); + break; + case 1: + // Already on tenders + break; + case 2: + // Navigate to profile + // context.go('/profile'); + Router.neglect(context, () => context.go('/profile')); + break; + } + }, + ), + Expanded( + child: SizedBox( + width: 740, + child: Column( + children: [ + SizedBox(height: 64.0), + TabletDesktopAppbar(), + SizedBox(height: 20.0), + MainTabBar( + controller: controller, + titles: [ + AppStrings.approvedTenders, + AppStrings.tenderSubmitted, + ], + ), + Expanded( + child: Consumer( + builder: (context, viewModel, child) { + if (viewModel.isLoading) { + return const Center( + child: CircularProgressIndicator( + color: AppColors.secondary50, + ), ); - }, - ), + } + + if (viewModel.errorMessage != null) { + return Center(child: Text(viewModel.errorMessage!)); + } + + return TabBarView( + controller: controller, + children: [ + ApprovedTenders(tendersSubmitted: []), + TendersSubmitted(approvedTenders: viewModel.data!), + ], + ); + }, ), - ], - ), + ), + ], ), ), - ], - ), + ), + ], ), ); } diff --git a/lib/views/your_tenders/pages/your_tenders_tablet_page.dart b/lib/views/your_tenders/pages/your_tenders_tablet_page.dart index 8cb0c52..4fea7af 100644 --- a/lib/views/your_tenders/pages/your_tenders_tablet_page.dart +++ b/lib/views/your_tenders/pages/your_tenders_tablet_page.dart @@ -38,55 +38,53 @@ class _YourTendersTabletPageState extends State @override Widget build(BuildContext context) { - return SafeArea( - child: Scaffold( - backgroundColor: AppColors.backgroundColor, + return Scaffold( + backgroundColor: AppColors.backgroundColor, - body: Center( - child: SizedBox( - width: 720, - child: Column( - children: [ - SizedBox(height: 64.0.h()), - Padding( - padding: EdgeInsets.symmetric(horizontal: 8.0.w()), - child: TabletDesktopAppbar(), - ), - SizedBox(height: 24.0.h()), - MainTabBar( - controller: controller, - titles: [ - AppStrings.approvedTenders, - AppStrings.tenderSubmitted, - ], - ), - Expanded( - child: Consumer( - builder: (context, viewModel, child) { - if (viewModel.isLoading) { - return const Center( - child: CircularProgressIndicator( - color: AppColors.secondary50, - ), - ); - } - - if (viewModel.errorMessage != null) { - return Center(child: Text(viewModel.errorMessage!)); - } - - return TabBarView( - controller: controller, - children: [ - ApprovedTenders(tendersSubmitted: []), - TendersSubmitted(approvedTenders: viewModel.data!), - ], + body: Center( + child: SizedBox( + width: 720, + child: Column( + children: [ + SizedBox(height: 64.0.h()), + Padding( + padding: EdgeInsets.symmetric(horizontal: 8.0.w()), + child: TabletDesktopAppbar(), + ), + SizedBox(height: 24.0.h()), + MainTabBar( + controller: controller, + titles: [ + AppStrings.approvedTenders, + AppStrings.tenderSubmitted, + ], + ), + Expanded( + child: Consumer( + builder: (context, viewModel, child) { + if (viewModel.isLoading) { + return const Center( + child: CircularProgressIndicator( + color: AppColors.secondary50, + ), ); - }, - ), + } + + if (viewModel.errorMessage != null) { + return Center(child: Text(viewModel.errorMessage!)); + } + + return TabBarView( + controller: controller, + children: [ + ApprovedTenders(tendersSubmitted: []), + TendersSubmitted(approvedTenders: viewModel.data!), + ], + ); + }, ), - ], - ), + ), + ], ), ), ),