diff --git a/lib/core/utils/breakpoints.dart b/lib/core/utils/breakpoints.dart new file mode 100644 index 0000000..abf1087 --- /dev/null +++ b/lib/core/utils/breakpoints.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; + +enum DisplaySize { + extraSmall, //mobile + small, //tablet + medium, //laptop + large, //desktop +} + +extension DisplaySizeDetector on Size { + DisplaySize get displaySize { + if (width < 600) { + return DisplaySize.extraSmall; + } else if (width < 1024) { + return DisplaySize.small; + } else if (width < 1440) { + return DisplaySize.medium; + } else { + return DisplaySize.large; + } + } + + String get displaySizeName { + switch (displaySize) { + case DisplaySize.extraSmall: + return 'Mobile'; + case DisplaySize.small: + return 'Tablet'; + case DisplaySize.medium: + return 'Laptop'; + case DisplaySize.large: + return 'Desktop'; + } + } +} diff --git a/lib/core/utils/size_config.dart b/lib/core/utils/size_config.dart index 49c0eeb..cda31ff 100644 --- a/lib/core/utils/size_config.dart +++ b/lib/core/utils/size_config.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:tm_app/core/utils/breakpoints.dart'; class SizeConfig { static double screenWidth = 0.0; @@ -14,15 +15,31 @@ class SizeConfig { extension SizeDoubleExt on double { double h() { + final displaySize = + Size(SizeConfig.screenWidth, SizeConfig.screenHeight).displaySize; final double screenHeight = SizeConfig.screenHeight; final double res = (this / 917.0) * screenHeight; - return res; + if (displaySize == DisplaySize.extraSmall + // displaySize == DisplaySize.small + ) { + return res; + } else { + return this; + } } double w() { + final displaySize = + Size(SizeConfig.screenWidth, SizeConfig.screenHeight).displaySize; final double screenWidth = SizeConfig.screenWidth; final double res = (this / 412.0) * screenWidth; - return res; + if (displaySize == DisplaySize.extraSmall + // displaySize == DisplaySize.small + ) { + return res; + } else { + return this; + } } double sp() { diff --git a/lib/views/home/home_screen.dart b/lib/views/home/home_screen.dart deleted file mode 100644 index 52bc771..0000000 --- a/lib/views/home/home_screen.dart +++ /dev/null @@ -1,195 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:tm_app/core/routes/app_routes.dart'; -import 'package:tm_app/views/shared/tender_app_bar.dart'; - -import '../../../core/constants/strings.dart'; -import '../../core/theme/colors.dart'; -import '../../core/utils/size_config.dart'; -import 'widgets.dart'; - -class HomeScreen extends StatelessWidget { - const HomeScreen({super.key}); - - @override - Widget build(BuildContext context) { - SizeConfig.init(context); - return SafeArea( - child: Scaffold( - backgroundColor: AppColors.backgroundColor, - body: _body(context), - appBar: tenderAppBar(title: AppStrings.home), - ), - ); - } - - Widget _body(BuildContext context) { - return ListView( - children: [ - Padding( - padding: EdgeInsetsDirectional.fromSTEB( - 24.0.w(), - 26.0.h(), - 24.0.w(), - 24.0.h(), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // _appbar(), - // SizedBox(height: 32.0.h()), - _progressBarsRow(), - SizedBox(height: 32.0.h()), - _firstStatisticsRow(context), - SizedBox(height: 8.0.h()), - _secondStatisticsRow(), - SizedBox(height: 32.0.h()), - _yourTenderText(), - SizedBox(height: 28.0.h()), - _bottomListView(), - ], - ), - ), - ], - ); - } - - Widget _progressBarsRow() { - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - ProgressBarColumn( - text: AppStrings.partnership, - value: 0.75, - amount: '75%', - ), - ProgressBarColumn( - text: AppStrings.selfApply, - value: 0.88, - amount: '12', - ), - ProgressBarColumn( - text: AppStrings.contracting, - value: 0.36, - amount: '36', - ), - ], - ); - } - - Widget _firstStatisticsRow(BuildContext context) { - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - StatisticsCard( - backgroundColor: AppColors.primary20, - iconPath: 'assets/icons/arrows.svg', - title: AppStrings.tenderSubmitting, - amount: '12', - textColor: Color(0xFF0164FF), - enableTap: true, - onTap: () { - YourTendersRouteData().push(context); - }, - ), - StatisticsCard( - backgroundColor: AppColors.primary10, - iconPath: 'assets/icons/thumb.svg', - title: AppStrings.approvedTenders, - amount: '03', - textColor: Color(0xFF24848E), - enableTap: true, - onTap: () { - YourTendersRouteData().push(context); - }, - ), - ], - ); - } - - Widget _secondStatisticsRow() { - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - StatisticsCard( - backgroundColor: AppColors.orange10, - iconPath: 'assets/icons/shield.svg', - title: AppStrings.tenderValue, - amount: '\$250,000', - textColor: Color(0xFFE5821E), - enableTap: true, - onTap: () {}, - ), - StatisticsCard( - backgroundColor: AppColors.grey10, - iconPath: 'assets/icons/edit.svg', - title: AppStrings.thunderStatus, - amount: '23', - textColor: Color(0xFF9E9E9E), - enableTap: false, - onTap: () {}, - ), - ], - ); - } - - Widget _yourTenderText() { - return Text( - AppStrings.yourTenders, - style: TextStyle( - fontSize: 20.0.sp(), - fontWeight: FontWeight.w600, - color: AppColors.grey60, - ), - ); - } - - Widget _bottomListView() { - return SizedBox( - width: double.infinity, - height: 310.0.h(), - child: ListView.builder( - itemCount: 10, - scrollDirection: Axis.horizontal, - itemBuilder: (context, index) { - return TendersListItem(); - }, - ), - ); - } -} - -class TenderAppBar extends StatelessWidget { - const TenderAppBar({super.key}); - - @override - Widget build(BuildContext context) { - return PreferredSize( - preferredSize: Size.fromHeight(56.0.h()), - child: Container( - color: AppColors.backgroundColor, - padding: EdgeInsets.symmetric(horizontal: 24.0.w()), - height: 56.0.h(), - width: double.infinity, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - AppStrings.home, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: AppColors.grey70, - ), - ), - Image.asset( - 'assets/icons/tenderLogo.png', - width: 59.0.w(), - height: 28.0.h(), - fit: BoxFit.cover, - ), - ], - ), - ), - ); - } -} diff --git a/lib/views/home/pages/d_home_page.dart b/lib/views/home/pages/d_home_page.dart new file mode 100644 index 0000000..48f2afa --- /dev/null +++ b/lib/views/home/pages/d_home_page.dart @@ -0,0 +1,154 @@ +import 'package:flutter/material.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 '../widgets.dart'; + +class DesktopHomePage extends StatelessWidget { + const DesktopHomePage({super.key}); + + @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(), + ], + ), + ), + ); + } + + Widget _progressBarsRow() { + return Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ProgressBarColumn( + text: AppStrings.partnership, + value: 0.75, + amount: '75%', + circularProgressIndicatorWidth: 176, + circularProgressIndicatorHeight: 176, + ), + SizedBox(width: 106), + ProgressBarColumn( + text: AppStrings.selfApply, + value: 0.88, + amount: '12', + circularProgressIndicatorWidth: 176, + circularProgressIndicatorHeight: 176, + ), + SizedBox(width: 106), + ProgressBarColumn( + text: AppStrings.contracting, + value: 0.36, + amount: '36', + circularProgressIndicatorWidth: 176, + circularProgressIndicatorHeight: 176, + ), + ], + ); + } + + Widget _firstTenderCardsRow(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TenderCard( + backgroundColor: AppColors.primary20, + iconPath: 'assets/icons/arrows.svg', + title: AppStrings.tenderSubmitting, + amount: '12', + textColor: Color(0xFF0164FF), + enableTap: true, + width: 178, + height: 148, + onTap: () { + YourTendersRouteData().push(context); + }, + ), + SizedBox(width: 10), + TenderCard( + backgroundColor: AppColors.primary10, + iconPath: 'assets/icons/thumb.svg', + title: AppStrings.approvedTenders, + amount: '03', + textColor: Color(0xFF24848E), + enableTap: true, + width: 178, + height: 148, + onTap: () { + YourTendersRouteData().push(context); + }, + ), + SizedBox(width: 10), + TenderCard( + backgroundColor: AppColors.orange10, + iconPath: 'assets/icons/shield.svg', + title: AppStrings.tenderValue, + amount: '\$250,000', + textColor: Color(0xFFE5821E), + enableTap: true, + width: 178, + height: 148, + onTap: () {}, + ), + SizedBox(width: 10), + TenderCard( + backgroundColor: AppColors.grey10, + iconPath: 'assets/icons/edit.svg', + title: AppStrings.thunderStatus, + amount: '23', + textColor: Color(0xFF9E9E9E), + enableTap: false, + width: 178, + height: 148, + onTap: () {}, + ), + ], + ); + } + + Widget _yourTenderText() { + return ConstrainedBox( + constraints: BoxConstraints(maxWidth: 740), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + AppStrings.yourTenders, + style: TextStyle( + fontSize: 20.0.sp(), + fontWeight: FontWeight.w600, + color: AppColors.grey60, + ), + ), + ), + ); + } + + Widget _bottomListView() { + return SizedBox( + width: 740, + height: 310.0.h(), + child: ListView.builder( + itemCount: 10, + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + return TendersListItem(); + }, + ), + ); + } +} diff --git a/lib/views/home/pages/home_screen.dart b/lib/views/home/pages/home_screen.dart new file mode 100644 index 0000000..4052657 --- /dev/null +++ b/lib/views/home/pages/home_screen.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; + +import '../../../core/utils/size_config.dart'; +import '../../shared/responsive_builder.dart'; +import '../widgets.dart'; + +class HomeScreen extends StatelessWidget { + const HomeScreen({super.key}); + + @override + Widget build(BuildContext context) { + SizeConfig.init(context); + return ResponsiveBuilder( + mobile: MobileHomePage(), + tablet: TabletHomePage(), + desktop: DesktopHomePage(), + ); + } +} diff --git a/lib/views/home/pages/m_home_page.dart b/lib/views/home/pages/m_home_page.dart new file mode 100644 index 0000000..a981a75 --- /dev/null +++ b/lib/views/home/pages/m_home_page.dart @@ -0,0 +1,153 @@ +import 'package:flutter/material.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/views/shared/tender_app_bar.dart'; + +import '../widgets.dart'; + +class MobileHomePage extends StatelessWidget { + const MobileHomePage({super.key}); + + @override + 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(), + ], + ), + ), + ); + } + + Widget _progressBarsRow() { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 24.0.w()), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ProgressBarColumn( + text: AppStrings.partnership, + value: 0.75, + amount: '75%', + ), + ProgressBarColumn( + text: AppStrings.selfApply, + value: 0.88, + amount: '12', + ), + ProgressBarColumn( + text: AppStrings.contracting, + value: 0.36, + amount: '36', + ), + ], + ), + ); + } + + Widget _firstTenderCardsRow(BuildContext context) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 24.0.w()), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + TenderCard( + backgroundColor: AppColors.primary20, + iconPath: 'assets/icons/arrows.svg', + title: AppStrings.tenderSubmitting, + amount: '12', + textColor: Color(0xFF0164FF), + enableTap: true, + onTap: () { + YourTendersRouteData().push(context); + }, + ), + TenderCard( + backgroundColor: AppColors.primary10, + iconPath: 'assets/icons/thumb.svg', + title: AppStrings.approvedTenders, + amount: '03', + textColor: Color(0xFF24848E), + enableTap: true, + onTap: () { + YourTendersRouteData().push(context); + }, + ), + ], + ), + ); + } + + Widget _secondTenderCardsRow() { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 24.0.w()), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + TenderCard( + backgroundColor: AppColors.orange10, + iconPath: 'assets/icons/shield.svg', + title: AppStrings.tenderValue, + amount: '\$250,000', + textColor: Color(0xFFE5821E), + enableTap: true, + onTap: () {}, + ), + TenderCard( + backgroundColor: AppColors.grey10, + iconPath: 'assets/icons/edit.svg', + title: AppStrings.thunderStatus, + amount: '23', + textColor: Color(0xFF9E9E9E), + enableTap: false, + onTap: () {}, + ), + ], + ), + ); + } + + Widget _yourTenderText() { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 24.0.w()), + child: Text( + AppStrings.yourTenders, + style: TextStyle( + fontSize: 20.0.sp(), + fontWeight: FontWeight.w600, + color: AppColors.grey60, + ), + ), + ); + } + + Widget _bottomListView() { + return SizedBox( + width: double.infinity, + height: 310.0.h(), + child: ListView.builder( + padding: EdgeInsets.symmetric(horizontal: 24.0.w()), + itemCount: 10, + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + return TendersListItem(); + }, + ), + ); + } +} diff --git a/lib/views/home/pages/t_home_page.dart b/lib/views/home/pages/t_home_page.dart new file mode 100644 index 0000000..f9ba4f4 --- /dev/null +++ b/lib/views/home/pages/t_home_page.dart @@ -0,0 +1,172 @@ +import 'package:flutter/material.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 '../widgets.dart'; + +class TabletHomePage extends StatelessWidget { + const TabletHomePage({super.key}); + + @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(), + ], + ), + ), + ), + ); + } + + Widget _progressBarsRow() { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ProgressBarColumn( + text: AppStrings.partnership, + value: 0.75, + amount: '75%', + circularProgressIndicatorWidth: 176.0, + circularProgressIndicatorHeight: 176.0, + strokeWidth: 8.0, + ), + ProgressBarColumn( + text: AppStrings.selfApply, + value: 0.88, + amount: '12', + circularProgressIndicatorWidth: 176.0, + circularProgressIndicatorHeight: 176.0, + strokeWidth: 8.0, + ), + ProgressBarColumn( + text: AppStrings.contracting, + value: 0.36, + amount: '36', + circularProgressIndicatorWidth: 176.0, + circularProgressIndicatorHeight: 176.0, + strokeWidth: 8.0, + ), + ], + ); + } + + Widget _firstTenderCardsRow(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: TenderCard( + backgroundColor: AppColors.primary20, + iconPath: 'assets/icons/arrows.svg', + title: AppStrings.tenderSubmitting, + amount: '12', + textColor: Color(0xFF0164FF), + enableTap: true, + width: double.infinity, + height: 148, + onTap: () { + YourTendersRouteData().push(context); + }, + ), + ), + SizedBox(width: 16.0), + Expanded( + child: TenderCard( + backgroundColor: AppColors.primary10, + iconPath: 'assets/icons/thumb.svg', + title: AppStrings.approvedTenders, + amount: '03', + textColor: Color(0xFF24848E), + enableTap: true, + width: double.infinity, + height: 148, + onTap: () { + YourTendersRouteData().push(context); + }, + ), + ), + ], + ); + } + + Widget _secondTenderCardsRow() { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: TenderCard( + backgroundColor: AppColors.orange10, + iconPath: 'assets/icons/shield.svg', + title: AppStrings.tenderValue, + amount: '\$250,000', + textColor: Color(0xFFE5821E), + enableTap: true, + width: double.infinity, + height: 148, + onTap: () {}, + ), + ), + SizedBox(width: 16.0), + Expanded( + child: TenderCard( + backgroundColor: AppColors.grey10, + iconPath: 'assets/icons/edit.svg', + title: AppStrings.thunderStatus, + amount: '23', + textColor: Color(0xFF9E9E9E), + enableTap: false, + width: double.infinity, + height: 148, + onTap: () {}, + ), + ), + ], + ); + } + + Widget _yourTenderText() { + return Text( + AppStrings.yourTenders, + style: TextStyle( + fontSize: 20.0.sp(), + fontWeight: FontWeight.w600, + color: AppColors.grey60, + ), + ); + } + + Widget _bottomListView() { + return SizedBox( + width: double.infinity, + height: 310.0.h(), + child: ListView.builder( + itemCount: 10, + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + return TendersListItem(); + }, + ), + ); + } +} diff --git a/lib/views/home/progress_bar_column.dart b/lib/views/home/progress_bar_column.dart index 453ae8b..f915963 100644 --- a/lib/views/home/progress_bar_column.dart +++ b/lib/views/home/progress_bar_column.dart @@ -8,12 +8,18 @@ class ProgressBarColumn extends StatefulWidget { required this.text, required this.value, required this.amount, + this.circularProgressIndicatorWidth, + this.circularProgressIndicatorHeight, + this.strokeWidth, super.key, }); final String text; final double value; final String amount; + final double? circularProgressIndicatorWidth; + final double? circularProgressIndicatorHeight; + final double? strokeWidth; @override State createState() => _ProgressBarColumnState(); @@ -66,15 +72,15 @@ class _ProgressBarColumnState extends State Widget _progressIndicator() { return SizedBox( - width: 96.0.w(), - height: 96.0.w(), + width: widget.circularProgressIndicatorWidth ?? 96.0.w(), + height: widget.circularProgressIndicatorHeight ?? 96.0.w(), child: AnimatedBuilder( animation: _animation, builder: (context, child) => CircularProgressIndicator( backgroundColor: Color(0xFFE1E1E1), strokeCap: StrokeCap.round, - strokeWidth: 8.0, + strokeWidth: widget.strokeWidth ?? 6.0, valueColor: AlwaysStoppedAnimation(AppColors.jellyBean), value: _animation.value, ), diff --git a/lib/views/home/statistics_card.dart b/lib/views/home/tender_card.dart similarity index 89% rename from lib/views/home/statistics_card.dart rename to lib/views/home/tender_card.dart index 994a23b..4010297 100644 --- a/lib/views/home/statistics_card.dart +++ b/lib/views/home/tender_card.dart @@ -3,8 +3,8 @@ import 'package:flutter_svg/flutter_svg.dart'; import '../../core/utils/size_config.dart'; -class StatisticsCard extends StatelessWidget { - const StatisticsCard({ +class TenderCard extends StatelessWidget { + const TenderCard({ required this.backgroundColor, required this.iconPath, required this.title, @@ -12,6 +12,8 @@ class StatisticsCard extends StatelessWidget { required this.textColor, required this.onTap, required this.enableTap, + this.width, + this.height, super.key, }); @@ -22,14 +24,16 @@ class StatisticsCard extends StatelessWidget { final Color textColor; final VoidCallback onTap; final bool enableTap; + final double? width; + final double? height; @override Widget build(BuildContext context) { return InkWell( onTap: enableTap ? onTap : null, child: Container( - width: 178.0.w(), - height: 148.0.h(), + width: width ?? 178.0.w(), + height: height ?? 148.0.h(), padding: EdgeInsets.symmetric(horizontal: 16.0.w(), vertical: 12.0.h()), decoration: BoxDecoration( color: backgroundColor, diff --git a/lib/views/home/tenders_list_item.dart b/lib/views/home/tenders_list_item.dart index 93e4dde..6c9cdc1 100644 --- a/lib/views/home/tenders_list_item.dart +++ b/lib/views/home/tenders_list_item.dart @@ -15,7 +15,7 @@ class TendersListItem extends StatelessWidget { borderRadius: BorderRadius.circular(4), ), margin: EdgeInsetsDirectional.only(end: 16.0.w()), - width: 327.0.w(), + width: 320.0.w(), height: 309.0.h(), child: Padding( padding: EdgeInsets.symmetric(horizontal: 16.0.w(), vertical: 16.0.h()), diff --git a/lib/views/home/widgets.dart b/lib/views/home/widgets.dart index 57c84fa..31715de 100644 --- a/lib/views/home/widgets.dart +++ b/lib/views/home/widgets.dart @@ -1,3 +1,6 @@ +export 'pages/d_home_page.dart'; +export 'pages/m_home_page.dart'; +export 'pages/t_home_page.dart'; export 'progress_bar_column.dart'; -export 'statistics_card.dart'; +export 'tender_card.dart'; export 'tenders_list_item.dart'; diff --git a/lib/views/profile/profile_screen.dart b/lib/views/profile/profile_screen.dart index 202727f..b5cbfb1 100644 --- a/lib/views/profile/profile_screen.dart +++ b/lib/views/profile/profile_screen.dart @@ -14,7 +14,7 @@ class ProfileScreen extends StatelessWidget { return SafeArea( child: Scaffold( backgroundColor: AppColors.backgroundColor, - appBar: tenderAppBar(title: AppStrings.profile), + appBar: tenderMobileAppBar(title: AppStrings.profile), body: Padding( padding: EdgeInsets.symmetric( horizontal: 24.0.w(), diff --git a/lib/views/shared/responsive_builder.dart b/lib/views/shared/responsive_builder.dart new file mode 100644 index 0000000..0d3c088 --- /dev/null +++ b/lib/views/shared/responsive_builder.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; +import 'package:tm_app/core/utils/breakpoints.dart'; + +/// A responsive builder widget that automatically switches between different +/// layouts based on the current display size. +/// +/// This widget can be used by all screens to handle responsive layouts. +class ResponsiveBuilder extends StatelessWidget { + /// The widget to display on extra small screens (mobile) + final Widget? mobile; + + /// The widget to display on small screens (tablet) + final Widget? tablet; + + /// The widget to display on large screens (desktop) + final Widget? desktop; + + /// A builder function that receives the current display size + /// Use this when you want to handle the layout logic yourself + final Widget Function(BuildContext context, DisplaySize? displaySize)? + builder; + + const ResponsiveBuilder({ + super.key, + this.mobile, + this.tablet, + this.desktop, + this.builder, + }) : assert( + builder != null || mobile != null, + 'Either builder or at least mobile layout must be provided', + ); + + @override + Widget build(BuildContext context) { + final size = MediaQuery.sizeOf(context); + final displaySize = size.displaySize; + + // If builder is provided, use it + if (builder != null) { + return builder!(context, displaySize); + } + + // Otherwise, use the appropriate widget based on display size + return switch (displaySize) { + DisplaySize.extraSmall => mobile ?? _defaultWidget(), + DisplaySize.small => tablet ?? mobile ?? _defaultWidget(), + DisplaySize.medium => desktop ?? mobile ?? _defaultWidget(), + DisplaySize.large => desktop ?? mobile ?? _defaultWidget(), + }; + } + + Widget _defaultWidget() { + return const SizedBox.shrink(); + } +} diff --git a/lib/views/shared/tender_app_bar.dart b/lib/views/shared/tender_app_bar.dart index 5285336..0a7fbfa 100644 --- a/lib/views/shared/tender_app_bar.dart +++ b/lib/views/shared/tender_app_bar.dart @@ -4,7 +4,7 @@ import 'package:tm_app/core/constants/assets.dart'; import 'package:tm_app/core/theme/colors.dart'; import 'package:tm_app/core/utils/size_config.dart'; -PreferredSize tenderAppBar({required String title}) { +PreferredSize tenderMobileAppBar({required String title}) { return PreferredSize( preferredSize: Size.fromHeight(kToolbarHeight.h()), child: Container( diff --git a/lib/views/tenders/tenders_screen.dart b/lib/views/tenders/tenders_screen.dart index 183d623..53df727 100644 --- a/lib/views/tenders/tenders_screen.dart +++ b/lib/views/tenders/tenders_screen.dart @@ -38,7 +38,7 @@ class _TendersScreenState extends State return SafeArea( child: Scaffold( backgroundColor: AppColors.backgroundColor, - appBar: tenderAppBar(title: AppStrings.tendersTitle), + appBar: tenderMobileAppBar(title: AppStrings.tendersTitle), body: SingleChildScrollView( child: Padding( padding: EdgeInsets.symmetric(vertical: 24.0.h()), diff --git a/lib/views/your_tenders/your_tenders_screen.dart b/lib/views/your_tenders/your_tenders_screen.dart index 1adc180..df35a44 100644 --- a/lib/views/your_tenders/your_tenders_screen.dart +++ b/lib/views/your_tenders/your_tenders_screen.dart @@ -35,7 +35,7 @@ class _YourTendersScreenState extends State return SafeArea( child: Scaffold( backgroundColor: AppColors.backgroundColor, - appBar: tenderAppBar(title: AppStrings.yourTenders), + appBar: tenderMobileAppBar(title: AppStrings.yourTenders), body: Column( children: [ MainTabBar(