diff --git a/analysis_options.yaml b/analysis_options.yaml index e48fab2a..bcd6e349 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -11,4 +11,19 @@ dart_code_metrics: metrics-exclude: - test/** rules: - - avoid-dynamic \ No newline at end of file + - avoid-dynamic + - avoid-passing-async-when-sync-expected + - avoid-redundant-async + - avoid-unnecessary-type-assertions + - avoid-unnecessary-type-casts + - avoid-unrelated-type-assertions + - avoid-unused-parameters + - avoid-nested-conditional-expressions + - newline-before-return + - no-boolean-literal-compare + - no-empty-block + - prefer-trailing-comma + - prefer-conditional-expressions + - no-equal-then-else + - prefer-moving-to-variable + - prefer-match-file-name \ No newline at end of file diff --git a/lib/audioplayer/download_class.dart b/lib/audioplayer/download_class.dart index a8a58d6b..6e169ed2 100644 --- a/lib/audioplayer/download_class.dart +++ b/lib/audioplayer/download_class.dart @@ -85,7 +85,7 @@ class _Download { } } // ignore: unnecessary_cast - downloadAmountListener.value = progress as double; + downloadAmountListener.value = progress as double; // it is necessary }).onDone(() async { try { await file.writeAsBytes(_bytes); @@ -103,6 +103,7 @@ class _Download { ), ); } + return; }); } @@ -115,11 +116,8 @@ class _Download { .then((value) => _throwResponse = value); _total = _throwResponse?.contentLength ?? 0; } - if (_received != null && _total != null) { - return _received! / _total!; - } else { - return 0; - } + + return (_received != null && _total != null) ? (_received! / _total!) : 0; } } @@ -148,20 +146,23 @@ class DownloadSingleton { double getProgress(AudioFile file) { if (_download == null) return -1; if (isDownloadingMe(file)) return _download?.getProgress() ?? 0.0; + return -1; } - bool start(BuildContext context, AudioFile file, MediaItem mediaItem) { + bool start(AudioFile file, MediaItem mediaItem) { if (_download == null) return false; if (_download?.isDownloadingMe(file) ?? false) return true; if (isDownloadingSomething()) return false; if (_download?.isThisFile(file) ?? false) { _download?.startDownloading(file, mediaItem); + return true; } _download = _Download(file); _download?.startDownloading(file, mediaItem); + return true; } diff --git a/lib/audioplayer/media_lib.dart b/lib/audioplayer/media_library.dart similarity index 63% rename from lib/audioplayer/media_lib.dart rename to lib/audioplayer/media_library.dart index 47bc8725..106cb14d 100644 --- a/lib/audioplayer/media_lib.dart +++ b/lib/audioplayer/media_library.dart @@ -1,19 +1,20 @@ import 'package:audio_service/audio_service.dart'; class MediaLibrary { - static MediaItem getMediaLibrary( - {String? description, - String? title, - String? illustrationUrl, - String? secondaryColor, - String? primaryColor, - int? durationAsMilliseconds, - String? fileId, - String? attributions, - String? voice, - String? length, - bool? hasBgSound, - int? sessionId}) { + static MediaItem getMediaLibrary({ + String? description, + String? title, + String? illustrationUrl, + String? secondaryColor, + String? primaryColor, + int? durationAsMilliseconds, + String? fileId, + String? attributions, + String? voice, + String? length, + bool? hasBgSound, + int? sessionId, + }) { return MediaItem( id: fileId ?? '', extras: { @@ -25,10 +26,12 @@ class MediaLibrary { ATTR: attributions, LENGTH: length, DURATION: durationAsMilliseconds, - HAS_BG_SOUND : hasBgSound, + HAS_BG_SOUND: hasBgSound, }, artist: voice, - album: '', //empty to remove it from the notification + displayDescription: description, + album: '', + //empty to remove it from the notification title: title ?? '', artUri: Uri.parse(illustrationUrl ?? ''), ); @@ -45,4 +48,4 @@ const String PRIMARY_COLOUR = 'primaryColor'; const String ID = 'id'; const String SESSION_ID = 'sessionId'; const String SESSION_TITLE = 'sessionTitle'; -const String LOCATION = 'location'; \ No newline at end of file +const String LOCATION = 'location'; diff --git a/lib/audioplayer/medito_audio_handler.dart b/lib/audioplayer/medito_audio_handler.dart index 2f801080..725f03a2 100644 --- a/lib/audioplayer/medito_audio_handler.dart +++ b/lib/audioplayer/medito_audio_handler.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'dart:io'; import 'dart:math'; -import 'package:Medito/constants/constants.dart'; import 'package:Medito/utils/utils.dart'; import 'package:audio_service/audio_service.dart'; import 'package:audio_session/audio_session.dart'; @@ -11,7 +10,7 @@ import 'package:just_audio/just_audio.dart'; import '../network/auth.dart'; import '../network/cache.dart'; import '../utils/bgvolume_utils.dart'; -import 'media_lib.dart'; +import 'media_library.dart'; import 'player_utils.dart'; //This is the duration of bgSound fade towards the end. @@ -170,7 +169,7 @@ class MeditoAudioHandler extends BaseAudioHandler unawaited(_bgPlayer.setVolume(_bgVolume)); break; case PLAY_BG_SOUND: - await _playBgSound(extras); + _playBgSound(extras); break; case INIT_BG_SOUND: _bgVolume = extras?[SET_BG_SOUND_VOL] ?? DEFAULT_VOLUME; @@ -186,7 +185,7 @@ class MeditoAudioHandler extends BaseAudioHandler return super.customAction(name, extras); } - Future _playBgSound(Map? extras) async { + void _playBgSound(Map? extras) { var bgSound = extras?[PLAY_BG_SOUND]; if (bgSound != null) { unawaited(_bgPlayer.setFilePath(extras?[PLAY_BG_SOUND])); @@ -212,13 +211,16 @@ class MeditoAudioHandler extends BaseAudioHandler print(_bgPlayer.volume - (_bgVolume / FADE_DURATION)); if (_bgPlayer.volume > 0) { unawaited( - _bgPlayer.setVolume(_bgPlayer.volume - (_bgVolume / FADE_DURATION))); + _bgPlayer.setVolume(_bgPlayer.volume - (_bgVolume / FADE_DURATION)), + ); } } void skipForward30Secs() { - var seekDuration = min(_duration?.inMilliseconds ?? 0, - _player.position.inMilliseconds + Duration(seconds: 30).inMilliseconds); + var seekDuration = min( + _duration?.inMilliseconds ?? 0, + _player.position.inMilliseconds + Duration(seconds: 30).inMilliseconds, + ); _player.seek(Duration(milliseconds: seekDuration)); } diff --git a/lib/audioplayer/player_utils.dart b/lib/audioplayer/player_utils.dart index df5cedaa..23160a68 100644 --- a/lib/audioplayer/player_utils.dart +++ b/lib/audioplayer/player_utils.dart @@ -40,6 +40,7 @@ Future checkBgSoundExists(String name) async { var filePath = (await getFilePath(name)); var file = File(filePath); var exists = await file.exists(); + return exists; } diff --git a/lib/main.dart b/lib/main.dart index c68691ce..4a5b7fb4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -12,8 +12,8 @@ Affero GNU General Public License for more details. You should have received a copy of the Affero GNU General Public License along with Medito App. If not, see .*/ -import 'package:flutter_web_plugins/url_strategy.dart'; import 'dart:async'; + import 'package:Medito/audioplayer/medito_audio_handler.dart'; import 'package:Medito/constants/constants.dart'; import 'package:Medito/routes/routes.dart'; @@ -22,10 +22,12 @@ import 'package:audio_service/audio_service.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_web_plugins/url_strategy.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; + import 'audioplayer/audio_inherited_widget.dart'; import 'network/auth.dart'; @@ -106,14 +108,15 @@ class _ParentWidgetState extends State return MaterialApp.router( routerConfig: router, theme: ThemeData( - splashColor: ColorConstants.moonlight, - canvasColor: ColorConstants.greyIsTheNewBlack, - pageTransitionsTheme: PageTransitionsTheme(builders: { - TargetPlatform.iOS: CupertinoPageTransitionsBuilder(), - TargetPlatform.android: SlideTransitionBuilder(), - }), - colorScheme: ColorScheme.dark(secondary: ColorConstants.walterWhite), - textTheme: meditoTextTheme(context)), + splashColor: ColorConstants.moonlight, + canvasColor: ColorConstants.greyIsTheNewBlack, + pageTransitionsTheme: PageTransitionsTheme(builders: { + TargetPlatform.iOS: CupertinoPageTransitionsBuilder(), + TargetPlatform.android: SlideTransitionBuilder(), + }), + colorScheme: ColorScheme.dark(secondary: ColorConstants.walterWhite), + textTheme: meditoTextTheme(context), + ), title: ParentWidget._title, ); } diff --git a/lib/network/downloads/downloads_bloc.dart b/lib/network/downloads/downloads_bloc.dart index b6b90207..5d326972 100644 --- a/lib/network/downloads/downloads_bloc.dart +++ b/lib/network/downloads/downloads_bloc.dart @@ -2,11 +2,10 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; -import 'package:Medito/audioplayer/media_lib.dart'; +import 'package:Medito/audioplayer/media_library.dart'; import 'package:Medito/audioplayer/player_utils.dart'; import 'package:Medito/network/session_options/session_opts.dart'; import 'package:audio_service/audio_service.dart'; -import 'package:flutter/cupertino.dart'; import 'package:package_info/package_info.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -15,16 +14,19 @@ class DownloadsBloc { static Future seenTip() async { var prefs = await SharedPreferences.getInstance(); + return prefs.getBool('seenDownloadsToolTip') ?? false; } static Future setSeenTip() async { var prefs = await SharedPreferences.getInstance(); + return prefs.setBool('seenDownloadsToolTip', true); } static Future saveFileToDownloadedFilesList( - MediaItem _mediaItem) async { + MediaItem _mediaItem, + ) async { var prefs = await SharedPreferences.getInstance(); var list = prefs.getStringList(savedFilesKey) ?? []; @@ -42,7 +44,7 @@ class DownloadsBloc { 'artist': _mediaItem.artist, 'duration': _mediaItem.duration?.inMilliseconds, 'artUri': _mediaItem.artUri.toString(), - 'extras': _mediaItem.extras + 'extras': _mediaItem.extras, }); } @@ -66,12 +68,13 @@ class DownloadsBloc { static MediaItem _getMediaItemFromMap(json) { return MediaItem( - id: json['id'], - title: json['title'], - artist: json['artist'], - duration: Duration(milliseconds: json['duration'] ?? 0), - artUri: Uri.parse(json['artUri']), - extras: json['extras']); + id: json['id'], + title: json['title'], + artist: json['artist'], + duration: Duration(milliseconds: json['duration'] ?? 0), + artUri: Uri.parse(json['artUri']), + extras: json['extras'], + ); } static Future isAudioFileDownloaded(AudioFile? file) async { @@ -87,7 +90,8 @@ class DownloadsBloc { } static Future removeSessionFromDownloads( - BuildContext context, MediaItem mediaFile) async { + MediaItem mediaFile, + ) async { // Delete the download file from disk for this session var filePath = (await getFilePath(mediaFile.id)); var file = File(filePath); @@ -99,7 +103,8 @@ class DownloadsBloc { // Remove the session from all downloads list var prefs = await SharedPreferences.getInstance(); var list = prefs.getStringList(savedFilesKey) ?? []; - list.removeWhere((element) => _getMediaItemFromMap(jsonDecode(element)).id == mediaFile.id); + list.removeWhere((element) => + _getMediaItemFromMap(jsonDecode(element)).id == mediaFile.id); await prefs.setStringList(savedFilesKey, list); } @@ -107,8 +112,9 @@ class DownloadsBloc { /// Saves a given `List` of `MediaItem` elements (downloaded sessions) static Future saveDownloads(List mediaList) async { var prefs = await SharedPreferences.getInstance(); - var list = - mediaList.map((MediaItem mediaItem) => _jsonEncodeMediaItem(mediaItem)).toList(); + var list = mediaList + .map((MediaItem mediaItem) => _jsonEncodeMediaItem(mediaItem)) + .toList(); await prefs.setStringList(savedFilesKey, list); } } diff --git a/lib/network/folder/new_folder_screen.dart b/lib/network/folder/new_folder_screen.dart index 9d7f1ecf..33b84e22 100644 --- a/lib/network/folder/new_folder_screen.dart +++ b/lib/network/folder/new_folder_screen.dart @@ -6,6 +6,7 @@ import 'package:Medito/utils/utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; + import 'folder_provider.dart'; class NewFolderScreen extends ConsumerWidget { @@ -34,21 +35,26 @@ class NewFolderScreen extends ConsumerWidget { }, child: Scaffold( body: CollapsibleHeaderComponent( - bgImage: AssetConstants.dalle, - title: folder?.data?.title ?? '', - description: folder?.data?.description, - children: [ - for (int i = 0; i < (folder?.data?.items?.length ?? 0); i++) - GestureDetector( - onTap: () => _onListItemTap(folder?.data?.items?[i].item?.id, - folder?.data?.items?[i].item?.type, ref.context), - child: _buildListTile( - context, - folder?.data?.items?[i].item?.title, - folder?.data?.items?[i].item?.subtitle, - true), - ) - ]), + bgImage: AssetConstants.dalle, + title: folder?.data?.title ?? '', + description: folder?.data?.description, + children: [ + for (int i = 0; i < (folder?.data?.items?.length ?? 0); i++) + GestureDetector( + onTap: () => _onListItemTap( + folder?.data?.items?[i].item?.id, + folder?.data?.items?[i].item?.type, + ref.context, + ), + child: _buildListTile( + context, + folder?.data?.items?[i].item?.title, + folder?.data?.items?[i].item?.subtitle, + true, + ), + ), + ], + ), ), ); } diff --git a/lib/network/player/player_repo.dart b/lib/network/player/player_repo.dart index 5ff6841a..593fe334 100644 --- a/lib/network/player/player_repo.dart +++ b/lib/network/player/player_repo.dart @@ -13,7 +13,7 @@ Affero GNU General Public License for more details. You should have received a copy of the Affero GNU General Public License along with Medito App. If not, see .*/ -import 'package:Medito/audioplayer/media_lib.dart'; +import 'package:Medito/audioplayer/media_library.dart'; import 'package:Medito/network/auth.dart'; import 'package:Medito/network/http_get.dart'; import 'package:Medito/network/session_options/background_sounds.dart'; diff --git a/lib/network/session_options/session_options_bloc.dart b/lib/network/session_options/session_options_bloc.dart index 07869976..a6587f0c 100644 --- a/lib/network/session_options/session_options_bloc.dart +++ b/lib/network/session_options/session_options_bloc.dart @@ -16,12 +16,12 @@ along with Medito App. If not, see .*/ import 'dart:async'; import 'package:Medito/audioplayer/download_class.dart'; -import 'package:Medito/audioplayer/media_lib.dart'; +import 'package:Medito/audioplayer/media_library.dart'; import 'package:Medito/network/api_response.dart'; import 'package:Medito/network/session_options/session_options_repo.dart'; import 'package:Medito/network/session_options/session_opts.dart'; import 'package:Medito/tracking/tracking.dart'; -import 'package:Medito/utils/duration_ext.dart'; +import 'package:Medito/utils/duration_extensions.dart'; import 'package:audio_service/audio_service.dart'; import 'package:pedantic/pedantic.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -131,7 +131,7 @@ class SessionOptionsBloc { { Tracking.SESSION_ID: mediaItem.extras?[SESSION_ID].toString() ?? '', Tracking.SESSION_DURATION: mediaItem.extras?[LENGTH].toString() ?? '', - Tracking.SESSION_GUIDE: mediaItem.artist ?? '' + Tracking.SESSION_GUIDE: mediaItem.artist ?? '', }, ), ); @@ -148,7 +148,7 @@ class SessionOptionsBloc { secondaryColor: _options?.colorSecondary, primaryColor: _options?.colorPrimary, durationAsMilliseconds: - clockTimeToDuration(file?.length).inMilliseconds, + clockTimeToDuration(file?.length).inMilliseconds, fileId: file?.id, sessionId: _options?.id, attributions: _options?.attribution); @@ -169,10 +169,10 @@ class SessionOptionsBloc { // Add file data against each voice voiceSet.toList().forEach((voice) { var listForThisVoice = - items.where((element) => element?.voice == voice).toList(); + items.where((element) => element?.voice == voice).toList(); var voiceItem = - VoiceItem(headerValue: voice, listForVoice: listForThisVoice); + VoiceItem(headerValue: voice, listForVoice: listForThisVoice); voiceList.add(voiceItem); }); diff --git a/lib/network/text/text_response.dart b/lib/network/text/text_response.dart index 3d77d8b3..7a580184 100644 --- a/lib/network/text/text_response.dart +++ b/lib/network/text/text_response.dart @@ -19,6 +19,7 @@ class TextResponse { if (data != null) { data['data'] = this.data?.toJson(); } + return data; } } @@ -44,6 +45,7 @@ class Data { data['title'] = title; data['subtitle'] = subtitle; data['body'] = body; + return data; } } diff --git a/lib/network/user/user_response.dart b/lib/network/user/user_response.dart index 08b73777..017fad45 100644 --- a/lib/network/user/user_response.dart +++ b/lib/network/user/user_response.dart @@ -14,6 +14,7 @@ class UserResponse { if (this.data != null) { data['data'] = this.data?.toJson(); } + return data; } } @@ -30,6 +31,7 @@ class Data { Map toJson() { final data = {}; data['id'] = id; + return data; } } \ No newline at end of file diff --git a/lib/network/user/user_utils.dart b/lib/network/user/user_utils.dart index cf070ccf..bdb52f2f 100644 --- a/lib/network/user/user_utils.dart +++ b/lib/network/user/user_utils.dart @@ -17,6 +17,7 @@ Future firstOpenOperations() async { var prefs = await SharedPreferences.getInstance(); var opened = _beginClearStorage(prefs); await _logAccount(prefs); + return opened; } @@ -46,6 +47,7 @@ bool _beginClearStorage(SharedPreferences prefs) { if (!opened) { unawaited(_clearStorage(prefs)); } + return opened; } @@ -105,6 +107,7 @@ class UserRepo { Future get generatedToken async { var prefs = await SharedPreferences.getInstance(); + return prefs.getString(TOKEN); } @@ -141,7 +144,7 @@ Future> getDeviceDetails() async { DEVICE_MODEL: deviceModel, DEVICE_OS: deviceOS, DEVICE_PLATFORM: devicePlatform, - DEVICE_LANGUAGE: deviceLanguage + DEVICE_LANGUAGE: deviceLanguage, }; } diff --git a/lib/repositories/background_sounds/background_sounds_repository.dart b/lib/repositories/background_sounds/background_sounds_repository.dart index 80b5c967..4d19cd4c 100644 --- a/lib/repositories/background_sounds/background_sounds_repository.dart +++ b/lib/repositories/background_sounds/background_sounds_repository.dart @@ -3,6 +3,7 @@ import 'package:Medito/models/models.dart'; import 'package:Medito/services/network/dio_api_services.dart'; import 'package:Medito/services/network/dio_client_provider.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; + part 'background_sounds_repository.g.dart'; abstract class BackgroundSoundsRepository { @@ -19,6 +20,7 @@ class BackgroundSoundsRepositoryImpl extends BackgroundSoundsRepository { try { var res = await client.getRequest(HTTPConstants.BACKGROUND_SOUNDS); var tempResponse = res as List; + return tempResponse .map((x) => BackgroundSoundsModel.fromJson(x)) .toList(); @@ -30,6 +32,7 @@ class BackgroundSoundsRepositoryImpl extends BackgroundSoundsRepository { @riverpod BackgroundSoundsRepositoryImpl backgroundSoundsRepository( - BackgroundSoundsRepositoryRef ref) { + BackgroundSoundsRepositoryRef ref, +) { return BackgroundSoundsRepositoryImpl(client: ref.watch(dioClientProvider)); } diff --git a/lib/repositories/downloader/downloader_repository.dart b/lib/repositories/downloader/downloader_repository.dart index 0a7f0751..5e5d4f58 100644 --- a/lib/repositories/downloader/downloader_repository.dart +++ b/lib/repositories/downloader/downloader_repository.dart @@ -6,21 +6,30 @@ import 'package:Medito/services/network/dio_client_provider.dart'; import 'package:dio/dio.dart'; import 'package:path_provider/path_provider.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; + part 'downloader_repository.g.dart'; abstract class DownloaderRepository { - Future downloadFile(String url, - {String? name, void Function(int, int)? onReceiveProgress}); + Future downloadFile( + String url, { + String? name, + void Function(int, int)? onReceiveProgress, + }); + Future getDownloadedFile(String name); } class DownloaderRepositoryImpl extends DownloaderRepository { DioApiService client; + DownloaderRepositoryImpl({required this.client}); @override - Future downloadFile(String url, - {String? name, void Function(int, int)? onReceiveProgress}) async { + Future downloadFile( + String url, { + String? name, + void Function(int, int)? onReceiveProgress, + }) async { try { var file = await getApplicationDocumentsDirectory(); var fileName = name ?? url.substring(url.lastIndexOf('/') + 1); @@ -28,12 +37,15 @@ class DownloaderRepositoryImpl extends DownloaderRepository { print(savePath); var isExists = await File(savePath).exists(); if (!isExists) { - await client.dio.download(url, savePath, - options: Options(headers: { - HttpHeaders.acceptEncodingHeader: '*', - HttpHeaders.authorizationHeader: HTTPConstants.CONTENT_TOKEN - }), - onReceiveProgress: onReceiveProgress); + await client.dio.download( + url, + savePath, + options: Options(headers: { + HttpHeaders.acceptEncodingHeader: '*', + HttpHeaders.authorizationHeader: HTTPConstants.CONTENT_TOKEN, + }), + onReceiveProgress: onReceiveProgress, + ); } else { throw ('File already exists'); } diff --git a/lib/repositories/folder/folder_repository.dart b/lib/repositories/folder/folder_repository.dart index 2bda5389..d262f931 100644 --- a/lib/repositories/folder/folder_repository.dart +++ b/lib/repositories/folder/folder_repository.dart @@ -3,6 +3,7 @@ import 'package:Medito/models/models.dart'; import 'package:Medito/services/network/dio_api_services.dart'; import 'package:Medito/services/network/dio_client_provider.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; + part 'folder_repository.g.dart'; abstract class FolderRepository { @@ -18,6 +19,7 @@ class FolderRepositoryImpl extends FolderRepository { Future fetchFolders(int folderId) async { try { var res = await client.getRequest('${HTTPConstants.FOLDERS}/$folderId'); + return FolderModel.fromJson(res); } catch (e) { rethrow; diff --git a/lib/repositories/session/session_repository.dart b/lib/repositories/session/session_repository.dart index 62c6ddde..02bf7009 100644 --- a/lib/repositories/session/session_repository.dart +++ b/lib/repositories/session/session_repository.dart @@ -3,6 +3,7 @@ import 'package:Medito/models/models.dart'; import 'package:Medito/services/network/dio_api_services.dart'; import 'package:Medito/services/network/dio_client_provider.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; + part 'session_repository.g.dart'; abstract class SessionRepository { @@ -18,6 +19,7 @@ class SessionRepositoryImpl extends SessionRepository { Future fetchSession(int sessionId) async { try { var res = await client.getRequest('${HTTPConstants.SESSIONS}/$sessionId'); + return SessionModel.fromJson(res); } catch (e) { rethrow; diff --git a/lib/routes/routes.dart b/lib/routes/routes.dart index 8f98d68e..271f5349 100644 --- a/lib/routes/routes.dart +++ b/lib/routes/routes.dart @@ -32,47 +32,47 @@ final router = GoRouter( debugLogDiagnostics: true, routes: [ GoRoute( - path: HomePath, - builder: (context, state) => HomeWrapperWidget(), - routes: [ - _getSessionRoute(), - _getArticleRoute(), - _getDailyRoute(), - _getWebviewRoute(), - GoRoute( - path: 'app', - routes: [_getPlayerRoute()], - pageBuilder: (context, state) => getCollectionMaterialPage(state), - ), - GoRoute( - path: 'folder/:fid', - routes: [ - _getSessionRoute(), - _getArticleRoute(), - _getWebviewRoute(), - GoRoute( - path: 'folder2/:f2id', - routes: [ - _getSessionRoute(), - _getArticleRoute(), - _getWebviewRoute(), - GoRoute( - path: 'folder3/:f3id', - pageBuilder: (context, state) => - getFolderMaterialPage(state), - routes: [ - _getSessionRoute(), - _getArticleRoute(), - _getWebviewRoute(), - ], - ), - ], - pageBuilder: (context, state) => getFolderMaterialPage(state), - ), - ], - pageBuilder: (context, state) => getFolderMaterialPage(state), - ), - ]), + path: HomePath, + builder: (context, state) => HomeWrapperWidget(), + routes: [ + _getSessionRoute(), + _getArticleRoute(), + _getDailyRoute(), + _getWebviewRoute(), + GoRoute( + path: 'app', + routes: [_getPlayerRoute()], + pageBuilder: (context, state) => getCollectionMaterialPage(state), + ), + GoRoute( + path: 'folder/:fid', + routes: [ + _getSessionRoute(), + _getArticleRoute(), + _getWebviewRoute(), + GoRoute( + path: 'folder2/:f2id', + routes: [ + _getSessionRoute(), + _getArticleRoute(), + _getWebviewRoute(), + GoRoute( + path: 'folder3/:f3id', + pageBuilder: (context, state) => getFolderMaterialPage(state), + routes: [ + _getSessionRoute(), + _getArticleRoute(), + _getWebviewRoute(), + ], + ), + ], + pageBuilder: (context, state) => getFolderMaterialPage(state), + ), + ], + pageBuilder: (context, state) => getFolderMaterialPage(state), + ), + ], + ), ], ); @@ -101,11 +101,12 @@ GoRoute _getSessionRoute() { GoRoute _getPlayerRoute() { return GoRoute( - path: 'player', - pageBuilder: (context, state) { - return getPlayerMaterialPage(state); - }, - routes: [_getWebviewRoute(), _getBackgroundSoundRoute()]); + path: 'player', + pageBuilder: (context, state) { + return getPlayerMaterialPage(state); + }, + routes: [_getWebviewRoute(), _getBackgroundSoundRoute()], + ); } GoRoute _getBackgroundSoundRoute() { @@ -125,6 +126,7 @@ GoRoute _getWebviewRoute() { path: 'webview', pageBuilder: (context, state) { final url = state.extra! as Map; + return MaterialPage( key: state.pageKey, child: WebViewComponent(url: url['url']!), @@ -179,19 +181,19 @@ MaterialPage getPlayerMaterialPage(GoRouterState state) { MaterialPage getFolderMaterialPage(GoRouterState state) { if (state.params.length == 1) { return MaterialPage( - key: state.pageKey, child: FolderView(id: state.params['fid']) - // child: NewFolderScreen(id: state.params['fid']), - ); + key: state.pageKey, child: FolderView(id: state.params['fid']), + // child: NewFolderScreen(id: state.params['fid']), + ); } else if (state.params.length == 2) { return MaterialPage( - key: state.pageKey, child: FolderView(id: state.params['fid']) - // child: NewFolderScreen(id: state.params['f2id']), - ); + key: state.pageKey, child: FolderView(id: state.params['fid']), + // child: NewFolderScreen(id: state.params['f2id']), + ); } else { return MaterialPage( - key: state.pageKey, child: FolderView(id: state.params['fid']) - // child: NewFolderScreen(id: state.params['f3id']), - ); + key: state.pageKey, child: FolderView(id: state.params['fid']), + // child: NewFolderScreen(id: state.params['f3id']), + ); } } @@ -228,5 +230,6 @@ String getPathFromString(String? place, List ids) { if (place == 'app') { return CollectionPath; } + return ''; } diff --git a/lib/services/network/dio_api_services.dart b/lib/services/network/dio_api_services.dart index 571bf624..7c2a6b55 100644 --- a/lib/services/network/dio_api_services.dart +++ b/lib/services/network/dio_api_services.dart @@ -22,6 +22,7 @@ class DioApiService { cancelToken: cancelToken, onReceiveProgress: onReceiveProgress, ); + return response.data; } on DioError catch (err) { _returnDioErrorResponse(err); @@ -48,6 +49,7 @@ class DioApiService { onSendProgress: onSendProgress, onReceiveProgress: onReceiveProgress, ); + return response.data; } on DioError catch (err) { _returnDioErrorResponse(err); @@ -61,20 +63,25 @@ class DioApiService { switch (error.response?.statusCode) { case 400: throw BadRequestException( - error.response!.statusMessage ?? 'Bad request'); + error.response!.statusMessage ?? 'Bad request', + ); case 401: throw UnauthorisedException( - 'Unauthorised request: ${error.response!.statusCode}'); + 'Unauthorised request: ${error.response!.statusCode}', + ); case 403: throw UnauthorisedException( - 'Access forbidden: ${error.response!.statusCode}'); + 'Access forbidden: ${error.response!.statusCode}', + ); case 404: throw FetchDataException( - 'Api not found: ${error.response!.statusCode}'); + 'Api not found: ${error.response!.statusCode}', + ); case 500: default: throw FetchDataException( - 'Error occurred while Communication with Server '); + 'Error occurred while Communication with Server ', + ); } } } diff --git a/lib/services/network/dio_client_provider.dart b/lib/services/network/dio_client_provider.dart index bb729174..33979c7c 100644 --- a/lib/services/network/dio_client_provider.dart +++ b/lib/services/network/dio_client_provider.dart @@ -1,31 +1,38 @@ import 'dart:io'; + import 'package:Medito/constants/constants.dart'; import 'package:Medito/services/network/dio_api_services.dart'; import 'package:dio/dio.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'dio_client_provider.g.dart'; +part 'dio_client_provider.g.dart'; @riverpod DioApiService dioClient(DioClientRef ref) { var dio = Dio(); dio.options = BaseOptions( - connectTimeout: Duration(milliseconds: 60000), - // baseUrl: 'https://medito-content.medito-api.repl.co/v1/', - baseUrl: HTTPConstants.BASE_URL, - headers: { - HttpHeaders.authorizationHeader: HTTPConstants.CONTENT_TOKEN, - HttpHeaders.accessControlAllowOriginHeader: '*', - HttpHeaders.accessControlAllowHeadersHeader: - 'Origin,Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,locale', - HttpHeaders.accessControlAllowCredentialsHeader: 'true', - HttpHeaders.accessControlAllowMethodsHeader: 'POST, OPTIONS, HEAD, GET', - HttpHeaders.contentTypeHeader: ContentType.json.value, - HttpHeaders.refererHeader: 'no-referrer-when-downgrade', - HttpHeaders.acceptHeader: '*/*' - }); + connectTimeout: Duration(milliseconds: 60000), + // baseUrl: 'https://medito-content.medito-api.repl.co/v1/', + baseUrl: HTTPConstants.BASE_URL, + headers: { + HttpHeaders.authorizationHeader: HTTPConstants.CONTENT_TOKEN, + HttpHeaders.accessControlAllowOriginHeader: '*', + HttpHeaders.accessControlAllowHeadersHeader: + 'Origin,Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,locale', + HttpHeaders.accessControlAllowCredentialsHeader: 'true', + HttpHeaders.accessControlAllowMethodsHeader: 'POST, OPTIONS, HEAD, GET', + HttpHeaders.contentTypeHeader: ContentType.json.value, + HttpHeaders.refererHeader: 'no-referrer-when-downgrade', + HttpHeaders.acceptHeader: '*/*', + }, + ); dio.interceptors.add(LogInterceptor( - request: true, responseBody: true, requestBody: true, error: true)); + request: true, + responseBody: true, + requestBody: true, + error: true, + )); var dioApiService = DioApiService(dio: dio); + return dioApiService; } diff --git a/lib/services/shared_preference/shared_preferences_service.dart b/lib/services/shared_preference/shared_preferences_service.dart index 9c85f35f..40894f7e 100644 --- a/lib/services/shared_preference/shared_preferences_service.dart +++ b/lib/services/shared_preference/shared_preferences_service.dart @@ -9,6 +9,7 @@ class SharedPreferencesService { static Future getStringFromSF(String key) async { var pref = await SharedPreferences.getInstance(); var stringValue = pref.getString(key); + return stringValue; } @@ -20,6 +21,7 @@ class SharedPreferencesService { static Future getIntFromSF(String key) async { var pref = await SharedPreferences.getInstance(); var intValue = pref.getInt(key); + return intValue; } @@ -31,6 +33,7 @@ class SharedPreferencesService { static Future getDoubleFromSF(String key) async { var pref = await SharedPreferences.getInstance(); var doubleValue = pref.getDouble(key); + return doubleValue; } @@ -41,18 +44,21 @@ class SharedPreferencesService { static Future getBoolFromPref(String key) async { var pref = await SharedPreferences.getInstance(); + return pref.getBool(key); } static Future removeValueFromSF(String key) async { var pref = await SharedPreferences.getInstance(); var isRemoved = await pref.remove(key); + return isRemoved; } static Future checkValueInSF(String key) async { var pref = await SharedPreferences.getInstance(); var isRemoved = pref.containsKey(key); + return isRemoved; } } diff --git a/lib/tracking/tracking.dart b/lib/tracking/tracking.dart index 001c71b9..b17dbca2 100644 --- a/lib/tracking/tracking.dart +++ b/lib/tracking/tracking.dart @@ -51,12 +51,14 @@ class Tracking { static List> destinationData(String type, String item) { return [ - {TYPE: type, ITEM: item} + {TYPE: type, ITEM: item}, ]; } - static Future postUsage(String type, - [Map body = const {}]) async { + static Future postUsage( + String type, [ + Map body = const {}, + ]) async { if (kReleaseMode) { var packageInfo = await PackageInfo.fromPlatform(); var version = packageInfo.buildNumber; @@ -91,6 +93,7 @@ class Tracking { ), ); print('post usage failed: ' + e.toString()); + return; } } @@ -130,5 +133,6 @@ String mapToPlural(String fileType) { if (fileType.contains('daily')) { return 'dailies'; } + return ''; } diff --git a/lib/utils/bgvolume_utils.dart b/lib/utils/bgvolume_utils.dart index c954a3cd..6fce13e7 100644 --- a/lib/utils/bgvolume_utils.dart +++ b/lib/utils/bgvolume_utils.dart @@ -42,6 +42,7 @@ Future _getSavedVolume() async { } if (vol == null || vol > 1) vol = DEFAULT_VOLUME; + return vol; } diff --git a/lib/utils/duration_ext.dart b/lib/utils/duration_extensions.dart similarity index 90% rename from lib/utils/duration_ext.dart rename to lib/utils/duration_extensions.dart index 9c0646e5..6e5ac9d9 100644 --- a/lib/utils/duration_ext.dart +++ b/lib/utils/duration_extensions.dart @@ -5,24 +5,29 @@ extension DurationExtensions on Duration { /// 05:35 -> 05 min 35 sec String toMinutesSeconds() { var twoDigitMinutes = _toTwoDigits( - inMinutes.remainder(100)); //NB: if it's over 100 min it'll show 0:00!! + inMinutes.remainder(100), + ); //NB: if it's over 100 min it'll show 0:00!! var twoDigitSeconds = _toTwoDigits(inSeconds.remainder(60)); + return '$twoDigitMinutes:$twoDigitSeconds'; } String toReadable() { var twoDigitMinutes = _toTwoDigits( - inMinutes.remainder(100)); //NB: if it's over 100 min it'll show 0:00!! + inMinutes.remainder(100), + ); //NB: if it's over 100 min it'll show 0:00!! var twoDigitSeconds = _toTwoDigits(inSeconds.remainder(60)); if (twoDigitSeconds.isNotNullAndNotEmpty() && twoDigitMinutes != '00') { return '$twoDigitMinutes min $twoDigitSeconds sec'; } + return '$twoDigitSeconds sec'; } String _toTwoDigits(int n) { if (n >= 10) return '$n'; + return '0$n'; } } @@ -41,9 +46,11 @@ String formatSessionLength(String? item) { } time = min.toString(); } + return '$time min'; } if (item == null) return ''; + return item + ' min'; } diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index cd76d301..e1a532ad 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -15,23 +15,26 @@ along with Medito App. If not, see .*/ import 'dart:io'; +import 'package:Medito/constants/constants.dart'; import 'package:Medito/network/auth.dart'; import 'package:Medito/network/user/user_utils.dart'; -import 'package:Medito/constants/constants.dart'; import 'package:connectivity/connectivity.dart'; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:url_launcher/url_launcher.dart'; -import 'package:url_launcher/url_launcher_string.dart'; Widget getNetworkImageWidget(String? url) { if (url.isNullOrEmpty()) return Container(); final headers = {HttpHeaders.authorizationHeader: CONTENT_TOKEN}; + return Image.network(url!, fit: BoxFit.fill, headers: headers); } NetworkImage getNetworkImage(String url) { - final headers = {HttpHeaders.authorizationHeader: HTTPConstants.CONTENT_TOKEN}; + final headers = { + + HttpHeaders.authorizationHeader: HTTPConstants.CONTENT_TOKEN + }; return NetworkImage(url, headers: headers); } diff --git a/lib/views/btm_nav/downloads_widget.dart b/lib/views/btm_nav/downloads_widget.dart index 15ab5263..05d28763 100644 --- a/lib/views/btm_nav/downloads_widget.dart +++ b/lib/views/btm_nav/downloads_widget.dart @@ -1,8 +1,8 @@ -import 'package:Medito/audioplayer/media_lib.dart'; +import 'package:Medito/audioplayer/media_library.dart'; import 'package:Medito/audioplayer/medito_audio_handler.dart'; -import 'package:Medito/network/downloads/downloads_bloc.dart'; import 'package:Medito/constants/constants.dart'; -import 'package:Medito/utils/duration_ext.dart'; +import 'package:Medito/network/downloads/downloads_bloc.dart'; +import 'package:Medito/utils/duration_extensions.dart'; import 'package:Medito/utils/utils.dart'; import 'package:Medito/views/empty_widget.dart'; import 'package:Medito/views/main/app_bar_widget.dart'; @@ -93,7 +93,7 @@ class _DownloadsListWidgetState extends State onDismissed: (direction) { if (mounted) { _downloadList.removeWhere((element) => element == item); - DownloadsBloc.removeSessionFromDownloads(context, item); + DownloadsBloc.removeSessionFromDownloads(item); setState(() {}); } @@ -142,7 +142,8 @@ class _DownloadsListWidgetState extends State } void showSwipeToDeleteTip() { - createSnackBar(StringConstants.SWIPE_TO_DELETE, context, color: ColorConstants.darkMoon); + createSnackBar(StringConstants.SWIPE_TO_DELETE, context, + color: ColorConstants.darkMoon); } void _refreshDownloadList() { diff --git a/lib/views/btm_nav/home_widget.dart b/lib/views/btm_nav/home_widget.dart index d74d2b70..13eb0b97 100644 --- a/lib/views/btm_nav/home_widget.dart +++ b/lib/views/btm_nav/home_widget.dart @@ -14,15 +14,16 @@ You should have received a copy of the Affero GNU General Public License along with Medito App. If not, see .*/ import 'dart:async'; + +import 'package:Medito/constants/constants.dart'; import 'package:Medito/network/api_response.dart'; import 'package:Medito/network/downloads/downloads_bloc.dart'; import 'package:Medito/network/home/home_bloc.dart'; import 'package:Medito/network/home/home_repo.dart'; import 'package:Medito/network/home/menu_response.dart'; import 'package:Medito/network/user/user_utils.dart'; -import 'package:Medito/tracking/tracking.dart'; -import 'package:Medito/constants/constants.dart'; import 'package:Medito/routes/routes.dart'; +import 'package:Medito/tracking/tracking.dart'; import 'package:Medito/utils/utils.dart'; import 'package:Medito/views/home/courses_row_widget.dart'; import 'package:Medito/views/home/daily_message_widget.dart'; @@ -92,9 +93,9 @@ class _HomeWidgetState extends ConsumerState { type, id, context, Tracking.SHORTCUT_TAPPED), ), CoursesRowWidget( - key: _coursesKey, - onTap: (type, id) => _navigate( - type, id, context, Tracking.COURSE_TAPPED)), + key: _coursesKey, + onTap: (type, id) => _navigate( + type, id, context, Tracking.COURSE_TAPPED)), StatsWidget(), SizedBox(height: 16), DailyMessageWidget(key: _dailyMessageKey), @@ -194,40 +195,50 @@ class _HomeWidgetState extends ConsumerState { } Widget _getTitleWidget(BuildContext context) => FutureBuilder( - future: _bloc.getTitleText(DateTime.now()), - initialData: 'Medito', - builder: (context, snapshot) { - return GestureDetector( - onLongPress: () => _showVersionPopUp(context), - child: Text(snapshot.data ?? '', - style: Theme.of(context).textTheme.headline1), - ); - }); + future: _bloc.getTitleText(DateTime.now()), + initialData: 'Medito', + builder: (context, snapshot) { + return GestureDetector( + onLongPress: () => _showVersionPopUp(context), + child: Text( + snapshot.data ?? '', + style: Theme.of(context).textTheme.headline1, + ), + ); + }, + ); Future _showVersionPopUp(BuildContext context) async { var line1 = await getDeviceInfoString(); var prefs = await SharedPreferences.getInstance(); var userID = prefs.getString(USER_ID) ?? 'None'; final snackBar = SnackBar( - content: GestureDetector( - onTap: () { - Share.share('$line1 $userID'); - }, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('Tap here to copy', - style: TextStyle(color: ColorConstants.walterWhite)), - Text(line1, - style: TextStyle(color: ColorConstants.meditoTextGrey)), - Text(userID, - style: TextStyle(color: ColorConstants.meditoTextGrey)) - ], - ), + content: GestureDetector( + onTap: () { + Share.share('$line1 $userID'); + }, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Tap here to copy', + style: TextStyle(color: ColorConstants.walterWhite), + ), + Text( + line1, + style: TextStyle(color: ColorConstants.meditoTextGrey), + ), + Text( + userID, + style: TextStyle(color: ColorConstants.meditoTextGrey), + ), + ], ), - backgroundColor: ColorConstants.midnight); + ), + backgroundColor: ColorConstants.midnight, + ); // Find the Scaffold in the Widget tree and use it to show a SnackBar! ScaffoldMessenger.of(context).showSnackBar(snackBar); @@ -252,8 +263,11 @@ class _HomeWidgetState extends ConsumerState { await DownloadsBloc.seenTip().then((seen) { if (!seen) { unawaited(DownloadsBloc.setSeenTip()); - createSnackBar(StringConstants.SWIPE_TO_DELETE, context, - color: ColorConstants.darkMoon); + createSnackBar( + StringConstants.SWIPE_TO_DELETE, + context, + color: ColorConstants.darkMoon, + ); } }); } diff --git a/lib/views/empty_widget.dart b/lib/views/empty_widget.dart index e4dab5e6..8b1c84fe 100644 --- a/lib/views/empty_widget.dart +++ b/lib/views/empty_widget.dart @@ -5,6 +5,7 @@ import 'package:flutter_svg/svg.dart'; class EmptyStateWidget extends StatelessWidget { final String? message; final SvgPicture? image; + const EmptyStateWidget({Key? key, this.message, this.image}) : super(key: key); diff --git a/lib/views/folder/folder_view.dart b/lib/views/folder/folder_view.dart index 123597b8..22a24da0 100644 --- a/lib/views/folder/folder_view.dart +++ b/lib/views/folder/folder_view.dart @@ -33,7 +33,10 @@ class FolderView extends ConsumerWidget { Widget _buildLoadingWidget() => const FolderShimmerComponent(); RefreshIndicator _buildScaffoldWithData( - BuildContext context, FolderModel folder, WidgetRef ref) { + BuildContext context, + FolderModel folder, + WidgetRef ref, + ) { return RefreshIndicator( onRefresh: () async { return await ref.refresh(FoldersProvider(folderId: 28)); @@ -60,7 +63,11 @@ class FolderView extends ConsumerWidget { } Container _buildListTile( - BuildContext context, String? title, String? subtitle, String type) { + BuildContext context, + String? title, + String? subtitle, + String type, + ) { return Container( decoration: BoxDecoration( border: Border( diff --git a/lib/views/player/components/duration_indicatior_component.dart b/lib/views/player/components/duration_indicatior_component.dart index 30350a7e..6c51d697 100644 --- a/lib/views/player/components/duration_indicatior_component.dart +++ b/lib/views/player/components/duration_indicatior_component.dart @@ -1,6 +1,6 @@ import 'package:Medito/constants/constants.dart'; import 'package:Medito/models/models.dart'; -import 'package:Medito/utils/duration_ext.dart'; +import 'package:Medito/utils/duration_extensions.dart'; import 'package:Medito/view_model/audio_player/audio_player_viewmodel.dart'; import 'package:Medito/view_model/player/audio_position_viewmodel.dart'; import 'package:flutter/material.dart'; diff --git a/lib/views/player_old/components/background_sounds_sheet_widget.dart b/lib/views/player_old/components/background_sounds_sheet_widget.dart index b6c8a4c5..e50ab782 100644 --- a/lib/views/player_old/components/background_sounds_sheet_widget.dart +++ b/lib/views/player_old/components/background_sounds_sheet_widget.dart @@ -16,10 +16,10 @@ along with Medito App. If not, see .*/ import 'package:Medito/audioplayer/audio_inherited_widget.dart'; import 'package:Medito/audioplayer/medito_audio_handler.dart'; import 'package:Medito/audioplayer/player_utils.dart'; +import 'package:Medito/constants/constants.dart'; import 'package:Medito/network/api_response.dart'; import 'package:Medito/network/session_options/background_sounds.dart'; import 'package:Medito/utils/bgvolume_utils.dart'; -import 'package:Medito/constants/constants.dart'; import 'package:Medito/utils/shared_preferences_utils.dart'; import 'package:Medito/utils/utils.dart'; import 'package:Medito/views/player_old/components/position_indicator_widget.dart'; @@ -60,8 +60,12 @@ class _ChooseBackgroundSoundDialogState } // On some android phones, the back button kills the session :/ - bool backInterceptor(bool stopDefaultButtonEvent, RouteInfo info) { + bool backInterceptor( + bool stopDefaultButtonEvent, + RouteInfo info, + ) { Navigator.pop(context); + return true; } @@ -70,6 +74,7 @@ class _ChooseBackgroundSoundDialogState _volume = await retrieveSavedBgVolume(); await await Future.delayed(Duration(milliseconds: 200)).then((value) { _handler?.customAction(SET_BG_SOUND_VOL, {SET_BG_SOUND_VOL: _volume}); + return _handler?.customAction(SEND_BG_SOUND, {SEND_BG_SOUND: bgSound}); }); } @@ -79,94 +84,69 @@ class _ChooseBackgroundSoundDialogState _handler = AudioHandlerInheritedWidget.of(context).audioHandler; return StreamBuilder( - stream: Stream.fromFuture( - Connectivity().checkConnectivity(), - ), - builder: (context, snapshot) { - if (snapshot.hasData) { - if (snapshot.data == ConnectivityResult.none) { - _isOffline = true; - } - return StreamBuilder( - stream: widget.handler?.customEvent.stream, - initialData: {SEND_BG_SOUND: NONE}, - builder: (context, snapshot) { - var currentSound = - _getCurrentSoundFromSnapshot(snapshot.data); - return DraggableScrollableSheet( - expand: false, - builder: (BuildContext context, - ScrollController scrollController) { - return SafeArea( - top: true, - bottom: false, - child: Material( - color: ColorConstants.moonlight, - child: _isOffline - ? _offlineBackgroundSounds( - currentSound, scrollController) - : _onlineBackgroundSounds( - currentSound, scrollController)), - ); - }, - ); - }); - } else { - return Container(); // return a spinner + stream: Stream.fromFuture( + Connectivity().checkConnectivity(), + ), + builder: (context, snapshot) { + if (snapshot.hasData) { + if (snapshot.data == ConnectivityResult.none) { + _isOffline = true; } - }); + + return StreamBuilder( + stream: widget.handler?.customEvent.stream, + initialData: {SEND_BG_SOUND: NONE}, + builder: (context, snapshot) { + var currentSound = _getCurrentSoundFromSnapshot(snapshot.data); + + return DraggableScrollableSheet( + expand: false, + builder: + (BuildContext context, ScrollController scrollController) { + return SafeArea( + top: true, + bottom: false, + child: Material( + color: ColorConstants.moonlight, + child: _isOffline + ? _offlineBackgroundSounds( + currentSound, scrollController) + : _onlineBackgroundSounds( + currentSound, scrollController), + ), + ); + }, + ); + }, + ); + } else { + return Container(); // return a spinner + } + }, + ); } Widget _onlineBackgroundSounds( - String currentSound, ScrollController scrollController) { + String currentSound, + ScrollController scrollController, + ) { return StreamBuilder>( - stream: widget.stream, - initialData: ApiResponse.loading(), - builder: (context, snapshot) { - switch (snapshot.data?.status) { - case Status.LOADING: - return Center( - child: const CircularProgressIndicator( - backgroundColor: Colors.black, - valueColor: AlwaysStoppedAnimation( - ColorConstants.walterWhite))); - case Status.COMPLETED: - var list = snapshot.data?.body?.data; + stream: widget.stream, + initialData: ApiResponse.loading(), + builder: (context, snapshot) { + switch (snapshot.data?.status) { + case Status.LOADING: + return Center( + child: const CircularProgressIndicator( + backgroundColor: Colors.black, + valueColor: AlwaysStoppedAnimation( + ColorConstants.walterWhite, + ), + ), + ); + case Status.COMPLETED: + var list = snapshot.data?.body?.data; - var widgetList = [ - Divider(height: 16), - _getHeader(), - Divider(height: 16), - _getVolumeWidget(), - Divider(height: 16), - _getNoneListItem(currentSound) - ]; - if (list != null) { - widgetList.addAll(list - .map((e) => - _getBackgroundSoundListTile(e, currentSound, context)) - .toList()); - } - - return ListView( - controller: scrollController, children: widgetList); - - case Status.ERROR: - return _getErrorWidget(); - case null: - return Container(); - } - }); - } - - Widget _offlineBackgroundSounds( - String currentSound, ScrollController scrollController) { - return FutureBuilder>( - future: getBgSoundFromOfflineSharedPrefs(), - initialData: [], - builder: (context, snapshot) { - if (snapshot.hasData) { - var list = snapshot.data; var widgetList = [ Divider(height: 16), _getHeader(), @@ -177,20 +157,57 @@ class _ChooseBackgroundSoundDialogState ]; if (list != null) { widgetList.addAll(list - .map((e) => + .map((e) => _getBackgroundSoundListTile(e, currentSound, context)) .toList()); } return ListView(controller: scrollController, children: widgetList); - } else { - return Center( - child: const CircularProgressIndicator( - backgroundColor: Colors.black, - valueColor: AlwaysStoppedAnimation( - ColorConstants.walterWhite))); + + case Status.ERROR: + return _getErrorWidget(); + case null: + return Container(); + } + }, + ); + } + + Widget _offlineBackgroundSounds( + String currentSound, ScrollController scrollController) { + return FutureBuilder>( + future: getBgSoundFromOfflineSharedPrefs(), + initialData: [], + builder: (context, snapshot) { + if (snapshot.hasData) { + var list = snapshot.data; + var widgetList = [ + Divider(height: 16), + _getHeader(), + Divider(height: 16), + _getVolumeWidget(), + Divider(height: 16), + _getNoneListItem(currentSound), + ]; + if (list != null) { + widgetList.addAll(list + .map((e) => + _getBackgroundSoundListTile(e, currentSound, context)) + .toList()); } - }); + + return ListView(controller: scrollController, children: widgetList); + } else { + return Center( + child: const CircularProgressIndicator( + backgroundColor: Colors.black, + valueColor: + AlwaysStoppedAnimation(ColorConstants.walterWhite), + ), + ); + } + }, + ); } Widget _getErrorWidget() => Padding( @@ -217,11 +234,12 @@ class _ChooseBackgroundSoundDialogState TextStyle? _getTheme(current, String? name) { return Theme.of(context).textTheme.bodyText2?.copyWith( - fontWeight: - _isSelected(current, name) ? FontWeight.w600 : FontWeight.normal, - color: _isSelected(current, name) - ? ColorConstants.walterWhite - : ColorConstants.meditoTextGrey); + fontWeight: + _isSelected(current, name) ? FontWeight.w600 : FontWeight.normal, + color: _isSelected(current, name) + ? ColorConstants.walterWhite + : ColorConstants.meditoTextGrey, + ); } Widget _getVisibilityWidget(String name, String current, Widget child) => @@ -234,44 +252,65 @@ class _ChooseBackgroundSoundDialogState current == name || (current == '' && name == NONE); Widget _getBackgroundSoundListTile( - BackgroundSoundData item, String current, BuildContext context) { + BackgroundSoundData item, + String current, + BuildContext context, + ) { var assetUrl = item.file?.toAssetUrl(); return InkWell( - onTap: () { - setState(() { - _downloadingItem = item.name; - }); + onTap: () { + setState(() { + _downloadingItem = item.name; + }); - downloadBGMusicFromURL(assetUrl, item.name).then((filePath) { - if (filePath == 'Connectivity lost') { - _downloadingItem = ''; - _isOffline = true; - setState(() {}); - createSnackBar( - 'Connectivity lost. Displaying offline background sounds.', - context); - _noneSelected(); - } + downloadBGMusicFromURL(assetUrl, item.name).then((filePath) { + if (filePath == 'Connectivity lost') { _downloadingItem = ''; - addBgSoundSelectionToSharedPrefs(filePath, item.name); - widget.handler - ?.customAction(PLAY_BG_SOUND, {PLAY_BG_SOUND: filePath}); - return widget.handler - ?.customAction(SEND_BG_SOUND, {SEND_BG_SOUND: item.name}); - }); - }, - child: ListTile( - enableFeedback: true, - title: Text('${item.name}', style: _getTheme(current, item.name)), - trailing: _isDownloading(item) - ? _getSmallLoadingWidget() - : _getVisibilityWidget( - item.name ?? '', - current, - Icon( - Icons.check_circle_outline, - color: ColorConstants.walterWhite, - )))); + _isOffline = true; + setState(() {}); + createSnackBar( + 'Connectivity lost. Displaying offline background sounds.', + context, + ); + _noneSelected(); + } + _downloadingItem = ''; + addBgSoundSelectionToSharedPrefs( + filePath, + item.name, + ); + widget.handler?.customAction( + PLAY_BG_SOUND, + {PLAY_BG_SOUND: filePath}, + ); + + return widget.handler?.customAction( + SEND_BG_SOUND, + {SEND_BG_SOUND: item.name}, + ); + }); + }, + child: ListTile( + enableFeedback: true, + title: Text( + '${item.name}', + style: _getTheme( + current, + item.name, + ), + ), + trailing: _isDownloading(item) + ? _getSmallLoadingWidget() + : _getVisibilityWidget( + item.name ?? '', + current, + Icon( + Icons.check_circle_outline, + color: ColorConstants.walterWhite, + ), + ), + ), + ); } bool _isDownloading(BackgroundSoundData item) => @@ -280,12 +319,14 @@ class _ChooseBackgroundSoundDialogState Widget _getSmallLoadingWidget() => Padding( padding: const EdgeInsets.only(right: 6.0), child: SizedBox( - height: 16, - width: 16, - child: const CircularProgressIndicator( - backgroundColor: Colors.black, - valueColor: - AlwaysStoppedAnimation(ColorConstants.walterWhite))), + height: 16, + width: 16, + child: const CircularProgressIndicator( + backgroundColor: Colors.black, + valueColor: + AlwaysStoppedAnimation(ColorConstants.walterWhite), + ), + ), ); void _noneSelected() { @@ -297,11 +338,12 @@ class _ChooseBackgroundSoundDialogState Widget _getHeader() { return Padding( - padding: const EdgeInsets.only(bottom: 8.0, left: 16.0, top: 8.0), - child: Text( - StringConstants.BACKGROUND_SOUNDS, - style: Theme.of(context).textTheme.headline1, - )); + padding: const EdgeInsets.only(bottom: 8.0, left: 16.0, top: 8.0), + child: Text( + StringConstants.BACKGROUND_SOUNDS, + style: Theme.of(context).textTheme.headline1, + ), + ); } Widget _getVolumeWidget() { @@ -310,45 +352,49 @@ class _ChooseBackgroundSoundDialogState child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), child: StreamBuilder( - stream: _dragBgVolumeSubject, - builder: (context, snapshot) { - var volume = _dragBgVolumeSubject.value; - var volumeIcon = _volumeIconFunction(volume); - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(volumeIcon, size: 24, color: ColorConstants.walterWhite), - Expanded( - child: Padding( - padding: const EdgeInsets.only(left: 24.0, right: 4), - child: SliderTheme( - data: SliderThemeData( - trackShape: CustomTrackShape(addTopPadding: false), - thumbShape: - RoundSliderThumbShape(enabledThumbRadius: 10.0), - ), - child: Slider( - min: 0.0, - activeColor: ColorConstants.walterWhite, - inactiveColor: - ColorConstants.walterWhite.withOpacity(0.7), - max: 1.0, - value: volume, - onChanged: (value) { - _dragBgVolumeSubject.add(value); - _handler?.customAction( - SET_BG_SOUND_VOL, {SET_BG_SOUND_VOL: value}); - }, - onChangeEnd: (value) { - saveBgVolume(value); - }, - ), + stream: _dragBgVolumeSubject, + builder: (context, snapshot) { + var volume = _dragBgVolumeSubject.value; + var volumeIcon = _volumeIconFunction(volume); + + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(volumeIcon, size: 24, color: ColorConstants.walterWhite), + Expanded( + child: Padding( + padding: const EdgeInsets.only(left: 24.0, right: 4), + child: SliderTheme( + data: SliderThemeData( + trackShape: CustomTrackShape(addTopPadding: false), + thumbShape: + RoundSliderThumbShape(enabledThumbRadius: 10.0), + ), + child: Slider( + min: 0.0, + activeColor: ColorConstants.walterWhite, + inactiveColor: + ColorConstants.walterWhite.withOpacity(0.7), + max: 1.0, + value: volume, + onChanged: (value) { + _dragBgVolumeSubject.add(value); + _handler?.customAction( + SET_BG_SOUND_VOL, + {SET_BG_SOUND_VOL: value}, + ); + }, + onChangeEnd: (value) { + saveBgVolume(value); + }, ), ), ), - ], - ); - }), + ), + ], + ); + }, + ), ), ); } diff --git a/lib/views/player_old/components/position_indicator_widget.dart b/lib/views/player_old/components/position_indicator_widget.dart index b4d4fac5..ff25ba42 100644 --- a/lib/views/player_old/components/position_indicator_widget.dart +++ b/lib/views/player_old/components/position_indicator_widget.dart @@ -1,14 +1,13 @@ import 'dart:math'; -import 'package:Medito/audioplayer/media_lib.dart'; + +import 'package:Medito/audioplayer/media_library.dart'; import 'package:Medito/audioplayer/medito_audio_handler.dart'; -import 'package:Medito/network/player/player_bloc.dart'; import 'package:Medito/constants/constants.dart'; -import 'package:Medito/utils/duration_ext.dart'; import 'package:Medito/routes/routes.dart'; +import 'package:Medito/utils/duration_extensions.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:rxdart/rxdart.dart'; -import 'background_sounds_sheet_widget.dart'; class PositionIndicatorWidget extends StatefulWidget { final MeditoAudioHandler? handler; diff --git a/lib/views/player_old/player2/player_view.dart b/lib/views/player_old/player2/player_view.dart index 5136967f..329cb1d4 100644 --- a/lib/views/player_old/player2/player_view.dart +++ b/lib/views/player_old/player2/player_view.dart @@ -15,11 +15,11 @@ along with Medito App. If not, see .*/ import 'dart:async'; -import 'package:Medito/audioplayer/media_lib.dart'; +import 'package:Medito/audioplayer/media_library.dart'; import 'package:Medito/audioplayer/medito_audio_handler.dart'; import 'package:Medito/components/components.dart'; -import 'package:Medito/network/player/player_bloc.dart'; import 'package:Medito/constants/constants.dart'; +import 'package:Medito/network/player/player_bloc.dart'; import 'package:Medito/routes/routes.dart'; import 'package:Medito/utils/shared_preferences_utils.dart'; import 'package:Medito/utils/utils.dart'; @@ -29,6 +29,7 @@ import 'package:audio_service/audio_service.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; + import '../../../audioplayer/audio_inherited_widget.dart'; import '../../../tracking/tracking.dart'; import '../../../utils/bgvolume_utils.dart'; @@ -93,13 +94,16 @@ class _PlayerWidgetState extends State { event[AUDIO_COMPLETE] == true) { _trackSessionEnd(_handler?.mediaItem.value); showGeneralDialog( - transitionDuration: Duration(milliseconds: 400), - context: context, - barrierColor: ColorConstants.darkMoon, - pageBuilder: (_, __, ___) { - return AudioCompleteDialog( - bloc: _bloc, mediaItem: _handler?.mediaItem.value); - }); + transitionDuration: Duration(milliseconds: 400), + context: context, + barrierColor: ColorConstants.darkMoon, + pageBuilder: (_, __, ___) { + return AudioCompleteDialog( + bloc: _bloc, + mediaItem: _handler?.mediaItem.value, + ); + }, + ); } }); @@ -112,8 +116,9 @@ class _PlayerWidgetState extends State { image: getNetworkImage(mediaItem?.artUri?.toString() ?? ''), fit: BoxFit.fill, colorFilter: ColorFilter.mode( - ColorConstants.almostBlack.withOpacity(0.65), - BlendMode.overlay), + ColorConstants.almostBlack.withOpacity(0.65), + BlendMode.overlay, + ), ), ), child: SafeArea( @@ -131,8 +136,9 @@ class _PlayerWidgetState extends State { _buildPlayerButtonRow(mediaItem), // A seek bar. PositionIndicatorWidget( - handler: _handler, - bgSoundsStream: _bloc.bgSoundsListController?.stream), + handler: _handler, + bgSoundsStream: _bloc.bgSoundsListController?.stream, + ), Container(height: 24), ], ), @@ -149,12 +155,14 @@ class _PlayerWidgetState extends State { getSavedBgSoundData(); } } on Exception catch (e, s) { - unawaited(Sentry.captureException(e, - stackTrace: s, - hint: Hint.withMap({ - 'message': - 'Failed trying to get save background sounds data: extras[HAS_BG_SOUND]: ${_hasBGSound()}' - }))); + unawaited(Sentry.captureException( + e, + stackTrace: s, + hint: Hint.withMap({ + 'message': + 'Failed trying to get save background sounds data: extras[HAS_BG_SOUND]: ${_hasBGSound()}', + }), + )); } } @@ -207,10 +215,12 @@ class _PlayerWidgetState extends State { Padding _getSubtitleWidget(MediaItem? mediaItem) { var attr = mediaItem?.extras != null ? (mediaItem?.extras?['attr']) : ''; + return Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: MarkdownComponent( - body: 'Giovanni Dienstmann https://www.google.com/'), + body: 'Giovanni Dienstmann https://www.google.com/', + ), ); } @@ -255,7 +265,7 @@ class _PlayerWidgetState extends State { { Tracking.SESSION_ID: mediaItem.extras?[SESSION_ID].toString() ?? '', Tracking.SESSION_DURATION: mediaItem.extras?[LENGTH].toString() ?? '', - Tracking.SESSION_GUIDE: mediaItem.artist ?? '' + Tracking.SESSION_GUIDE: mediaItem.artist ?? '', }, ), ); diff --git a/lib/views/text/text_file_widget.dart b/lib/views/text/text_file_widget.dart index 3c7bcec9..a3541d6d 100644 --- a/lib/views/text/text_file_widget.dart +++ b/lib/views/text/text_file_widget.dart @@ -13,9 +13,8 @@ Affero GNU General Public License for more details. You should have received a copy of the Affero GNU General Public License along with Medito App. If not, see .*/ +import 'package:Medito/constants/constants.dart'; import 'package:Medito/network/text/text_bloc.dart'; -import 'package:Medito/constants/constants.dart'; -import 'package:Medito/constants/constants.dart'; import 'package:Medito/utils/utils.dart'; import 'package:Medito/views/main/app_bar_widget.dart'; import 'package:flutter/material.dart'; @@ -62,14 +61,15 @@ class _TextFileWidgetState extends State appBar: PreferredSize( preferredSize: const Size(double.infinity, kToolbarHeight), child: StreamBuilder( - stream: _bloc.titleController.stream, - initialData: '...', - builder: (context, snapshot) { - return MeditoAppBarWidget( - isTransparent: true, - title: snapshot.data ?? '', - ); - }), // StreamBuilder + stream: _bloc.titleController.stream, + initialData: '...', + builder: (context, snapshot) { + return MeditoAppBarWidget( + isTransparent: true, + title: snapshot.data ?? '', + ); + }, + ), // StreamBuilder ), body: RefreshIndicator( onRefresh: () => _bloc.fetchText(widget.id, true), @@ -105,32 +105,43 @@ class _TextFileWidgetState extends State children: [ Padding( padding: const EdgeInsets.only( - left: 16.0, right: 16.0, top: 12.0, bottom: 16.0), + left: 16.0, + right: 16.0, + top: 12.0, + bottom: 16.0, + ), child: StreamBuilder( - stream: _bloc.bodyController.stream, - initialData: 'Loading...', - builder: (context, snapshot) { - return Markdown( - data: snapshot.data ?? '', - onTapLink: _linkTap, - physics: NeverScrollableScrollPhysics(), - padding: const EdgeInsets.all(0), - shrinkWrap: true, - selectable: true, - styleSheet: buildMarkdownStyleSheet(context).copyWith( - horizontalRuleDecoration: BoxDecoration( - border: Border( - top: BorderSide( - width: 1.0, - color: ColorConstants.meditoTextGrey, - ), - ), - ), - h2: TextStyle( - color: ColorConstants.walterWhite, height: 1.5), - p: TextStyle( - color: ColorConstants.walterWhite, height: 1.5))); - }), + stream: _bloc.bodyController.stream, + initialData: 'Loading...', + builder: (context, snapshot) { + return Markdown( + data: snapshot.data ?? '', + onTapLink: _linkTap, + physics: NeverScrollableScrollPhysics(), + padding: const EdgeInsets.all(0), + shrinkWrap: true, + selectable: true, + styleSheet: buildMarkdownStyleSheet(context).copyWith( + horizontalRuleDecoration: BoxDecoration( + border: Border( + top: BorderSide( + width: 1.0, + color: ColorConstants.meditoTextGrey, + ), + ), + ), + h2: TextStyle( + color: ColorConstants.walterWhite, + height: 1.5, + ), + p: TextStyle( + color: ColorConstants.walterWhite, + height: 1.5, + ), + ), + ); + }, + ), ), ], ), diff --git a/test/folder/folder_viewmodel_test.dart b/test/folder/folder_viewmodel_test.dart index 75fee989..a4f00b48 100644 --- a/test/folder/folder_viewmodel_test.dart +++ b/test/folder/folder_viewmodel_test.dart @@ -36,11 +36,12 @@ void main() { isPublished: true, items: [ FolderItemsModel( - type: 'session', - id: 120, - title: 'Complete meditation', - subtitle: '19 min', - path: 'sessions/120') + type: 'session', + id: 120, + title: 'Complete meditation', + subtitle: '19 min', + path: 'sessions/120', + ), ], ); final mockFolderRepository = MockFolderRepository();