From e2165d090d8bd9d162fa7857fcb72bc905c7148f Mon Sep 17 00:00:00 2001 From: Osama Asif <49792938+osamaasifoak@users.noreply.github.com> Date: Fri, 6 Oct 2023 12:25:04 +0500 Subject: [PATCH] Client email navigation (#494) * chore: device and user info added in client email --- ios/Podfile | 7 +++ ios/Podfile.lock | 2 +- ios/Runner.xcodeproj/project.pbxproj | 12 ++--- lib/constants/strings/string_constants.dart | 1 + lib/constants/types/type_constants.dart | 1 + .../device_and_app_info_provider.dart | 32 ++++++++++++ lib/root_page_view.dart | 2 +- lib/utils/utils.dart | 36 +++++++++---- lib/views/auth/join_verify_OTP_view.dart | 7 ++- lib/views/folder/folder_view.dart | 26 +++++++--- .../announcement/announcement_widget.dart | 29 ++++++++--- .../debug/debug_bottom_sheet_widget.dart | 51 ++++--------------- .../menu/menu_bottom_sheet_widget.dart | 30 ++++++++--- .../home/widgets/filters/filter_widget.dart | 30 ++++++++--- .../widgets/overlay_cover_image_widget.dart | 6 +-- pubspec.yaml | 4 +- 16 files changed, 178 insertions(+), 98 deletions(-) diff --git a/ios/Podfile b/ios/Podfile index 56c4302c3..56bdc93ce 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -42,5 +42,12 @@ post_install do |installer| config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0' end flutter_additional_ios_build_settings(target) + target.build_configurations.each do |config| + config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ + '$(inherited)', + # dart: PermissionGroup.notification + 'PERMISSION_NOTIFICATIONS=1', + ] + end end end diff --git a/ios/Podfile.lock b/ios/Podfile.lock index a0d836aba..06bf1d5c4 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -229,7 +229,7 @@ SPEC CHECKSUMS: sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4 webview_flutter_wkwebview: 2e2d318f21a5e036e2c3f26171342e95908bd60a - PODFILE CHECKSUM: 70d9d25280d0dd177a5f637cdb0f0b0b12c6a189 + COCOAPODS: 1.12.1 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 89b1a5511..72f34eaf5 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -475,7 +475,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 20055; + CURRENT_PROJECT_VERSION = 20057; DEVELOPMENT_TEAM = JLKV36C38P; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -483,7 +483,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.0.55; + MARKETING_VERSION = 2.0.57; PRODUCT_BUNDLE_IDENTIFIER = org.meditofoundation; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -662,7 +662,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 20055; + CURRENT_PROJECT_VERSION = 20057; DEVELOPMENT_TEAM = JLKV36C38P; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -670,7 +670,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.0.55; + MARKETING_VERSION = 2.0.57; PRODUCT_BUNDLE_IDENTIFIER = org.meditofoundation; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -691,7 +691,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 20055; + CURRENT_PROJECT_VERSION = 20057; DEVELOPMENT_TEAM = JLKV36C38P; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -699,7 +699,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.0.55; + MARKETING_VERSION = 2.0.57; PRODUCT_BUNDLE_IDENTIFIER = org.meditofoundation; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; diff --git a/lib/constants/strings/string_constants.dart b/lib/constants/strings/string_constants.dart index 186db1a75..d850978a5 100644 --- a/lib/constants/strings/string_constants.dart +++ b/lib/constants/strings/string_constants.dart @@ -88,6 +88,7 @@ class StringConstants { 'Allow notifications for gentle meditation reminders and updates on fresh content and new features.'; static const String allowNotifications = 'Allow notifications'; static const String notNow = 'Not now'; + static const String bugReport = 'Bug report'; static const String debugInfo = '--- Debug info ---'; static const String writeBelowThisLine = '--- Write below this line ---'; diff --git a/lib/constants/types/type_constants.dart b/lib/constants/types/type_constants.dart index e9ad0ad96..a52d381b9 100644 --- a/lib/constants/types/type_constants.dart +++ b/lib/constants/types/type_constants.dart @@ -2,6 +2,7 @@ class TypeConstants { static const String LINK = 'link'; static const String FOLDER = 'folder'; static const String MEDITATION = 'meditation'; + static const String EMAIL = 'email'; } class EventTypes { diff --git a/lib/providers/device_and_app_info/device_and_app_info_provider.dart b/lib/providers/device_and_app_info/device_and_app_info_provider.dart index 4d6d24bdc..b2a4c4eac 100644 --- a/lib/providers/device_and_app_info/device_and_app_info_provider.dart +++ b/lib/providers/device_and_app_info/device_and_app_info_provider.dart @@ -1,4 +1,6 @@ +import 'package:Medito/constants/constants.dart'; import 'package:Medito/models/models.dart'; +import 'package:Medito/providers/providers.dart'; import 'package:Medito/repositories/repositories.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'device_and_app_info_provider.g.dart'; @@ -10,3 +12,33 @@ Future deviceAndAppInfo(ref) { return info.getDeviceAndAppInfo(); } + +final deviceAppAndUserInfoProvider = + FutureProvider.autoDispose((ref) async { + var me = await ref.watch(meProvider.future); + var deviceInfo = await ref.watch(deviceAndAppInfoProvider.future); + + return _formatString(me, deviceInfo); +}); + +String _formatString( + MeModel? me, + DeviceAndAppInfoModel? deviceInfo, +) { + var id = StringConstants.id + ': ${me?.id ?? ''}'; + var email = StringConstants.email + ': ${me?.email ?? ''}'; + var appVersion = + '${StringConstants.appVersion}: ${deviceInfo?.appVersion ?? ''}'; + var deviceModel = + '${StringConstants.deviceModel}: ${deviceInfo?.model ?? ''}'; + var deviceOs = '${StringConstants.deviceOs}: ${deviceInfo?.os ?? ''}'; + var devicePlatform = + '${StringConstants.devicePlatform}: ${deviceInfo?.platform ?? ''}'; + var buidNumber = + '${StringConstants.buidNumber}: ${deviceInfo?.buildNumber ?? ''}'; + + var formattedString = + '$id\n$email\n$appVersion\n$deviceModel\n$deviceOs\n$devicePlatform\n$buidNumber'; + + return formattedString; +} diff --git a/lib/root_page_view.dart b/lib/root_page_view.dart index 22104d19e..744e6e9e4 100644 --- a/lib/root_page_view.dart +++ b/lib/root_page_view.dart @@ -29,7 +29,7 @@ class _RootPageViewState extends ConsumerState { ref.read(audioPlayerNotifierProvider).initAudioHandler(); ref.read(remoteStatsProvider); ref.read(postLocalStatsProvider); - ref.read(meProvider); + ref.read(deviceAppAndUserInfoProvider); ref.read(pageviewNotifierProvider).addListenerToPage(); _saveFcmTokenEvent(ref); ref diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index d93943392..f86c61c62 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -87,7 +87,14 @@ Future launchUrlMedito(String? href) async { } if (href != null && href.startsWith('mailto')) { - _launchEmailSubmission(href); + var version = await getDeviceInfoString(); + var userId = prefs.getString(USER_ID); + var info = + '--- Please write email below this line $version, id:$userId ----'; + + await launchEmailSubmission(href, body: info); + + return true; } else if (href != null) { final params = Uri( path: href.replaceAll('mailto:', ''), @@ -101,23 +108,30 @@ Future launchUrlMedito(String? href) async { return true; } -void _launchEmailSubmission(String href) async { - var version = await getDeviceInfoString(); - - var prefs = await SharedPreferences.getInstance(); - var userId = prefs.getString(USER_ID); - var info = '--- Please write email below this line $version, id:$userId ----'; +Future launchEmailSubmission( + String href, { + String? subject, + String? body, +}) async { + var query = ''; + if (subject != null) { + query = 'subject=$subject'; + } + if (body != null) { + var _body = body.replaceAll('\n', '\r\n'); + query = query != '' ? '$query&body=$_body' : 'body=$_body'; + } final params = Uri( scheme: 'mailto', path: href.replaceAll('mailto:', ''), - query: 'body=$info', + query: query, ); - var url = params.toString(); if (await canLaunchUrl(params)) { - await launchUrlMedito(url); + await launchUrl(params); } else { + var url = params.toString(); print('Could not launch $url'); } } @@ -159,7 +173,7 @@ Future capturePng(BuildContext context, GlobalKey globalKey) async { final directory = await getTemporaryDirectory(); final file = File('${directory.path}/stats.png'); - + return await file.writeAsBytes(exportedPng); } diff --git a/lib/views/auth/join_verify_OTP_view.dart b/lib/views/auth/join_verify_OTP_view.dart index 9b56e6b2b..05b86499e 100644 --- a/lib/views/auth/join_verify_OTP_view.dart +++ b/lib/views/auth/join_verify_OTP_view.dart @@ -38,8 +38,13 @@ class _JoinVerifyOTPViewState extends ConsumerState { if (status == Status.COMPLETED) { await removeFirebaseToken(); await requestGenerateFirebaseToken(); + // ignore: unused_result + ref.invalidate(meProvider); + ref.read(meProvider); var params = JoinRouteParamsModel( - screen: widget.fromScreen, email: widget.email); + screen: widget.fromScreen, + email: widget.email, + ); unawaited(context.push( RouteConstants.joinWelcomePath, extra: params, diff --git a/lib/views/folder/folder_view.dart b/lib/views/folder/folder_view.dart index 4fcc6a681..7144cdd85 100644 --- a/lib/views/folder/folder_view.dart +++ b/lib/views/folder/folder_view.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:Medito/widgets/widgets.dart'; import 'package:Medito/constants/constants.dart'; import 'package:Medito/models/models.dart'; @@ -164,29 +166,39 @@ class _FolderViewState extends ConsumerState String? path, BuildContext context, ) { - checkConnectivity().then((value) { + checkConnectivity().then((value) async { if (value) { var location = GoRouter.of(context).location; if (type == TypeConstants.FOLDER) { if (location.contains('folder2')) { - context.push(getPathFromString( + unawaited(context.push(getPathFromString( RouteConstants.folder3Path, [location.split('/')[2], widget.id, id.toString()], - )); + ))); } else { - context.push(getPathFromString( + unawaited(context.push(getPathFromString( RouteConstants.folder2Path, [widget.id, id.toString()], - )); + ))); } + } else if (type == TypeConstants.EMAIL) { + var deviceAppAndUserInfo = + await ref.read(deviceAppAndUserInfoProvider.future); + var _info = + '${StringConstants.debugInfo}\n$deviceAppAndUserInfo\n${StringConstants.writeBelowThisLine}'; + + await launchEmailSubmission( + path.toString(), + body: _info, + ); } else { - context.push( + unawaited(context.push( getPathFromString( type, [id.toString()], ), extra: {'url': path ?? ''}, - ); + )); } } else { createSnackBar(StringConstants.checkConnection, context); diff --git a/lib/views/home/widgets/announcement/announcement_widget.dart b/lib/views/home/widgets/announcement/announcement_widget.dart index f7a4bd0e5..f6241b951 100644 --- a/lib/views/home/widgets/announcement/announcement_widget.dart +++ b/lib/views/home/widgets/announcement/announcement_widget.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:Medito/constants/constants.dart'; import 'package:Medito/models/models.dart'; import 'package:Medito/providers/providers.dart'; @@ -141,15 +143,26 @@ class _AnnouncementWidgetState extends ConsumerState { BuildContext context, WidgetRef ref, AnnouncementModel element, - ) { + ) async { _handleTrackEvent(ref, element.id, element.ctaTitle); - context.push( - getPathFromString( - element.ctaType, - [element.ctaPath.toString().getIdFromPath()], - ), - extra: {'url': element.ctaPath}, - ); + if (element.ctaType == TypeConstants.EMAIL) { + var deviceAppAndUserInfo = + await ref.read(deviceAppAndUserInfoProvider.future); + var _info = + '${StringConstants.debugInfo}\n$deviceAppAndUserInfo\n${StringConstants.writeBelowThisLine}'; + await launchEmailSubmission( + element.ctaPath.toString(), + body: _info, + ); + } else { + unawaited(context.push( + getPathFromString( + element.ctaType, + [element.ctaPath.toString().getIdFromPath()], + ), + extra: {'url': element.ctaPath}, + )); + } } void _handleTrackEvent( diff --git a/lib/views/home/widgets/bottom_sheet/debug/debug_bottom_sheet_widget.dart b/lib/views/home/widgets/bottom_sheet/debug/debug_bottom_sheet_widget.dart index 0c6cd747d..b9332f996 100644 --- a/lib/views/home/widgets/bottom_sheet/debug/debug_bottom_sheet_widget.dart +++ b/lib/views/home/widgets/bottom_sheet/debug/debug_bottom_sheet_widget.dart @@ -1,21 +1,18 @@ import 'package:Medito/constants/constants.dart'; -import 'package:Medito/models/models.dart'; import 'package:Medito/providers/providers.dart'; import 'package:Medito/utils/utils.dart'; import 'package:Medito/widgets/widgets.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../share_btn/share_btn_widget.dart'; -import 'package:url_launcher/url_launcher.dart'; class DebugBottomSheetWidget extends ConsumerWidget { const DebugBottomSheetWidget({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { - var me = ref.watch(meProvider); - var deviceInfo = ref.watch(deviceAndAppInfoProvider); var globalKey = GlobalKey(); + var deviceAppAndUserInfo = ref.watch(deviceAppAndUserInfoProvider); return Container( decoration: bottomSheetBoxDecoration, @@ -26,13 +23,12 @@ class DebugBottomSheetWidget extends ConsumerWidget { height16, HandleBarWidget(), height16, - me.when( + deviceAppAndUserInfo.when( skipLoadingOnRefresh: false, data: (data) => _debugItemsList( context, globalKey, data, - deviceInfo.value, ), error: (err, stack) => Expanded( child: MeditoErrorWidget( @@ -54,11 +50,8 @@ class DebugBottomSheetWidget extends ConsumerWidget { Column _debugItemsList( BuildContext context, GlobalKey key, - MeModel? me, - DeviceAndAppInfoModel? deviceInfo, + String info, ) { - var info = _formatString(me, deviceInfo); - return Column( mainAxisSize: MainAxisSize.min, children: [ @@ -93,16 +86,12 @@ class DebugBottomSheetWidget extends ConsumerWidget { var _info = '${StringConstants.debugInfo}\n$deviceInfo\n${StringConstants.writeBelowThisLine}'; - final params = Uri( - scheme: 'mailto', - path: StringConstants.supportEmail, - query: 'body=$_info', - ); - try { - if (await canLaunchUrl(params)) { - await launchUrl(params); - } + await launchEmailSubmission( + StringConstants.supportEmail, + subject: StringConstants.bugReport, + body: _info, + ); } catch (e) { createSnackBar( e.toString(), @@ -111,26 +100,4 @@ class DebugBottomSheetWidget extends ConsumerWidget { ); } } - - String _formatString( - MeModel? me, - DeviceAndAppInfoModel? deviceInfo, - ) { - var id = StringConstants.id + ': ${me?.id ?? ''}'; - var email = StringConstants.email + ': ${me?.email ?? ''}'; - var appVersion = - '${StringConstants.appVersion}: ${deviceInfo?.appVersion ?? ''}'; - var deviceModel = - '${StringConstants.deviceModel}: ${deviceInfo?.model ?? ''}'; - var deviceOs = '${StringConstants.deviceOs}: ${deviceInfo?.os ?? ''}'; - var devicePlatform = - '${StringConstants.devicePlatform}: ${deviceInfo?.platform ?? ''}'; - var buidNumber = - '${StringConstants.buidNumber}: ${deviceInfo?.buildNumber ?? ''}'; - - var formattedString = - '$id\n$email\n$appVersion\n$deviceModel\n$deviceOs\n$devicePlatform\n$buidNumber'; - - return formattedString; - } -} \ No newline at end of file +} diff --git a/lib/views/home/widgets/bottom_sheet/menu/menu_bottom_sheet_widget.dart b/lib/views/home/widgets/bottom_sheet/menu/menu_bottom_sheet_widget.dart index 0edd38b31..52c429ebc 100644 --- a/lib/views/home/widgets/bottom_sheet/menu/menu_bottom_sheet_widget.dart +++ b/lib/views/home/widgets/bottom_sheet/menu/menu_bottom_sheet_widget.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:Medito/constants/constants.dart'; import 'package:Medito/models/models.dart'; import 'package:Medito/providers/providers.dart'; @@ -51,16 +53,28 @@ class MenuBottomSheetWidget extends ConsumerWidget { BuildContext context, WidgetRef ref, HomeMenuModel element, - ) { + ) async { _handleTrackEvent(ref, element.id, element.title); Navigator.pop(context); - context.push( - getPathFromString( - element.type, - [element.path.toString().getIdFromPath()], - ), - extra: {'url': element.path}, - ); + if (element.type == TypeConstants.EMAIL) { + var deviceAppAndUserInfo = + await ref.read(deviceAppAndUserInfoProvider.future); + var _info = + '${StringConstants.debugInfo}\n$deviceAppAndUserInfo\n${StringConstants.writeBelowThisLine}'; + + await launchEmailSubmission( + element.path.toString(), + body: _info, + ); + } else { + unawaited(context.push( + getPathFromString( + element.type, + [element.path.toString().getIdFromPath()], + ), + extra: {'url': element.path}, + )); + } } void _handleTrackEvent(WidgetRef ref, String itemId, String itemTitle) { diff --git a/lib/views/home/widgets/filters/filter_widget.dart b/lib/views/home/widgets/filters/filter_widget.dart index 79f1886ae..11d41e535 100644 --- a/lib/views/home/widgets/filters/filter_widget.dart +++ b/lib/views/home/widgets/filters/filter_widget.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:Medito/constants/constants.dart'; import 'package:Medito/models/models.dart'; import 'package:Medito/providers/providers.dart'; @@ -68,15 +70,27 @@ class FilterWidget extends ConsumerWidget { BuildContext context, WidgetRef ref, HomeChipsItemsModel element, - ) { + ) async { _handleTrackEvent(ref, element.id, element.title); - context.push( - getPathFromString( - element.type, - [element.path.toString().getIdFromPath()], - ), - extra: {'url': element.path}, - ); + if (element.type == TypeConstants.EMAIL) { + var deviceAppAndUserInfo = + await ref.read(deviceAppAndUserInfoProvider.future); + var _info = + '${StringConstants.debugInfo}\n$deviceAppAndUserInfo\n${StringConstants.writeBelowThisLine}'; + + await launchEmailSubmission( + element.path.toString(), + body: _info, + ); + } else { + unawaited(context.push( + getPathFromString( + element.type, + [element.path.toString().getIdFromPath()], + ), + extra: {'url': element.path}, + )); + } } void _handleTrackEvent(WidgetRef ref, String chipId, String chipTitle) { diff --git a/lib/views/player/widgets/overlay_cover_image_widget.dart b/lib/views/player/widgets/overlay_cover_image_widget.dart index 3614f85bc..52baeb7a0 100644 --- a/lib/views/player/widgets/overlay_cover_image_widget.dart +++ b/lib/views/player/widgets/overlay_cover_image_widget.dart @@ -6,8 +6,9 @@ class OverlayCoverImageWidget extends StatelessWidget { final String imageUrl; @override Widget build(BuildContext context) { + var size = MediaQuery.of(context).size; const divisor = 2.1; - final coverImageHeight = MediaQuery.of(context).size.height / divisor; + final coverImageHeight = size.height / divisor; return Container( height: coverImageHeight, @@ -15,8 +16,7 @@ class OverlayCoverImageWidget extends StatelessWidget { child: NetworkImageWidget( url: imageUrl, isCache: false, - height: 342, - width: 342, + width: size.width, ), ); } diff --git a/pubspec.yaml b/pubspec.yaml index fb37920e6..d1033e2ee 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,7 +11,7 @@ description: A meditation learning tool # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 2.0.55+20055 +version: 2.0.57+20057 environment: sdk: ">=2.18.0 <3.7.0-13.0" flutter: ">=3.0.0" @@ -23,7 +23,7 @@ dependencies: dio: ^5.0.2 flutter_svg: ^1.1.6 path_provider: ^2.0.1 - url_launcher: ^6.0.3 + url_launcher: ^6.1.14 flutter_markdown: ^0.6.7 shared_preferences: ^2.0.5 auto_size_text: ^3.0.0-nullsafety.0