diff --git a/lib/views/profile/pages/m_profile_page.dart b/lib/views/profile/pages/m_profile_page.dart index 6ea0337..d507a09 100644 --- a/lib/views/profile/pages/m_profile_page.dart +++ b/lib/views/profile/pages/m_profile_page.dart @@ -1,11 +1,9 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.dart'; import 'package:provider/provider.dart'; import 'package:tm_app/core/routes/app_routes.dart'; import 'package:tm_app/view_models/profile_view_model.dart'; -import 'package:tm_app/views/profile/widgets/theme_toggle.dart'; +import 'package:tm_app/views/profile/widgets/main_data_tab.dart'; -import '../../../core/constants/assets.dart'; import '../../../core/constants/common_strings.dart'; import '../../../core/theme/colors.dart'; import '../../../core/utils/app_toast.dart'; @@ -13,7 +11,7 @@ import '../../../core/utils/size_config.dart'; import '../../../view_models/auth_view_model.dart'; import '../../shared/tender_app_bar.dart'; import '../strings/profile_strings.dart'; -import '../widgets/title_description.dart'; +import '../widgets/profile_tab_bar.dart'; class MobileProfilePage extends StatefulWidget { const MobileProfilePage({super.key}); @@ -22,12 +20,15 @@ class MobileProfilePage extends StatefulWidget { State createState() => _MobileProfilePageState(); } -class _MobileProfilePageState extends State { +class _MobileProfilePageState extends State + with SingleTickerProviderStateMixin { late ProfileViewModel viewModel; + late final TabController tabController; @override void initState() { super.initState(); viewModel = context.read(); + tabController = TabController(length: 3, vsync: this); viewModel.addListener(_profileListener); // Load notification info saved in SharedPreferences } @@ -53,137 +54,56 @@ class _MobileProfilePageState extends State { return Scaffold( backgroundColor: AppColors.backgroundColor, appBar: tenderMobileAppBar(title: ProfileStrings.profileTitle), - body: Consumer( - builder: (context, viewModel, child) { - if (viewModel.isLoading) { - return const Center( - child: CircularProgressIndicator(color: AppColors.secondary50), - ); - } + body: SafeArea( + 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!)); - } + if (viewModel.errorMessage != null) { + return Center(child: Text(viewModel.errorMessage!)); + } - if (viewModel.profileData == null) { - return const Center(child: Text(CommonStrings.noData)); - } + if (viewModel.profileData == null) { + return const Center(child: Text(CommonStrings.noData)); + } - return SafeArea( - child: Padding( + return Padding( padding: EdgeInsets.symmetric( horizontal: 24.0.w(), vertical: 16.0.h(), ), child: Column( children: [ - SizedBox(height: 36.0.h()), - Align( - alignment: AlignmentDirectional.centerStart, - child: Text( - 'Last Notification', - style: TextStyle( - fontSize: 18.0.sp(), - fontWeight: FontWeight.w600, - color: AppColors.grey70, - ), - ), + ProfileTabBar( + controller: tabController, + titles: [ + ProfileStrings.mainDataTab, + ProfileStrings.membersTab, + ProfileStrings.subjectTab, + ], ), - - SizedBox(height: 24.0.h()), - TitleDescription( - title: ProfileStrings.fullname, - description: viewModel.profileData!.fullName ?? '', - ), - TitleDescription( - title: ProfileStrings.username, - description: viewModel.profileData!.username ?? '', - ), - TitleDescription( - title: ProfileStrings.email, - description: viewModel.profileData!.email ?? '', - ), - TitleDescription( - title: ProfileStrings.phone, - description: viewModel.profileData!.phone ?? '', - ), - TitleDescription( - title: ProfileStrings.companyName, - description: - viewModel.profileData!.companies!.first.name ?? '', - ), - SizedBox(height: 32.0.h()), - Align( - alignment: AlignmentDirectional.centerStart, - child: Text( - ProfileStrings.settings, - style: TextStyle( - fontSize: 20.0.sp(), - fontWeight: FontWeight.w600, - color: AppColors.grey70, - ), - ), - ), - SizedBox(height: 36.0.h()), - _themeChangeRow(), - SizedBox(height: 24.0.h()), - Divider(color: AppColors.dividerColor, thickness: 1), - SizedBox(height: 24.0.h()), - const Spacer(), - InkWell( - onTap: () => viewModel.logout(), - borderRadius: BorderRadius.circular(100), - child: Container( - width: double.infinity, - height: 56.0.h(), - decoration: BoxDecoration( - color: AppColors.primary20, - borderRadius: BorderRadius.circular(100), - ), - alignment: Alignment.center, - child: Text( - ProfileStrings.logout, - style: TextStyle( - fontSize: 14.0.sp(), - fontWeight: FontWeight.w500, - color: AppColors.primaryColor, + Expanded( + child: TabBarView( + controller: tabController, + children: [ + MainDataTab( + profileData: viewModel.profileData!, + onLogout: () => viewModel.logout(), ), - ), + const Center(child: Text('Members Tab Content')), + const Center(child: Text('Subject Tab Content')), + ], ), ), ], ), - ), - ); - }, - ), - ); - } - - Widget _themeChangeRow() { - return Padding( - padding: EdgeInsets.symmetric(horizontal: 8.0.w()), - child: Row( - children: [ - Text( - ProfileStrings.appTheme, - style: TextStyle( - fontSize: 16.0.sp(), - fontWeight: FontWeight.w400, - color: AppColors.grey70, - ), - ), - const Spacer(), - SvgPicture.asset(AssetsManager.sun), - SizedBox(width: 12.0.w()), - SizedBox( - width: 52.0.w(), - height: 32.0.h(), - child: const ThemeToggle(), - ), - SizedBox(width: 12.0.w()), - SvgPicture.asset(AssetsManager.moon), - ], + ); + }, + ), ), ); } diff --git a/lib/views/profile/strings/profile_strings.dart b/lib/views/profile/strings/profile_strings.dart index 5baa79a..ab08801 100644 --- a/lib/views/profile/strings/profile_strings.dart +++ b/lib/views/profile/strings/profile_strings.dart @@ -20,4 +20,7 @@ class ProfileStrings { static const String position = 'position'; static const String phone = 'phone'; static const String fullname = 'full name'; + static const String mainDataTab = 'Main Data'; + static const String membersTab = 'Members'; + static const String subjectTab = 'Subject'; } diff --git a/lib/views/profile/widgets/main_data_tab.dart b/lib/views/profile/widgets/main_data_tab.dart new file mode 100644 index 0000000..9171a59 --- /dev/null +++ b/lib/views/profile/widgets/main_data_tab.dart @@ -0,0 +1,133 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:tm_app/core/utils/size_config.dart'; + +import '../../../core/constants/assets.dart'; +import '../../../core/theme/colors.dart'; +import '../../../data/services/model/profile_data/profile_data.dart'; +import '../strings/profile_strings.dart'; +import 'theme_toggle.dart'; +import 'title_description.dart'; + +class MainDataTab extends StatelessWidget { + const MainDataTab({ + required this.profileData, + required this.onLogout, + super.key, + }); + + final ProfileData profileData; + final VoidCallback onLogout; + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox(height: 36.0.h()), + Align( + alignment: AlignmentDirectional.centerStart, + child: Text( + 'Last Notification', + style: TextStyle( + fontSize: 18.0.sp(), + fontWeight: FontWeight.w600, + color: AppColors.grey70, + ), + ), + ), + + SizedBox(height: 24.0.h()), + TitleDescription( + title: ProfileStrings.fullname, + description: profileData.fullName ?? '', + ), + TitleDescription( + title: ProfileStrings.username, + description: profileData.username ?? '', + ), + TitleDescription( + title: ProfileStrings.email, + description: profileData.email ?? '', + ), + TitleDescription( + title: ProfileStrings.phone, + description: profileData.phone ?? '', + ), + TitleDescription( + title: ProfileStrings.companyName, + description: profileData.companies!.first.name ?? '', + ), + SizedBox(height: 32.0.h()), + Align( + alignment: AlignmentDirectional.centerStart, + child: Text( + ProfileStrings.settings, + style: TextStyle( + fontSize: 20.0.sp(), + fontWeight: FontWeight.w600, + color: AppColors.grey70, + ), + ), + ), + SizedBox(height: 36.0.h()), + _themeChangeRow(), + SizedBox(height: 24.0.h()), + Divider(color: AppColors.dividerColor, thickness: 1), + SizedBox(height: 24.0.h()), + + InkWell( + onTap: onLogout, + borderRadius: BorderRadius.circular(100), + child: Container( + width: double.infinity, + height: 56.0.h(), + decoration: BoxDecoration( + color: AppColors.primary20, + borderRadius: BorderRadius.circular(100), + ), + alignment: Alignment.center, + child: Text( + ProfileStrings.logout, + style: TextStyle( + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + color: AppColors.primaryColor, + ), + ), + ), + ), + ], + ), + ); + } + + Widget _themeChangeRow() { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 8.0.w()), + child: Row( + children: [ + Text( + ProfileStrings.appTheme, + style: TextStyle( + fontSize: 16.0.sp(), + fontWeight: FontWeight.w400, + color: AppColors.grey70, + ), + ), + const Spacer(), + SvgPicture.asset(AssetsManager.sun), + SizedBox(width: 12.0.w()), + SizedBox( + width: 52.0.w(), + height: 32.0.h(), + child: const ThemeToggle(), + ), + SizedBox(width: 12.0.w()), + SvgPicture.asset(AssetsManager.moon), + ], + ), + ); + } +} diff --git a/lib/views/profile/widgets/profile_tab_bar.dart b/lib/views/profile/widgets/profile_tab_bar.dart new file mode 100644 index 0000000..2c0efe5 --- /dev/null +++ b/lib/views/profile/widgets/profile_tab_bar.dart @@ -0,0 +1,70 @@ +import 'package:flutter/material.dart'; +import 'package:tm_app/core/utils/size_config.dart'; + +import '../../../core/theme/colors.dart'; + +class ProfileTabBar extends StatefulWidget { + const ProfileTabBar({ + required this.controller, + required this.titles, + this.onTap, + super.key, + }); + + final TabController controller; + final List titles; + final ValueChanged? onTap; + + @override + State createState() => _ProfileTabBarState(); +} + +class _ProfileTabBarState extends State { + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + child: Container( + width: double.infinity, + height: 51.0.h(), + padding: EdgeInsets.symmetric(horizontal: 8.0.w(), vertical: 8.0.h()), + decoration: BoxDecoration( + color: AppColors.grey10, + borderRadius: BorderRadius.circular(10), + ), + alignment: Alignment.center, + child: TabBar( + controller: widget.controller, + onTap: widget.onTap, + indicatorSize: TabBarIndicatorSize.tab, + dividerColor: Colors.transparent, + indicator: BoxDecoration( + color: AppColors.primary0, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.black.withValues(alpha: 0.12), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ), + labelColor: AppColors.mainBlue, + unselectedLabelColor: AppColors.grey60, + labelStyle: TextStyle( + fontSize: 16.0.sp(), + fontWeight: FontWeight.w600, + ), + unselectedLabelStyle: TextStyle( + fontSize: 16.0.sp(), + fontWeight: FontWeight.w600, + ), + tabs: [ + Tab(text: widget.titles[0]), + Tab(text: widget.titles[1]), + Tab(text: widget.titles[2]), + ], + ), + ), + ); + } +}