From a50c4387b87198815b6f946a15e5350a8c2c9cc6 Mon Sep 17 00:00:00 2001 From: Ahmed Aladdin Date: Thu, 31 Oct 2024 19:04:29 +0300 Subject: [PATCH 01/12] fix: modify the api calling code --- devtools_options.yaml | 4 + lib/core/constants/server_constants.dart | 10 +- lib/core/mock/user_mock.dart | 2 +- lib/core/models/user_model.dart | 8 +- lib/core/models/user_model.g.dart | 2 +- lib/core/utils.dart | 9 - .../auth/models/auth_response_model.dart | 7 +- .../repository/auth_remote_repository.dart | 10 +- .../auth/view/screens/log_in_screen.dart | 1 - .../auth/view_model/auth_view_model.dart | 7 +- .../auth/view_model/auth_view_model.g.dart | 2 +- .../user/view/screens/settings_screen.dart | 160 ++++++++++-------- 12 files changed, 123 insertions(+), 99 deletions(-) create mode 100644 devtools_options.yaml diff --git a/devtools_options.yaml b/devtools_options.yaml new file mode 100644 index 00000000..2bc8e05f --- /dev/null +++ b/devtools_options.yaml @@ -0,0 +1,4 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: + - provider: true \ No newline at end of file diff --git a/lib/core/constants/server_constants.dart b/lib/core/constants/server_constants.dart index 424f2584..35c59f41 100644 --- a/lib/core/constants/server_constants.dart +++ b/lib/core/constants/server_constants.dart @@ -6,5 +6,11 @@ import 'package:flutter_dotenv/flutter_dotenv.dart'; final String API_URL = dotenv.env['API_URL']!; final String GOOGLE_AUTH_URL = API_URL + dotenv.env['GOOGLE_AUTH_URL']!; final String GITHUB_AUTH_URL = API_URL + dotenv.env['GITHUB_AUTH_URL']!; -final BASE_OPTIONS = - BaseOptions(baseUrl: API_URL, contentType: 'application/json'); +final BASE_OPTIONS = BaseOptions( + baseUrl: API_URL, + contentType: 'application/json', + connectTimeout: const Duration(seconds: 5), // 5 seconds + receiveTimeout: const Duration(seconds: 3), // 3 seconds + sendTimeout: const Duration(seconds: 3), // 3 seconds +); + diff --git a/lib/core/mock/user_mock.dart b/lib/core/mock/user_mock.dart index 814f5772..c6b501fb 100644 --- a/lib/core/mock/user_mock.dart +++ b/lib/core/mock/user_mock.dart @@ -9,7 +9,7 @@ const UserModel userMock = UserModel( maxFileSize: 30, automaticDownloadEnable: true, lastSeenPrivacy: 'recently', - readReceiptsEnablePrivacy: 'enable', + readReceiptsEnablePrivacy: true, storiesPrivacy: 'private', picturePrivacy: 'global', invitePermissionsPrivacy: 'enable', diff --git a/lib/core/models/user_model.dart b/lib/core/models/user_model.dart index 10665d2b..4a6104d6 100644 --- a/lib/core/models/user_model.dart +++ b/lib/core/models/user_model.dart @@ -26,7 +26,7 @@ class UserModel { @HiveField(8) final String lastSeenPrivacy; @HiveField(9) - final String readReceiptsEnablePrivacy; + final bool readReceiptsEnablePrivacy; @HiveField(10) final String storiesPrivacy; @HiveField(11) @@ -107,7 +107,7 @@ class UserModel { int? maxFileSize, bool? automaticDownloadEnable, String? lastSeenPrivacy, - String? readReceiptsEnablePrivacy, + bool? readReceiptsEnablePrivacy, String? storiesPrivacy, String? picturePrivacy, String? invitePermissionsPrivacy, @@ -161,11 +161,11 @@ class UserModel { maxFileSize: map['maxFileSize'] as int, automaticDownloadEnable: map['automaticDownloadEnable'] as bool, lastSeenPrivacy: map['lastSeenPrivacy'] as String, - readReceiptsEnablePrivacy: map['readReceiptsEnablePrivacy'] as String, + readReceiptsEnablePrivacy: map['readReceiptsEnablePrivacy'] as bool, storiesPrivacy: map['storiesPrivacy'] as String, picturePrivacy: map['picturePrivacy'] as String, invitePermissionsPrivacy: map['invitePermessionsPrivacy'] as String, - phone: map['phone'] as String, + phone: map['phoneNumber'] as String, ); } diff --git a/lib/core/models/user_model.g.dart b/lib/core/models/user_model.g.dart index e6b74f86..8073ab0d 100644 --- a/lib/core/models/user_model.g.dart +++ b/lib/core/models/user_model.g.dart @@ -26,7 +26,7 @@ class UserModelAdapter extends TypeAdapter { maxFileSize: fields[6] as int, automaticDownloadEnable: fields[7] as bool, lastSeenPrivacy: fields[8] as String, - readReceiptsEnablePrivacy: fields[9] as String, + readReceiptsEnablePrivacy: fields[9] as bool, storiesPrivacy: fields[10] as String, picturePrivacy: fields[11] as String, invitePermissionsPrivacy: fields[12] as String, diff --git a/lib/core/utils.dart b/lib/core/utils.dart index 4e6e89d7..05513112 100644 --- a/lib/core/utils.dart +++ b/lib/core/utils.dart @@ -29,15 +29,6 @@ String? passwordValidator(String? value) { return null; } -String? passwordValidatorLogIn(String? value) { - if (value == null || value.isEmpty) { - return null; - } else if (value.length < 8) { - return 'Password must be at least 8 characters long'; - } - return null; -} - // todo(ahmed): update this function to handle more cases String? confirmPasswordValidation(String? password, String? confirmedPassword) { if (password!.isEmpty || confirmedPassword!.isEmpty) return null; diff --git a/lib/features/auth/models/auth_response_model.dart b/lib/features/auth/models/auth_response_model.dart index 1c967f44..c1c11d3c 100644 --- a/lib/features/auth/models/auth_response_model.dart +++ b/lib/features/auth/models/auth_response_model.dart @@ -10,9 +10,14 @@ class AuthResponseModel { }); factory AuthResponseModel.fromMap(Map map) { + map.forEach( + (key, value) { + print('key: $key, value: $value, value type: ${value.runtimeType}'); + }, + ); return AuthResponseModel( user: UserModel.fromMap(map['user'] as Map), - token: map['accessToken'] as String, + token: map['sessionId'] as String, ); } diff --git a/lib/features/auth/repository/auth_remote_repository.dart b/lib/features/auth/repository/auth_remote_repository.dart index c851f7aa..b3e82036 100644 --- a/lib/features/auth/repository/auth_remote_repository.dart +++ b/lib/features/auth/repository/auth_remote_repository.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:fpdart/fpdart.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:dio/dio.dart'; @@ -100,7 +98,7 @@ class AuthRemoteRepository { final response = await _dio.get( '/users/me', options: Options( - headers: {HttpHeaders.authorizationHeader: 'Bearer $sessionId'}, + headers: {'X-Session-Token': sessionId}, ), ); @@ -160,7 +158,7 @@ class AuthRemoteRepository { final response = await _dio.post( route, options: Options( - headers: {HttpHeaders.authorizationHeader: 'Bearer $token'}, + headers: {'X-Session-Token': token}, ), ); @@ -180,7 +178,7 @@ class AuthRemoteRepository { Future forgotPassword(String email) async { try { final response = - await _dio.post('/auth/forgot-password', data: {email: email}); + await _dio.post('/auth/password/forget', data: {email: email}); if (response.statusCode! > 200 || response.statusCode! < 200) { final String message = response.data?['message'] ?? 'Unexpected Error'; @@ -202,7 +200,7 @@ class AuthRemoteRepository { AppError handleDioException(DioException dioException) { String? message; if (dioException.response != null) { - message = (dioException.response!.data)['data']['message']; + message = (dioException.response!.data as Map)['message']; debugPrint(message); } else if (dioException.type == DioExceptionType.connectionTimeout || dioException.type == DioExceptionType.connectionError || diff --git a/lib/features/auth/view/screens/log_in_screen.dart b/lib/features/auth/view/screens/log_in_screen.dart index 42eedc9d..8ed4c6f2 100644 --- a/lib/features/auth/view/screens/log_in_screen.dart +++ b/lib/features/auth/view/screens/log_in_screen.dart @@ -184,7 +184,6 @@ class _LogInScreenState extends ConsumerState { right: Dimensions.inputPaddingLeft, ), obscure: true, - validator: passwordValidatorLogIn, visibilityKey: const Key('login-password-visibility'), ), _forgetPasswordButton(), diff --git a/lib/features/auth/view_model/auth_view_model.dart b/lib/features/auth/view_model/auth_view_model.dart index f0e6fbc0..c5342b43 100644 --- a/lib/features/auth/view_model/auth_view_model.dart +++ b/lib/features/auth/view_model/auth_view_model.dart @@ -263,10 +263,13 @@ class AuthViewModel extends _$AuthViewModel { final token = ref.read(tokenProvider); + // started log out operation + print('log out operation started'); + print('token: $token'); final appError = await ref .read(authRemoteRepositoryProvider) - .logOut(token: token!, route: 'auth/logout'); - + .logOut(token: token!, route: '/auth/logout'); + print('log out operation ended'); await _handleLogOutState(appError); } diff --git a/lib/features/auth/view_model/auth_view_model.g.dart b/lib/features/auth/view_model/auth_view_model.g.dart index 51a56f15..784b2441 100644 --- a/lib/features/auth/view_model/auth_view_model.g.dart +++ b/lib/features/auth/view_model/auth_view_model.g.dart @@ -6,7 +6,7 @@ part of 'auth_view_model.dart'; // RiverpodGenerator // ************************************************************************** -String _$authViewModelHash() => r'1e0200c69dc6030ca961853130fbf7f3b96e0823'; +String _$authViewModelHash() => r'46a9d20ca0d4cc70d299e1371b2ca3fdcc69b912'; /// See also [AuthViewModel]. @ProviderFor(AuthViewModel) diff --git a/lib/features/user/view/screens/settings_screen.dart b/lib/features/user/view/screens/settings_screen.dart index 79c1a139..1da1d8c1 100644 --- a/lib/features/user/view/screens/settings_screen.dart +++ b/lib/features/user/view/screens/settings_screen.dart @@ -5,6 +5,8 @@ import 'package:go_router/go_router.dart'; import 'package:telware_cross_platform/core/routes/routes.dart'; import 'package:telware_cross_platform/core/theme/dimensions.dart'; import 'package:telware_cross_platform/core/theme/palette.dart'; +import 'package:telware_cross_platform/core/utils.dart'; +import 'package:telware_cross_platform/features/auth/view_model/auth_state.dart'; import 'package:telware_cross_platform/features/auth/view_model/auth_view_model.dart'; import 'package:telware_cross_platform/features/user/view/widget/profile_header_widget.dart'; import 'package:telware_cross_platform/features/user/view/widget/settings_option_widget.dart'; @@ -135,84 +137,100 @@ class _SettingsScreen extends ConsumerState { @override Widget build(BuildContext context) { + ref.listen(authViewModelProvider, (_, state) { + if (state.type == AuthStateType.fail) { + showToastMessage(state.message!); + } else if (state.type == AuthStateType.unauthorized) { + context.push(Routes.home); + } + }); + + bool isLoading = + ref.watch(authViewModelProvider).type == AuthStateType.loading; + debugPrint('isLoading: $isLoading'); + return Scaffold( - body: CustomScrollView( - slivers: [ - SliverAppBar( - expandedHeight: 145.0, - toolbarHeight: 80, - floating: false, - pinned: true, - leading: IconButton( - icon: const Icon(Icons.arrow_back), - onPressed: () => context.pop()), - actions: [ - const Icon(Icons.search), - const SizedBox(width: 16), - IconButton(onPressed: () { - ref.read(authViewModelProvider.notifier).logOut(); - context.go(Routes.logIn); - }, icon: const Icon(Icons.more_vert)), - ], - flexibleSpace: LayoutBuilder( - builder: (context, constraints) { - double factor = _calculateFactor(constraints); - return FlexibleSpaceBar( - title: ProfileHeader(fullName: fullName, factor: factor), - centerTitle: true, - background: Container( - alignment: Alignment.topLeft, - color: Palette.trinary, - padding: EdgeInsets.zero, + body: isLoading + ? const Center(child: CircularProgressIndicator.adaptive()) + : CustomScrollView( + slivers: [ + SliverAppBar( + expandedHeight: 145.0, + toolbarHeight: 80, + floating: false, + pinned: true, + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () => context.pop()), + actions: [ + const Icon(Icons.search), + const SizedBox(width: 16), + IconButton( + onPressed: () { + ref.read(authViewModelProvider.notifier).logOut(); + }, + icon: const Icon(Icons.more_vert)), + ], + flexibleSpace: LayoutBuilder( + builder: (context, constraints) { + double factor = _calculateFactor(constraints); + return FlexibleSpaceBar( + title: + ProfileHeader(fullName: fullName, factor: factor), + centerTitle: true, + background: Container( + alignment: Alignment.topLeft, + color: Palette.trinary, + padding: EdgeInsets.zero, + ), + ); + }, ), - ); - }, - ), - ), - const SliverToBoxAdapter( - child: Column( - children: [ - SettingsSection( - settingsOptions: [], - actions: [ - SettingsOptionWidget( - key: ValueKey("set-profile-photo-option"), - icon: Icons.camera_alt_outlined, - iconColor: Palette.primary, - text: "Set Profile Photo", - color: Palette.primary, - showDivider: false, - ) - ], - ), - ], - )), - SliverList( - delegate: SliverChildBuilderDelegate( - (context, index) { - final section = profileSections[index]; - final title = section["title"] ?? ""; - final options = section["options"]; - final trailing = section["trailing"] ?? ""; - return Column( + ), + const SliverToBoxAdapter( + child: Column( children: [ - const SizedBox(height: Dimensions.sectionGaps), SettingsSection( - title: title, - settingsOptions: options, - trailing: trailing, + settingsOptions: [], + actions: [ + SettingsOptionWidget( + key: ValueKey("set-profile-photo-option"), + icon: Icons.camera_alt_outlined, + iconColor: Palette.primary, + text: "Set Profile Photo", + color: Palette.primary, + showDivider: false, + ) + ], ), ], - ); - }, - childCount: profileSections.length, + )), + SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) { + final section = profileSections[index]; + final title = section["title"] ?? ""; + final options = section["options"]; + final trailing = section["trailing"] ?? ""; + return Column( + children: [ + const SizedBox(height: Dimensions.sectionGaps), + SettingsSection( + title: title, + settingsOptions: options, + trailing: trailing, + ), + ], + ); + }, + childCount: profileSections.length, + ), + ), + const SliverToBoxAdapter( + child: SizedBox(height: Dimensions.sectionGaps), + ), + ], ), - ), - const SliverToBoxAdapter( - child: SizedBox(height: Dimensions.sectionGaps), - ), - ], - ), ); } From 05a73ece321077e8c6812c507092ba14c524f927 Mon Sep 17 00:00:00 2001 From: Ahmed Aladdin Date: Thu, 31 Oct 2024 20:18:59 +0300 Subject: [PATCH 02/12] feat: use the user real profile data in the drawer --- lib/core/mock/user_mock.dart | 2 +- lib/core/models/user_model.dart | 83 +++++++++++-------- lib/core/models/user_model.g.dart | 8 +- lib/core/utils.dart | 12 +++ .../auth/view_model/auth_view_model.dart | 2 +- .../auth/view_model/auth_view_model.g.dart | 2 +- lib/features/home/view/widget/drawer.dart | 59 ++++++++----- .../stories/utils/utils_functions.dart | 5 +- .../view/widget/profile_header_widget.dart | 15 +--- 9 files changed, 112 insertions(+), 76 deletions(-) diff --git a/lib/core/mock/user_mock.dart b/lib/core/mock/user_mock.dart index c6b501fb..c374fbd5 100644 --- a/lib/core/mock/user_mock.dart +++ b/lib/core/mock/user_mock.dart @@ -1,6 +1,6 @@ import 'package:telware_cross_platform/core/models/user_model.dart'; -const UserModel userMock = UserModel( +final UserModel userMock = UserModel( username: 'mock.user', screenName: 'Mocka Mocka', email: 'mock@gmail.com', diff --git a/lib/core/models/user_model.dart b/lib/core/models/user_model.dart index 4a6104d6..a6c30718 100644 --- a/lib/core/models/user_model.dart +++ b/lib/core/models/user_model.dart @@ -1,7 +1,9 @@ // ignore_for_file: public_member_api_docs, sort_constructors_first import 'dart:convert'; +import 'dart:typed_data'; import 'package:hive/hive.dart'; +import 'package:telware_cross_platform/features/stories/utils/utils_functions.dart'; part 'user_model.g.dart'; @@ -35,8 +37,10 @@ class UserModel { final String invitePermissionsPrivacy; @HiveField(13) final String phone; + @HiveField(14) + Uint8List? photoBytes; - const UserModel({ + UserModel({ required this.username, required this.screenName, required this.email, @@ -51,45 +55,50 @@ class UserModel { required this.picturePrivacy, required this.invitePermissionsPrivacy, required this.phone, - }); + }) { + _setPhotoBytes(); + } + + _setPhotoBytes() async { + photoBytes = await downloadImage(photo); + } @override bool operator ==(covariant UserModel other) { if (identical(this, other)) return true; - - return - other.username == username && - other.screenName == screenName && - other.email == email && - other.photo == photo && - other.status == status && - other.bio == bio && - other.maxFileSize == maxFileSize && - other.automaticDownloadEnable == automaticDownloadEnable && - other.lastSeenPrivacy == lastSeenPrivacy && - other.readReceiptsEnablePrivacy == readReceiptsEnablePrivacy && - other.storiesPrivacy == storiesPrivacy && - other.picturePrivacy == picturePrivacy && - other.invitePermissionsPrivacy == invitePermissionsPrivacy && - other.phone == phone; + + return other.username == username && + other.screenName == screenName && + other.email == email && + other.photo == photo && + other.status == status && + other.bio == bio && + other.maxFileSize == maxFileSize && + other.automaticDownloadEnable == automaticDownloadEnable && + other.lastSeenPrivacy == lastSeenPrivacy && + other.readReceiptsEnablePrivacy == readReceiptsEnablePrivacy && + other.storiesPrivacy == storiesPrivacy && + other.picturePrivacy == picturePrivacy && + other.invitePermissionsPrivacy == invitePermissionsPrivacy && + other.phone == phone; } @override int get hashCode { return username.hashCode ^ - screenName.hashCode ^ - email.hashCode ^ - photo.hashCode ^ - status.hashCode ^ - bio.hashCode ^ - maxFileSize.hashCode ^ - automaticDownloadEnable.hashCode ^ - lastSeenPrivacy.hashCode ^ - readReceiptsEnablePrivacy.hashCode ^ - storiesPrivacy.hashCode ^ - picturePrivacy.hashCode ^ - invitePermissionsPrivacy.hashCode ^ - phone.hashCode; + screenName.hashCode ^ + email.hashCode ^ + photo.hashCode ^ + status.hashCode ^ + bio.hashCode ^ + maxFileSize.hashCode ^ + automaticDownloadEnable.hashCode ^ + lastSeenPrivacy.hashCode ^ + readReceiptsEnablePrivacy.hashCode ^ + storiesPrivacy.hashCode ^ + picturePrivacy.hashCode ^ + invitePermissionsPrivacy.hashCode ^ + phone.hashCode; } @override @@ -121,12 +130,15 @@ class UserModel { status: status ?? this.status, bio: bio ?? this.bio, maxFileSize: maxFileSize ?? this.maxFileSize, - automaticDownloadEnable: automaticDownloadEnable ?? this.automaticDownloadEnable, + automaticDownloadEnable: + automaticDownloadEnable ?? this.automaticDownloadEnable, lastSeenPrivacy: lastSeenPrivacy ?? this.lastSeenPrivacy, - readReceiptsEnablePrivacy: readReceiptsEnablePrivacy ?? this.readReceiptsEnablePrivacy, + readReceiptsEnablePrivacy: + readReceiptsEnablePrivacy ?? this.readReceiptsEnablePrivacy, storiesPrivacy: storiesPrivacy ?? this.storiesPrivacy, picturePrivacy: picturePrivacy ?? this.picturePrivacy, - invitePermissionsPrivacy: invitePermissionsPrivacy ?? this.invitePermissionsPrivacy, + invitePermissionsPrivacy: + invitePermissionsPrivacy ?? this.invitePermissionsPrivacy, phone: phone ?? this.phone, ); } @@ -171,5 +183,6 @@ class UserModel { String toJson() => json.encode(toMap()); - factory UserModel.fromJson(String source) => UserModel.fromMap(json.decode(source) as Map); + factory UserModel.fromJson(String source) => + UserModel.fromMap(json.decode(source) as Map); } diff --git a/lib/core/models/user_model.g.dart b/lib/core/models/user_model.g.dart index 8073ab0d..19f77b68 100644 --- a/lib/core/models/user_model.g.dart +++ b/lib/core/models/user_model.g.dart @@ -31,13 +31,13 @@ class UserModelAdapter extends TypeAdapter { picturePrivacy: fields[11] as String, invitePermissionsPrivacy: fields[12] as String, phone: fields[13] as String, - ); + )..photoBytes = fields[14] as Uint8List?; } @override void write(BinaryWriter writer, UserModel obj) { writer - ..writeByte(14) + ..writeByte(15) ..writeByte(0) ..write(obj.username) ..writeByte(1) @@ -65,7 +65,9 @@ class UserModelAdapter extends TypeAdapter { ..writeByte(12) ..write(obj.invitePermissionsPrivacy) ..writeByte(13) - ..write(obj.phone); + ..write(obj.phone) + ..writeByte(14) + ..write(obj.photoBytes); } @override diff --git a/lib/core/utils.dart b/lib/core/utils.dart index 05513112..2cda609d 100644 --- a/lib/core/utils.dart +++ b/lib/core/utils.dart @@ -93,3 +93,15 @@ String toKebabCase(String input) { // Remove leading or trailing hyphens return kebabCased.replaceAll(RegExp(r'^-+|-+$'), ''); } + +String getInitials(String name) { + List nameParts = name.split(' '); + String initials = ""; + if (nameParts.isNotEmpty) { + initials = nameParts[0][0]; + if (nameParts.length > 1) { + initials += nameParts[1][0]; + } + } + return initials.toUpperCase(); +} diff --git a/lib/features/auth/view_model/auth_view_model.dart b/lib/features/auth/view_model/auth_view_model.dart index c5342b43..6f8a39ed 100644 --- a/lib/features/auth/view_model/auth_view_model.dart +++ b/lib/features/auth/view_model/auth_view_model.dart @@ -35,7 +35,7 @@ class AuthViewModel extends _$AuthViewModel { } if (USE_MOCK_DATA) { - const user = userMock; + final user = userMock; ref.read(userProvider.notifier).update((_) => user); state = AuthState.authorized; return; diff --git a/lib/features/auth/view_model/auth_view_model.g.dart b/lib/features/auth/view_model/auth_view_model.g.dart index 784b2441..b7ef53d5 100644 --- a/lib/features/auth/view_model/auth_view_model.g.dart +++ b/lib/features/auth/view_model/auth_view_model.g.dart @@ -6,7 +6,7 @@ part of 'auth_view_model.dart'; // RiverpodGenerator // ************************************************************************** -String _$authViewModelHash() => r'46a9d20ca0d4cc70d299e1371b2ca3fdcc69b912'; +String _$authViewModelHash() => r'56ce475d492ceec78ac7c980be3946fecefc8b92'; /// See also [AuthViewModel]. @ProviderFor(AuthViewModel) diff --git a/lib/features/home/view/widget/drawer.dart b/lib/features/home/view/widget/drawer.dart index 2f351368..6fdcb0e4 100644 --- a/lib/features/home/view/widget/drawer.dart +++ b/lib/features/home/view/widget/drawer.dart @@ -1,31 +1,34 @@ import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; +import 'package:telware_cross_platform/core/providers/user_provider.dart'; import 'package:telware_cross_platform/core/theme/palette.dart'; import 'package:telware_cross_platform/core/theme/sizes.dart'; import 'package:telware_cross_platform/core/utils.dart'; -import 'package:telware_cross_platform/features/user/view/screens/profile_info_screen.dart'; import 'package:telware_cross_platform/features/user/view/screens/settings_screen.dart'; import 'package:telware_cross_platform/features/user/view/screens/user_profile_screen.dart'; -class AppDrawer extends StatelessWidget { +class AppDrawer extends ConsumerWidget { const AppDrawer({super.key}); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { return Drawer( elevation: 20, backgroundColor: Palette.background, child: ListView( padding: EdgeInsets.zero, children: [ - _header(context), + _header(context, ref), _drawerItems(context), ], ), ); } - Widget _header(BuildContext context) { + Widget _header(BuildContext context, WidgetRef ref) { + final user = ref.watch(userProvider); + final userImageBytes = user?.photoBytes; return Container( // margin: EdgeInsets.zero, padding: EdgeInsets.only( @@ -38,27 +41,36 @@ class AppDrawer extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Column( + Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ CircleAvatar( minRadius: 34, - backgroundImage: NetworkImage( - 'https://animenew.com.br/wp-content/uploads/2022/03/Este-e-o-PRIMEIRO-ESBOCO-do-VISUAL-de-Kamado-Tanjiro-em-Demon-Slayer-jpg.webp', - // fit: BoxFit., - ), + backgroundImage: + userImageBytes != null ? MemoryImage(userImageBytes) : null, + backgroundColor: + userImageBytes == null ? Palette.primary : null, + child: userImageBytes == null + ? Text( + getInitials(user?.screenName ?? 'Moamen Hefny'), + style: const TextStyle( + fontWeight: FontWeight.w500, + color: Palette.primaryText, + ), + ) + : null, ), - SizedBox(height: 18), + const SizedBox(height: 18), // todo: take real user name and number Text( - 'Ahmed Aladdin', - style: TextStyle( + user?.screenName ?? 'Moamen Hefny', + style: const TextStyle( color: Palette.primaryText, fontWeight: FontWeight.bold), ), - SizedBox(height: 2), + const SizedBox(height: 2), Text( - '+20 011 00000001', - style: TextStyle( + user?.phone ?? '+20 110 5035588', + style: const TextStyle( color: Palette.accentText, fontSize: Sizes.infoText), ), ], @@ -68,7 +80,8 @@ class AppDrawer extends StatelessWidget { children: [ IconButton( onPressed: () {}, - icon: const Icon(Icons.light_mode_rounded, color: Palette.icons)) + icon: const Icon(Icons.light_mode_rounded, + color: Palette.icons)) ], ), ], @@ -80,13 +93,15 @@ class AppDrawer extends StatelessWidget { return Wrap( children: [ // todo(ahmed): add routes to the drawer items when available - _drawerItem(context, Icons.account_circle_outlined, 'My Profile', verticalPadding: 5, route: UserProfileScreen.route), + _drawerItem(context, Icons.account_circle_outlined, 'My Profile', + verticalPadding: 5, route: UserProfileScreen.route), const Divider(thickness: 0.3, color: Palette.black, height: 0), _drawerItem(context, Icons.people_alt_outlined, 'New Group'), _drawerItem(context, Icons.person_outline_rounded, 'Contacts'), _drawerItem(context, Icons.call_outlined, 'Calls'), _drawerItem(context, Icons.bookmark_outline_rounded, 'Saved Messages'), - _drawerItem(context, Icons.settings_outlined, 'Settings', route: SettingsScreen.route), + _drawerItem(context, Icons.settings_outlined, 'Settings', + route: SettingsScreen.route), const Divider(thickness: 0.3, color: Palette.black, height: 0), _drawerItem(context, Icons.person_add_outlined, 'Invite Friends'), _drawerItem(context, Icons.info_outlined, 'TelWare Features'), @@ -94,10 +109,12 @@ class AppDrawer extends StatelessWidget { ); } - Widget _drawerItem(BuildContext context, IconData icon, String title, {double verticalPadding = 0, String? route}) { + Widget _drawerItem(BuildContext context, IconData icon, String title, + {double verticalPadding = 0, String? route}) { return ListTile( // tileColor: Colors.red, - contentPadding: EdgeInsets.symmetric(vertical: verticalPadding, horizontal: 19), + contentPadding: + EdgeInsets.symmetric(vertical: verticalPadding, horizontal: 19), leading: Icon(icon, size: 28, color: Palette.accentText), title: Row( children: [ diff --git a/lib/features/stories/utils/utils_functions.dart b/lib/features/stories/utils/utils_functions.dart index 98a47872..a842e805 100644 --- a/lib/features/stories/utils/utils_functions.dart +++ b/lib/features/stories/utils/utils_functions.dart @@ -4,7 +4,10 @@ import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import 'package:http_parser/http_parser.dart'; -Future downloadImage(String url) async { +Future downloadImage(String? url) async { + if (url == null) { + return null; + } try { final response = await http.get(Uri.parse(url)); if (response.statusCode == 200) { diff --git a/lib/features/user/view/widget/profile_header_widget.dart b/lib/features/user/view/widget/profile_header_widget.dart index 312d8841..dcb60063 100644 --- a/lib/features/user/view/widget/profile_header_widget.dart +++ b/lib/features/user/view/widget/profile_header_widget.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:telware_cross_platform/core/theme/palette.dart'; +import 'package:telware_cross_platform/core/utils.dart'; class ProfileHeader extends StatelessWidget { @@ -9,18 +10,6 @@ class ProfileHeader extends StatelessWidget { const ProfileHeader({super.key, required this.fullName, this.imagePath, this.factor = 0}); - String _getInitials(String name) { - List nameParts = name.split(' '); - String initials = ""; - if (nameParts.isNotEmpty) { - initials = nameParts[0][0]; - if (nameParts.length > 1) { - initials += nameParts[1][0]; - } - } - return initials.toUpperCase(); - } - @override Widget build(BuildContext context) { return Padding( @@ -37,7 +26,7 @@ class ProfileHeader extends StatelessWidget { backgroundColor: imagePath == null ? Palette.primary : null, child: imagePath == null ? Text( - _getInitials(fullName), + getInitials(fullName), style: const TextStyle( fontWeight: FontWeight.w500, color: Palette.primaryText, From f2f62578f6a0c8d3d90410b1bb156e6c89ee95cf Mon Sep 17 00:00:00 2001 From: Ahmed Aladdin Date: Thu, 31 Oct 2024 23:10:28 +0200 Subject: [PATCH 03/12] feat: use user data in the drawer and profile header --- lib/core/mock/user_mock.dart | 2 +- .../auth/view_model/auth_view_model.dart | 11 +++-- .../user/view/screens/settings_screen.dart | 2 +- .../view/screens/user_profile_screen.dart | 2 +- .../view/widget/profile_header_widget.dart | 44 ++++++++++--------- 5 files changed, 33 insertions(+), 28 deletions(-) diff --git a/lib/core/mock/user_mock.dart b/lib/core/mock/user_mock.dart index c374fbd5..ad023554 100644 --- a/lib/core/mock/user_mock.dart +++ b/lib/core/mock/user_mock.dart @@ -4,7 +4,7 @@ final UserModel userMock = UserModel( username: 'mock.user', screenName: 'Mocka Mocka', email: 'mock@gmail.com', - status: 'verified', + status: 'online', bio: 'I am a mocking user', maxFileSize: 30, automaticDownloadEnable: true, diff --git a/lib/features/auth/view_model/auth_view_model.dart b/lib/features/auth/view_model/auth_view_model.dart index 6f8a39ed..385dbf01 100644 --- a/lib/features/auth/view_model/auth_view_model.dart +++ b/lib/features/auth/view_model/auth_view_model.dart @@ -257,19 +257,22 @@ class AuthViewModel extends _$AuthViewModel { await ref.read(authLocalRepositoryProvider).deleteUser(); ref.read(userProvider.notifier).update((_) => null); - state = AuthState.unauthenticated; + state = AuthState.unauthorized; return; } final token = ref.read(tokenProvider); // started log out operation - print('log out operation started'); - print('token: $token'); + debugPrint('==============================='); + debugPrint('log out operation started'); + debugPrint('token: $token'); final appError = await ref .read(authRemoteRepositoryProvider) .logOut(token: token!, route: '/auth/logout'); - print('log out operation ended'); + debugPrint('==============================='); + debugPrint('log out operation ended'); + debugPrint('Error: ${appError?.error}'); await _handleLogOutState(appError); } diff --git a/lib/features/user/view/screens/settings_screen.dart b/lib/features/user/view/screens/settings_screen.dart index 1da1d8c1..02263512 100644 --- a/lib/features/user/view/screens/settings_screen.dart +++ b/lib/features/user/view/screens/settings_screen.dart @@ -176,7 +176,7 @@ class _SettingsScreen extends ConsumerState { double factor = _calculateFactor(constraints); return FlexibleSpaceBar( title: - ProfileHeader(fullName: fullName, factor: factor), + ProfileHeader(factor: factor), centerTitle: true, background: Container( alignment: Alignment.topLeft, diff --git a/lib/features/user/view/screens/user_profile_screen.dart b/lib/features/user/view/screens/user_profile_screen.dart index d7f21327..c9dbab8d 100644 --- a/lib/features/user/view/screens/user_profile_screen.dart +++ b/lib/features/user/view/screens/user_profile_screen.dart @@ -49,7 +49,7 @@ class _UserProfileScreen extends State { builder: (context, constraints) { double factor = _calculateFactor(constraints); return FlexibleSpaceBar( - title: ProfileHeader(fullName: fullName, factor: factor), + title: ProfileHeader(factor: factor), centerTitle: true, background: Container( alignment: Alignment.topLeft, diff --git a/lib/features/user/view/widget/profile_header_widget.dart b/lib/features/user/view/widget/profile_header_widget.dart index dcb60063..3c106e88 100644 --- a/lib/features/user/view/widget/profile_header_widget.dart +++ b/lib/features/user/view/widget/profile_header_widget.dart @@ -1,17 +1,19 @@ import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:telware_cross_platform/core/providers/user_provider.dart'; import 'package:telware_cross_platform/core/theme/palette.dart'; import 'package:telware_cross_platform/core/utils.dart'; -class ProfileHeader extends StatelessWidget { - final String fullName; - final String? imagePath; +class ProfileHeader extends ConsumerWidget { final double factor; - const ProfileHeader({super.key, required this.fullName, this.imagePath, this.factor = 0}); + const ProfileHeader({super.key, this.factor = 0}); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { + final user = ref.watch(userProvider); + final userImageBytes = user?.photoBytes; return Padding( padding: EdgeInsets.fromLTRB(factor, 0, 0, 0), child: Row( @@ -19,28 +21,28 @@ class ProfileHeader extends StatelessWidget { children: [ const SizedBox(width: 8), CircleAvatar( - radius: 20, - backgroundImage: imagePath != null - ? AssetImage(imagePath!) - : null, - backgroundColor: imagePath == null ? Palette.primary : null, - child: imagePath == null - ? Text( - getInitials(fullName), - style: const TextStyle( - fontWeight: FontWeight.w500, - color: Palette.primaryText, + radius: 20, + backgroundImage: + userImageBytes != null ? MemoryImage(userImageBytes) : null, + backgroundColor: + userImageBytes == null ? Palette.primary : null, + child: userImageBytes == null + ? Text( + getInitials(user?.screenName ?? 'Moamen Hefny'), + style: const TextStyle( + fontWeight: FontWeight.w500, + color: Palette.primaryText, + ), + ) + : null, ), - ) - : null, - ), const SizedBox(width: 10), Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - fullName, + user?.screenName ?? 'Moamen Hefny', style: TextStyle( fontSize: 14 + 6 * factor / 100, fontWeight: FontWeight.bold, @@ -48,7 +50,7 @@ class ProfileHeader extends StatelessWidget { ), ), Text( - "online", + user?.status ?? 'no status', style: TextStyle( fontSize: 10 + 6 * factor / 100, color: Palette.accentText, From c8ca581fe693b9b7ed61b7964330a3633f413cbe Mon Sep 17 00:00:00 2001 From: Ahmed Aladdin Date: Fri, 1 Nov 2024 06:03:09 +0200 Subject: [PATCH 04/12] fix: fix wrong range of status code --- lib/core/classes/telware_toast.dart | 43 +++++++++++++++++++ lib/core/utils.dart | 9 ++-- .../repository/auth_remote_repository.dart | 11 +++-- .../auth/view_model/auth_view_model.dart | 2 +- .../stories/utils/utils_functions.dart | 2 +- 5 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 lib/core/classes/telware_toast.dart diff --git a/lib/core/classes/telware_toast.dart b/lib/core/classes/telware_toast.dart new file mode 100644 index 00000000..83837f3f --- /dev/null +++ b/lib/core/classes/telware_toast.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; + +class TelwareToast{ + static String? _message; + + static Future showToast({ + required String msg, + Toast? toastLength, + int timeInSecForIosWeb = 1, + double? fontSize, + String? fontAsset, + ToastGravity? gravity, + Color? backgroundColor, + Color? textColor, + bool webShowClose = false, + webBgColor = "linear-gradient(to right, #00b09b, #96c93d)", + webPosition = "right", + }) async { + _message = msg; + return await Fluttertoast.showToast( + msg: msg, + toastLength: toastLength, + timeInSecForIosWeb: timeInSecForIosWeb, + fontSize: fontSize, + fontAsset: fontAsset, + gravity: gravity, + backgroundColor: backgroundColor, + textColor: textColor, + webShowClose: webShowClose, + webBgColor: webBgColor, + webPosition: webPosition, + ); + } + + static Future cancel() async { + return await Fluttertoast.cancel(); + } + + static String? get message => _message; + + TelwareToast._(); +} \ No newline at end of file diff --git a/lib/core/utils.dart b/lib/core/utils.dart index 2cda609d..b8e2fa85 100644 --- a/lib/core/utils.dart +++ b/lib/core/utils.dart @@ -1,7 +1,7 @@ // common utility functions are added here import 'dart:math'; import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.dart'; +import 'package:telware_cross_platform/core/classes/telware_toast.dart'; String? emailValidator(String? value) { const String emailPattern = @@ -53,8 +53,8 @@ void showSnackBarMessage(BuildContext context, String message) { } void showToastMessage(String message) async { - await Fluttertoast.cancel(); - Fluttertoast.showToast(msg: message); + await TelwareToast.cancel(); + TelwareToast.showToast(msg: message); } String formatPhoneNumber(String phoneNumber) { @@ -95,6 +95,9 @@ String toKebabCase(String input) { } String getInitials(String name) { + if (name.isEmpty) { + return "NN"; + } List nameParts = name.split(' '); String initials = ""; if (nameParts.isNotEmpty) { diff --git a/lib/features/auth/repository/auth_remote_repository.dart b/lib/features/auth/repository/auth_remote_repository.dart index b3e82036..f31b7f29 100644 --- a/lib/features/auth/repository/auth_remote_repository.dart +++ b/lib/features/auth/repository/auth_remote_repository.dart @@ -102,11 +102,13 @@ class AuthRemoteRepository { ), ); - if (response.statusCode! > 200 || response.statusCode! < 200) { + if (response.statusCode! >= 300 || response.statusCode! < 200) { final message = response.data['message']; return Left(AppError(message)); } + debugPrint('========================================='); + debugPrint('Get me was successful'); final user = UserModel.fromMap(response.data['data']['user']); return Right(user); } on DioException catch (dioException) { @@ -131,7 +133,7 @@ class AuthRemoteRepository { }, ); - if (response.statusCode! > 200 || response.statusCode! < 200) { + if (response.statusCode! >= 300 || response.statusCode! < 200) { final String message = response.data?['message'] ?? 'Unexpected Error'; if (response.statusCode == 403) { return Left(AppError(message, code: 403)); @@ -162,7 +164,7 @@ class AuthRemoteRepository { ), ); - if (response.statusCode! > 200 || response.statusCode! < 200) { + if (response.statusCode! >= 300 || response.statusCode! < 200) { final message = response.data['message']; return AppError(message); } @@ -180,7 +182,7 @@ class AuthRemoteRepository { final response = await _dio.post('/auth/password/forget', data: {email: email}); - if (response.statusCode! > 200 || response.statusCode! < 200) { + if (response.statusCode! >= 300 || response.statusCode! < 200) { final String message = response.data?['message'] ?? 'Unexpected Error'; return AppError(message); } @@ -199,6 +201,7 @@ class AuthRemoteRepository { AppError handleDioException(DioException dioException) { String? message; + debugPrint('Dio Exception: ${dioException.response?.data.toString()}'); if (dioException.response != null) { message = (dioException.response!.data as Map)['message']; debugPrint(message); diff --git a/lib/features/auth/view_model/auth_view_model.dart b/lib/features/auth/view_model/auth_view_model.dart index 385dbf01..12ecfdaa 100644 --- a/lib/features/auth/view_model/auth_view_model.dart +++ b/lib/features/auth/view_model/auth_view_model.dart @@ -259,7 +259,7 @@ class AuthViewModel extends _$AuthViewModel { ref.read(userProvider.notifier).update((_) => null); state = AuthState.unauthorized; return; - } + } final token = ref.read(tokenProvider); diff --git a/lib/features/stories/utils/utils_functions.dart b/lib/features/stories/utils/utils_functions.dart index a842e805..6aa93746 100644 --- a/lib/features/stories/utils/utils_functions.dart +++ b/lib/features/stories/utils/utils_functions.dart @@ -5,7 +5,7 @@ import 'package:http/http.dart' as http; import 'package:http_parser/http_parser.dart'; Future downloadImage(String? url) async { - if (url == null) { + if (url == null || url.isEmpty) { return null; } try { From 6f85d9a35e83f35a7e7ccd4bea5a2a5e037f18ca Mon Sep 17 00:00:00 2001 From: Bishoywadea Date: Fri, 1 Nov 2024 06:04:38 +0200 Subject: [PATCH 05/12] REF(Sessions): add update profile pic --- lib/core/routes/routes.dart | 38 ++--- .../repository/auth_remote_repository.dart | 6 +- .../contacts_remote_repository.dart | 149 +++--------------- ...y_screen.dart => add_my_image_screen.dart} | 17 +- ...reen.dart => show_taken_image_screen.dart} | 10 +- ...ottom_action_buttons_edit_taken_image.dart | 37 ++++- .../view_model/contact_view_model.dart | 4 + .../user/view/screens/settings_screen.dart | 29 ++-- .../view/screens/user_profile_screen.dart | 136 +++++++++------- lib/main.dart | 12 +- 10 files changed, 204 insertions(+), 234 deletions(-) rename lib/features/stories/view/screens/{add_my_story_screen.dart => add_my_image_screen.dart} (91%) rename lib/features/stories/view/screens/{show_taken_story_screen.dart => show_taken_image_screen.dart} (93%) diff --git a/lib/core/routes/routes.dart b/lib/core/routes/routes.dart index 838e9937..c8ce2404 100644 --- a/lib/core/routes/routes.dart +++ b/lib/core/routes/routes.dart @@ -13,8 +13,8 @@ import 'package:telware_cross_platform/features/auth/view/screens/verification_s import 'package:telware_cross_platform/features/auth/view_model/auth_view_model.dart'; import 'package:telware_cross_platform/features/home/view/screens/home_screen.dart'; import 'package:telware_cross_platform/features/home/view/screens/inbox_screen.dart'; -import 'package:telware_cross_platform/features/stories/view/screens/add_my_story_screen.dart'; -import 'package:telware_cross_platform/features/stories/view/screens/show_taken_story_screen.dart'; +import 'package:telware_cross_platform/features/stories/view/screens/add_my_image_screen.dart'; +import 'package:telware_cross_platform/features/stories/view/screens/show_taken_image_screen.dart'; import 'package:telware_cross_platform/features/stories/view/screens/story_screen.dart'; import 'package:telware_cross_platform/features/user/view/screens/block_user.dart'; import 'package:telware_cross_platform/features/user/view/screens/blocked_users.dart'; @@ -34,8 +34,8 @@ class Routes { static const String verification = VerificationScreen.route; static const String socialAuthLoading = SocialAuthLoadingScreen.route; static const String inboxScreen = InboxScreen.route; - static const String addMyStory = AddMyStoryScreen.route; - static const String showTakenStory = ShowTakenStoryScreen.route; + static const String addMyStory = AddMyImageScreen.route; + static const String showTakenStory = ShowTakenImageScreen.route; static const String storyScreen = StoryScreen.route; static const String devicesScreen = DevicesScreen.route; static const String settings = SettingsScreen.route; @@ -49,19 +49,19 @@ class Routes { static GoRouter appRouter(WidgetRef ref) => GoRouter( initialLocation: Routes.home, - // redirect: (context, state) { - // final isAuthenticated = - // ref.read(authViewModelProvider.notifier).isAuthenticated(); - // if (!isAuthenticated) { - // if (state.fullPath != Routes.logIn && - // state.fullPath != Routes.signUp && - // state.fullPath != Routes.verification && - // state.fullPath != Routes.splash) { - // return Routes.logIn; - // } - // } - // return null; - // }, + redirect: (context, state) { + final isAuthenticated = + ref.read(authViewModelProvider.notifier).isAuthenticated(); + if (!isAuthenticated) { + if (state.fullPath != Routes.logIn && + state.fullPath != Routes.signUp && + state.fullPath != Routes.verification && + state.fullPath != Routes.splash) { + return Routes.logIn; + } + } + return null; + }, routes: [ GoRoute( path: Routes.splash, @@ -110,7 +110,7 @@ class Routes { path: Routes.addMyStory, pageBuilder: (context, state) => CustomTransitionPage( key: state.pageKey, - child: const AddMyStoryScreen(), + child: const AddMyImageScreen(), transitionsBuilder: _slideRightTransitionBuilder, ), ), @@ -118,7 +118,7 @@ class Routes { path: Routes.showTakenStory, pageBuilder: (context, state) => CustomTransitionPage( key: state.pageKey, - child: ShowTakenStoryScreen(image: state.extra as File), + child: ShowTakenImageScreen(image: state.extra as File), transitionsBuilder: _slideRightTransitionBuilder, ), ), diff --git a/lib/features/auth/repository/auth_remote_repository.dart b/lib/features/auth/repository/auth_remote_repository.dart index c851f7aa..c70a37f2 100644 --- a/lib/features/auth/repository/auth_remote_repository.dart +++ b/lib/features/auth/repository/auth_remote_repository.dart @@ -133,7 +133,7 @@ class AuthRemoteRepository { }, ); - if (response.statusCode! > 200 || response.statusCode! < 200) { + if (response.statusCode! >= 300 || response.statusCode! < 200) { final String message = response.data?['message'] ?? 'Unexpected Error'; if (response.statusCode == 403) { return Left(AppError(message, code: 403)); @@ -201,8 +201,10 @@ class AuthRemoteRepository { AppError handleDioException(DioException dioException) { String? message; + debugPrint('Dio Exception: ${dioException.response?.toString()}'); if (dioException.response != null) { - message = (dioException.response!.data)['data']['message']; + message = + (dioException.response!.data as Map)['message']; debugPrint(message); } else if (dioException.type == DioExceptionType.connectionTimeout || dioException.type == DioExceptionType.connectionError || diff --git a/lib/features/stories/repository/contacts_remote_repository.dart b/lib/features/stories/repository/contacts_remote_repository.dart index 55570862..08ac5e43 100644 --- a/lib/features/stories/repository/contacts_remote_repository.dart +++ b/lib/features/stories/repository/contacts_remote_repository.dart @@ -22,139 +22,15 @@ class ContactsRemoteRepository { Future> fetchContactsFromBackend() async { await Future.delayed(const Duration(seconds: 2)); List users = [ - ContactModel( - userName: 'game of thrones', - userImageUrl: - 'https://st2.depositphotos.com/2703645/7304/v/450/depositphotos_73040253-stock-illustration-male-avatar-icon.jpg', - stories: [ - StoryModel( - storyId: 'idd11', - createdAt: DateTime(2024, 10, 21, 12, 0), - storyContentUrl: - 'https://raw.githubusercontent.com/Bishoywadea/hosted_images/refs/heads/main/1.jpg', - isSeen: false, - storyCaption: 'very good caption', - seenIds: ['id1', 'id2']), - StoryModel( - storyId: 'idd12', - createdAt: DateTime(2024, 10, 21, 12, 0), - storyContentUrl: - 'https://raw.githubusercontent.com/Bishoywadea/hosted_images/refs/heads/main/2.jpeg', - isSeen: false, - storyCaption: 'very good good good caption', - seenIds: ['id2'], - ), - StoryModel( - storyId: 'idd13', - createdAt: DateTime(2024, 10, 21, 12, 0), - storyContentUrl: - 'https://www.e3lam.com/images/large/2015/01/unnamed-14.jpg', - isSeen: false, - seenIds: ['id1', 'id2'], - ), - ], - userId: 'myUser', - ), - ContactModel( - stories: [ - StoryModel( - storyId: 'id11', - createdAt: DateTime(2024, 10, 21, 12, 0), - storyContentUrl: - 'https://raw.githubusercontent.com/Bishoywadea/hosted_images/refs/heads/main/1.jpg', - isSeen: false, - seenIds: [], - ), - StoryModel( - storyId: 'id12', - createdAt: DateTime(2024, 10, 21, 12, 0), - storyContentUrl: - 'https://raw.githubusercontent.com/Bishoywadea/hosted_images/refs/heads/main/2.jpeg', - isSeen: false, - storyCaption: 'very good good good caption', - seenIds: [], - ), - ], - userName: 'game of thrones', - userImageUrl: - 'https://raw.githubusercontent.com/Bishoywadea/hosted_images/refs/heads/main/2.jpeg', - userId: 'id1', - ), - ContactModel( - stories: [ - StoryModel( - storyId: 'id21', - createdAt: DateTime(2024, 10, 21, 12, 0), - storyContentUrl: - 'https://raw.githubusercontent.com/Bishoywadea/hosted_images/refs/heads/main/1.jpg', - isSeen: false, - seenIds: [], - ), - StoryModel( - storyId: 'id22', - createdAt: DateTime(2024, 10, 21, 12, 0), - storyContentUrl: - 'https://raw.githubusercontent.com/Bishoywadea/hosted_images/refs/heads/main/2.jpeg', - isSeen: false, - seenIds: [], - ), - StoryModel( - storyId: 'id23', - createdAt: DateTime(2024, 10, 21, 12, 0), - storyContentUrl: - 'https://raw.githubusercontent.com/Bishoywadea/hosted_images/refs/heads/main/1.jpg', - isSeen: false, - seenIds: [], - ), - ], - userName: 'rings of power', - userImageUrl: - 'https://raw.githubusercontent.com/Bishoywadea/hosted_images/refs/heads/main/1.jpg', - userId: 'id2', - ), - ContactModel( - stories: [ - StoryModel( - storyId: 'id31', - createdAt: DateTime(2024, 10, 21, 12, 0), - storyContentUrl: - 'https://raw.githubusercontent.com/Bishoywadea/hosted_images/refs/heads/main/1.jpg', - isSeen: false, - storyCaption: 'very good good good caption', - seenIds: [], - ), - StoryModel( - storyId: 'id32', - createdAt: DateTime(2024, 10, 21, 12, 0), - storyContentUrl: - 'https://raw.githubusercontent.com/Bishoywadea/hosted_images/refs/heads/main/2.jpeg', - isSeen: false, - seenIds: [], - ), - StoryModel( - storyId: 'id33', - createdAt: DateTime(2024, 10, 21, 12, 0), - storyContentUrl: - 'https://raw.githubusercontent.com/Bishoywadea/hosted_images/refs/heads/main/1.jpg', - isSeen: false, - seenIds: [], - ), - ], - userName: 'rings of power', - userImageUrl: - 'https://raw.githubusercontent.com/Bishoywadea/hosted_images/refs/heads/main/1.jpg', - userId: 'id3', - ), ]; return users; } Future postStory(File storyImage, String? caption) async { - print('fdsaib'); String uploadUrl = 'http://testing.telware.tech:3000/api/v1/users/stories'; var uri = Uri.parse(uploadUrl); var request = http.MultipartRequest('POST', uri); - request.headers['X-Session-Token'] = '410b860a-de14-4cbe-b5f2-7cff8518a2f7'; + request.headers['X-Session-Token'] = authLocalRepository.getToken() ?? ''; var multipartFile = await http.MultipartFile.fromPath( 'file', @@ -178,6 +54,29 @@ class ContactsRemoteRepository { } } + Future updateProfilePicture(File storyImage) async { + String uploadUrl = 'http://testing.telware.tech:3000/api/v1/users/picture'; + var uri = Uri.parse(uploadUrl); + var request = http.MultipartRequest('PATCH', uri); + request.headers['X-Session-Token'] = authLocalRepository.getToken() ?? '410b860a-de14-4cbe-b5f2-7cff8518a2f7'; + var multipartFile = await http.MultipartFile.fromPath( + 'file', + storyImage.path, + contentType: MediaType('image', 'jpeg'), + ); + request.files.add(multipartFile); + + try { + var response = await request.send(); + return response.statusCode == 201; + } catch (e) { + if (kDebugMode) { + print('Error occurred: $e'); + } + return false; + } + } + Future markStoryAsSeen(String storyId) async { String uploadUrl = 'http://testing.telware.tech:3000/api/v1/stories/:storyId/views'; // var uri = Uri.parse(uploadUrl); diff --git a/lib/features/stories/view/screens/add_my_story_screen.dart b/lib/features/stories/view/screens/add_my_image_screen.dart similarity index 91% rename from lib/features/stories/view/screens/add_my_story_screen.dart rename to lib/features/stories/view/screens/add_my_image_screen.dart index 8e479100..fa94d16b 100644 --- a/lib/features/stories/view/screens/add_my_story_screen.dart +++ b/lib/features/stories/view/screens/add_my_image_screen.dart @@ -7,20 +7,21 @@ import 'package:flutter/services.dart'; import 'package:go_router/go_router.dart'; import 'package:telware_cross_platform/core/routes/routes.dart'; import 'package:path_provider/path_provider.dart'; -import 'package:telware_cross_platform/features/stories/view/screens/show_taken_story_screen.dart'; +import 'package:telware_cross_platform/features/stories/view/screens/show_taken_image_screen.dart'; import '../widget/take_photo_row.dart'; import '../widget/toggleCameraMode.dart'; -class AddMyStoryScreen extends StatefulWidget { - static const String route = '/add-my-story'; - - const AddMyStoryScreen({super.key}); +class AddMyImageScreen extends StatefulWidget { + static const String route = '/add-my-image'; + final String destination; + const AddMyImageScreen({super.key, this.destination = 'story',}); @override - _AddMyStoryScreenState createState() => _AddMyStoryScreenState(); + _AddMyImageScreenState createState() => _AddMyImageScreenState(); } -class _AddMyStoryScreenState extends State { +class _AddMyImageScreenState extends State { + CameraController? _controller; Future? _initializeControllerFuture; String _selectedMode = 'Photo'; @@ -101,7 +102,7 @@ class _AddMyStoryScreenState extends State { Navigator.push( context, MaterialPageRoute( - builder: (context) => ShowTakenStoryScreen(image: savedFile), + builder: (context) => ShowTakenImageScreen(image: savedFile, destination:widget.destination), ), ); } catch (e) { diff --git a/lib/features/stories/view/screens/show_taken_story_screen.dart b/lib/features/stories/view/screens/show_taken_image_screen.dart similarity index 93% rename from lib/features/stories/view/screens/show_taken_story_screen.dart rename to lib/features/stories/view/screens/show_taken_image_screen.dart index 433334aa..873b987b 100644 --- a/lib/features/stories/view/screens/show_taken_story_screen.dart +++ b/lib/features/stories/view/screens/show_taken_image_screen.dart @@ -16,17 +16,18 @@ import '../widget/bottom_action_buttons_edit_taken_image.dart'; import '../widget/signature_pen.dart'; import '../widget/story_caption_text_field.dart'; -class ShowTakenStoryScreen extends ConsumerStatefulWidget { +class ShowTakenImageScreen extends ConsumerStatefulWidget { static const String route = '/show-taken-story'; final File image; + final String destination; - const ShowTakenStoryScreen({super.key, required this.image}); + const ShowTakenImageScreen({super.key, required this.image, this.destination = 'story',}); @override _ShowTakenStoryScreenState createState() => _ShowTakenStoryScreenState(); } -class _ShowTakenStoryScreenState extends ConsumerState { +class _ShowTakenStoryScreenState extends ConsumerState { final GlobalKey _signatureBoundaryKey = GlobalKey(); File? _imageFile; File? _originalImageFile; @@ -155,13 +156,14 @@ class _ShowTakenStoryScreenState extends ConsumerState { child: Column( mainAxisSize: MainAxisSize.min, children: [ - StoryCaptionField(controller: _captionController), + widget.destination == 'story' ? StoryCaptionField(controller: _captionController) : const SizedBox(), BottomActionButtonsEditTakenImage( cropImage: _cropImage, discardChanges: _discardChanges, saveAndPostStory: _saveCombinedImage, captionController: _captionController, ref: ref, + destination: widget.destination, ), ], ), diff --git a/lib/features/stories/view/widget/bottom_action_buttons_edit_taken_image.dart b/lib/features/stories/view/widget/bottom_action_buttons_edit_taken_image.dart index 6c2690bc..4958c5bf 100644 --- a/lib/features/stories/view/widget/bottom_action_buttons_edit_taken_image.dart +++ b/lib/features/stories/view/widget/bottom_action_buttons_edit_taken_image.dart @@ -10,6 +10,7 @@ class BottomActionButtonsEditTakenImage extends StatelessWidget { final Future Function() saveAndPostStory; final TextEditingController captionController; final WidgetRef ref; + final String destination; const BottomActionButtonsEditTakenImage({ Key? key, @@ -18,6 +19,7 @@ class BottomActionButtonsEditTakenImage extends StatelessWidget { required this.saveAndPostStory, required this.captionController, required this.ref, + this.destination = 'story' }) : super(key: key); @override @@ -41,14 +43,33 @@ class BottomActionButtonsEditTakenImage extends StatelessWidget { FocusScope.of(context).unfocus(); File combinedImageFile = await saveAndPostStory(); String storyCaption = captionController.text; - final contactViewModel = ref.read(usersViewModelProvider.notifier); - bool uploadResult = await contactViewModel.postStory(combinedImageFile, storyCaption); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(uploadResult ? 'Story Posted Successfully' : 'Failed to post Story'), - ), - ); - + bool uploadResult = false; + if(destination == 'story') { + final contactViewModel = ref.read( + usersViewModelProvider.notifier); + uploadResult = await contactViewModel.postStory( + combinedImageFile, storyCaption); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(uploadResult + ? 'Story Posted Successfully' + : 'Failed to post Story'), + ), + ); + } + else{ + final contactViewModel = ref.read( + usersViewModelProvider.notifier); + uploadResult = await contactViewModel.updateProfilePicture( + combinedImageFile); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(uploadResult + ? 'Profile Picture updated' + : 'Failed to post update profile picture'), + ), + ); + } if (uploadResult) { Future.delayed(const Duration(seconds: 2), () { Navigator.of(context).pop(); diff --git a/lib/features/stories/view_model/contact_view_model.dart b/lib/features/stories/view_model/contact_view_model.dart index 70fbe7b3..69381cc0 100644 --- a/lib/features/stories/view_model/contact_view_model.dart +++ b/lib/features/stories/view_model/contact_view_model.dart @@ -150,6 +150,10 @@ class ContactViewModel extends StateNotifier { return _contactsRemoteRepository.postStory(storyImage, storyCaption); } + Future updateProfilePicture(File storyImage) async { + return _contactsRemoteRepository.updateProfilePicture(storyImage); + } + Future deleteStory(String storyId) async { return _contactsRemoteRepository.deleteStory(storyId); } diff --git a/lib/features/user/view/screens/settings_screen.dart b/lib/features/user/view/screens/settings_screen.dart index 80d5f3f3..889df165 100644 --- a/lib/features/user/view/screens/settings_screen.dart +++ b/lib/features/user/view/screens/settings_screen.dart @@ -10,6 +10,8 @@ import 'package:telware_cross_platform/features/user/view/widget/profile_header_ import 'package:telware_cross_platform/features/user/view/widget/settings_option_widget.dart'; import 'package:telware_cross_platform/features/user/view/widget/settings_section.dart'; +import '../../../stories/view/screens/add_my_image_screen.dart'; + class SettingsScreen extends ConsumerStatefulWidget { static const String route = '/settings'; @@ -169,19 +171,28 @@ class _SettingsScreen extends ConsumerState { }, ), ), - const SliverToBoxAdapter( + SliverToBoxAdapter( child: Column( children: [ SettingsSection( - settingsOptions: [], + settingsOptions: const [], actions: [ - SettingsOptionWidget( - key: ValueKey("set-profile-photo-option"), - icon: Icons.camera_alt_outlined, - iconColor: Palette.primary, - text: "Set Profile Photo", - color: Palette.primary, - showDivider: false, + GestureDetector( + onTap: (){ + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => AddMyImageScreen(destination: 'profile'), + ), + ); + }, + child: SettingsOptionWidget( + key: ValueKey("set-profile-photo-option"), + icon: Icons.camera_alt_outlined, + iconColor: Palette.primary, + text: "Set Profile Photo", + color: Palette.primary, + showDivider: false, + ), ) ], ), diff --git a/lib/features/user/view/screens/user_profile_screen.dart b/lib/features/user/view/screens/user_profile_screen.dart index d7f21327..9474e681 100644 --- a/lib/features/user/view/screens/user_profile_screen.dart +++ b/lib/features/user/view/screens/user_profile_screen.dart @@ -3,6 +3,7 @@ import 'package:go_router/go_router.dart'; import 'package:telware_cross_platform/core/routes/routes.dart'; import 'package:telware_cross_platform/core/theme/dimensions.dart'; import 'package:telware_cross_platform/core/theme/palette.dart'; +import 'package:telware_cross_platform/features/stories/view/screens/add_my_image_screen.dart'; import 'package:telware_cross_platform/features/user/view/widget/profile_header_widget.dart'; import 'package:telware_cross_platform/features/user/view/widget/settings_option_widget.dart'; import 'package:telware_cross_platform/features/user/view/widget/settings_section.dart'; @@ -28,73 +29,98 @@ class _UserProfileScreen extends State { @override Widget build(BuildContext context) { return Scaffold( - body: CustomScrollView( - slivers: [ - SliverAppBar( - expandedHeight: 145.0, - toolbarHeight: 80, - floating: false, - pinned: true, - leading: IconButton( - icon: const Icon(Icons.arrow_back), - onPressed: () => context.pop(), - ), - actions: [ - IconButton(icon: const Icon(Icons.edit), - onPressed: () => context.push(Routes.profileInfo)), - const SizedBox(width: 16), - const Icon(Icons.more_vert), - ], - flexibleSpace: LayoutBuilder( - builder: (context, constraints) { - double factor = _calculateFactor(constraints); - return FlexibleSpaceBar( - title: ProfileHeader(fullName: fullName, factor: factor), - centerTitle: true, - background: Container( - alignment: Alignment.topLeft, - color: Palette.trinary, - padding: EdgeInsets.zero, + body: Stack( + children: [ + CustomScrollView( + slivers: [ + SliverAppBar( + expandedHeight: 145.0, + toolbarHeight: 80, + floating: false, + pinned: true, + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () => context.pop(), + ), + actions: [ + IconButton( + icon: const Icon(Icons.edit), + onPressed: () => context.push(Routes.profileInfo), ), - ); - }, - ), - ), - SliverToBoxAdapter( - child: Column( - children: [ - SettingsSection( - title: "Info", - settingsOptions: const [], - actions: [ - SettingsOptionWidget(text: user["phoneNumber"] ?? "", - icon: null, - subtext: "Mobile", + const SizedBox(width: 16), + const Icon(Icons.more_vert), + ], + flexibleSpace: LayoutBuilder( + builder: (context, constraints) { + double factor = _calculateFactor(constraints); + return FlexibleSpaceBar( + title: ProfileHeader(fullName: fullName, factor: factor), + centerTitle: true, + background: Container( + alignment: Alignment.topLeft, + color: Palette.trinary, + padding: EdgeInsets.zero, ), - if (user["bio"] != null) - SettingsOptionWidget(icon: null, - text: user["bio"] ?? "", - subtext: "Bio" + ); + }, + ), + ), + SliverToBoxAdapter( + child: Column( + children: [ + SettingsSection( + title: "Info", + settingsOptions: const [], + actions: [ + SettingsOptionWidget( + text: user["phoneNumber"] ?? "", + icon: null, + subtext: "Mobile", ), - if (user["username"] != null) - SettingsOptionWidget(icon: null, + if (user["bio"] != null) + SettingsOptionWidget( + icon: null, + text: user["bio"] ?? "", + subtext: "Bio", + ), + if (user["username"] != null) + SettingsOptionWidget( + icon: null, text: "@${user["username"]}", - subtext: "Username" - ), - ], - ), - ], + subtext: "Username", + ), + ], + ), + ], + ), + ), + const SliverToBoxAdapter( + child: SizedBox(height: Dimensions.sectionGaps), ), + ], ), - - const SliverToBoxAdapter( - child: SizedBox(height: Dimensions.sectionGaps), + Positioned( + top:140, + right: 16.0, + child: FloatingActionButton( + onPressed: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => AddMyImageScreen(destination: 'profile'), + ), + ); + }, + shape: const CircleBorder(), + backgroundColor: Palette.primary, + child: const Icon(Icons.add), + ), ), ], ), ); } + double _calculateFactor(BoxConstraints constraints) { double maxExtent = 130.0; double scrollOffset = constraints.maxHeight - kToolbarHeight; diff --git a/lib/main.dart b/lib/main.dart index d470b61e..10d9fd9a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -28,10 +28,14 @@ Future init() async { Hive.registerAdapter(StoryModelAdapter()); Hive.registerAdapter(ContactModelBlockAdapter()); await Hive.initFlutter(); - await Hive.openBox('contacts'); - await Hive.openBox('contacts-block'); - await Hive.openBox('auth-token'); - await Hive.openBox('auth-user'); + dynamic box = await Hive.openBox('contacts'); + await box.clear(); + box = await Hive.openBox('contacts-block'); + await box.clear(); + box = await Hive.openBox('auth-token'); + await box.clear(); + box = await Hive.openBox('auth-user'); + await box.clear(); await dotenv.load(fileName: "lib/.env"); } From 63cc02c67176d646b908cbbcd0b62c3ea1c15286 Mon Sep 17 00:00:00 2001 From: Ahmed Aladdin Date: Fri, 1 Nov 2024 06:35:24 +0200 Subject: [PATCH 06/12] fix: wrong body in the forget password request --- lib/features/auth/repository/auth_remote_repository.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/features/auth/repository/auth_remote_repository.dart b/lib/features/auth/repository/auth_remote_repository.dart index 057cabf7..b292b18e 100644 --- a/lib/features/auth/repository/auth_remote_repository.dart +++ b/lib/features/auth/repository/auth_remote_repository.dart @@ -179,9 +179,11 @@ class AuthRemoteRepository { Future forgotPassword(String email) async { try { + debugPrint('email: $email'); final response = - await _dio.post('/auth/password/forget', data: {email: email}); + await _dio.post('/auth/password/forget', data: {'email': email}); + debugPrint('Forgot Password response: ${response.data ?? 'No data'}'); if (response.statusCode! >= 300 || response.statusCode! < 200) { final String message = response.data?['message'] ?? 'Unexpected Error'; return AppError(message); From ef245ea1155bd607702e1d60c9f3d4d2eb8e7843 Mon Sep 17 00:00:00 2001 From: Ahmed Aladdin Date: Fri, 1 Nov 2024 06:41:15 +0200 Subject: [PATCH 07/12] fix: handle wrong spacing in the login and sign up screens --- lib/features/auth/view/screens/log_in_screen.dart | 3 ++- lib/features/auth/view/screens/sign_up_screen.dart | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/features/auth/view/screens/log_in_screen.dart b/lib/features/auth/view/screens/log_in_screen.dart index 8ed4c6f2..a6232aeb 100644 --- a/lib/features/auth/view/screens/log_in_screen.dart +++ b/lib/features/auth/view/screens/log_in_screen.dart @@ -192,7 +192,8 @@ class _LogInScreenState extends ConsumerState { mainAxisAlignment: MainAxisAlignment.center, children: [ const TitleElement( - name: 'Don\'t have an account? ', + padding: EdgeInsets.only(right: 5), + name: 'Don\'t have an account?', color: Palette.primaryText, fontSize: Sizes.infoText, ), diff --git a/lib/features/auth/view/screens/sign_up_screen.dart b/lib/features/auth/view/screens/sign_up_screen.dart index f00aa7eb..82238725 100644 --- a/lib/features/auth/view/screens/sign_up_screen.dart +++ b/lib/features/auth/view/screens/sign_up_screen.dart @@ -16,7 +16,6 @@ import 'package:telware_cross_platform/core/view/widget/responsive.dart'; import 'package:telware_cross_platform/features/auth/view/widget/auth_floating_action_button.dart'; import 'package:telware_cross_platform/features/auth/view/widget/auth_phone_number.dart'; import 'package:telware_cross_platform/features/auth/view/widget/auth_sub_text_button.dart'; -import 'package:telware_cross_platform/features/auth/view/widget/confirmation_dialog.dart'; import 'package:telware_cross_platform/features/auth/view/widget/shake_my_auth_input.dart'; import 'package:telware_cross_platform/features/auth/view/widget/social_log_in.dart'; import 'package:telware_cross_platform/features/auth/view/widget/title_element.dart'; @@ -251,7 +250,8 @@ class _SignUpScreenState extends ConsumerState { mainAxisAlignment: MainAxisAlignment.center, children: [ const TitleElement( - name: 'Already have an account? ', + padding: EdgeInsets.only(right: 5), + name: 'Already have an account?', color: Palette.primaryText, fontSize: Sizes.infoText), AuthSubTextButton( From 1120a2ec4ecbd826285e294cd5c77d42976d3208 Mon Sep 17 00:00:00 2001 From: Ahmed Aladdin Date: Fri, 1 Nov 2024 07:13:04 +0200 Subject: [PATCH 08/12] feat: make the screen name 'No Name' in case of the using not having a name --- lib/core/models/user_model.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/core/models/user_model.dart b/lib/core/models/user_model.dart index a6c30718..85275bb8 100644 --- a/lib/core/models/user_model.dart +++ b/lib/core/models/user_model.dart @@ -163,9 +163,13 @@ class UserModel { } factory UserModel.fromMap(Map map) { + String screenName = map['screenName'] as String; + if (screenName.isEmpty) { + screenName = 'No Name'; + } return UserModel( username: map['username'] as String, - screenName: map['screenName'] as String, + screenName: screenName, email: map['email'] as String, photo: map['photo'] != null ? map['photo'] as String : null, status: map['status'] as String, From ea64f77504b9a086013e0b84724fcd3c1673233f Mon Sep 17 00:00:00 2001 From: Ahmed Aladdin Date: Fri, 1 Nov 2024 07:49:47 +0200 Subject: [PATCH 09/12] fix: merge brackets problem --- .../user/view/screens/settings_screen.dart | 95 +++++++++---------- .../view/screens/user_profile_screen.dart | 13 ++- 2 files changed, 52 insertions(+), 56 deletions(-) diff --git a/lib/features/user/view/screens/settings_screen.dart b/lib/features/user/view/screens/settings_screen.dart index 4ba7e158..0ec70abd 100644 --- a/lib/features/user/view/screens/settings_screen.dart +++ b/lib/features/user/view/screens/settings_screen.dart @@ -177,8 +177,7 @@ class _SettingsScreen extends ConsumerState { builder: (context, constraints) { double factor = _calculateFactor(constraints); return FlexibleSpaceBar( - title: - ProfileHeader(factor: factor), + title: ProfileHeader(factor: factor), centerTitle: true, background: Container( alignment: Alignment.topLeft, @@ -188,61 +187,59 @@ class _SettingsScreen extends ConsumerState { ); }, ), - ); - }, - ), - ), - SliverToBoxAdapter( - child: Column( - children: [ - SettingsSection( - settingsOptions: const [], - actions: [ - GestureDetector( - onTap: (){ - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => AddMyImageScreen(destination: 'profile'), - ), - ); - }, - child: SettingsOptionWidget( - key: ValueKey("set-profile-photo-option"), - icon: Icons.camera_alt_outlined, - iconColor: Palette.primary, - text: "Set Profile Photo", - color: Palette.primary, - showDivider: false, - ), - ) - ], - ), - ], - )), - SliverList( - delegate: SliverChildBuilderDelegate( - (context, index) { - final section = profileSections[index]; - final title = section["title"] ?? ""; - final options = section["options"]; - final trailing = section["trailing"] ?? ""; - return Column( + ), + SliverToBoxAdapter( + child: Column( children: [ SettingsSection( - settingsOptions: [], + settingsOptions: const [], actions: [ - SettingsOptionWidget( - key: ValueKey("set-profile-photo-option"), - icon: Icons.camera_alt_outlined, - iconColor: Palette.primary, - text: "Set Profile Photo", - color: Palette.primary, - showDivider: false, + GestureDetector( + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const AddMyImageScreen( + destination: 'profile'), + ), + ); + }, + child: const SettingsOptionWidget( + key: ValueKey("set-profile-photo-option"), + icon: Icons.camera_alt_outlined, + iconColor: Palette.primary, + text: "Set Profile Photo", + color: Palette.primary, + showDivider: false, + ), ) ], ), ], )), + SliverList( + delegate: SliverChildBuilderDelegate((context, index) { + final section = profileSections[index]; + final title = section["title"] ?? ""; + final options = section["options"]; + final trailing = section["trailing"] ?? ""; + return const Column( + children: [ + SettingsSection( + settingsOptions: [], + actions: [ + SettingsOptionWidget( + key: ValueKey("set-profile-photo-option"), + icon: Icons.camera_alt_outlined, + iconColor: Palette.primary, + text: "Set Profile Photo", + color: Palette.primary, + showDivider: false, + ) + ], + ), + ], + ); + })), SliverList( delegate: SliverChildBuilderDelegate( (context, index) { diff --git a/lib/features/user/view/screens/user_profile_screen.dart b/lib/features/user/view/screens/user_profile_screen.dart index 9474e681..fd73e675 100644 --- a/lib/features/user/view/screens/user_profile_screen.dart +++ b/lib/features/user/view/screens/user_profile_screen.dart @@ -18,8 +18,6 @@ class UserProfileScreen extends StatefulWidget { } class _UserProfileScreen extends State { - static const String fullName = "Moamen Hefny"; - static var user = { "phoneNumber": "+20 110 5035588", "username": "Moamen", @@ -54,7 +52,7 @@ class _UserProfileScreen extends State { builder: (context, constraints) { double factor = _calculateFactor(constraints); return FlexibleSpaceBar( - title: ProfileHeader(fullName: fullName, factor: factor), + title: ProfileHeader(factor: factor), centerTitle: true, background: Container( alignment: Alignment.topLeft, @@ -100,13 +98,14 @@ class _UserProfileScreen extends State { ], ), Positioned( - top:140, + top: 140, right: 16.0, child: FloatingActionButton( onPressed: () { Navigator.of(context).push( MaterialPageRoute( - builder: (context) => AddMyImageScreen(destination: 'profile'), + builder: (context) => + const AddMyImageScreen(destination: 'profile'), ), ); }, @@ -120,11 +119,11 @@ class _UserProfileScreen extends State { ); } - double _calculateFactor(BoxConstraints constraints) { double maxExtent = 130.0; double scrollOffset = constraints.maxHeight - kToolbarHeight; - double factor = scrollOffset > 0 ? (maxExtent - scrollOffset) / maxExtent * 90.0 : 60.0; + double factor = + scrollOffset > 0 ? (maxExtent - scrollOffset) / maxExtent * 90.0 : 60.0; return factor.clamp(0, 90.0); } } From becc997f04317bef523048eef5eef26a9f25cac7 Mon Sep 17 00:00:00 2001 From: Ahmed Aladdin Mohamed <118504851+Ahmed-Aladdiin@users.noreply.github.com> Date: Fri, 1 Nov 2024 08:01:49 +0200 Subject: [PATCH 10/12] Update main.dart --- lib/main.dart | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 10d9fd9a..7995cb5d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -29,13 +29,9 @@ Future init() async { Hive.registerAdapter(ContactModelBlockAdapter()); await Hive.initFlutter(); dynamic box = await Hive.openBox('contacts'); - await box.clear(); box = await Hive.openBox('contacts-block'); - await box.clear(); box = await Hive.openBox('auth-token'); - await box.clear(); box = await Hive.openBox('auth-user'); - await box.clear(); await dotenv.load(fileName: "lib/.env"); } From c021806bccc7e062302774bf6b423c785ca1d6d7 Mon Sep 17 00:00:00 2001 From: Ahmed Aladdin Mohamed <118504851+Ahmed-Aladdiin@users.noreply.github.com> Date: Fri, 1 Nov 2024 08:02:42 +0200 Subject: [PATCH 11/12] Update main.dart --- lib/main.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 7995cb5d..d470b61e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -28,10 +28,10 @@ Future init() async { Hive.registerAdapter(StoryModelAdapter()); Hive.registerAdapter(ContactModelBlockAdapter()); await Hive.initFlutter(); - dynamic box = await Hive.openBox('contacts'); - box = await Hive.openBox('contacts-block'); - box = await Hive.openBox('auth-token'); - box = await Hive.openBox('auth-user'); + await Hive.openBox('contacts'); + await Hive.openBox('contacts-block'); + await Hive.openBox('auth-token'); + await Hive.openBox('auth-user'); await dotenv.load(fileName: "lib/.env"); } From 8600d00770bb6e404aeaf14ab6dc9b746aa3cbed Mon Sep 17 00:00:00 2001 From: Ahmed Aladdin Date: Fri, 1 Nov 2024 08:31:09 +0200 Subject: [PATCH 12/12] fix: add a missing import in the sign up screen --- lib/features/auth/view/screens/sign_up_screen.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/features/auth/view/screens/sign_up_screen.dart b/lib/features/auth/view/screens/sign_up_screen.dart index cfbd45b4..ea784b6e 100644 --- a/lib/features/auth/view/screens/sign_up_screen.dart +++ b/lib/features/auth/view/screens/sign_up_screen.dart @@ -5,6 +5,7 @@ import 'package:flutter_shakemywidget/flutter_shakemywidget.dart'; import 'package:go_router/go_router.dart'; import 'package:phone_form_field/phone_form_field.dart'; import 'package:telware_cross_platform/core/models/signup_result.dart'; +import 'package:telware_cross_platform/features/auth/view/widget/confirmation_dialog.dart'; import 'package:vibration/vibration.dart'; import 'package:webview_flutter_plus/webview_flutter_plus.dart';