mirror of
https://github.com/meditohq/medito-app.git
synced 2024-08-16 15:40:36 +03:00
Merge branch 'develop' into github-apk
This commit is contained in:
commit
bd8039f54a
@ -8,6 +8,7 @@ The app is free, forever: no ads, no spam, no need to sign up or pay.
|
||||
|
||||
Medito App is a flutter project available on Android and iOS maintained by the Medito Foundation and the community.
|
||||
|
||||
|
||||
## Download the app
|
||||
- Play Store: https://play.google.com/store/apps/details?id=meditofoundation.medito
|
||||
- App Store: https://apps.apple.com/us/app/medito/id1500780518
|
||||
@ -15,6 +16,13 @@ Medito App is a flutter project available on Android and iOS maintained by the M
|
||||
|
||||
NOTE: If you install Medito app using APK file, please make sure to verify that the APK file is signed by Medito Foundation. See [VERIFY_APK](VERIFY_APK.md) for more information.
|
||||
|
||||
## Install
|
||||
[![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/meditohq/medito-app?label=latest%20version&sort=semver)](https://github.com/meditohq/medito-app/releases)
|
||||
|
||||
| Android | iOS |
|
||||
| :--: | :--: |
|
||||
| <a href="https://play.google.com/store/apps/details?id=meditofoundation.medito"><img src="https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png" alt="Get it on Google Play" height="80"/></a><br/>|<a href="https://apps.apple.com/us/app/medito/id1500780518"><img src="https://developer.apple.com/assets/elements/badges/download-on-the-app-store.svg" alt="Download on the App Store" height="55"/></a> |
|
||||
|
||||
## How to use this code
|
||||
|
||||
The best way to start is by opening the project with [Android Studio](https://developer.android.com/studio) or [Visual Studio](https://visualstudio.microsoft.com/)
|
||||
|
@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
@ -1,14 +1,14 @@
|
||||
#!/bin/sh
|
||||
# This is a generated file; do not edit or check into version control.
|
||||
export "FLUTTER_ROOT=/Users/mike/Development/flutter"
|
||||
export "FLUTTER_APPLICATION_PATH=/Users/mike/Projects/medito-app"
|
||||
export "FLUTTER_TARGET=/Users/mike/Projects/medito-app/lib/main.dart"
|
||||
export "FLUTTER_ROOT=C:\src\flutter\flutter"
|
||||
export "FLUTTER_APPLICATION_PATH=C:\Users\Harshad\Desktop\Workspace\medito-app"
|
||||
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
|
||||
export "FLUTTER_TARGET=lib\main.dart"
|
||||
export "FLUTTER_BUILD_DIR=build"
|
||||
export "SYMROOT=${SOURCE_ROOT}/../build/ios"
|
||||
export "FLUTTER_BUILD_NAME=2.0.16"
|
||||
export "FLUTTER_BUILD_NUMBER=20016"
|
||||
export "DART_DEFINES=flutter.inspector.structuredErrors%3Dtrue"
|
||||
export "SYMROOT=${SOURCE_ROOT}/../build\ios"
|
||||
export "FLUTTER_BUILD_NAME=2.0.24"
|
||||
export "FLUTTER_BUILD_NUMBER=20024"
|
||||
export "DART_OBFUSCATION=false"
|
||||
export "TRACK_WIDGET_CREATION=true"
|
||||
export "TRACK_WIDGET_CREATION=false"
|
||||
export "TREE_SHAKE_ICONS=false"
|
||||
export "PACKAGE_CONFIG=/Users/mike/Projects/medito-app/.dart_tool/package_config.json"
|
||||
export "PACKAGE_CONFIG=.packages"
|
||||
|
@ -14,6 +14,7 @@ import 'package:just_audio/just_audio.dart';
|
||||
const fadeDuration = 20;
|
||||
const PLAY_BG_SOUND = 'play_bg_sound';
|
||||
const SEND_BG_SOUND = 'send_bg_sound';
|
||||
const INIT_BG_SOUND = 'init_bg_sound';
|
||||
const SET_BG_SOUND_VOL = 'set_bg_sound_vol';
|
||||
|
||||
/// This task defines logic for playing a list of podcast episodes.
|
||||
@ -24,11 +25,11 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
||||
StreamSubscription<PlaybackEvent> _eventSubscription;
|
||||
var _duration = Duration();
|
||||
|
||||
var _currentlyPlayingBGSound;
|
||||
var _currentlyPlayingBGSound = '';
|
||||
|
||||
int get index => _player.currentIndex;
|
||||
MediaItem mediaItem;
|
||||
var initialBgVolume = 0.6;
|
||||
var initialBgVolume = 0.4;
|
||||
var _updatedStats = false;
|
||||
|
||||
@override
|
||||
@ -132,7 +133,9 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
||||
|
||||
@override
|
||||
Future<void> onPlay() {
|
||||
_bgPlayer.play();
|
||||
if(_currentlyPlayingBGSound.isNotEmptyAndNotNull()) {
|
||||
_bgPlayer.play();
|
||||
}
|
||||
return _player.play();
|
||||
}
|
||||
|
||||
@ -156,10 +159,12 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
||||
await _player.stop();
|
||||
await _broadcastState();
|
||||
break;
|
||||
case INIT_BG_SOUND:
|
||||
AudioServiceBackground.sendCustomEvent(
|
||||
{SEND_BG_SOUND: _currentlyPlayingBGSound});
|
||||
break;
|
||||
case SEND_BG_SOUND:
|
||||
if ((params as String).isNotEmptyAndNotNull()) {
|
||||
_currentlyPlayingBGSound = params;
|
||||
}
|
||||
_currentlyPlayingBGSound = params ?? '';
|
||||
AudioServiceBackground.sendCustomEvent(
|
||||
{SEND_BG_SOUND: _currentlyPlayingBGSound});
|
||||
break;
|
||||
|
@ -80,4 +80,13 @@ class DownloadsBloc {
|
||||
list.removeWhere((element) => MediaItem.fromJson(jsonDecode(element)).id == mediaFile.id);
|
||||
await prefs.setStringList(savedFilesKey, list);
|
||||
}
|
||||
|
||||
// This method is used to save the updated order of the list of downloaded sessions
|
||||
/// 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) => jsonEncode(mediaItem)).toList();
|
||||
await prefs.setStringList(savedFilesKey, list);
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ const String DOWNLOADS = 'Downloads';
|
||||
const String DOWNLOAD = 'Download';
|
||||
const String SOUNDS = 'Sounds';
|
||||
const String BEGIN = 'Begin';
|
||||
const String PICK_NARRATOR = 'PICK A NARRATOR & DURATION';
|
||||
const String PICK_NARRATOR_AND_DURATION = 'Pick a narrator & duration';
|
||||
const String PICK_DURATION = 'Pick a duration';
|
||||
const String SHOW_DOWNLOADS = 'Show downloads';
|
||||
const String FAVOURITES = 'Favouites';
|
||||
const String EMPTY_DOWNLOADS_MESSAGE =
|
||||
|
@ -40,20 +40,29 @@ class _DownloadsListWidgetState extends State<DownloadsListWidget>
|
||||
hasCloseButton: true,
|
||||
),
|
||||
key: scaffoldKey,
|
||||
body: _downloadList.isEmpty
|
||||
? _getEmptyWidget()
|
||||
: _getDownloadList(),
|
||||
body: _downloadList.isEmpty ? _getEmptyWidget() : _getDownloadList(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getDownloadList() {
|
||||
return ListView.builder(
|
||||
padding: EdgeInsets.symmetric(vertical: 8),
|
||||
itemCount: _downloadList.length,
|
||||
itemBuilder: (context, i) {
|
||||
var item = _downloadList[i];
|
||||
return _getSlidingItem(item, context);
|
||||
// In order for the Dismissible action still to work on the list items,
|
||||
// the default ReorderableListView is used (instead of the .builder one)
|
||||
return ReorderableListView(
|
||||
padding: EdgeInsets.symmetric(vertical: 8),
|
||||
onReorder: (int oldIndex, int newIndex) {
|
||||
setState(() {
|
||||
if (oldIndex < newIndex) {
|
||||
newIndex -= 1;
|
||||
}
|
||||
var reorderedItem = _downloadList.removeAt(oldIndex);
|
||||
_downloadList.insert(newIndex, reorderedItem);
|
||||
// To ensure, that the new list order is saved
|
||||
DownloadsBloc.saveDownloads(_downloadList);
|
||||
});
|
||||
},
|
||||
children:
|
||||
_downloadList.map((item) => _getSlidingItem(item, context)).toList(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getEmptyWidget() => EmptyStateWidget(
|
||||
@ -67,6 +76,8 @@ class _DownloadsListWidgetState extends State<DownloadsListWidget>
|
||||
|
||||
Widget _getSlidingItem(MediaItem item, BuildContext context) {
|
||||
return InkWell(
|
||||
// This (additional) key is required in order for the ReorderableListView to distinguish between the different list items
|
||||
key: ValueKey(item.id),
|
||||
onTap: () {
|
||||
_openPlayer(item, context);
|
||||
},
|
||||
|
@ -24,15 +24,15 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||
|
||||
class HeaderWidget extends StatelessWidget {
|
||||
HeaderWidget({Key key,
|
||||
HeaderWidget({
|
||||
Key key,
|
||||
this.primaryColorController,
|
||||
this.titleController,
|
||||
this.coverController,
|
||||
this.backgroundImageController,
|
||||
this.descriptionController,
|
||||
this.whiteText = false,
|
||||
})
|
||||
: super(key: key);
|
||||
}) : super(key: key);
|
||||
final StreamController<String> primaryColorController;
|
||||
final StreamController<String> titleController;
|
||||
final StreamController<ApiResponse<String>> coverController;
|
||||
@ -66,15 +66,11 @@ class HeaderWidget extends StatelessWidget {
|
||||
children: [
|
||||
MeditoAppBarWidget(transparent: true),
|
||||
_getRow(),
|
||||
Container(height: whiteText ? 0 : 16)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: _getDescriptionWidget(),
|
||||
)
|
||||
_getDescriptionWidget(),
|
||||
],
|
||||
),
|
||||
);
|
||||
@ -123,21 +119,17 @@ class HeaderWidget extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
StreamBuilder<String> _getTitleStream() =>
|
||||
StreamBuilder<String>(
|
||||
initialData: '',
|
||||
stream: titleController.stream,
|
||||
builder: (context, snapshot) {
|
||||
return Text(
|
||||
snapshot.data,
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme
|
||||
.of(context)
|
||||
.textTheme
|
||||
.headline1,
|
||||
);
|
||||
});
|
||||
StreamBuilder<String> _getTitleStream() => StreamBuilder<String>(
|
||||
initialData: '',
|
||||
stream: titleController.stream,
|
||||
builder: (context, snapshot) {
|
||||
return Text(
|
||||
snapshot.data,
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context).textTheme.headline1,
|
||||
);
|
||||
});
|
||||
|
||||
StreamBuilder<ApiResponse<String>> _actualImageStream() {
|
||||
return StreamBuilder<ApiResponse<String>>(
|
||||
@ -153,7 +145,7 @@ class HeaderWidget extends StatelessWidget {
|
||||
child: CircularProgressIndicator(
|
||||
backgroundColor: MeditoColors.transparent,
|
||||
valueColor:
|
||||
AlwaysStoppedAnimation<Color>(MeditoColors.darkMoon),
|
||||
AlwaysStoppedAnimation<Color>(MeditoColors.darkMoon),
|
||||
)),
|
||||
);
|
||||
break;
|
||||
@ -194,7 +186,8 @@ class HeaderWidget extends StatelessWidget {
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData && snapshot.data.isNotEmptyAndNotNull()) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 20.0),
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 20.0),
|
||||
child: Markdown(
|
||||
data: snapshot?.data ?? '',
|
||||
onTapLink: _linkTap,
|
||||
@ -202,20 +195,16 @@ class HeaderWidget extends StatelessWidget {
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
styleSheet: MarkdownStyleSheet.fromTheme(Theme.of(context))
|
||||
.copyWith(
|
||||
p: Theme
|
||||
.of(context)
|
||||
.textTheme
|
||||
.subtitle1
|
||||
.copyWith(
|
||||
fontSize: 14.0,
|
||||
color: whiteText
|
||||
? MeditoColors.walterWhite
|
||||
: MeditoColors.meditoTextGrey)),
|
||||
p: Theme.of(context).textTheme.subtitle1.copyWith(
|
||||
fontSize: 14.0,
|
||||
color: whiteText
|
||||
? MeditoColors.walterWhite
|
||||
: MeditoColors.meditoTextGrey)),
|
||||
shrinkWrap: true,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Container();
|
||||
return Container(height: 20);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ class SmallShortcutsRowWidget extends StatefulWidget {
|
||||
|
||||
class SmallShortcutsRowWidgetState extends State<SmallShortcutsRowWidget> {
|
||||
final _bloc = ShortcutsBloc();
|
||||
|
||||
bool isLandscape = false;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -31,46 +31,52 @@ class SmallShortcutsRowWidgetState extends State<SmallShortcutsRowWidget> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizeChangedLayoutNotifier(
|
||||
child: StreamBuilder<ApiResponse<ShortcutsResponse>>(
|
||||
stream: _bloc.shortcutList.stream,
|
||||
initialData: ApiResponse.loading(),
|
||||
builder: (context, snapshot) {
|
||||
switch (snapshot.data.status) {
|
||||
case Status.LOADING:
|
||||
return _getLoadingWidget();
|
||||
break;
|
||||
case Status.COMPLETED:
|
||||
return GridView.count(
|
||||
crossAxisCount: 2,
|
||||
padding:
|
||||
const EdgeInsets.only(left: 12.0, right: 12.0, top: 8.0),
|
||||
scrollDirection: Axis.vertical,
|
||||
childAspectRatio: 2.6,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
children: List.generate(snapshot.data.body?.data?.length ?? 0,
|
||||
(index) {
|
||||
return Card(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
color: MeditoColors.deepNight,
|
||||
child: SmallShortcutWidget(
|
||||
snapshot.data.body.data[index], widget.onTap),
|
||||
return OrientationBuilder(builder: (context, orientation) {
|
||||
if (MediaQuery.of(context).size.width > 600) {
|
||||
isLandscape = true;
|
||||
} else {
|
||||
isLandscape = false;
|
||||
}
|
||||
return SizeChangedLayoutNotifier(
|
||||
child: StreamBuilder<ApiResponse<ShortcutsResponse>>(
|
||||
stream: _bloc.shortcutList.stream,
|
||||
initialData: ApiResponse.loading(),
|
||||
builder: (context, snapshot) {
|
||||
switch (snapshot.data.status) {
|
||||
case Status.LOADING:
|
||||
return _getLoadingWidget();
|
||||
break;
|
||||
case Status.COMPLETED:
|
||||
return GridView.count(
|
||||
crossAxisCount: isLandscape ? 4 : 2,
|
||||
padding: const EdgeInsets.only(
|
||||
left: 12.0, right: 12.0, top: 8.0),
|
||||
scrollDirection: Axis.vertical,
|
||||
childAspectRatio: 2.6,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
children: List.generate(
|
||||
snapshot.data.body?.data?.length ?? 0, (index) {
|
||||
return Card(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
color: MeditoColors.deepNight,
|
||||
child: SmallShortcutWidget(
|
||||
snapshot.data.body.data[index], widget.onTap),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}),
|
||||
);
|
||||
break;
|
||||
case Status.ERROR:
|
||||
return Icon(Icons.error);
|
||||
break;
|
||||
}
|
||||
return Container();
|
||||
}),
|
||||
);
|
||||
break;
|
||||
case Status.ERROR:
|
||||
return Icon(Icons.error);
|
||||
break;
|
||||
}
|
||||
return Container();
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
Widget _getLoadingWidget() => GridView.count(
|
||||
crossAxisCount: 2,
|
||||
crossAxisCount: isLandscape ? 4 : 2,
|
||||
padding: const EdgeInsets.only(left: 12.0, right: 12.0, top: 8.0),
|
||||
scrollDirection: Axis.vertical,
|
||||
childAspectRatio: 2.6,
|
||||
|
@ -26,7 +26,6 @@ import 'package:Medito/widgets/player/position_indicator_widget.dart';
|
||||
import 'package:audio_service/audio_service.dart';
|
||||
import 'package:back_button_interceptor/back_button_interceptor.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:pedantic/pedantic.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
|
||||
class ChooseBackgroundSoundDialog extends StatefulWidget {
|
||||
@ -68,7 +67,7 @@ class _ChooseBackgroundSoundDialogState
|
||||
volume = await retrieveSavedBgVolume();
|
||||
_dragBgVolumeSubject.add(volume);
|
||||
await AudioService.customAction(SET_BG_SOUND_VOL, volume / 100);
|
||||
await AudioService.customAction(SEND_BG_SOUND);
|
||||
await AudioService.customAction(INIT_BG_SOUND, "");
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,7 +79,7 @@ class _ChooseBackgroundSoundDialogState
|
||||
builder: (context, snapshot) {
|
||||
var currentSounds;
|
||||
try {
|
||||
currentSounds = snapshot.data[SEND_BG_SOUND] ?? NONE;
|
||||
currentSounds = (snapshot.data[SEND_BG_SOUND] as String).isNotEmptyAndNotNull() ? snapshot.data[SEND_BG_SOUND] : NONE;
|
||||
} catch (e) {
|
||||
currentSounds = NONE;
|
||||
}
|
||||
@ -222,7 +221,7 @@ class _ChooseBackgroundSoundDialogState
|
||||
);
|
||||
|
||||
void _noneSelected() {
|
||||
AudioService.customAction(SEND_BG_SOUND, NONE);
|
||||
AudioService.customAction(SEND_BG_SOUND, '');
|
||||
AudioService.customAction(PLAY_BG_SOUND, '');
|
||||
addBgSoundSelectionToSharedPrefs('', '');
|
||||
}
|
||||
|
@ -13,6 +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 'dart:ui';
|
||||
|
||||
import 'package:Medito/network/api_response.dart';
|
||||
import 'package:Medito/network/downloads/downloads_bloc.dart';
|
||||
import 'package:Medito/network/session_options/session_options_bloc.dart';
|
||||
@ -114,7 +116,8 @@ class _SessionOptionsScreenState extends State<SessionOptionsScreen> {
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.subtitle2
|
||||
.copyWith(color: parseColor(snapshot.data)));
|
||||
.copyWith(
|
||||
color: parseColor(snapshot.data)));
|
||||
}),
|
||||
)),
|
||||
)
|
||||
@ -167,6 +170,9 @@ class _SessionOptionsScreenState extends State<SessionOptionsScreen> {
|
||||
|
||||
Widget _buildOptionsPanel(List<VoiceItem> items) {
|
||||
var childList = <Widget>[];
|
||||
// To check whether any of the VoiceItems contains a narrator
|
||||
var containsNarrator =
|
||||
items.any((voiceItem) => voiceItem.headerValue.isNotEmptyAndNotNull());
|
||||
|
||||
items.forEach((value) {
|
||||
var section = _getListItem(context, value);
|
||||
@ -186,11 +192,13 @@ class _SessionOptionsScreenState extends State<SessionOptionsScreen> {
|
||||
Container(height: 20),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 16),
|
||||
child: Text(PICK_NARRATOR.toUpperCase(),
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.copyWith(color: MeditoColors.meditoTextGrey))),
|
||||
child: Text(
|
||||
containsNarrator
|
||||
? PICK_NARRATOR_AND_DURATION.toUpperCase()
|
||||
: PICK_DURATION.toUpperCase(),
|
||||
style: Theme.of(context).textTheme.bodyText1.copyWith(
|
||||
color: MeditoColors.meditoTextGrey,
|
||||
fontWeight: FontWeight.w600))),
|
||||
Container(height: 12),
|
||||
Column(children: childList),
|
||||
])));
|
||||
@ -276,22 +284,21 @@ class _DownloadPanelWidgetState extends State<DownloadPanelWidget> {
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 20, horizontal: 16),
|
||||
padding: EdgeInsets.only(top: 20, bottom: 16, left: 16, right: 16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(DOWNLOAD.toUpperCase(),
|
||||
style: Theme.of(context).textTheme.bodyText2),
|
||||
style: Theme.of(context).textTheme.bodyText1.copyWith(
|
||||
color: MeditoColors.meditoTextGrey,
|
||||
fontWeight: FontWeight.w600)),
|
||||
Container(height: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(_getDownloadLabel(),
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.copyWith(color: MeditoColors.meditoTextGrey)),
|
||||
style: Theme.of(context).textTheme.bodyText1),
|
||||
_getTrailing()
|
||||
],
|
||||
)
|
||||
|
@ -11,7 +11,7 @@ description: A meditation learning tool
|
||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
version: 2.0.23+20023
|
||||
version: 2.0.24+20024
|
||||
environment:
|
||||
sdk: ">=2.6.0 <3.0.0"
|
||||
|
||||
@ -27,10 +27,10 @@ dependencies:
|
||||
shared_preferences: ^2.0.5
|
||||
cached_network_image: ^3.0.0
|
||||
auto_size_text: ^3.0.0-nullsafety.0
|
||||
just_audio: ^0.7.4
|
||||
just_audio: ^0.9.5
|
||||
audio_session: ^0.1.0
|
||||
audio_service: ^0.17.0
|
||||
rxdart: ^0.26.0
|
||||
rxdart: ^0.27.1
|
||||
share: ^2.0.1
|
||||
firebase_core: ^1.1.0
|
||||
firebase_messaging: ^10.0.0
|
||||
|
Loading…
Reference in New Issue
Block a user