Fixed warnings

This commit is contained in:
Michael Speed 2023-03-22 19:31:21 +01:00
parent 482b73f374
commit bead831986
35 changed files with 649 additions and 458 deletions

View File

@ -11,4 +11,19 @@ dart_code_metrics:
metrics-exclude: metrics-exclude:
- test/** - test/**
rules: rules:
- avoid-dynamic - 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

View File

@ -85,7 +85,7 @@ class _Download {
} }
} }
// ignore: unnecessary_cast // ignore: unnecessary_cast
downloadAmountListener.value = progress as double; downloadAmountListener.value = progress as double; // it is necessary
}).onDone(() async { }).onDone(() async {
try { try {
await file.writeAsBytes(_bytes); await file.writeAsBytes(_bytes);
@ -103,6 +103,7 @@ class _Download {
), ),
); );
} }
return; return;
}); });
} }
@ -115,11 +116,8 @@ class _Download {
.then((value) => _throwResponse = value); .then((value) => _throwResponse = value);
_total = _throwResponse?.contentLength ?? 0; _total = _throwResponse?.contentLength ?? 0;
} }
if (_received != null && _total != null) {
return _received! / _total!; return (_received != null && _total != null) ? (_received! / _total!) : 0;
} else {
return 0;
}
} }
} }
@ -148,20 +146,23 @@ class DownloadSingleton {
double getProgress(AudioFile file) { double getProgress(AudioFile file) {
if (_download == null) return -1; if (_download == null) return -1;
if (isDownloadingMe(file)) return _download?.getProgress() ?? 0.0; if (isDownloadingMe(file)) return _download?.getProgress() ?? 0.0;
return -1; return -1;
} }
bool start(BuildContext context, AudioFile file, MediaItem mediaItem) { bool start(AudioFile file, MediaItem mediaItem) {
if (_download == null) return false; if (_download == null) return false;
if (_download?.isDownloadingMe(file) ?? false) return true; if (_download?.isDownloadingMe(file) ?? false) return true;
if (isDownloadingSomething()) return false; if (isDownloadingSomething()) return false;
if (_download?.isThisFile(file) ?? false) { if (_download?.isThisFile(file) ?? false) {
_download?.startDownloading(file, mediaItem); _download?.startDownloading(file, mediaItem);
return true; return true;
} }
_download = _Download(file); _download = _Download(file);
_download?.startDownloading(file, mediaItem); _download?.startDownloading(file, mediaItem);
return true; return true;
} }

View File

@ -1,19 +1,20 @@
import 'package:audio_service/audio_service.dart'; import 'package:audio_service/audio_service.dart';
class MediaLibrary { class MediaLibrary {
static MediaItem getMediaLibrary( static MediaItem getMediaLibrary({
{String? description, String? description,
String? title, String? title,
String? illustrationUrl, String? illustrationUrl,
String? secondaryColor, String? secondaryColor,
String? primaryColor, String? primaryColor,
int? durationAsMilliseconds, int? durationAsMilliseconds,
String? fileId, String? fileId,
String? attributions, String? attributions,
String? voice, String? voice,
String? length, String? length,
bool? hasBgSound, bool? hasBgSound,
int? sessionId}) { int? sessionId,
}) {
return MediaItem( return MediaItem(
id: fileId ?? '', id: fileId ?? '',
extras: { extras: {
@ -25,10 +26,12 @@ class MediaLibrary {
ATTR: attributions, ATTR: attributions,
LENGTH: length, LENGTH: length,
DURATION: durationAsMilliseconds, DURATION: durationAsMilliseconds,
HAS_BG_SOUND : hasBgSound, HAS_BG_SOUND: hasBgSound,
}, },
artist: voice, artist: voice,
album: '', //empty to remove it from the notification displayDescription: description,
album: '',
//empty to remove it from the notification
title: title ?? '', title: title ?? '',
artUri: Uri.parse(illustrationUrl ?? ''), artUri: Uri.parse(illustrationUrl ?? ''),
); );
@ -45,4 +48,4 @@ const String PRIMARY_COLOUR = 'primaryColor';
const String ID = 'id'; const String ID = 'id';
const String SESSION_ID = 'sessionId'; const String SESSION_ID = 'sessionId';
const String SESSION_TITLE = 'sessionTitle'; const String SESSION_TITLE = 'sessionTitle';
const String LOCATION = 'location'; const String LOCATION = 'location';

View File

@ -2,7 +2,6 @@ import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:Medito/constants/constants.dart';
import 'package:Medito/utils/utils.dart'; import 'package:Medito/utils/utils.dart';
import 'package:audio_service/audio_service.dart'; import 'package:audio_service/audio_service.dart';
import 'package:audio_session/audio_session.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/auth.dart';
import '../network/cache.dart'; import '../network/cache.dart';
import '../utils/bgvolume_utils.dart'; import '../utils/bgvolume_utils.dart';
import 'media_lib.dart'; import 'media_library.dart';
import 'player_utils.dart'; import 'player_utils.dart';
//This is the duration of bgSound fade towards the end. //This is the duration of bgSound fade towards the end.
@ -170,7 +169,7 @@ class MeditoAudioHandler extends BaseAudioHandler
unawaited(_bgPlayer.setVolume(_bgVolume)); unawaited(_bgPlayer.setVolume(_bgVolume));
break; break;
case PLAY_BG_SOUND: case PLAY_BG_SOUND:
await _playBgSound(extras); _playBgSound(extras);
break; break;
case INIT_BG_SOUND: case INIT_BG_SOUND:
_bgVolume = extras?[SET_BG_SOUND_VOL] ?? DEFAULT_VOLUME; _bgVolume = extras?[SET_BG_SOUND_VOL] ?? DEFAULT_VOLUME;
@ -186,7 +185,7 @@ class MeditoAudioHandler extends BaseAudioHandler
return super.customAction(name, extras); return super.customAction(name, extras);
} }
Future<void> _playBgSound(Map<String, dynamic>? extras) async { void _playBgSound(Map<String, dynamic>? extras) {
var bgSound = extras?[PLAY_BG_SOUND]; var bgSound = extras?[PLAY_BG_SOUND];
if (bgSound != null) { if (bgSound != null) {
unawaited(_bgPlayer.setFilePath(extras?[PLAY_BG_SOUND])); unawaited(_bgPlayer.setFilePath(extras?[PLAY_BG_SOUND]));
@ -212,13 +211,16 @@ class MeditoAudioHandler extends BaseAudioHandler
print(_bgPlayer.volume - (_bgVolume / FADE_DURATION)); print(_bgPlayer.volume - (_bgVolume / FADE_DURATION));
if (_bgPlayer.volume > 0) { if (_bgPlayer.volume > 0) {
unawaited( unawaited(
_bgPlayer.setVolume(_bgPlayer.volume - (_bgVolume / FADE_DURATION))); _bgPlayer.setVolume(_bgPlayer.volume - (_bgVolume / FADE_DURATION)),
);
} }
} }
void skipForward30Secs() { void skipForward30Secs() {
var seekDuration = min(_duration?.inMilliseconds ?? 0, var seekDuration = min(
_player.position.inMilliseconds + Duration(seconds: 30).inMilliseconds); _duration?.inMilliseconds ?? 0,
_player.position.inMilliseconds + Duration(seconds: 30).inMilliseconds,
);
_player.seek(Duration(milliseconds: seekDuration)); _player.seek(Duration(milliseconds: seekDuration));
} }

View File

@ -40,6 +40,7 @@ Future<bool?> checkBgSoundExists(String name) async {
var filePath = (await getFilePath(name)); var filePath = (await getFilePath(name));
var file = File(filePath); var file = File(filePath);
var exists = await file.exists(); var exists = await file.exists();
return exists; return exists;
} }

View File

@ -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 You should have received a copy of the Affero GNU General Public License
along with Medito App. If not, see <https://www.gnu.org/licenses/>.*/ along with Medito App. If not, see <https://www.gnu.org/licenses/>.*/
import 'package:flutter_web_plugins/url_strategy.dart';
import 'dart:async'; import 'dart:async';
import 'package:Medito/audioplayer/medito_audio_handler.dart'; import 'package:Medito/audioplayer/medito_audio_handler.dart';
import 'package:Medito/constants/constants.dart'; import 'package:Medito/constants/constants.dart';
import 'package:Medito/routes/routes.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/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_riverpod/flutter_riverpod.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:sentry_flutter/sentry_flutter.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'audioplayer/audio_inherited_widget.dart'; import 'audioplayer/audio_inherited_widget.dart';
import 'network/auth.dart'; import 'network/auth.dart';
@ -106,14 +108,15 @@ class _ParentWidgetState extends State<ParentWidget>
return MaterialApp.router( return MaterialApp.router(
routerConfig: router, routerConfig: router,
theme: ThemeData( theme: ThemeData(
splashColor: ColorConstants.moonlight, splashColor: ColorConstants.moonlight,
canvasColor: ColorConstants.greyIsTheNewBlack, canvasColor: ColorConstants.greyIsTheNewBlack,
pageTransitionsTheme: PageTransitionsTheme(builders: { pageTransitionsTheme: PageTransitionsTheme(builders: {
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(), TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
TargetPlatform.android: SlideTransitionBuilder(), TargetPlatform.android: SlideTransitionBuilder(),
}), }),
colorScheme: ColorScheme.dark(secondary: ColorConstants.walterWhite), colorScheme: ColorScheme.dark(secondary: ColorConstants.walterWhite),
textTheme: meditoTextTheme(context)), textTheme: meditoTextTheme(context),
),
title: ParentWidget._title, title: ParentWidget._title,
); );
} }

View File

@ -2,11 +2,10 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; 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/audioplayer/player_utils.dart';
import 'package:Medito/network/session_options/session_opts.dart'; import 'package:Medito/network/session_options/session_opts.dart';
import 'package:audio_service/audio_service.dart'; import 'package:audio_service/audio_service.dart';
import 'package:flutter/cupertino.dart';
import 'package:package_info/package_info.dart'; import 'package:package_info/package_info.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@ -15,16 +14,19 @@ class DownloadsBloc {
static Future<bool> seenTip() async { static Future<bool> seenTip() async {
var prefs = await SharedPreferences.getInstance(); var prefs = await SharedPreferences.getInstance();
return prefs.getBool('seenDownloadsToolTip') ?? false; return prefs.getBool('seenDownloadsToolTip') ?? false;
} }
static Future<bool> setSeenTip() async { static Future<bool> setSeenTip() async {
var prefs = await SharedPreferences.getInstance(); var prefs = await SharedPreferences.getInstance();
return prefs.setBool('seenDownloadsToolTip', true); return prefs.setBool('seenDownloadsToolTip', true);
} }
static Future<void> saveFileToDownloadedFilesList( static Future<void> saveFileToDownloadedFilesList(
MediaItem _mediaItem) async { MediaItem _mediaItem,
) async {
var prefs = await SharedPreferences.getInstance(); var prefs = await SharedPreferences.getInstance();
var list = prefs.getStringList(savedFilesKey) ?? []; var list = prefs.getStringList(savedFilesKey) ?? [];
@ -42,7 +44,7 @@ class DownloadsBloc {
'artist': _mediaItem.artist, 'artist': _mediaItem.artist,
'duration': _mediaItem.duration?.inMilliseconds, 'duration': _mediaItem.duration?.inMilliseconds,
'artUri': _mediaItem.artUri.toString(), 'artUri': _mediaItem.artUri.toString(),
'extras': _mediaItem.extras 'extras': _mediaItem.extras,
}); });
} }
@ -66,12 +68,13 @@ class DownloadsBloc {
static MediaItem _getMediaItemFromMap(json) { static MediaItem _getMediaItemFromMap(json) {
return MediaItem( return MediaItem(
id: json['id'], id: json['id'],
title: json['title'], title: json['title'],
artist: json['artist'], artist: json['artist'],
duration: Duration(milliseconds: json['duration'] ?? 0), duration: Duration(milliseconds: json['duration'] ?? 0),
artUri: Uri.parse(json['artUri']), artUri: Uri.parse(json['artUri']),
extras: json['extras']); extras: json['extras'],
);
} }
static Future<bool> isAudioFileDownloaded(AudioFile? file) async { static Future<bool> isAudioFileDownloaded(AudioFile? file) async {
@ -87,7 +90,8 @@ class DownloadsBloc {
} }
static Future<void> removeSessionFromDownloads( static Future<void> removeSessionFromDownloads(
BuildContext context, MediaItem mediaFile) async { MediaItem mediaFile,
) async {
// Delete the download file from disk for this session // Delete the download file from disk for this session
var filePath = (await getFilePath(mediaFile.id)); var filePath = (await getFilePath(mediaFile.id));
var file = File(filePath); var file = File(filePath);
@ -99,7 +103,8 @@ class DownloadsBloc {
// Remove the session from all downloads list // Remove the session from all downloads list
var prefs = await SharedPreferences.getInstance(); var prefs = await SharedPreferences.getInstance();
var list = prefs.getStringList(savedFilesKey) ?? []; 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); await prefs.setStringList(savedFilesKey, list);
} }
@ -107,8 +112,9 @@ class DownloadsBloc {
/// Saves a given `List` of `MediaItem` elements (downloaded sessions) /// Saves a given `List` of `MediaItem` elements (downloaded sessions)
static Future<void> saveDownloads(List<MediaItem> mediaList) async { static Future<void> saveDownloads(List<MediaItem> mediaList) async {
var prefs = await SharedPreferences.getInstance(); var prefs = await SharedPreferences.getInstance();
var list = var list = mediaList
mediaList.map((MediaItem mediaItem) => _jsonEncodeMediaItem(mediaItem)).toList(); .map((MediaItem mediaItem) => _jsonEncodeMediaItem(mediaItem))
.toList();
await prefs.setStringList(savedFilesKey, list); await prefs.setStringList(savedFilesKey, list);
} }
} }

View File

@ -6,6 +6,7 @@ import 'package:Medito/utils/utils.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'folder_provider.dart'; import 'folder_provider.dart';
class NewFolderScreen extends ConsumerWidget { class NewFolderScreen extends ConsumerWidget {
@ -34,21 +35,26 @@ class NewFolderScreen extends ConsumerWidget {
}, },
child: Scaffold( child: Scaffold(
body: CollapsibleHeaderComponent( body: CollapsibleHeaderComponent(
bgImage: AssetConstants.dalle, bgImage: AssetConstants.dalle,
title: folder?.data?.title ?? '', title: folder?.data?.title ?? '',
description: folder?.data?.description, description: folder?.data?.description,
children: [ children: [
for (int i = 0; i < (folder?.data?.items?.length ?? 0); i++) for (int i = 0; i < (folder?.data?.items?.length ?? 0); i++)
GestureDetector( GestureDetector(
onTap: () => _onListItemTap(folder?.data?.items?[i].item?.id, onTap: () => _onListItemTap(
folder?.data?.items?[i].item?.type, ref.context), folder?.data?.items?[i].item?.id,
child: _buildListTile( folder?.data?.items?[i].item?.type,
context, ref.context,
folder?.data?.items?[i].item?.title, ),
folder?.data?.items?[i].item?.subtitle, child: _buildListTile(
true), context,
) folder?.data?.items?[i].item?.title,
]), folder?.data?.items?[i].item?.subtitle,
true,
),
),
],
),
), ),
); );
} }

View File

@ -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 You should have received a copy of the Affero GNU General Public License
along with Medito App. If not, see <https://www.gnu.org/licenses/>.*/ along with Medito App. If not, see <https://www.gnu.org/licenses/>.*/
import 'package:Medito/audioplayer/media_lib.dart'; import 'package:Medito/audioplayer/media_library.dart';
import 'package:Medito/network/auth.dart'; import 'package:Medito/network/auth.dart';
import 'package:Medito/network/http_get.dart'; import 'package:Medito/network/http_get.dart';
import 'package:Medito/network/session_options/background_sounds.dart'; import 'package:Medito/network/session_options/background_sounds.dart';

View File

@ -16,12 +16,12 @@ along with Medito App. If not, see <https://www.gnu.org/licenses/>.*/
import 'dart:async'; import 'dart:async';
import 'package:Medito/audioplayer/download_class.dart'; 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/api_response.dart';
import 'package:Medito/network/session_options/session_options_repo.dart'; import 'package:Medito/network/session_options/session_options_repo.dart';
import 'package:Medito/network/session_options/session_opts.dart'; import 'package:Medito/network/session_options/session_opts.dart';
import 'package:Medito/tracking/tracking.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:audio_service/audio_service.dart';
import 'package:pedantic/pedantic.dart'; import 'package:pedantic/pedantic.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@ -131,7 +131,7 @@ class SessionOptionsBloc {
{ {
Tracking.SESSION_ID: mediaItem.extras?[SESSION_ID].toString() ?? '', Tracking.SESSION_ID: mediaItem.extras?[SESSION_ID].toString() ?? '',
Tracking.SESSION_DURATION: mediaItem.extras?[LENGTH].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, secondaryColor: _options?.colorSecondary,
primaryColor: _options?.colorPrimary, primaryColor: _options?.colorPrimary,
durationAsMilliseconds: durationAsMilliseconds:
clockTimeToDuration(file?.length).inMilliseconds, clockTimeToDuration(file?.length).inMilliseconds,
fileId: file?.id, fileId: file?.id,
sessionId: _options?.id, sessionId: _options?.id,
attributions: _options?.attribution); attributions: _options?.attribution);
@ -169,10 +169,10 @@ class SessionOptionsBloc {
// Add file data against each voice // Add file data against each voice
voiceSet.toList().forEach((voice) { voiceSet.toList().forEach((voice) {
var listForThisVoice = var listForThisVoice =
items.where((element) => element?.voice == voice).toList(); items.where((element) => element?.voice == voice).toList();
var voiceItem = var voiceItem =
VoiceItem(headerValue: voice, listForVoice: listForThisVoice); VoiceItem(headerValue: voice, listForVoice: listForThisVoice);
voiceList.add(voiceItem); voiceList.add(voiceItem);
}); });

View File

@ -19,6 +19,7 @@ class TextResponse {
if (data != null) { if (data != null) {
data['data'] = this.data?.toJson(); data['data'] = this.data?.toJson();
} }
return data; return data;
} }
} }
@ -44,6 +45,7 @@ class Data {
data['title'] = title; data['title'] = title;
data['subtitle'] = subtitle; data['subtitle'] = subtitle;
data['body'] = body; data['body'] = body;
return data; return data;
} }
} }

View File

@ -14,6 +14,7 @@ class UserResponse {
if (this.data != null) { if (this.data != null) {
data['data'] = this.data?.toJson(); data['data'] = this.data?.toJson();
} }
return data; return data;
} }
} }
@ -30,6 +31,7 @@ class Data {
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final data = <String, dynamic>{}; final data = <String, dynamic>{};
data['id'] = id; data['id'] = id;
return data; return data;
} }
} }

View File

@ -17,6 +17,7 @@ Future<bool> firstOpenOperations() async {
var prefs = await SharedPreferences.getInstance(); var prefs = await SharedPreferences.getInstance();
var opened = _beginClearStorage(prefs); var opened = _beginClearStorage(prefs);
await _logAccount(prefs); await _logAccount(prefs);
return opened; return opened;
} }
@ -46,6 +47,7 @@ bool _beginClearStorage(SharedPreferences prefs) {
if (!opened) { if (!opened) {
unawaited(_clearStorage(prefs)); unawaited(_clearStorage(prefs));
} }
return opened; return opened;
} }
@ -105,6 +107,7 @@ class UserRepo {
Future<String?> get generatedToken async { Future<String?> get generatedToken async {
var prefs = await SharedPreferences.getInstance(); var prefs = await SharedPreferences.getInstance();
return prefs.getString(TOKEN); return prefs.getString(TOKEN);
} }
@ -141,7 +144,7 @@ Future<Map<String, String>> getDeviceDetails() async {
DEVICE_MODEL: deviceModel, DEVICE_MODEL: deviceModel,
DEVICE_OS: deviceOS, DEVICE_OS: deviceOS,
DEVICE_PLATFORM: devicePlatform, DEVICE_PLATFORM: devicePlatform,
DEVICE_LANGUAGE: deviceLanguage DEVICE_LANGUAGE: deviceLanguage,
}; };
} }

View File

@ -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_api_services.dart';
import 'package:Medito/services/network/dio_client_provider.dart'; import 'package:Medito/services/network/dio_client_provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'background_sounds_repository.g.dart'; part 'background_sounds_repository.g.dart';
abstract class BackgroundSoundsRepository { abstract class BackgroundSoundsRepository {
@ -19,6 +20,7 @@ class BackgroundSoundsRepositoryImpl extends BackgroundSoundsRepository {
try { try {
var res = await client.getRequest(HTTPConstants.BACKGROUND_SOUNDS); var res = await client.getRequest(HTTPConstants.BACKGROUND_SOUNDS);
var tempResponse = res as List; var tempResponse = res as List;
return tempResponse return tempResponse
.map((x) => BackgroundSoundsModel.fromJson(x)) .map((x) => BackgroundSoundsModel.fromJson(x))
.toList(); .toList();
@ -30,6 +32,7 @@ class BackgroundSoundsRepositoryImpl extends BackgroundSoundsRepository {
@riverpod @riverpod
BackgroundSoundsRepositoryImpl backgroundSoundsRepository( BackgroundSoundsRepositoryImpl backgroundSoundsRepository(
BackgroundSoundsRepositoryRef ref) { BackgroundSoundsRepositoryRef ref,
) {
return BackgroundSoundsRepositoryImpl(client: ref.watch(dioClientProvider)); return BackgroundSoundsRepositoryImpl(client: ref.watch(dioClientProvider));
} }

View File

@ -6,21 +6,30 @@ import 'package:Medito/services/network/dio_client_provider.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'downloader_repository.g.dart'; part 'downloader_repository.g.dart';
abstract class DownloaderRepository { abstract class DownloaderRepository {
Future<dynamic> downloadFile(String url, Future<dynamic> downloadFile(
{String? name, void Function(int, int)? onReceiveProgress}); String url, {
String? name,
void Function(int, int)? onReceiveProgress,
});
Future<dynamic> getDownloadedFile(String name); Future<dynamic> getDownloadedFile(String name);
} }
class DownloaderRepositoryImpl extends DownloaderRepository { class DownloaderRepositoryImpl extends DownloaderRepository {
DioApiService client; DioApiService client;
DownloaderRepositoryImpl({required this.client}); DownloaderRepositoryImpl({required this.client});
@override @override
Future downloadFile(String url, Future downloadFile(
{String? name, void Function(int, int)? onReceiveProgress}) async { String url, {
String? name,
void Function(int, int)? onReceiveProgress,
}) async {
try { try {
var file = await getApplicationDocumentsDirectory(); var file = await getApplicationDocumentsDirectory();
var fileName = name ?? url.substring(url.lastIndexOf('/') + 1); var fileName = name ?? url.substring(url.lastIndexOf('/') + 1);
@ -28,12 +37,15 @@ class DownloaderRepositoryImpl extends DownloaderRepository {
print(savePath); print(savePath);
var isExists = await File(savePath).exists(); var isExists = await File(savePath).exists();
if (!isExists) { if (!isExists) {
await client.dio.download(url, savePath, await client.dio.download(
options: Options(headers: { url,
HttpHeaders.acceptEncodingHeader: '*', savePath,
HttpHeaders.authorizationHeader: HTTPConstants.CONTENT_TOKEN options: Options(headers: {
}), HttpHeaders.acceptEncodingHeader: '*',
onReceiveProgress: onReceiveProgress); HttpHeaders.authorizationHeader: HTTPConstants.CONTENT_TOKEN,
}),
onReceiveProgress: onReceiveProgress,
);
} else { } else {
throw ('File already exists'); throw ('File already exists');
} }

View File

@ -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_api_services.dart';
import 'package:Medito/services/network/dio_client_provider.dart'; import 'package:Medito/services/network/dio_client_provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'folder_repository.g.dart'; part 'folder_repository.g.dart';
abstract class FolderRepository { abstract class FolderRepository {
@ -18,6 +19,7 @@ class FolderRepositoryImpl extends FolderRepository {
Future<FolderModel> fetchFolders(int folderId) async { Future<FolderModel> fetchFolders(int folderId) async {
try { try {
var res = await client.getRequest('${HTTPConstants.FOLDERS}/$folderId'); var res = await client.getRequest('${HTTPConstants.FOLDERS}/$folderId');
return FolderModel.fromJson(res); return FolderModel.fromJson(res);
} catch (e) { } catch (e) {
rethrow; rethrow;

View File

@ -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_api_services.dart';
import 'package:Medito/services/network/dio_client_provider.dart'; import 'package:Medito/services/network/dio_client_provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'session_repository.g.dart'; part 'session_repository.g.dart';
abstract class SessionRepository { abstract class SessionRepository {
@ -18,6 +19,7 @@ class SessionRepositoryImpl extends SessionRepository {
Future<SessionModel> fetchSession(int sessionId) async { Future<SessionModel> fetchSession(int sessionId) async {
try { try {
var res = await client.getRequest('${HTTPConstants.SESSIONS}/$sessionId'); var res = await client.getRequest('${HTTPConstants.SESSIONS}/$sessionId');
return SessionModel.fromJson(res); return SessionModel.fromJson(res);
} catch (e) { } catch (e) {
rethrow; rethrow;

View File

@ -32,47 +32,47 @@ final router = GoRouter(
debugLogDiagnostics: true, debugLogDiagnostics: true,
routes: [ routes: [
GoRoute( GoRoute(
path: HomePath, path: HomePath,
builder: (context, state) => HomeWrapperWidget(), builder: (context, state) => HomeWrapperWidget(),
routes: [ routes: [
_getSessionRoute(), _getSessionRoute(),
_getArticleRoute(), _getArticleRoute(),
_getDailyRoute(), _getDailyRoute(),
_getWebviewRoute(), _getWebviewRoute(),
GoRoute( GoRoute(
path: 'app', path: 'app',
routes: [_getPlayerRoute()], routes: [_getPlayerRoute()],
pageBuilder: (context, state) => getCollectionMaterialPage(state), pageBuilder: (context, state) => getCollectionMaterialPage(state),
), ),
GoRoute( GoRoute(
path: 'folder/:fid', path: 'folder/:fid',
routes: [ routes: [
_getSessionRoute(), _getSessionRoute(),
_getArticleRoute(), _getArticleRoute(),
_getWebviewRoute(), _getWebviewRoute(),
GoRoute( GoRoute(
path: 'folder2/:f2id', path: 'folder2/:f2id',
routes: [ routes: [
_getSessionRoute(), _getSessionRoute(),
_getArticleRoute(), _getArticleRoute(),
_getWebviewRoute(), _getWebviewRoute(),
GoRoute( GoRoute(
path: 'folder3/:f3id', path: 'folder3/:f3id',
pageBuilder: (context, state) => pageBuilder: (context, state) => getFolderMaterialPage(state),
getFolderMaterialPage(state), routes: [
routes: [ _getSessionRoute(),
_getSessionRoute(), _getArticleRoute(),
_getArticleRoute(), _getWebviewRoute(),
_getWebviewRoute(), ],
], ),
), ],
], pageBuilder: (context, state) => getFolderMaterialPage(state),
pageBuilder: (context, state) => getFolderMaterialPage(state), ),
), ],
], pageBuilder: (context, state) => getFolderMaterialPage(state),
pageBuilder: (context, state) => getFolderMaterialPage(state), ),
), ],
]), ),
], ],
); );
@ -101,11 +101,12 @@ GoRoute _getSessionRoute() {
GoRoute _getPlayerRoute() { GoRoute _getPlayerRoute() {
return GoRoute( return GoRoute(
path: 'player', path: 'player',
pageBuilder: (context, state) { pageBuilder: (context, state) {
return getPlayerMaterialPage(state); return getPlayerMaterialPage(state);
}, },
routes: [_getWebviewRoute(), _getBackgroundSoundRoute()]); routes: [_getWebviewRoute(), _getBackgroundSoundRoute()],
);
} }
GoRoute _getBackgroundSoundRoute() { GoRoute _getBackgroundSoundRoute() {
@ -125,6 +126,7 @@ GoRoute _getWebviewRoute() {
path: 'webview', path: 'webview',
pageBuilder: (context, state) { pageBuilder: (context, state) {
final url = state.extra! as Map; final url = state.extra! as Map;
return MaterialPage( return MaterialPage(
key: state.pageKey, key: state.pageKey,
child: WebViewComponent(url: url['url']!), child: WebViewComponent(url: url['url']!),
@ -179,19 +181,19 @@ MaterialPage<void> getPlayerMaterialPage(GoRouterState state) {
MaterialPage<void> getFolderMaterialPage(GoRouterState state) { MaterialPage<void> getFolderMaterialPage(GoRouterState state) {
if (state.params.length == 1) { if (state.params.length == 1) {
return MaterialPage( return MaterialPage(
key: state.pageKey, child: FolderView(id: state.params['fid']) key: state.pageKey, child: FolderView(id: state.params['fid']),
// child: NewFolderScreen(id: state.params['fid']), // child: NewFolderScreen(id: state.params['fid']),
); );
} else if (state.params.length == 2) { } else if (state.params.length == 2) {
return MaterialPage( return MaterialPage(
key: state.pageKey, child: FolderView(id: state.params['fid']) key: state.pageKey, child: FolderView(id: state.params['fid']),
// child: NewFolderScreen(id: state.params['f2id']), // child: NewFolderScreen(id: state.params['f2id']),
); );
} else { } else {
return MaterialPage( return MaterialPage(
key: state.pageKey, child: FolderView(id: state.params['fid']) key: state.pageKey, child: FolderView(id: state.params['fid']),
// child: NewFolderScreen(id: state.params['f3id']), // child: NewFolderScreen(id: state.params['f3id']),
); );
} }
} }
@ -228,5 +230,6 @@ String getPathFromString(String? place, List<String?> ids) {
if (place == 'app') { if (place == 'app') {
return CollectionPath; return CollectionPath;
} }
return ''; return '';
} }

View File

@ -22,6 +22,7 @@ class DioApiService {
cancelToken: cancelToken, cancelToken: cancelToken,
onReceiveProgress: onReceiveProgress, onReceiveProgress: onReceiveProgress,
); );
return response.data; return response.data;
} on DioError catch (err) { } on DioError catch (err) {
_returnDioErrorResponse(err); _returnDioErrorResponse(err);
@ -48,6 +49,7 @@ class DioApiService {
onSendProgress: onSendProgress, onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress, onReceiveProgress: onReceiveProgress,
); );
return response.data; return response.data;
} on DioError catch (err) { } on DioError catch (err) {
_returnDioErrorResponse(err); _returnDioErrorResponse(err);
@ -61,20 +63,25 @@ class DioApiService {
switch (error.response?.statusCode) { switch (error.response?.statusCode) {
case 400: case 400:
throw BadRequestException( throw BadRequestException(
error.response!.statusMessage ?? 'Bad request'); error.response!.statusMessage ?? 'Bad request',
);
case 401: case 401:
throw UnauthorisedException( throw UnauthorisedException(
'Unauthorised request: ${error.response!.statusCode}'); 'Unauthorised request: ${error.response!.statusCode}',
);
case 403: case 403:
throw UnauthorisedException( throw UnauthorisedException(
'Access forbidden: ${error.response!.statusCode}'); 'Access forbidden: ${error.response!.statusCode}',
);
case 404: case 404:
throw FetchDataException( throw FetchDataException(
'Api not found: ${error.response!.statusCode}'); 'Api not found: ${error.response!.statusCode}',
);
case 500: case 500:
default: default:
throw FetchDataException( throw FetchDataException(
'Error occurred while Communication with Server '); 'Error occurred while Communication with Server ',
);
} }
} }
} }

View File

@ -1,31 +1,38 @@
import 'dart:io'; import 'dart:io';
import 'package:Medito/constants/constants.dart'; import 'package:Medito/constants/constants.dart';
import 'package:Medito/services/network/dio_api_services.dart'; import 'package:Medito/services/network/dio_api_services.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'dio_client_provider.g.dart';
part 'dio_client_provider.g.dart';
@riverpod @riverpod
DioApiService dioClient(DioClientRef ref) { DioApiService dioClient(DioClientRef ref) {
var dio = Dio(); var dio = Dio();
dio.options = BaseOptions( dio.options = BaseOptions(
connectTimeout: Duration(milliseconds: 60000), connectTimeout: Duration(milliseconds: 60000),
// baseUrl: 'https://medito-content.medito-api.repl.co/v1/', // baseUrl: 'https://medito-content.medito-api.repl.co/v1/',
baseUrl: HTTPConstants.BASE_URL, baseUrl: HTTPConstants.BASE_URL,
headers: { headers: {
HttpHeaders.authorizationHeader: HTTPConstants.CONTENT_TOKEN, HttpHeaders.authorizationHeader: HTTPConstants.CONTENT_TOKEN,
HttpHeaders.accessControlAllowOriginHeader: '*', HttpHeaders.accessControlAllowOriginHeader: '*',
HttpHeaders.accessControlAllowHeadersHeader: HttpHeaders.accessControlAllowHeadersHeader:
'Origin,Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,locale', 'Origin,Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,locale',
HttpHeaders.accessControlAllowCredentialsHeader: 'true', HttpHeaders.accessControlAllowCredentialsHeader: 'true',
HttpHeaders.accessControlAllowMethodsHeader: 'POST, OPTIONS, HEAD, GET', HttpHeaders.accessControlAllowMethodsHeader: 'POST, OPTIONS, HEAD, GET',
HttpHeaders.contentTypeHeader: ContentType.json.value, HttpHeaders.contentTypeHeader: ContentType.json.value,
HttpHeaders.refererHeader: 'no-referrer-when-downgrade', HttpHeaders.refererHeader: 'no-referrer-when-downgrade',
HttpHeaders.acceptHeader: '*/*' HttpHeaders.acceptHeader: '*/*',
}); },
);
dio.interceptors.add(LogInterceptor( 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); var dioApiService = DioApiService(dio: dio);
return dioApiService; return dioApiService;
} }

View File

@ -9,6 +9,7 @@ class SharedPreferencesService {
static Future<String?> getStringFromSF(String key) async { static Future<String?> getStringFromSF(String key) async {
var pref = await SharedPreferences.getInstance(); var pref = await SharedPreferences.getInstance();
var stringValue = pref.getString(key); var stringValue = pref.getString(key);
return stringValue; return stringValue;
} }
@ -20,6 +21,7 @@ class SharedPreferencesService {
static Future<int?> getIntFromSF(String key) async { static Future<int?> getIntFromSF(String key) async {
var pref = await SharedPreferences.getInstance(); var pref = await SharedPreferences.getInstance();
var intValue = pref.getInt(key); var intValue = pref.getInt(key);
return intValue; return intValue;
} }
@ -31,6 +33,7 @@ class SharedPreferencesService {
static Future<double?> getDoubleFromSF(String key) async { static Future<double?> getDoubleFromSF(String key) async {
var pref = await SharedPreferences.getInstance(); var pref = await SharedPreferences.getInstance();
var doubleValue = pref.getDouble(key); var doubleValue = pref.getDouble(key);
return doubleValue; return doubleValue;
} }
@ -41,18 +44,21 @@ class SharedPreferencesService {
static Future<bool?> getBoolFromPref(String key) async { static Future<bool?> getBoolFromPref(String key) async {
var pref = await SharedPreferences.getInstance(); var pref = await SharedPreferences.getInstance();
return pref.getBool(key); return pref.getBool(key);
} }
static Future<bool> removeValueFromSF(String key) async { static Future<bool> removeValueFromSF(String key) async {
var pref = await SharedPreferences.getInstance(); var pref = await SharedPreferences.getInstance();
var isRemoved = await pref.remove(key); var isRemoved = await pref.remove(key);
return isRemoved; return isRemoved;
} }
static Future<bool> checkValueInSF(String key) async { static Future<bool> checkValueInSF(String key) async {
var pref = await SharedPreferences.getInstance(); var pref = await SharedPreferences.getInstance();
var isRemoved = pref.containsKey(key); var isRemoved = pref.containsKey(key);
return isRemoved; return isRemoved;
} }
} }

View File

@ -51,12 +51,14 @@ class Tracking {
static List<Map<String, String>> destinationData(String type, String item) { static List<Map<String, String>> destinationData(String type, String item) {
return [ return [
{TYPE: type, ITEM: item} {TYPE: type, ITEM: item},
]; ];
} }
static Future<void> postUsage(String type, static Future<void> postUsage(
[Map<String, String> body = const {}]) async { String type, [
Map<String, String> body = const {},
]) async {
if (kReleaseMode) { if (kReleaseMode) {
var packageInfo = await PackageInfo.fromPlatform(); var packageInfo = await PackageInfo.fromPlatform();
var version = packageInfo.buildNumber; var version = packageInfo.buildNumber;
@ -91,6 +93,7 @@ class Tracking {
), ),
); );
print('post usage failed: ' + e.toString()); print('post usage failed: ' + e.toString());
return; return;
} }
} }
@ -130,5 +133,6 @@ String mapToPlural(String fileType) {
if (fileType.contains('daily')) { if (fileType.contains('daily')) {
return 'dailies'; return 'dailies';
} }
return ''; return '';
} }

View File

@ -42,6 +42,7 @@ Future<double> _getSavedVolume() async {
} }
if (vol == null || vol > 1) vol = DEFAULT_VOLUME; if (vol == null || vol > 1) vol = DEFAULT_VOLUME;
return vol; return vol;
} }

View File

@ -5,24 +5,29 @@ extension DurationExtensions on Duration {
/// 05:35 -> 05 min 35 sec /// 05:35 -> 05 min 35 sec
String toMinutesSeconds() { String toMinutesSeconds() {
var twoDigitMinutes = _toTwoDigits( 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)); var twoDigitSeconds = _toTwoDigits(inSeconds.remainder(60));
return '$twoDigitMinutes:$twoDigitSeconds'; return '$twoDigitMinutes:$twoDigitSeconds';
} }
String toReadable() { String toReadable() {
var twoDigitMinutes = _toTwoDigits( 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)); var twoDigitSeconds = _toTwoDigits(inSeconds.remainder(60));
if (twoDigitSeconds.isNotNullAndNotEmpty() && twoDigitMinutes != '00') { if (twoDigitSeconds.isNotNullAndNotEmpty() && twoDigitMinutes != '00') {
return '$twoDigitMinutes min $twoDigitSeconds sec'; return '$twoDigitMinutes min $twoDigitSeconds sec';
} }
return '$twoDigitSeconds sec'; return '$twoDigitSeconds sec';
} }
String _toTwoDigits(int n) { String _toTwoDigits(int n) {
if (n >= 10) return '$n'; if (n >= 10) return '$n';
return '0$n'; return '0$n';
} }
} }
@ -41,9 +46,11 @@ String formatSessionLength(String? item) {
} }
time = min.toString(); time = min.toString();
} }
return '$time min'; return '$time min';
} }
if (item == null) return ''; if (item == null) return '';
return item + ' min'; return item + ' min';
} }

View File

@ -15,23 +15,26 @@ along with Medito App. If not, see <https://www.gnu.org/licenses/>.*/
import 'dart:io'; import 'dart:io';
import 'package:Medito/constants/constants.dart';
import 'package:Medito/network/auth.dart'; import 'package:Medito/network/auth.dart';
import 'package:Medito/network/user/user_utils.dart'; import 'package:Medito/network/user/user_utils.dart';
import 'package:Medito/constants/constants.dart';
import 'package:connectivity/connectivity.dart'; import 'package:connectivity/connectivity.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:url_launcher/url_launcher_string.dart';
Widget getNetworkImageWidget(String? url) { Widget getNetworkImageWidget(String? url) {
if (url.isNullOrEmpty()) return Container(); if (url.isNullOrEmpty()) return Container();
final headers = {HttpHeaders.authorizationHeader: CONTENT_TOKEN}; final headers = {HttpHeaders.authorizationHeader: CONTENT_TOKEN};
return Image.network(url!, fit: BoxFit.fill, headers: headers); return Image.network(url!, fit: BoxFit.fill, headers: headers);
} }
NetworkImage getNetworkImage(String url) { NetworkImage getNetworkImage(String url) {
final headers = {HttpHeaders.authorizationHeader: HTTPConstants.CONTENT_TOKEN}; final headers = {
HttpHeaders.authorizationHeader: HTTPConstants.CONTENT_TOKEN
};
return NetworkImage(url, headers: headers); return NetworkImage(url, headers: headers);
} }

View File

@ -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/audioplayer/medito_audio_handler.dart';
import 'package:Medito/network/downloads/downloads_bloc.dart';
import 'package:Medito/constants/constants.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/utils/utils.dart';
import 'package:Medito/views/empty_widget.dart'; import 'package:Medito/views/empty_widget.dart';
import 'package:Medito/views/main/app_bar_widget.dart'; import 'package:Medito/views/main/app_bar_widget.dart';
@ -93,7 +93,7 @@ class _DownloadsListWidgetState extends State<DownloadsListWidget>
onDismissed: (direction) { onDismissed: (direction) {
if (mounted) { if (mounted) {
_downloadList.removeWhere((element) => element == item); _downloadList.removeWhere((element) => element == item);
DownloadsBloc.removeSessionFromDownloads(context, item); DownloadsBloc.removeSessionFromDownloads(item);
setState(() {}); setState(() {});
} }
@ -142,7 +142,8 @@ class _DownloadsListWidgetState extends State<DownloadsListWidget>
} }
void showSwipeToDeleteTip() { void showSwipeToDeleteTip() {
createSnackBar(StringConstants.SWIPE_TO_DELETE, context, color: ColorConstants.darkMoon); createSnackBar(StringConstants.SWIPE_TO_DELETE, context,
color: ColorConstants.darkMoon);
} }
void _refreshDownloadList() { void _refreshDownloadList() {

View File

@ -14,15 +14,16 @@ You should have received a copy of the Affero GNU General Public License
along with Medito App. If not, see <https://www.gnu.org/licenses/>.*/ along with Medito App. If not, see <https://www.gnu.org/licenses/>.*/
import 'dart:async'; import 'dart:async';
import 'package:Medito/constants/constants.dart';
import 'package:Medito/network/api_response.dart'; import 'package:Medito/network/api_response.dart';
import 'package:Medito/network/downloads/downloads_bloc.dart'; import 'package:Medito/network/downloads/downloads_bloc.dart';
import 'package:Medito/network/home/home_bloc.dart'; import 'package:Medito/network/home/home_bloc.dart';
import 'package:Medito/network/home/home_repo.dart'; import 'package:Medito/network/home/home_repo.dart';
import 'package:Medito/network/home/menu_response.dart'; import 'package:Medito/network/home/menu_response.dart';
import 'package:Medito/network/user/user_utils.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/routes/routes.dart';
import 'package:Medito/tracking/tracking.dart';
import 'package:Medito/utils/utils.dart'; import 'package:Medito/utils/utils.dart';
import 'package:Medito/views/home/courses_row_widget.dart'; import 'package:Medito/views/home/courses_row_widget.dart';
import 'package:Medito/views/home/daily_message_widget.dart'; import 'package:Medito/views/home/daily_message_widget.dart';
@ -92,9 +93,9 @@ class _HomeWidgetState extends ConsumerState<HomeWidget> {
type, id, context, Tracking.SHORTCUT_TAPPED), type, id, context, Tracking.SHORTCUT_TAPPED),
), ),
CoursesRowWidget( CoursesRowWidget(
key: _coursesKey, key: _coursesKey,
onTap: (type, id) => _navigate( onTap: (type, id) => _navigate(
type, id, context, Tracking.COURSE_TAPPED)), type, id, context, Tracking.COURSE_TAPPED)),
StatsWidget(), StatsWidget(),
SizedBox(height: 16), SizedBox(height: 16),
DailyMessageWidget(key: _dailyMessageKey), DailyMessageWidget(key: _dailyMessageKey),
@ -194,40 +195,50 @@ class _HomeWidgetState extends ConsumerState<HomeWidget> {
} }
Widget _getTitleWidget(BuildContext context) => FutureBuilder<String>( Widget _getTitleWidget(BuildContext context) => FutureBuilder<String>(
future: _bloc.getTitleText(DateTime.now()), future: _bloc.getTitleText(DateTime.now()),
initialData: 'Medito', initialData: 'Medito',
builder: (context, snapshot) { builder: (context, snapshot) {
return GestureDetector( return GestureDetector(
onLongPress: () => _showVersionPopUp(context), onLongPress: () => _showVersionPopUp(context),
child: Text(snapshot.data ?? '', child: Text(
style: Theme.of(context).textTheme.headline1), snapshot.data ?? '',
); style: Theme.of(context).textTheme.headline1,
}); ),
);
},
);
Future<void> _showVersionPopUp(BuildContext context) async { Future<void> _showVersionPopUp(BuildContext context) async {
var line1 = await getDeviceInfoString(); var line1 = await getDeviceInfoString();
var prefs = await SharedPreferences.getInstance(); var prefs = await SharedPreferences.getInstance();
var userID = prefs.getString(USER_ID) ?? 'None'; var userID = prefs.getString(USER_ID) ?? 'None';
final snackBar = SnackBar( final snackBar = SnackBar(
content: GestureDetector( content: GestureDetector(
onTap: () { onTap: () {
Share.share('$line1 $userID'); Share.share('$line1 $userID');
}, },
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text('Tap here to copy', Text(
style: TextStyle(color: ColorConstants.walterWhite)), 'Tap here to copy',
Text(line1, style: TextStyle(color: ColorConstants.walterWhite),
style: TextStyle(color: ColorConstants.meditoTextGrey)), ),
Text(userID, Text(
style: TextStyle(color: ColorConstants.meditoTextGrey)) 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! // Find the Scaffold in the Widget tree and use it to show a SnackBar!
ScaffoldMessenger.of(context).showSnackBar(snackBar); ScaffoldMessenger.of(context).showSnackBar(snackBar);
@ -252,8 +263,11 @@ class _HomeWidgetState extends ConsumerState<HomeWidget> {
await DownloadsBloc.seenTip().then((seen) { await DownloadsBloc.seenTip().then((seen) {
if (!seen) { if (!seen) {
unawaited(DownloadsBloc.setSeenTip()); unawaited(DownloadsBloc.setSeenTip());
createSnackBar(StringConstants.SWIPE_TO_DELETE, context, createSnackBar(
color: ColorConstants.darkMoon); StringConstants.SWIPE_TO_DELETE,
context,
color: ColorConstants.darkMoon,
);
} }
}); });
} }

View File

@ -5,6 +5,7 @@ import 'package:flutter_svg/svg.dart';
class EmptyStateWidget extends StatelessWidget { class EmptyStateWidget extends StatelessWidget {
final String? message; final String? message;
final SvgPicture? image; final SvgPicture? image;
const EmptyStateWidget({Key? key, this.message, this.image}) const EmptyStateWidget({Key? key, this.message, this.image})
: super(key: key); : super(key: key);

View File

@ -33,7 +33,10 @@ class FolderView extends ConsumerWidget {
Widget _buildLoadingWidget() => const FolderShimmerComponent(); Widget _buildLoadingWidget() => const FolderShimmerComponent();
RefreshIndicator _buildScaffoldWithData( RefreshIndicator _buildScaffoldWithData(
BuildContext context, FolderModel folder, WidgetRef ref) { BuildContext context,
FolderModel folder,
WidgetRef ref,
) {
return RefreshIndicator( return RefreshIndicator(
onRefresh: () async { onRefresh: () async {
return await ref.refresh(FoldersProvider(folderId: 28)); return await ref.refresh(FoldersProvider(folderId: 28));
@ -60,7 +63,11 @@ class FolderView extends ConsumerWidget {
} }
Container _buildListTile( Container _buildListTile(
BuildContext context, String? title, String? subtitle, String type) { BuildContext context,
String? title,
String? subtitle,
String type,
) {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border( border: Border(

View File

@ -1,6 +1,6 @@
import 'package:Medito/constants/constants.dart'; import 'package:Medito/constants/constants.dart';
import 'package:Medito/models/models.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/audio_player/audio_player_viewmodel.dart';
import 'package:Medito/view_model/player/audio_position_viewmodel.dart'; import 'package:Medito/view_model/player/audio_position_viewmodel.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';

View File

@ -16,10 +16,10 @@ along with Medito App. If not, see <https://www.gnu.org/licenses/>.*/
import 'package:Medito/audioplayer/audio_inherited_widget.dart'; import 'package:Medito/audioplayer/audio_inherited_widget.dart';
import 'package:Medito/audioplayer/medito_audio_handler.dart'; import 'package:Medito/audioplayer/medito_audio_handler.dart';
import 'package:Medito/audioplayer/player_utils.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/api_response.dart';
import 'package:Medito/network/session_options/background_sounds.dart'; import 'package:Medito/network/session_options/background_sounds.dart';
import 'package:Medito/utils/bgvolume_utils.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/shared_preferences_utils.dart';
import 'package:Medito/utils/utils.dart'; import 'package:Medito/utils/utils.dart';
import 'package:Medito/views/player_old/components/position_indicator_widget.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 :/ // 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); Navigator.pop(context);
return true; return true;
} }
@ -70,6 +74,7 @@ class _ChooseBackgroundSoundDialogState
_volume = await retrieveSavedBgVolume(); _volume = await retrieveSavedBgVolume();
await await Future.delayed(Duration(milliseconds: 200)).then((value) { await await Future.delayed(Duration(milliseconds: 200)).then((value) {
_handler?.customAction(SET_BG_SOUND_VOL, {SET_BG_SOUND_VOL: _volume}); _handler?.customAction(SET_BG_SOUND_VOL, {SET_BG_SOUND_VOL: _volume});
return _handler?.customAction(SEND_BG_SOUND, {SEND_BG_SOUND: bgSound}); return _handler?.customAction(SEND_BG_SOUND, {SEND_BG_SOUND: bgSound});
}); });
} }
@ -79,94 +84,69 @@ class _ChooseBackgroundSoundDialogState
_handler = AudioHandlerInheritedWidget.of(context).audioHandler; _handler = AudioHandlerInheritedWidget.of(context).audioHandler;
return StreamBuilder( return StreamBuilder(
stream: Stream.fromFuture( stream: Stream.fromFuture(
Connectivity().checkConnectivity(), Connectivity().checkConnectivity(),
), ),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData) { if (snapshot.hasData) {
if (snapshot.data == ConnectivityResult.none) { if (snapshot.data == ConnectivityResult.none) {
_isOffline = true; _isOffline = true;
}
return StreamBuilder<dynamic>(
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
} }
});
return StreamBuilder<dynamic>(
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( Widget _onlineBackgroundSounds(
String currentSound, ScrollController scrollController) { String currentSound,
ScrollController scrollController,
) {
return StreamBuilder<ApiResponse<BackgroundSoundsResponse>>( return StreamBuilder<ApiResponse<BackgroundSoundsResponse>>(
stream: widget.stream, stream: widget.stream,
initialData: ApiResponse.loading(), initialData: ApiResponse.loading(),
builder: (context, snapshot) { builder: (context, snapshot) {
switch (snapshot.data?.status) { switch (snapshot.data?.status) {
case Status.LOADING: case Status.LOADING:
return Center( return Center(
child: const CircularProgressIndicator( child: const CircularProgressIndicator(
backgroundColor: Colors.black, backgroundColor: Colors.black,
valueColor: AlwaysStoppedAnimation<Color>( valueColor: AlwaysStoppedAnimation<Color>(
ColorConstants.walterWhite))); ColorConstants.walterWhite,
case Status.COMPLETED: ),
var list = snapshot.data?.body?.data; ),
);
case Status.COMPLETED:
var list = snapshot.data?.body?.data;
var widgetList = <Widget>[
Divider(height: 16),
_getHeader(),
Divider(height: 16),
_getVolumeWidget(),
Divider(height: 16),
_getNoneListItem(currentSound)
];
if (list != null) {
widgetList.addAll(list
.map<Widget>((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<List<BackgroundSoundData>>(
future: getBgSoundFromOfflineSharedPrefs(),
initialData: [],
builder: (context, snapshot) {
if (snapshot.hasData) {
var list = snapshot.data;
var widgetList = <Widget>[ var widgetList = <Widget>[
Divider(height: 16), Divider(height: 16),
_getHeader(), _getHeader(),
@ -177,20 +157,57 @@ class _ChooseBackgroundSoundDialogState
]; ];
if (list != null) { if (list != null) {
widgetList.addAll(list widgetList.addAll(list
.map((e) => .map<Widget>((e) =>
_getBackgroundSoundListTile(e, currentSound, context)) _getBackgroundSoundListTile(e, currentSound, context))
.toList()); .toList());
} }
return ListView(controller: scrollController, children: widgetList); return ListView(controller: scrollController, children: widgetList);
} else {
return Center( case Status.ERROR:
child: const CircularProgressIndicator( return _getErrorWidget();
backgroundColor: Colors.black, case null:
valueColor: AlwaysStoppedAnimation<Color>( return Container();
ColorConstants.walterWhite))); }
},
);
}
Widget _offlineBackgroundSounds(
String currentSound, ScrollController scrollController) {
return FutureBuilder<List<BackgroundSoundData>>(
future: getBgSoundFromOfflineSharedPrefs(),
initialData: [],
builder: (context, snapshot) {
if (snapshot.hasData) {
var list = snapshot.data;
var widgetList = <Widget>[
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<Color>(ColorConstants.walterWhite),
),
);
}
},
);
} }
Widget _getErrorWidget() => Padding( Widget _getErrorWidget() => Padding(
@ -217,11 +234,12 @@ class _ChooseBackgroundSoundDialogState
TextStyle? _getTheme(current, String? name) { TextStyle? _getTheme(current, String? name) {
return Theme.of(context).textTheme.bodyText2?.copyWith( return Theme.of(context).textTheme.bodyText2?.copyWith(
fontWeight: fontWeight:
_isSelected(current, name) ? FontWeight.w600 : FontWeight.normal, _isSelected(current, name) ? FontWeight.w600 : FontWeight.normal,
color: _isSelected(current, name) color: _isSelected(current, name)
? ColorConstants.walterWhite ? ColorConstants.walterWhite
: ColorConstants.meditoTextGrey); : ColorConstants.meditoTextGrey,
);
} }
Widget _getVisibilityWidget(String name, String current, Widget child) => Widget _getVisibilityWidget(String name, String current, Widget child) =>
@ -234,44 +252,65 @@ class _ChooseBackgroundSoundDialogState
current == name || (current == '' && name == NONE); current == name || (current == '' && name == NONE);
Widget _getBackgroundSoundListTile( Widget _getBackgroundSoundListTile(
BackgroundSoundData item, String current, BuildContext context) { BackgroundSoundData item,
String current,
BuildContext context,
) {
var assetUrl = item.file?.toAssetUrl(); var assetUrl = item.file?.toAssetUrl();
return InkWell( return InkWell(
onTap: () { onTap: () {
setState(() { setState(() {
_downloadingItem = item.name; _downloadingItem = item.name;
}); });
downloadBGMusicFromURL(assetUrl, item.name).then((filePath) { downloadBGMusicFromURL(assetUrl, item.name).then((filePath) {
if (filePath == 'Connectivity lost') { if (filePath == 'Connectivity lost') {
_downloadingItem = '';
_isOffline = true;
setState(() {});
createSnackBar(
'Connectivity lost. Displaying offline background sounds.',
context);
_noneSelected();
}
_downloadingItem = ''; _downloadingItem = '';
addBgSoundSelectionToSharedPrefs(filePath, item.name); _isOffline = true;
widget.handler setState(() {});
?.customAction(PLAY_BG_SOUND, {PLAY_BG_SOUND: filePath}); createSnackBar(
return widget.handler 'Connectivity lost. Displaying offline background sounds.',
?.customAction(SEND_BG_SOUND, {SEND_BG_SOUND: item.name}); context,
}); );
}, _noneSelected();
child: ListTile( }
enableFeedback: true, _downloadingItem = '';
title: Text('${item.name}', style: _getTheme(current, item.name)), addBgSoundSelectionToSharedPrefs(
trailing: _isDownloading(item) filePath,
? _getSmallLoadingWidget() item.name,
: _getVisibilityWidget( );
item.name ?? '', widget.handler?.customAction(
current, PLAY_BG_SOUND,
Icon( {PLAY_BG_SOUND: filePath},
Icons.check_circle_outline, );
color: ColorConstants.walterWhite,
)))); 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) => bool _isDownloading(BackgroundSoundData item) =>
@ -280,12 +319,14 @@ class _ChooseBackgroundSoundDialogState
Widget _getSmallLoadingWidget() => Padding( Widget _getSmallLoadingWidget() => Padding(
padding: const EdgeInsets.only(right: 6.0), padding: const EdgeInsets.only(right: 6.0),
child: SizedBox( child: SizedBox(
height: 16, height: 16,
width: 16, width: 16,
child: const CircularProgressIndicator( child: const CircularProgressIndicator(
backgroundColor: Colors.black, backgroundColor: Colors.black,
valueColor: valueColor:
AlwaysStoppedAnimation<Color>(ColorConstants.walterWhite))), AlwaysStoppedAnimation<Color>(ColorConstants.walterWhite),
),
),
); );
void _noneSelected() { void _noneSelected() {
@ -297,11 +338,12 @@ class _ChooseBackgroundSoundDialogState
Widget _getHeader() { Widget _getHeader() {
return Padding( return Padding(
padding: const EdgeInsets.only(bottom: 8.0, left: 16.0, top: 8.0), padding: const EdgeInsets.only(bottom: 8.0, left: 16.0, top: 8.0),
child: Text( child: Text(
StringConstants.BACKGROUND_SOUNDS, StringConstants.BACKGROUND_SOUNDS,
style: Theme.of(context).textTheme.headline1, style: Theme.of(context).textTheme.headline1,
)); ),
);
} }
Widget _getVolumeWidget() { Widget _getVolumeWidget() {
@ -310,45 +352,49 @@ class _ChooseBackgroundSoundDialogState
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: StreamBuilder<Object>( child: StreamBuilder<Object>(
stream: _dragBgVolumeSubject, stream: _dragBgVolumeSubject,
builder: (context, snapshot) { builder: (context, snapshot) {
var volume = _dragBgVolumeSubject.value; var volume = _dragBgVolumeSubject.value;
var volumeIcon = _volumeIconFunction(volume); var volumeIcon = _volumeIconFunction(volume);
return Row(
mainAxisSize: MainAxisSize.min, return Row(
children: [ mainAxisSize: MainAxisSize.min,
Icon(volumeIcon, size: 24, color: ColorConstants.walterWhite), children: [
Expanded( Icon(volumeIcon, size: 24, color: ColorConstants.walterWhite),
child: Padding( Expanded(
padding: const EdgeInsets.only(left: 24.0, right: 4), child: Padding(
child: SliderTheme( padding: const EdgeInsets.only(left: 24.0, right: 4),
data: SliderThemeData( child: SliderTheme(
trackShape: CustomTrackShape(addTopPadding: false), data: SliderThemeData(
thumbShape: trackShape: CustomTrackShape(addTopPadding: false),
RoundSliderThumbShape(enabledThumbRadius: 10.0), thumbShape:
), RoundSliderThumbShape(enabledThumbRadius: 10.0),
child: Slider( ),
min: 0.0, child: Slider(
activeColor: ColorConstants.walterWhite, min: 0.0,
inactiveColor: activeColor: ColorConstants.walterWhite,
ColorConstants.walterWhite.withOpacity(0.7), inactiveColor:
max: 1.0, ColorConstants.walterWhite.withOpacity(0.7),
value: volume, max: 1.0,
onChanged: (value) { value: volume,
_dragBgVolumeSubject.add(value); onChanged: (value) {
_handler?.customAction( _dragBgVolumeSubject.add(value);
SET_BG_SOUND_VOL, {SET_BG_SOUND_VOL: value}); _handler?.customAction(
}, SET_BG_SOUND_VOL,
onChangeEnd: (value) { {SET_BG_SOUND_VOL: value},
saveBgVolume(value); );
}, },
), onChangeEnd: (value) {
saveBgVolume(value);
},
), ),
), ),
), ),
], ),
); ],
}), );
},
),
), ),
); );
} }

View File

@ -1,14 +1,13 @@
import 'dart:math'; 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/audioplayer/medito_audio_handler.dart';
import 'package:Medito/network/player/player_bloc.dart';
import 'package:Medito/constants/constants.dart'; import 'package:Medito/constants/constants.dart';
import 'package:Medito/utils/duration_ext.dart';
import 'package:Medito/routes/routes.dart'; import 'package:Medito/routes/routes.dart';
import 'package:Medito/utils/duration_extensions.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
import 'background_sounds_sheet_widget.dart';
class PositionIndicatorWidget extends StatefulWidget { class PositionIndicatorWidget extends StatefulWidget {
final MeditoAudioHandler? handler; final MeditoAudioHandler? handler;

View File

@ -15,11 +15,11 @@ along with Medito App. If not, see <https://www.gnu.org/licenses/>.*/
import 'dart:async'; 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/audioplayer/medito_audio_handler.dart';
import 'package:Medito/components/components.dart'; import 'package:Medito/components/components.dart';
import 'package:Medito/network/player/player_bloc.dart';
import 'package:Medito/constants/constants.dart'; import 'package:Medito/constants/constants.dart';
import 'package:Medito/network/player/player_bloc.dart';
import 'package:Medito/routes/routes.dart'; import 'package:Medito/routes/routes.dart';
import 'package:Medito/utils/shared_preferences_utils.dart'; import 'package:Medito/utils/shared_preferences_utils.dart';
import 'package:Medito/utils/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/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/sentry_flutter.dart';
import '../../../audioplayer/audio_inherited_widget.dart'; import '../../../audioplayer/audio_inherited_widget.dart';
import '../../../tracking/tracking.dart'; import '../../../tracking/tracking.dart';
import '../../../utils/bgvolume_utils.dart'; import '../../../utils/bgvolume_utils.dart';
@ -93,13 +94,16 @@ class _PlayerWidgetState extends State<PlayerWidget> {
event[AUDIO_COMPLETE] == true) { event[AUDIO_COMPLETE] == true) {
_trackSessionEnd(_handler?.mediaItem.value); _trackSessionEnd(_handler?.mediaItem.value);
showGeneralDialog( showGeneralDialog(
transitionDuration: Duration(milliseconds: 400), transitionDuration: Duration(milliseconds: 400),
context: context, context: context,
barrierColor: ColorConstants.darkMoon, barrierColor: ColorConstants.darkMoon,
pageBuilder: (_, __, ___) { pageBuilder: (_, __, ___) {
return AudioCompleteDialog( return AudioCompleteDialog(
bloc: _bloc, mediaItem: _handler?.mediaItem.value); bloc: _bloc,
}); mediaItem: _handler?.mediaItem.value,
);
},
);
} }
}); });
@ -112,8 +116,9 @@ class _PlayerWidgetState extends State<PlayerWidget> {
image: getNetworkImage(mediaItem?.artUri?.toString() ?? ''), image: getNetworkImage(mediaItem?.artUri?.toString() ?? ''),
fit: BoxFit.fill, fit: BoxFit.fill,
colorFilter: ColorFilter.mode( colorFilter: ColorFilter.mode(
ColorConstants.almostBlack.withOpacity(0.65), ColorConstants.almostBlack.withOpacity(0.65),
BlendMode.overlay), BlendMode.overlay,
),
), ),
), ),
child: SafeArea( child: SafeArea(
@ -131,8 +136,9 @@ class _PlayerWidgetState extends State<PlayerWidget> {
_buildPlayerButtonRow(mediaItem), _buildPlayerButtonRow(mediaItem),
// A seek bar. // A seek bar.
PositionIndicatorWidget( PositionIndicatorWidget(
handler: _handler, handler: _handler,
bgSoundsStream: _bloc.bgSoundsListController?.stream), bgSoundsStream: _bloc.bgSoundsListController?.stream,
),
Container(height: 24), Container(height: 24),
], ],
), ),
@ -149,12 +155,14 @@ class _PlayerWidgetState extends State<PlayerWidget> {
getSavedBgSoundData(); getSavedBgSoundData();
} }
} on Exception catch (e, s) { } on Exception catch (e, s) {
unawaited(Sentry.captureException(e, unawaited(Sentry.captureException(
stackTrace: s, e,
hint: Hint.withMap({ stackTrace: s,
'message': hint: Hint.withMap({
'Failed trying to get save background sounds data: extras[HAS_BG_SOUND]: ${_hasBGSound()}' 'message':
}))); 'Failed trying to get save background sounds data: extras[HAS_BG_SOUND]: ${_hasBGSound()}',
}),
));
} }
} }
@ -207,10 +215,12 @@ class _PlayerWidgetState extends State<PlayerWidget> {
Padding _getSubtitleWidget(MediaItem? mediaItem) { Padding _getSubtitleWidget(MediaItem? mediaItem) {
var attr = mediaItem?.extras != null ? (mediaItem?.extras?['attr']) : ''; var attr = mediaItem?.extras != null ? (mediaItem?.extras?['attr']) : '';
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0), padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: MarkdownComponent( child: MarkdownComponent(
body: 'Giovanni Dienstmann https://www.google.com/'), body: 'Giovanni Dienstmann https://www.google.com/',
),
); );
} }
@ -255,7 +265,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
{ {
Tracking.SESSION_ID: mediaItem.extras?[SESSION_ID].toString() ?? '', Tracking.SESSION_ID: mediaItem.extras?[SESSION_ID].toString() ?? '',
Tracking.SESSION_DURATION: mediaItem.extras?[LENGTH].toString() ?? '', Tracking.SESSION_DURATION: mediaItem.extras?[LENGTH].toString() ?? '',
Tracking.SESSION_GUIDE: mediaItem.artist ?? '' Tracking.SESSION_GUIDE: mediaItem.artist ?? '',
}, },
), ),
); );

View File

@ -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 You should have received a copy of the Affero GNU General Public License
along with Medito App. If not, see <https://www.gnu.org/licenses/>.*/ along with Medito App. If not, see <https://www.gnu.org/licenses/>.*/
import 'package:Medito/constants/constants.dart';
import 'package:Medito/network/text/text_bloc.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/utils/utils.dart';
import 'package:Medito/views/main/app_bar_widget.dart'; import 'package:Medito/views/main/app_bar_widget.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -62,14 +61,15 @@ class _TextFileWidgetState extends State<TextFileWidget>
appBar: PreferredSize( appBar: PreferredSize(
preferredSize: const Size(double.infinity, kToolbarHeight), preferredSize: const Size(double.infinity, kToolbarHeight),
child: StreamBuilder<String>( child: StreamBuilder<String>(
stream: _bloc.titleController.stream, stream: _bloc.titleController.stream,
initialData: '...', initialData: '...',
builder: (context, snapshot) { builder: (context, snapshot) {
return MeditoAppBarWidget( return MeditoAppBarWidget(
isTransparent: true, isTransparent: true,
title: snapshot.data ?? '', title: snapshot.data ?? '',
); );
}), // StreamBuilder },
), // StreamBuilder
), ),
body: RefreshIndicator( body: RefreshIndicator(
onRefresh: () => _bloc.fetchText(widget.id, true), onRefresh: () => _bloc.fetchText(widget.id, true),
@ -105,32 +105,43 @@ class _TextFileWidgetState extends State<TextFileWidget>
children: <Widget>[ children: <Widget>[
Padding( Padding(
padding: const EdgeInsets.only( 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<String>( child: StreamBuilder<String>(
stream: _bloc.bodyController.stream, stream: _bloc.bodyController.stream,
initialData: 'Loading...', initialData: 'Loading...',
builder: (context, snapshot) { builder: (context, snapshot) {
return Markdown( return Markdown(
data: snapshot.data ?? '', data: snapshot.data ?? '',
onTapLink: _linkTap, onTapLink: _linkTap,
physics: NeverScrollableScrollPhysics(), physics: NeverScrollableScrollPhysics(),
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
shrinkWrap: true, shrinkWrap: true,
selectable: true, selectable: true,
styleSheet: buildMarkdownStyleSheet(context).copyWith( styleSheet: buildMarkdownStyleSheet(context).copyWith(
horizontalRuleDecoration: BoxDecoration( horizontalRuleDecoration: BoxDecoration(
border: Border( border: Border(
top: BorderSide( top: BorderSide(
width: 1.0, width: 1.0,
color: ColorConstants.meditoTextGrey, color: ColorConstants.meditoTextGrey,
), ),
), ),
), ),
h2: TextStyle( h2: TextStyle(
color: ColorConstants.walterWhite, height: 1.5), color: ColorConstants.walterWhite,
p: TextStyle( height: 1.5,
color: ColorConstants.walterWhite, height: 1.5))); ),
}), p: TextStyle(
color: ColorConstants.walterWhite,
height: 1.5,
),
),
);
},
),
), ),
], ],
), ),

View File

@ -36,11 +36,12 @@ void main() {
isPublished: true, isPublished: true,
items: [ items: [
FolderItemsModel( FolderItemsModel(
type: 'session', type: 'session',
id: 120, id: 120,
title: 'Complete meditation', title: 'Complete meditation',
subtitle: '19 min', subtitle: '19 min',
path: 'sessions/120') path: 'sessions/120',
),
], ],
); );
final mockFolderRepository = MockFolderRepository(); final mockFolderRepository = MockFolderRepository();