From 1f714b3bc2a812e6141987084a7446546fb77a61 Mon Sep 17 00:00:00 2001 From: Username1548 Date: Wed, 6 Aug 2025 20:29:56 +0700 Subject: [PATCH 01/16] feat(diary): fixed commenting of diary --- .../diary/presentation/bloc/diary_cubit.dart | 58 +++++++------------ 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/lib/features/diary/presentation/bloc/diary_cubit.dart b/lib/features/diary/presentation/bloc/diary_cubit.dart index 1bbfbbc7..8f8c8a0a 100644 --- a/lib/features/diary/presentation/bloc/diary_cubit.dart +++ b/lib/features/diary/presentation/bloc/diary_cubit.dart @@ -136,15 +136,7 @@ class DiaryCubit extends Cubit { final fifthMeal = MealModel(id: 0, time: '0', typeNumber: 5, satiety: 0, mood: 0, portions: fifthMealPortions ?? [], photos: []); emit( DiaryState.loadedTomorrowWithDiet( - diary: diaryDay.copyWith( - meals: [ - firstMeal, - secondMeal, - thirdMeal, - fourthMeal, - fifthMeal, - ], - ), + diary: diaryDay.copyWith(meals: [firstMeal, secondMeal, thirdMeal, fourthMeal, fifthMeal]), selectedDay: selectedDay, selectedMeal: selectedMeal, ), @@ -156,7 +148,7 @@ class DiaryCubit extends Cubit { Future fetchDiary([bool needLoading = false, int? diaryId, int? currentDay]) async { this.diaryId ??= diaryId; - + final isConsultantView = this.diaryId != null; if (needLoading) { emit(const DiaryState.loading()); selectedMeal = 1; @@ -180,7 +172,8 @@ class DiaryCubit extends Cubit { String? planName; if (diaryDay.chosenPlanId != null) { final chosenPlanModel = await chatRepository.getChosenPlan(id: diaryDay.chosenPlanId!); - if (diaryDay.typeOfDiary.diaryState == DiaryStateEnum.lastDayCommented || diaryDay.typeOfDiary.diaryState == DiaryStateEnum.commented) { + if (isConsultantView && + (diaryDay.typeOfDiary.diaryState == DiaryStateEnum.lastDayCommented || diaryDay.typeOfDiary.diaryState == DiaryStateEnum.commented)) { await diaryRepository.viewCommentOfDiaryDayByConsultant(diaryId: diaryDay.id); } consultantReview = await diaryRepository.getDiaryComments(planId: diaryDay.chosenPlanId!, diaryId: diaryDay.id); @@ -192,24 +185,26 @@ class DiaryCubit extends Cubit { final isDiaryFinished = diaryDay.typeOfDiary.diaryState == DiaryStateEnum.finished || diaryDay.typeOfDiary.diaryState == DiaryStateEnum.lastDayFinished; - final isDiaryCommented = diaryDay.typeOfDiary.diaryState == DiaryStateEnum.commented || + final isDiaryCommented = + diaryDay.typeOfDiary.diaryState == DiaryStateEnum.commented || diaryDay.typeOfDiary.diaryState == DiaryStateEnum.lastDayCommented || diaryDay.typeOfDiary.diaryState == DiaryStateEnum.reviewedByUser; emit( DiaryState.loaded( - diary: diaryDay, - nutrition: nutrition, - selectedDay: selectedDay, - selectedMeal: selectedMeal, - isConsultantView: this.diaryId != null, - consultantReview: consultantReview, - isDiaryFinished: isDiaryFinished, - isDiaryCommented: isDiaryCommented, - chosenPlanCurrentDay: currentPlanDay, - chosenPlanDuration: planDuration, - chosenPlanName: planName, - isMoodEnabled: isMoodEnabled, - isWakeUpAndRetireEnabled: isWakeUpAndRetireTimeEnabled), + diary: diaryDay, + nutrition: nutrition, + selectedDay: selectedDay, + selectedMeal: selectedMeal, + isConsultantView: isConsultantView, + consultantReview: consultantReview, + isDiaryFinished: isDiaryFinished, + isDiaryCommented: isDiaryCommented, + chosenPlanCurrentDay: currentPlanDay, + chosenPlanDuration: planDuration, + chosenPlanName: planName, + isMoodEnabled: isMoodEnabled, + isWakeUpAndRetireEnabled: isWakeUpAndRetireTimeEnabled, + ), ); } catch (e, st) { log(e.toString(), stackTrace: st); @@ -217,17 +212,8 @@ class DiaryCubit extends Cubit { } } - Future finishDiaryDay({ - required int diaryId, - required String wakeUp, - required String retire, - }) async { - await diaryRepository.finishDiaryDay( - diaryId: diaryId, - wakeUp: wakeUp, - retire: retire, - comment: comment.isEmpty ? null : comment, - ); + Future finishDiaryDay({required int diaryId, required String wakeUp, required String retire}) async { + await diaryRepository.finishDiaryDay(diaryId: diaryId, wakeUp: wakeUp, retire: retire, comment: comment.isEmpty ? null : comment); await fetchDiary(); } From 7e7f8bfb034f49819637bbb0637add2df3b6bfee Mon Sep 17 00:00:00 2001 From: Username1548 Date: Wed, 6 Aug 2025 20:36:50 +0700 Subject: [PATCH 02/16] fix --- lib/features/diary/presentation/bloc/diary_cubit.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/features/diary/presentation/bloc/diary_cubit.dart b/lib/features/diary/presentation/bloc/diary_cubit.dart index 8f8c8a0a..6e6f8891 100644 --- a/lib/features/diary/presentation/bloc/diary_cubit.dart +++ b/lib/features/diary/presentation/bloc/diary_cubit.dart @@ -172,7 +172,7 @@ class DiaryCubit extends Cubit { String? planName; if (diaryDay.chosenPlanId != null) { final chosenPlanModel = await chatRepository.getChosenPlan(id: diaryDay.chosenPlanId!); - if (isConsultantView && + if (!isConsultantView && (diaryDay.typeOfDiary.diaryState == DiaryStateEnum.lastDayCommented || diaryDay.typeOfDiary.diaryState == DiaryStateEnum.commented)) { await diaryRepository.viewCommentOfDiaryDayByConsultant(diaryId: diaryDay.id); } From 832ba421e9bb8d3dbca5688ea2c777aa2b515c7e Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Wed, 6 Aug 2025 17:41:35 +0300 Subject: [PATCH 03/16] fix: secure storage --- pubspec.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index fefe422b..a56c030b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,7 +13,11 @@ dependencies: flutter_localizations: sdk: flutter - flutter_secure_storage: ^9.2.4 + flutter_secure_storage: + git: + url: https://github.com/sherlockvn/flutter_secure_storage.git + ref: remove-old-encrypt-algorithm + path: flutter_secure_storage flutter_bloc: ^9.1.1 cached_network_image: ^3.4.1 flutter_svg: ^2.2.0 From 1305e678179a9daec70e1f85038145be78f061c3 Mon Sep 17 00:00:00 2001 From: Username1548 Date: Thu, 7 Aug 2025 18:10:58 +0700 Subject: [PATCH 04/16] feat(env): added env loading to ci/cd --- .gitea/workflows/test-flight-cd.yaml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/test-flight-cd.yaml b/.gitea/workflows/test-flight-cd.yaml index 4320ecc5..c1244bd9 100644 --- a/.gitea/workflows/test-flight-cd.yaml +++ b/.gitea/workflows/test-flight-cd.yaml @@ -11,6 +11,30 @@ jobs: - name: Checkout uses: actions/checkout@v2 + - name: Checkout env repository + uses: actions/checkout@v2 + with: + repository: mso7nueh/eatvio_app_env + path: env_repo + token: ${{ vars.MSO7NUEH_TOKEN }} + ref: main + + - name: Copy .env file + run: | + mkdir -p env + cp env_repo/.env env/.env + + - name: Load environment variables from .env + run: | + set -a + source env/.env + set +a + # Export all variables to GITHUB_ENV + while IFS= read -r line; do + if [[ $line =~ ^[A-Za-z_][A-Za-z0-9_]*= ]]; then + echo "$line" >> $GITHUB_ENV + fi + done < env/.env - name: Unlock login keychain run: | @@ -36,4 +60,4 @@ jobs: MATCH_GIT_URL: http://gitea.office.local:3000/mso7nueh/fastlane FASTLANE_USER: eatvio2023@icloud.com FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD: ${{ vars.FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD }} - API_APPSTORE_KEY: ${{ vars.API_APPSTORE_KEY }} \ No newline at end of file + API_APPSTORE_KEY: ${{ vars.API_APPSTORE_KEY }} From f9b63f3401e9565e061d5fc2b05b34c7a11b3fb4 Mon Sep 17 00:00:00 2001 From: Username1548 Date: Thu, 7 Aug 2025 18:20:26 +0700 Subject: [PATCH 05/16] version update --- ios/Runner.xcodeproj/project.pbxproj | 6 +++--- ios/Runner/Info.plist | 2 +- pubspec.yaml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 9a27847e..14890f55 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -396,7 +396,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Distribution: ITVIO, OOO (VL68C36HYS)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 66; DEVELOPMENT_TEAM = VL68C36HYS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -546,7 +546,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Distribution: ITVIO, OOO (VL68C36HYS)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 66; DEVELOPMENT_TEAM = VL68C36HYS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -584,7 +584,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Distribution: ITVIO, OOO (VL68C36HYS)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 64; + CURRENT_PROJECT_VERSION = 66; DEVELOPMENT_TEAM = VL68C36HYS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 2341e63f..65ea6c40 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -21,7 +21,7 @@ CFBundleSignature ???? CFBundleVersion - 64 + 66 ITSAppUsesNonExemptEncryption LSRequiresIPhoneOS diff --git a/pubspec.yaml b/pubspec.yaml index 0154d606..a3560aec 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: eatvio_app description: A new Flutter project. -version: 1.2.6+64 +version: 1.2.6+66 publish_to: 'none' environment: From 905559b1f006de37c6328aa3df1e85b4edd7a70a Mon Sep 17 00:00:00 2001 From: Username1548 Date: Thu, 7 Aug 2025 19:06:27 +0700 Subject: [PATCH 06/16] feat(fastlane): changed fastlane build uploading --- ios/fastlane/Fastfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ios/fastlane/Fastfile b/ios/fastlane/Fastfile index d9653264..de31023b 100644 --- a/ios/fastlane/Fastfile +++ b/ios/fastlane/Fastfile @@ -28,6 +28,8 @@ platform :ios do xcargs: "--dart-define=HIDE_PLANS=true" ) app_store_connect_api_key(key_id: "325JS9JCZH", issuer_id: "dfa27d1d-2bb8-4d4d-847e-0b32f9b880b3", key_filepath: "./AuthKey.p8") - upload_to_testflight + upload_to_testflight( + use_legacy_upload: false + ) end end From 6fa7beb070ef040ca4bf9858b92941742bb18264 Mon Sep 17 00:00:00 2001 From: Username1548 Date: Thu, 7 Aug 2025 19:23:12 +0700 Subject: [PATCH 07/16] reverted changes --- ios/fastlane/Fastfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ios/fastlane/Fastfile b/ios/fastlane/Fastfile index de31023b..d9653264 100644 --- a/ios/fastlane/Fastfile +++ b/ios/fastlane/Fastfile @@ -28,8 +28,6 @@ platform :ios do xcargs: "--dart-define=HIDE_PLANS=true" ) app_store_connect_api_key(key_id: "325JS9JCZH", issuer_id: "dfa27d1d-2bb8-4d4d-847e-0b32f9b880b3", key_filepath: "./AuthKey.p8") - upload_to_testflight( - use_legacy_upload: false - ) + upload_to_testflight end end From 15248a65fe36e2dca9085fe6a617fe325f7b0811 Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Thu, 7 Aug 2025 18:05:11 +0300 Subject: [PATCH 08/16] feat(profile): Issue-248 --- .../presentation/pages/profile_screen.dart | 271 +++++++++++------- 1 file changed, 171 insertions(+), 100 deletions(-) diff --git a/lib/features/profile/presentation/pages/profile_screen.dart b/lib/features/profile/presentation/pages/profile_screen.dart index 211543a9..4e0a6524 100644 --- a/lib/features/profile/presentation/pages/profile_screen.dart +++ b/lib/features/profile/presentation/pages/profile_screen.dart @@ -41,6 +41,7 @@ import 'package:intl/intl.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:share_plus/share_plus.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'package:flutter/services.dart'; class ProfileScreen extends StatefulWidget { final Author? author; @@ -760,76 +761,92 @@ class _ProfileScreenState extends State { child: Row( children: [ PopupMenuButton( - onSelected: (value) async { - if (value == 'view') { - context.pushTransparentRoute(rootNavigator: true, PhotoViewScreen(imageUrls: [baseUrl + state.profile.profilePhotoUrl], index: 0)); - } - if (value == 'replace') { - showCupertinoModalPopup( - context: context, - builder: (context) { - final s = S.of(context); - return CupertinoActionSheet( - actions: [ - CupertinoActionSheetAction( - onPressed: () async { - PermissionHandler.checkPermission( - permission: Permission.camera, - title: s.allowAccessToCamera, - description: s.allowAccessToCameraDescription, - onGranted: () async { - AppRouter.navigatorKey.currentContext?.pop(); - final picker = ImagePicker(); - XFile? image = await picker.pickImage(source: ImageSource.camera); - if (image != null) { - await profileCubit.uploadPhoto(File(image.path)); - await sl().getMyProfile(); - } + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + color: Colors.white, + constraints: const BoxConstraints(minWidth: 260), + surfaceTintColor: Colors.transparent, + elevation: 2, + itemBuilder: (context) => [ + _buildCompactItem( + icon: 'assets/icons/eye.svg', + text: 'Посмотреть', + onTap: () async { + context.pushTransparentRoute(rootNavigator: true, PhotoViewScreen(imageUrls: [baseUrl + state.profile.profilePhotoUrl], index: 0)); + }, + ), + if (widget.author == null || widget.author!.authorIsMe) ...[ + _buildDivider(), + _buildCompactItem( + icon: 'assets/icons/edit_paint.svg', + text: 'Заменить', + onTap: () async { + showCupertinoModalPopup( + context: context, + builder: (context) { + final s = S.of(context); + return CupertinoActionSheet( + actions: [ + CupertinoActionSheetAction( + onPressed: () async { + PermissionHandler.checkPermission( + permission: Permission.camera, + title: s.allowAccessToCamera, + description: s.allowAccessToCameraDescription, + onGranted: () async { + AppRouter.navigatorKey.currentContext?.pop(); + final picker = ImagePicker(); + XFile? image = await picker.pickImage(source: ImageSource.camera); + if (image != null) { + await profileCubit.uploadPhoto(File(image.path)); + await sl().getMyProfile(); + } + }, + context: context, + ); }, - context: context, - ); - }, - child: const Row(children: [Icon(Icons.photo_camera), SizedBox(width: 8), Text('Фото')]), - ), - CupertinoActionSheetAction( - onPressed: () async { - PermissionHandler.checkPermission( - permission: Permission.photos, - title: s.allowAcessToGalery, - description: s.allowAcessToGaleryDescription, - onGranted: () async { - AppRouter.navigatorKey.currentContext?.pop(); - final picker = ImagePicker(); - XFile? image = await picker.pickImage(source: ImageSource.gallery); - if (image != null) { - await profileCubit.uploadPhoto(File(image.path)); - await sl().getMyProfile(); - } + child: const Row(children: [Icon(Icons.photo_camera), SizedBox(width: 8), Text('Фото')]), + ), + CupertinoActionSheetAction( + onPressed: () async { + PermissionHandler.checkPermission( + permission: Permission.photos, + title: s.allowAcessToGalery, + description: s.allowAcessToGaleryDescription, + onGranted: () async { + AppRouter.navigatorKey.currentContext?.pop(); + final picker = ImagePicker(); + XFile? image = await picker.pickImage(source: ImageSource.gallery); + if (image != null) { + await profileCubit.uploadPhoto(File(image.path)); + await sl().getMyProfile(); + } + }, + context: context, + ); }, - context: context, - ); - }, - child: const Row(children: [Icon(Icons.photo), SizedBox(width: 8), Text('Галерея')]), - ), - ], - cancelButton: CupertinoActionSheetAction( - onPressed: () => Navigator.of(context).pop(), - isDestructiveAction: true, - child: const Text('Отмена'), - ), + child: const Row(children: [Icon(Icons.photo), SizedBox(width: 8), Text('Галерея')]), + ), + ], + cancelButton: CupertinoActionSheetAction( + onPressed: () => Navigator.of(context).pop(), + isDestructiveAction: true, + child: const Text('Отмена'), + ), + ); + }, ); }, - ); - } - if (value == 'delete') { - await profileCubit.deletePhoto(); - await sl().getMyProfile(); - } - }, - itemBuilder: (context) => [ - const PopupMenuItem(value: 'view', child: Text('Посмотреть')), - if (widget.author == null || widget.author!.authorIsMe) const PopupMenuItem(value: 'replace', child: Text('Заменить')), - if (widget.author == null || widget.author!.authorIsMe) const PopupMenuItem(value: 'delete', child: Text('Удалить')), + ), + _buildDivider(), + _buildCompactItem( + icon: 'assets/icons/red_trash.svg', + text: 'Удалить', + onTap: () async { + await profileCubit.deletePhoto(); + await sl().getMyProfile(); + }, + ), + ], ], child: Hero( tag: state.profile.profilePhotoUrl, @@ -899,41 +916,68 @@ class _ProfileScreenState extends State { ), const Spacer(), PopupMenuButton( - onSelected: (value) { - if (value == 'share') { - final box = context.findRenderObject() as RenderBox?; - SharePlus.instance.share( - ShareParams(uri: Uri.parse('$baseUrl/ru/profile/${state.profile.slug}'), sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size), - ); - } else if (value == 'block') { - isFirstFetch = true; - sl().blockUser(state.profile.slug); - widget.author == null || widget.author!.authorIsMe ? profileCubit.getMyProfile() : profileCubit.getProfileBySlug(widget.author!.authorSlug); - if (state.profile.roles.contains('consultant')) { - plansCubit.getPlans(state.profile.slug); - } - isFirstFetch = false; - } else if (value == 'unblock') { - isFirstFetch = true; - sl().unblockUser(state.profile.slug); - widget.author == null || widget.author!.authorIsMe ? profileCubit.getMyProfile() : profileCubit.getProfileBySlug(widget.author!.authorSlug); - if (state.profile.roles.contains('consultant')) { - plansCubit.getPlans(state.profile.slug); - } - isFirstFetch = false; - } else { - showModalBottomSheet( - context: context, - isScrollControlled: true, - builder: (context) => ComplainingBottomSheet(complainedContentType: ComplainedContent.profile, slug: widget.author?.authorSlug), - ); - } - }, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + color: Colors.white, + constraints: const BoxConstraints(minWidth: 260), + surfaceTintColor: Colors.transparent, + elevation: 2, itemBuilder: (context) => [ - const PopupMenuItem(value: 'share', child: Text('Поделиться')), - if (widget.author != null) const PopupMenuItem(value: 'complain', child: Text('Пожаловаться')), - if (widget.author != null && !state.profile.isBlockedByMe) const PopupMenuItem(value: 'block', child: Text('Заблокировать')), - if (widget.author != null && state.profile.isBlockedByMe) const PopupMenuItem(value: 'unblock', child: Text('Разблокировать')), + _buildCompactItem( + icon: 'assets/icons/share2.svg', + text: 'Поделиться', + onTap: () { + final box = context.findRenderObject() as RenderBox?; + SharePlus.instance.share( + ShareParams(uri: Uri.parse('$baseUrl/ru/profile/${state.profile.slug}'), sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size), + ); + }, + ), + if (widget.author != null) ...[ + _buildDivider(), + _buildCompactItem( + icon: 'assets/icons/complain.svg', + text: 'Пожаловаться', + onTap: () { + showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (context) => ComplainingBottomSheet(complainedContentType: ComplainedContent.profile, slug: widget.author?.authorSlug), + ); + }, + ), + ], + if (widget.author != null && !state.profile.isBlockedByMe) ...[ + _buildDivider(), + _buildCompactItem( + icon: 'assets/icons/complain.svg', + text: 'Заблокировать', + onTap: () { + isFirstFetch = true; + sl().blockUser(state.profile.slug); + widget.author == null || widget.author!.authorIsMe ? profileCubit.getMyProfile() : profileCubit.getProfileBySlug(widget.author!.authorSlug); + if (state.profile.roles.contains('consultant')) { + plansCubit.getPlans(state.profile.slug); + } + isFirstFetch = false; + }, + ), + ], + if (widget.author != null && state.profile.isBlockedByMe) ...[ + _buildDivider(), + _buildCompactItem( + icon: 'assets/icons/complain.svg', + text: 'Разблокировать', + onTap: () { + isFirstFetch = true; + sl().unblockUser(state.profile.slug); + widget.author == null || widget.author!.authorIsMe ? profileCubit.getMyProfile() : profileCubit.getProfileBySlug(widget.author!.authorSlug); + if (state.profile.roles.contains('consultant')) { + plansCubit.getPlans(state.profile.slug); + } + isFirstFetch = false; + }, + ), + ], ], child: const Icon(Icons.more_horiz_rounded), ), @@ -942,6 +986,33 @@ class _ProfileScreenState extends State { ); } + PopupMenuItem _buildCompactItem({required String icon, required String text, required Function() onTap}) { + return PopupMenuItem( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), + height: 36, + onTap: onTap, + child: SizedBox( + width: double.infinity, + child: Row( + children: [ + Text(text, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500)), + const Spacer(), + SvgPicture.asset(icon), + ], + ), + ), + ); + } + + PopupMenuItem _buildDivider() { + return PopupMenuItem( + enabled: false, + height: 1, + padding: EdgeInsets.zero, + child: Container(margin: const EdgeInsets.symmetric(horizontal: 12), height: 1, color: appTheme.dividerColor), + ); + } + Row _additional(String title, String value) { return Row( children: [ From fe99890c0e8a2c239c37e8531c95a04722f1041f Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Thu, 7 Aug 2025 21:29:30 +0300 Subject: [PATCH 09/16] fix: analyzer --- lib/features/profile/presentation/pages/profile_screen.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/features/profile/presentation/pages/profile_screen.dart b/lib/features/profile/presentation/pages/profile_screen.dart index 4e0a6524..f3329074 100644 --- a/lib/features/profile/presentation/pages/profile_screen.dart +++ b/lib/features/profile/presentation/pages/profile_screen.dart @@ -41,7 +41,6 @@ import 'package:intl/intl.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:share_plus/share_plus.dart'; import 'package:url_launcher/url_launcher.dart'; -import 'package:flutter/services.dart'; class ProfileScreen extends StatefulWidget { final Author? author; From 2fac007675e6c78cb90ba7270fe77c87700639a5 Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Fri, 8 Aug 2025 11:11:00 +0300 Subject: [PATCH 10/16] feat(fastlane): Issue-622 --- .gitea/workflows/test-flight-cd.yaml | 9 +++++++- ios/fastlane/Fastfile | 34 ++++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/test-flight-cd.yaml b/.gitea/workflows/test-flight-cd.yaml index c1244bd9..0bb7c723 100644 --- a/.gitea/workflows/test-flight-cd.yaml +++ b/.gitea/workflows/test-flight-cd.yaml @@ -42,9 +42,16 @@ jobs: env: KEYCHAIN_PASSWORD: ${{ vars.IOS_RUNNER_CI_PASSWORD }} - - name: Flutter build + - name: Setup API key run: | echo "${API_APPSTORE_KEY}" | base64 --decode > ios/AuthKey.p8 + chmod 600 ios/AuthKey.p8 + ls -la ios/AuthKey.p8 + env: + API_APPSTORE_KEY: ${{ vars.API_APPSTORE_KEY }} + + - name: Flutter build + run: | flutter clean flutter pub get flutter pub upgrade diff --git a/ios/fastlane/Fastfile b/ios/fastlane/Fastfile index d9653264..a43260fe 100644 --- a/ios/fastlane/Fastfile +++ b/ios/fastlane/Fastfile @@ -18,8 +18,16 @@ default_platform(:ios) platform :ios do desc "Push a new beta build to TestFlight" lane :beta do + UI.message "Checking API key file..." + if File.exist?("./AuthKey.p8") + UI.message "API key file exists" + else + UI.user_error!("API key file not found at ./AuthKey.p8") + end + match(type: "appstore", readonly: true) increment_build_number(xcodeproj: "Runner.xcodeproj") + build_app( workspace: "Runner.xcworkspace", scheme: "Runner", @@ -27,7 +35,29 @@ platform :ios do codesigning_identity: "Apple Distribution", xcargs: "--dart-define=HIDE_PLANS=true" ) - app_store_connect_api_key(key_id: "325JS9JCZH", issuer_id: "dfa27d1d-2bb8-4d4d-847e-0b32f9b880b3", key_filepath: "./AuthKey.p8") - upload_to_testflight + + app_store_connect_api_key( + key_id: "325JS9JCZH", + issuer_id: "dfa27d1d-2bb8-4d4d-847e-0b32f9b880b3", + key_filepath: "./AuthKey.p8", + duration: 1200, + in_house: false + ) + + begin + upload_to_testflight( + api_key_path: "./AuthKey.p8", + skip_waiting_for_build_processing: true, + skip_submission: true, + distribute_external: false, + notify_external_testers: false, + changelog: "TestFlight build #{get_build_number(xcodeproj: 'Runner.xcodeproj')}", + verbose: true + ) + rescue => ex + UI.error "Upload to TestFlight failed: #{ex.message}" + UI.error "Full error: #{ex.backtrace.join("\n")}" + raise ex + end end end From 73f27efadd87cea03d45dae677ac8fccc302f8a1 Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Fri, 8 Aug 2025 11:14:41 +0300 Subject: [PATCH 11/16] fix(fastlane): testflight --- .gitea/workflows/test-flight-cd.yaml | 22 +++++++++++++++++++++- ios/fastlane/Fastfile | 3 +++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/test-flight-cd.yaml b/.gitea/workflows/test-flight-cd.yaml index 0bb7c723..faff6332 100644 --- a/.gitea/workflows/test-flight-cd.yaml +++ b/.gitea/workflows/test-flight-cd.yaml @@ -44,9 +44,20 @@ jobs: - name: Setup API key run: | - echo "${API_APPSTORE_KEY}" | base64 --decode > ios/AuthKey.p8 + echo "API_APPSTORE_KEY length: ${#API_APPSTORE_KEY}" + if [ -z "$API_APPSTORE_KEY" ]; then + echo "ERROR: API_APPSTORE_KEY is empty or not set" + exit 1 + fi + echo "${API_APPSTORE_KEY}" | tr -d '\n' | base64 --decode > ios/AuthKey.p8 chmod 600 ios/AuthKey.p8 ls -la ios/AuthKey.p8 + echo "File size: $(wc -c < ios/AuthKey.p8) bytes" + echo "First few characters of decoded file:" + head -c 50 ios/AuthKey.p8 | xxd + echo "Current directory: $(pwd)" + echo "Contents of ios directory:" + ls -la ios/ env: API_APPSTORE_KEY: ${{ vars.API_APPSTORE_KEY }} @@ -57,6 +68,15 @@ jobs: flutter pub upgrade flutter pub run build_runner build --delete-conflicting-outputs cd ios + echo "Current directory after cd ios: $(pwd)" + echo "Contents of current directory:" + ls -la + echo "Checking if AuthKey.p8 exists:" + if [ -f "AuthKey.p8" ]; then + echo "AuthKey.p8 exists, size: $(wc -c < AuthKey.p8) bytes" + else + echo "AuthKey.p8 does not exist" + fi pod update fastlane beta env: diff --git a/ios/fastlane/Fastfile b/ios/fastlane/Fastfile index a43260fe..6ecef599 100644 --- a/ios/fastlane/Fastfile +++ b/ios/fastlane/Fastfile @@ -18,9 +18,12 @@ default_platform(:ios) platform :ios do desc "Push a new beta build to TestFlight" lane :beta do + UI.message "Current working directory: #{Dir.pwd}" UI.message "Checking API key file..." + UI.message "Files in current directory: #{Dir.entries('.').join(', ')}" if File.exist?("./AuthKey.p8") UI.message "API key file exists" + UI.message "File size: #{File.size('./AuthKey.p8')} bytes" else UI.user_error!("API key file not found at ./AuthKey.p8") end From d8378e3686ccdc528c53736d6a57149b15696668 Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Fri, 8 Aug 2025 11:17:48 +0300 Subject: [PATCH 12/16] fix: fastlane --- .gitea/workflows/test-flight-cd.yaml | 20 -------------------- ios/fastlane/Fastfile | 13 ++++++------- 2 files changed, 6 insertions(+), 27 deletions(-) diff --git a/.gitea/workflows/test-flight-cd.yaml b/.gitea/workflows/test-flight-cd.yaml index faff6332..8b3a8cf5 100644 --- a/.gitea/workflows/test-flight-cd.yaml +++ b/.gitea/workflows/test-flight-cd.yaml @@ -44,20 +44,9 @@ jobs: - name: Setup API key run: | - echo "API_APPSTORE_KEY length: ${#API_APPSTORE_KEY}" - if [ -z "$API_APPSTORE_KEY" ]; then - echo "ERROR: API_APPSTORE_KEY is empty or not set" - exit 1 - fi echo "${API_APPSTORE_KEY}" | tr -d '\n' | base64 --decode > ios/AuthKey.p8 chmod 600 ios/AuthKey.p8 ls -la ios/AuthKey.p8 - echo "File size: $(wc -c < ios/AuthKey.p8) bytes" - echo "First few characters of decoded file:" - head -c 50 ios/AuthKey.p8 | xxd - echo "Current directory: $(pwd)" - echo "Contents of ios directory:" - ls -la ios/ env: API_APPSTORE_KEY: ${{ vars.API_APPSTORE_KEY }} @@ -68,15 +57,6 @@ jobs: flutter pub upgrade flutter pub run build_runner build --delete-conflicting-outputs cd ios - echo "Current directory after cd ios: $(pwd)" - echo "Contents of current directory:" - ls -la - echo "Checking if AuthKey.p8 exists:" - if [ -f "AuthKey.p8" ]; then - echo "AuthKey.p8 exists, size: $(wc -c < AuthKey.p8) bytes" - else - echo "AuthKey.p8 does not exist" - fi pod update fastlane beta env: diff --git a/ios/fastlane/Fastfile b/ios/fastlane/Fastfile index 6ecef599..059e30e1 100644 --- a/ios/fastlane/Fastfile +++ b/ios/fastlane/Fastfile @@ -18,14 +18,13 @@ default_platform(:ios) platform :ios do desc "Push a new beta build to TestFlight" lane :beta do - UI.message "Current working directory: #{Dir.pwd}" UI.message "Checking API key file..." - UI.message "Files in current directory: #{Dir.entries('.').join(', ')}" - if File.exist?("./AuthKey.p8") + + auth_key_path = "../AuthKey.p8" + if File.exist?(auth_key_path) UI.message "API key file exists" - UI.message "File size: #{File.size('./AuthKey.p8')} bytes" else - UI.user_error!("API key file not found at ./AuthKey.p8") + UI.user_error!("API key file not found at #{auth_key_path}") end match(type: "appstore", readonly: true) @@ -42,14 +41,14 @@ platform :ios do app_store_connect_api_key( key_id: "325JS9JCZH", issuer_id: "dfa27d1d-2bb8-4d4d-847e-0b32f9b880b3", - key_filepath: "./AuthKey.p8", + key_filepath: "../AuthKey.p8", duration: 1200, in_house: false ) begin upload_to_testflight( - api_key_path: "./AuthKey.p8", + api_key_path: "../AuthKey.p8", skip_waiting_for_build_processing: true, skip_submission: true, distribute_external: false, From cdb6fcb462b3738ebef0843aaf314e2cf29cf919 Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Fri, 8 Aug 2025 11:23:55 +0300 Subject: [PATCH 13/16] fix: fastlane --- .gitea/workflows/test-flight-cd.yaml | 3 +++ ios/fastlane/Fastfile | 29 +++++++++++++++++++++------- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/.gitea/workflows/test-flight-cd.yaml b/.gitea/workflows/test-flight-cd.yaml index 8b3a8cf5..ac54d483 100644 --- a/.gitea/workflows/test-flight-cd.yaml +++ b/.gitea/workflows/test-flight-cd.yaml @@ -47,6 +47,9 @@ jobs: echo "${API_APPSTORE_KEY}" | tr -d '\n' | base64 --decode > ios/AuthKey.p8 chmod 600 ios/AuthKey.p8 ls -la ios/AuthKey.p8 + echo "File size: $(wc -c < ios/AuthKey.p8) bytes" + echo "Contents of ios directory:" + ls -la ios/ env: API_APPSTORE_KEY: ${{ vars.API_APPSTORE_KEY }} diff --git a/ios/fastlane/Fastfile b/ios/fastlane/Fastfile index 059e30e1..8304f8bc 100644 --- a/ios/fastlane/Fastfile +++ b/ios/fastlane/Fastfile @@ -18,13 +18,28 @@ default_platform(:ios) platform :ios do desc "Push a new beta build to TestFlight" lane :beta do + UI.message "Current working directory: #{Dir.pwd}" UI.message "Checking API key file..." - auth_key_path = "../AuthKey.p8" - if File.exist?(auth_key_path) - UI.message "API key file exists" - else - UI.user_error!("API key file not found at #{auth_key_path}") + possible_paths = [ + "../AuthKey.p8", + "./AuthKey.p8", + "../../AuthKey.p8", + File.expand_path("../AuthKey.p8"), + File.expand_path("./AuthKey.p8") + ] + + auth_key_path = nil + possible_paths.each do |path| + if File.exist?(path) + UI.message "Found AuthKey.p8 at: #{path}" + auth_key_path = path + break + end + end + + if auth_key_path.nil? + UI.user_error!("API key file not found. Tried paths: #{possible_paths.join(', ')}") end match(type: "appstore", readonly: true) @@ -41,14 +56,14 @@ platform :ios do app_store_connect_api_key( key_id: "325JS9JCZH", issuer_id: "dfa27d1d-2bb8-4d4d-847e-0b32f9b880b3", - key_filepath: "../AuthKey.p8", + key_filepath: auth_key_path, duration: 1200, in_house: false ) begin upload_to_testflight( - api_key_path: "../AuthKey.p8", + api_key_path: auth_key_path, skip_waiting_for_build_processing: true, skip_submission: true, distribute_external: false, From 3c56c59c9f6289e32b73a432b1f7730ad04c2a54 Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Fri, 8 Aug 2025 11:29:47 +0300 Subject: [PATCH 14/16] fix: fastlane --- ios/fastlane/Fastfile | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ios/fastlane/Fastfile b/ios/fastlane/Fastfile index 8304f8bc..4d2e0516 100644 --- a/ios/fastlane/Fastfile +++ b/ios/fastlane/Fastfile @@ -33,7 +33,7 @@ platform :ios do possible_paths.each do |path| if File.exist?(path) UI.message "Found AuthKey.p8 at: #{path}" - auth_key_path = path + auth_key_path = File.expand_path(path) break end end @@ -42,6 +42,10 @@ platform :ios do UI.user_error!("API key file not found. Tried paths: #{possible_paths.join(', ')}") end + UI.message "Using auth_key_path: #{auth_key_path}" + UI.message "File exists check: #{File.exist?(auth_key_path)}" + UI.message "File size: #{File.size(auth_key_path)} bytes" + match(type: "appstore", readonly: true) increment_build_number(xcodeproj: "Runner.xcodeproj") @@ -53,6 +57,9 @@ platform :ios do xcargs: "--dart-define=HIDE_PLANS=true" ) + UI.message "About to call app_store_connect_api_key with key_filepath: #{auth_key_path}" + UI.message "File still exists: #{File.exist?(auth_key_path)}" + app_store_connect_api_key( key_id: "325JS9JCZH", issuer_id: "dfa27d1d-2bb8-4d4d-847e-0b32f9b880b3", From 06117ddb6a2a699bf31eeb367e5cec87f028088b Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Fri, 8 Aug 2025 11:34:41 +0300 Subject: [PATCH 15/16] fix: fastlane --- ios/fastlane/Fastfile | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ios/fastlane/Fastfile b/ios/fastlane/Fastfile index 4d2e0516..f7261196 100644 --- a/ios/fastlane/Fastfile +++ b/ios/fastlane/Fastfile @@ -43,8 +43,6 @@ platform :ios do end UI.message "Using auth_key_path: #{auth_key_path}" - UI.message "File exists check: #{File.exist?(auth_key_path)}" - UI.message "File size: #{File.size(auth_key_path)} bytes" match(type: "appstore", readonly: true) increment_build_number(xcodeproj: "Runner.xcodeproj") @@ -57,8 +55,7 @@ platform :ios do xcargs: "--dart-define=HIDE_PLANS=true" ) - UI.message "About to call app_store_connect_api_key with key_filepath: #{auth_key_path}" - UI.message "File still exists: #{File.exist?(auth_key_path)}" + app_store_connect_api_key( key_id: "325JS9JCZH", @@ -70,7 +67,6 @@ platform :ios do begin upload_to_testflight( - api_key_path: auth_key_path, skip_waiting_for_build_processing: true, skip_submission: true, distribute_external: false, From 60d30163e7b79e8b4f3e7a09adeb2d801eb51205 Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Fri, 8 Aug 2025 11:40:32 +0300 Subject: [PATCH 16/16] fix(fastlane): update version --- ios/Runner.xcodeproj/project.pbxproj | 6 +++--- ios/Runner/Info.plist | 2 +- pubspec.yaml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 14890f55..2e0d56e4 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -396,7 +396,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Distribution: ITVIO, OOO (VL68C36HYS)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_TEAM = VL68C36HYS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -546,7 +546,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Distribution: ITVIO, OOO (VL68C36HYS)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_TEAM = VL68C36HYS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -584,7 +584,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Distribution: ITVIO, OOO (VL68C36HYS)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 66; + CURRENT_PROJECT_VERSION = 67; DEVELOPMENT_TEAM = VL68C36HYS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 24c51e81..a1ded5ee 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -21,7 +21,7 @@ CFBundleSignature ???? CFBundleVersion - 66 + 67 ITSAppUsesNonExemptEncryption LSRequiresIPhoneOS diff --git a/pubspec.yaml b/pubspec.yaml index a56c030b..3895a06b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: eatvio_app description: A new Flutter project. -version: 1.2.7+66 +version: 1.2.8+68 publish_to: 'none' environment: