diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 1d38e4ba..cce443e2 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -4,7 +4,7 @@
-
+
@@ -33,9 +33,9 @@
.*/
import 'dart:async';
+import 'dart:io';
import 'package:Medito/constants/constants.dart';
import 'package:Medito/constants/theme/app_theme.dart';
import 'package:Medito/providers/providers.dart';
import 'package:Medito/routes/routes.dart';
import 'package:Medito/src/audio_pigeon.g.dart';
-import 'package:Medito/utils/stats_utils.dart';
import 'package:Medito/utils/utils.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/foundation.dart';
@@ -33,6 +33,7 @@ import 'package:sentry_flutter/sentry_flutter.dart';
import 'constants/environments/environment_constants.dart';
import 'services/notifications/notifications_service.dart';
+final _androidServiceApi = MeditoAndroidAudioServiceManager();
var audioStateNotifier = AudioStateNotifier();
var currentEnvironment = EnvironmentConstants.stagingEnv;
@@ -82,16 +83,6 @@ class ParentWidget extends ConsumerStatefulWidget {
class _ParentWidgetState extends ConsumerState
with WidgetsBindingObserver {
- AppLifecycleState currentState = AppLifecycleState.resumed;
-
- @override
- void didChangeAppLifecycleState(AppLifecycleState state) {
- if (state == AppLifecycleState.resumed) {
- unawaited(updateStatsFromBg(ref));
- }
- currentState = state;
- }
-
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
diff --git a/lib/providers/player/player_provider.dart b/lib/providers/player/player_provider.dart
index 93d7a3f0..4b19b26f 100644
--- a/lib/providers/player/player_provider.dart
+++ b/lib/providers/player/player_provider.dart
@@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:convert';
+import 'dart:io';
import 'package:Medito/models/models.dart';
import 'package:flutter/foundation.dart';
@@ -17,6 +18,7 @@ import '../shared_preference/shared_preference_provider.dart';
import 'download/audio_downloader_provider.dart';
final _api = MeditoAudioServiceApi();
+final _androidServiceApi = MeditoAndroidAudioServiceManager();
final playerProvider =
StateNotifierProvider((ref) {
@@ -72,6 +74,11 @@ class PlayerProvider extends StateNotifier {
var downloadPath = await ref.read(audioDownloaderProvider).getTrackPath(
_constructFileName(track, file),
);
+ if (Platform.isAndroid) {
+ await _androidServiceApi.startService();
+ // wait half a sec for the service to start
+ await Future.delayed(Duration(milliseconds: 500));
+ }
await _api.playAudio(
AudioData(
url: downloadPath ?? file.path,
@@ -161,10 +168,12 @@ class PlayerProvider extends StateNotifier {
fileGuide: guide,
timestamp: DateTime.now().millisecondsSinceEpoch,
);
- ref.read(audioStartedEventProvider(
- event: audio.toJson(),
- trackId: trackId,
- ));
+ ref.read(
+ audioStartedEventProvider(
+ event: audio.toJson(),
+ trackId: trackId,
+ ),
+ );
}
Future seekToPosition(int position) async {
diff --git a/lib/utils/cache.dart b/lib/utils/cache.dart
deleted file mode 100644
index 8d576a77..00000000
--- a/lib/utils/cache.dart
+++ /dev/null
@@ -1,101 +0,0 @@
-/*This file is part of Medito App.
-
-Medito App is free software: you can redistribute it and/or modify
-it under the terms of the Affero GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-Medito App is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-Affero GNU General Public License for more details.
-
-You should have received a copy of the Affero GNU General Public License
-along with Medito App. If not, see .*/
-
-import 'dart:convert';
-import 'dart:io';
-
-import 'package:flutter/foundation.dart';
-import 'package:path_provider/path_provider.dart';
-
-const TILES_ID = 'tiles';
-const AUDIO_SET = 'audio-set';
-const AUDIO_DATA = 'audio-data';
-const ATTRIBUTIONS = 'attrs';
-const TEXT = 'text';
-
-Future clearStorage() async {
- if (!kIsWeb) {
- final cacheDir = await getApplicationDocumentsDirectory();
-
- await cacheDir.list(recursive: true).forEach((element) {
- try {
- if (element.path.endsWith('txt') || element.path.endsWith('mp3')) {
- element.deleteSync(recursive: true);
- }
- } catch (e) {
- print(e);
- }
- });
- }
-}
-
-Future get _localPath async {
- if (kIsWeb) return '';
- final directory = await getApplicationDocumentsDirectory();
-
- return directory.path;
-}
-
-Future _localFile(String name) async {
- final path = await _localPath;
-
- return File('$path/$name.txt');
-}
-
-Future _readCache(String id) async {
- id = id.replaceAll('/', '+');
-
- final file = await _localFile(id);
-
- var lastModified;
- try {
- lastModified = await file.lastModified();
- } on FileSystemException {
- return null;
- }
-
- if (lastModified.add(Duration(days: 1)).isBefore(DateTime.now())) return null;
-
- // Read the file.
- return await file.readAsString();
-}
-
-String? encoded(obj) {
- return obj != null ? json.encode(obj) : null;
-}
-
-//ignore:avoid-dynamic
-dynamic decoded(String obj) {
- return json.decode(obj);
-}
-
-Future writeJSONToCache(String? body, String id) async {
- if (body != null) {
- id = id.replaceAll('/', '+');
- final file = await _localFile(id);
-
- return file.writeAsString('$body');
- }
-
- return null;
-}
-
-Future readJSONFromCache(String url) async {
- try {
- return await _readCache(url);
- } catch (e) {
- return null;
- }
-}
diff --git a/lib/utils/stats_utils.dart b/lib/utils/stats_utils.dart
deleted file mode 100644
index 91910f9b..00000000
--- a/lib/utils/stats_utils.dart
+++ /dev/null
@@ -1,282 +0,0 @@
-/*This file is part of Medito App.
-
-Medito App is free software: you can redistribute it and/or modify
-it under the terms of the Affero GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-Medito App is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-Affero GNU General Public License for more details.
-
-You should have received a copy of the Affero GNU General Public License
-along with Medito App. If not, see .*/
-
-import 'package:Medito/constants/constants.dart';
-import 'package:Medito/providers/providers.dart';
-import 'package:Medito/utils/cache.dart';
-import 'package:Medito/utils/utils.dart';
-import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:pedantic/pedantic.dart';
-import 'package:shared_preferences/shared_preferences.dart';
-
-//ignore: prefer-match-file-name
-enum UnitType { day, min, tracks }
-
-String getUnits(UnitType type, int _) {
- switch (type) {
- case UnitType.day:
- return 'd';
- case UnitType.min:
- return '';
- case UnitType.tracks:
- return '';
- }
-}
-
-Future getCurrentStreak() async {
- var prefs = await SharedPreferences.getInstance();
-
- var streak = prefs.getInt(SharedPreferenceConstants.streakCount) ?? 0;
- var streakList = await getStreakList();
-
- if (streakList.isNotEmpty) {
- var lastDayInStreak =
- DateTime.fromMillisecondsSinceEpoch(int.parse(streakList.last));
-
- final now = DateTime.now();
-
- if (longerThanOneDayAgo(lastDayInStreak, now)) {
- streak = 0;
- await prefs.setInt(SharedPreferenceConstants.streakCount, streak);
- }
- }
-
- return streak.toString();
-}
-
-Future> getStreakList() async {
- var prefs = await SharedPreferences.getInstance();
-
- return prefs.getStringList(SharedPreferenceConstants.streakList) ?? [];
-}
-
-Future setStreakList(List streakList) async {
- var prefs = await SharedPreferences.getInstance();
-
- return prefs.setStringList(SharedPreferenceConstants.streakList, streakList);
-}
-
-Future _getCurrentStreakInt() async {
- var prefs = await SharedPreferences.getInstance();
-
- var streak = prefs.getInt(SharedPreferenceConstants.streakCount);
-
- return streak ?? 0;
-}
-
-Future updateMinuteCounter(int additionalSecs) async {
- var prefs = await SharedPreferences.getInstance();
-
- var current = await _getSecondsListened();
- var plusOne = current + additionalSecs;
- await prefs.setInt(SharedPreferenceConstants.secsListened, plusOne);
-
- return true;
-}
-
-Future updateStreak({String streak = ''}) async {
- var prefs = await SharedPreferences.getInstance();
-
- if (streak.isNotEmpty) {
- await prefs.setInt(
- SharedPreferenceConstants.streakCount,
- int.parse(streak),
- );
- await _updateLongestStreak(int.parse(streak), prefs);
- await addPhantomTrackToStreakList();
-
- return;
- }
-
- var streakList = await getStreakList();
- var streakCount = prefs.getInt(SharedPreferenceConstants.streakCount) ?? 0;
-
- if (streakList.isNotEmpty) {
- //if you have meditated before, was it on today? if not, increase counter
- final lastDayInStreak =
- DateTime.fromMillisecondsSinceEpoch(int.parse(streakList.last));
- final now = DateTime.now();
-
- if (!isSameDay(lastDayInStreak, now)) {
- await incrementStreakCounter(streakCount);
- }
- } else {
- //if you've never done one before
- await incrementStreakCounter(streakCount);
- }
-
- streakList.add(DateTime.now().millisecondsSinceEpoch.toString());
- await setStreakList(streakList);
-}
-
-Future addPhantomTrackToStreakList() async {
- //add this track to the streak list to stop it resetting to 0,
- // but keep a note of it in fakeStreakList
-
- var prefs = await SharedPreferences.getInstance();
- var streakList = await getStreakList();
- var fakeStreakList =
- prefs.getStringList(SharedPreferenceConstants.fakeStreakList) ?? [];
- var streakTime = DateTime.now().millisecondsSinceEpoch.toString();
- streakList.add(streakTime);
- fakeStreakList.add(streakTime);
- await setStreakList(streakList);
- await prefs.setStringList(
- SharedPreferenceConstants.fakeStreakList,
- fakeStreakList,
- );
-}
-
-Future incrementStreakCounter(
- int streakCount,
-) async {
- var prefs = await SharedPreferences.getInstance();
-
- streakCount++;
- await prefs.setInt(SharedPreferenceConstants.streakCount, streakCount);
-
- //update longestStreak
- await _updateLongestStreak(streakCount, prefs);
-}
-
-Future _updateLongestStreak(int streakCount, SharedPreferences prefs) async {
- //update longestStreak
- var longest = await _getLongestStreakInt();
- if (streakCount > longest) {
- await prefs.setInt(SharedPreferenceConstants.longestStreak, streakCount);
- }
-}
-
-void setLongestStreakToCurrentStreak() async {
- var prefs = await SharedPreferences.getInstance();
- var current = await _getCurrentStreakInt();
- await prefs.setInt(SharedPreferenceConstants.longestStreak, current);
-}
-
-Future getMinutesListened() async {
- var prefs = await SharedPreferences.getInstance();
-
- var streak = prefs.getInt(SharedPreferenceConstants.secsListened);
-
- return streak == null ? '0' : Duration(seconds: streak).inMinutes.toString();
-}
-
-Future _getSecondsListened() async {
- var prefs = await SharedPreferences.getInstance();
-
- var streak = prefs.getInt(SharedPreferenceConstants.secsListened);
-
- return streak ?? 0;
-}
-
-Future getLongestStreak() async {
- var prefs = await SharedPreferences.getInstance();
-
- if (await _getLongestStreakInt() < await _getCurrentStreakInt()) {
- return getCurrentStreak();
- }
-
- var streak = prefs.getInt(SharedPreferenceConstants.longestStreak);
-
- return streak == null ? '0' : streak.toString();
-}
-
-Future _getLongestStreakInt() async {
- var prefs = await SharedPreferences.getInstance();
-
- var streak = prefs.getInt(SharedPreferenceConstants.longestStreak);
-
- return streak ?? 0;
-}
-
-Future getNumTracks() async {
- var prefs = await SharedPreferences.getInstance();
-
- var streak = prefs.getInt(SharedPreferenceConstants.numSessions);
-
- return streak == null ? '0' : streak.toString();
-}
-
-Future getNumTracksInt() async {
- var prefs = await SharedPreferences.getInstance();
-
- var streak = prefs.getInt(SharedPreferenceConstants.numSessions);
-
- return streak ?? 0;
-}
-
-Future incrementNumTracks() async {
- var prefs = await SharedPreferences.getInstance();
- var current = await getNumTracksInt();
- current++;
- await prefs.setInt(SharedPreferenceConstants.numSessions, current);
-
- return current;
-}
-
-void markAsListened(WidgetRef ref, String id) {
- unawaited(ref
- .read(sharedPreferencesProvider)
- .setBool(SharedPreferenceConstants.listened + id, true));
-}
-
-Future clearBgStats() {
- return writeJSONToCache('', SharedPreferenceConstants.stats);
-}
-
-void setVersionCopySeen(int id) async {
- var prefs = await SharedPreferences.getInstance();
- await prefs.setInt(SharedPreferenceConstants.copy, id);
-}
-
-Future getVersionCopyInt() async {
- var prefs = await SharedPreferences.getInstance();
-
- var version = prefs.getInt(SharedPreferenceConstants.copy);
-
- return version ?? -1;
-}
-
-bool isSameDay(DateTime day1, DateTime day2) {
- return day1.year == day2.year &&
- day1.month == day2.month &&
- day1.day == day2.day;
-}
-
-bool longerThanOneDayAgo(DateTime lastDayInStreak, DateTime now) {
- var thirtyTwoHoursAfterTime = DateTime.fromMillisecondsSinceEpoch(
- lastDayInStreak.millisecondsSinceEpoch + 115200000,
- );
-
- return now.isAfter(thirtyTwoHoursAfterTime);
-}
-
-Future updateStatsFromBg(WidgetRef ref) async {
- var read = await readJSONFromCache(SharedPreferenceConstants.stats);
-
- if (read.isNotNullAndNotEmpty()) {
- var map = decoded(read!);
- var id = map[SharedPreferenceConstants.id];
- var secsListened = map[SharedPreferenceConstants.secsListened];
-
- if (map != null && map.isNotEmpty) {
- await updateStreak();
- await incrementNumTracks();
- markAsListened(ref, id);
- await updateMinuteCounter(Duration(seconds: secsListened).inSeconds);
- }
- await clearBgStats();
- }
-}
diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart
index 910720ce..4ece6598 100644
--- a/lib/utils/utils.dart
+++ b/lib/utils/utils.dart
@@ -58,12 +58,6 @@ void createSnackBar(
}
}
-bool isDayBefore(DateTime day1, DateTime day2) {
- return day1.year == day2.year &&
- day1.month == day2.month &&
- day1.day == day2.day - 1;
-}
-
Future launchURLInBrowser(String url) async {
try {
final uri = Uri.parse(url);
@@ -184,12 +178,6 @@ double getBottomPaddingWithStickyMiniPlayer(BuildContext context) {
return totalPadding;
}
-Future getFilePathForOldAppDownloadedFiles(String mediaItemId) async {
- var dir = (await getApplicationSupportDirectory()).path;
-
- return '$dir/${mediaItemId.replaceAll('/', '_').replaceAll(' ', '_')}.mp3';
-}
-
int formatIcon(String icon) {
if (icon.isEmpty) return 0;
diff --git a/lib/views/auth/join_welcome_view.dart b/lib/views/auth/join_welcome_view.dart
index 69341c60..ca38c4d4 100644
--- a/lib/views/auth/join_welcome_view.dart
+++ b/lib/views/auth/join_welcome_view.dart
@@ -41,7 +41,11 @@ class JoinWelcomeView extends ConsumerWidget {
),
Padding(
padding: const EdgeInsets.only(
- top: 24, bottom: 16, left: 16, right: 16),
+ top: 24,
+ bottom: 16,
+ left: 16,
+ right: 16,
+ ),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
diff --git a/lib/views/downloads/downloads_view.dart b/lib/views/downloads/downloads_view.dart
index ce69ba36..ad4ce524 100644
--- a/lib/views/downloads/downloads_view.dart
+++ b/lib/views/downloads/downloads_view.dart
@@ -14,7 +14,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../providers/background_sounds/background_sounds_notifier.dart';
-import '../../providers/home/home_provider.dart';
class DownloadsView extends ConsumerStatefulWidget {
@override
diff --git a/lib/views/home/widgets/bottom_sheet/debug/debug_bottom_sheet_widget.dart b/lib/views/home/widgets/bottom_sheet/debug/debug_bottom_sheet_widget.dart
index 27ecded5..d6c3cd9a 100644
--- a/lib/views/home/widgets/bottom_sheet/debug/debug_bottom_sheet_widget.dart
+++ b/lib/views/home/widgets/bottom_sheet/debug/debug_bottom_sheet_widget.dart
@@ -5,7 +5,6 @@ import 'package:Medito/widgets/widgets.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
-import '../../../../../providers/me/me_provider.dart';
import '../share_btn/share_btn_widget.dart';
class DebugBottomSheetWidget extends ConsumerWidget {
diff --git a/pigeon_conf.dart b/pigeon_conf.dart
index c1d4e074..963d58ae 100644
--- a/pigeon_conf.dart
+++ b/pigeon_conf.dart
@@ -26,6 +26,11 @@ class AudioData {
Track track;
}
+@HostApi()
+abstract class MeditoAndroidAudioServiceManager {
+ void startService();
+}
+
@HostApi()
abstract class MeditoAudioServiceApi {
bool playAudio(AudioData audioData);