mirror of
https://github.com/meditohq/medito-app.git
synced 2024-08-16 15:40:36 +03:00
Fixed warnings
This commit is contained in:
parent
482b73f374
commit
bead831986
@ -11,4 +11,19 @@ dart_code_metrics:
|
||||
metrics-exclude:
|
||||
- test/**
|
||||
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
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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';
|
||||
const String LOCATION = 'location';
|
@ -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<void> _playBgSound(Map<String, dynamic>? extras) async {
|
||||
void _playBgSound(Map<String, dynamic>? 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));
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,7 @@ Future<bool?> checkBgSoundExists(String name) async {
|
||||
var filePath = (await getFilePath(name));
|
||||
var file = File(filePath);
|
||||
var exists = await file.exists();
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.*/
|
||||
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<ParentWidget>
|
||||
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,
|
||||
);
|
||||
}
|
||||
|
@ -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<bool> seenTip() async {
|
||||
var prefs = await SharedPreferences.getInstance();
|
||||
|
||||
return prefs.getBool('seenDownloadsToolTip') ?? false;
|
||||
}
|
||||
|
||||
static Future<bool> setSeenTip() async {
|
||||
var prefs = await SharedPreferences.getInstance();
|
||||
|
||||
return prefs.setBool('seenDownloadsToolTip', true);
|
||||
}
|
||||
|
||||
static Future<void> 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<bool> isAudioFileDownloaded(AudioFile? file) async {
|
||||
@ -87,7 +90,8 @@ class DownloadsBloc {
|
||||
}
|
||||
|
||||
static Future<void> 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<void> saveDownloads(List<MediaItem> 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);
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -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 <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/http_get.dart';
|
||||
import 'package:Medito/network/session_options/background_sounds.dart';
|
||||
|
@ -16,12 +16,12 @@ along with Medito App. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
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);
|
||||
});
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ class UserResponse {
|
||||
if (this.data != null) {
|
||||
data['data'] = this.data?.toJson();
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -30,6 +31,7 @@ class Data {
|
||||
Map<String, dynamic> toJson() {
|
||||
final data = <String, dynamic>{};
|
||||
data['id'] = id;
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@ Future<bool> 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<String?> get generatedToken async {
|
||||
var prefs = await SharedPreferences.getInstance();
|
||||
|
||||
return prefs.getString(TOKEN);
|
||||
}
|
||||
|
||||
@ -141,7 +144,7 @@ Future<Map<String, String>> getDeviceDetails() async {
|
||||
DEVICE_MODEL: deviceModel,
|
||||
DEVICE_OS: deviceOS,
|
||||
DEVICE_PLATFORM: devicePlatform,
|
||||
DEVICE_LANGUAGE: deviceLanguage
|
||||
DEVICE_LANGUAGE: deviceLanguage,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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<dynamic> downloadFile(String url,
|
||||
{String? name, void Function(int, int)? onReceiveProgress});
|
||||
Future<dynamic> downloadFile(
|
||||
String url, {
|
||||
String? name,
|
||||
void Function(int, int)? onReceiveProgress,
|
||||
});
|
||||
|
||||
Future<dynamic> 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');
|
||||
}
|
||||
|
@ -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<FolderModel> fetchFolders(int folderId) async {
|
||||
try {
|
||||
var res = await client.getRequest('${HTTPConstants.FOLDERS}/$folderId');
|
||||
|
||||
return FolderModel.fromJson(res);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
|
@ -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<SessionModel> fetchSession(int sessionId) async {
|
||||
try {
|
||||
var res = await client.getRequest('${HTTPConstants.SESSIONS}/$sessionId');
|
||||
|
||||
return SessionModel.fromJson(res);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
|
@ -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<void> getPlayerMaterialPage(GoRouterState state) {
|
||||
MaterialPage<void> 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<String?> ids) {
|
||||
if (place == 'app') {
|
||||
return CollectionPath;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
@ -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 ',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ class SharedPreferencesService {
|
||||
static Future<String?> getStringFromSF(String key) async {
|
||||
var pref = await SharedPreferences.getInstance();
|
||||
var stringValue = pref.getString(key);
|
||||
|
||||
return stringValue;
|
||||
}
|
||||
|
||||
@ -20,6 +21,7 @@ class SharedPreferencesService {
|
||||
static Future<int?> getIntFromSF(String key) async {
|
||||
var pref = await SharedPreferences.getInstance();
|
||||
var intValue = pref.getInt(key);
|
||||
|
||||
return intValue;
|
||||
}
|
||||
|
||||
@ -31,6 +33,7 @@ class SharedPreferencesService {
|
||||
static Future<double?> getDoubleFromSF(String key) async {
|
||||
var pref = await SharedPreferences.getInstance();
|
||||
var doubleValue = pref.getDouble(key);
|
||||
|
||||
return doubleValue;
|
||||
}
|
||||
|
||||
@ -41,18 +44,21 @@ class SharedPreferencesService {
|
||||
|
||||
static Future<bool?> getBoolFromPref(String key) async {
|
||||
var pref = await SharedPreferences.getInstance();
|
||||
|
||||
return pref.getBool(key);
|
||||
}
|
||||
|
||||
static Future<bool> removeValueFromSF(String key) async {
|
||||
var pref = await SharedPreferences.getInstance();
|
||||
var isRemoved = await pref.remove(key);
|
||||
|
||||
return isRemoved;
|
||||
}
|
||||
|
||||
static Future<bool> checkValueInSF(String key) async {
|
||||
var pref = await SharedPreferences.getInstance();
|
||||
var isRemoved = pref.containsKey(key);
|
||||
|
||||
return isRemoved;
|
||||
}
|
||||
}
|
||||
|
@ -51,12 +51,14 @@ class Tracking {
|
||||
|
||||
static List<Map<String, String>> destinationData(String type, String item) {
|
||||
return [
|
||||
{TYPE: type, ITEM: item}
|
||||
{TYPE: type, ITEM: item},
|
||||
];
|
||||
}
|
||||
|
||||
static Future<void> postUsage(String type,
|
||||
[Map<String, String> body = const {}]) async {
|
||||
static Future<void> postUsage(
|
||||
String type, [
|
||||
Map<String, String> 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 '';
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ Future<double> _getSavedVolume() async {
|
||||
}
|
||||
|
||||
if (vol == null || vol > 1) vol = DEFAULT_VOLUME;
|
||||
|
||||
return vol;
|
||||
}
|
||||
|
||||
|
@ -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';
|
||||
}
|
||||
|
@ -15,23 +15,26 @@ along with Medito App. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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<DownloadsListWidget>
|
||||
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<DownloadsListWidget>
|
||||
}
|
||||
|
||||
void showSwipeToDeleteTip() {
|
||||
createSnackBar(StringConstants.SWIPE_TO_DELETE, context, color: ColorConstants.darkMoon);
|
||||
createSnackBar(StringConstants.SWIPE_TO_DELETE, context,
|
||||
color: ColorConstants.darkMoon);
|
||||
}
|
||||
|
||||
void _refreshDownloadList() {
|
||||
|
@ -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/>.*/
|
||||
|
||||
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<HomeWidget> {
|
||||
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<HomeWidget> {
|
||||
}
|
||||
|
||||
Widget _getTitleWidget(BuildContext context) => FutureBuilder<String>(
|
||||
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<void> _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<HomeWidget> {
|
||||
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,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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';
|
||||
|
@ -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/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<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
|
||||
stream: Stream.fromFuture(
|
||||
Connectivity().checkConnectivity(),
|
||||
),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
if (snapshot.data == ConnectivityResult.none) {
|
||||
_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
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _onlineBackgroundSounds(
|
||||
String currentSound, ScrollController scrollController) {
|
||||
String currentSound,
|
||||
ScrollController scrollController,
|
||||
) {
|
||||
return StreamBuilder<ApiResponse<BackgroundSoundsResponse>>(
|
||||
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<Color>(
|
||||
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<Color>(
|
||||
ColorConstants.walterWhite,
|
||||
),
|
||||
),
|
||||
);
|
||||
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>[
|
||||
Divider(height: 16),
|
||||
_getHeader(),
|
||||
@ -177,20 +157,57 @@ class _ChooseBackgroundSoundDialogState
|
||||
];
|
||||
if (list != null) {
|
||||
widgetList.addAll(list
|
||||
.map((e) =>
|
||||
.map<Widget>((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)));
|
||||
|
||||
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>[
|
||||
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(
|
||||
@ -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<Color>(ColorConstants.walterWhite))),
|
||||
height: 16,
|
||||
width: 16,
|
||||
child: const CircularProgressIndicator(
|
||||
backgroundColor: Colors.black,
|
||||
valueColor:
|
||||
AlwaysStoppedAnimation<Color>(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<Object>(
|
||||
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);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -15,11 +15,11 @@ along with Medito App. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
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<PlayerWidget> {
|
||||
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<PlayerWidget> {
|
||||
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<PlayerWidget> {
|
||||
_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<PlayerWidget> {
|
||||
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<PlayerWidget> {
|
||||
|
||||
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<PlayerWidget> {
|
||||
{
|
||||
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 ?? '',
|
||||
},
|
||||
),
|
||||
);
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
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<TextFileWidget>
|
||||
appBar: PreferredSize(
|
||||
preferredSize: const Size(double.infinity, kToolbarHeight),
|
||||
child: StreamBuilder<String>(
|
||||
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<TextFileWidget>
|
||||
children: <Widget>[
|
||||
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<String>(
|
||||
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,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user