diff --git a/.vscode/launch.json b/.vscode/launch.json
deleted file mode 100644
index 3287bb6..0000000
--- a/.vscode/launch.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- // Use IntelliSense to learn about possible attributes.
- // Hover to view descriptions of existing attributes.
- // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
- "version": "0.2.0",
- "configurations": [
- {
- "name": "Flutter",
- "request": "launch",
- "type": "dart"
- }
- ]
-}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
deleted file mode 100644
index e0f15db..0000000
--- a/.vscode/settings.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "java.configuration.updateBuildConfiguration": "automatic"
-}
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml
index 5bd371a..82de3f0 100644
--- a/android/app/src/main/res/drawable/launch_background.xml
+++ b/android/app/src/main/res/drawable/launch_background.xml
@@ -14,4 +14,6 @@
android:gravity="bottom"
android:src="@mipmap/text" />
+
diff --git a/android/app/src/main/res/drawable/launch_background_night.xml b/android/app/src/main/res/drawable/launch_background_night.xml
index 18cc931..0ac4190 100644
--- a/android/app/src/main/res/drawable/launch_background_night.xml
+++ b/android/app/src/main/res/drawable/launch_background_night.xml
@@ -1,7 +1,7 @@
-
+
-
+ android:src="@mipmap/text_light" />
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/normal_background.xml b/android/app/src/main/res/drawable/normal_background.xml
deleted file mode 100644
index 689ff5b..0000000
--- a/android/app/src/main/res/drawable/normal_background.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
- -
-
-
- -
-
-
-
\ No newline at end of file
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
index 25442f8..f9b1bb2 100644
--- a/android/app/src/main/res/values/styles.xml
+++ b/android/app/src/main/res/values/styles.xml
@@ -5,7 +5,4 @@
Flutter draws its first frame -->
- @drawable/launch_background
-
diff --git a/lib/class/audiostate.dart b/lib/class/audiostate.dart
index b720f35..da0cc46 100644
--- a/lib/class/audiostate.dart
+++ b/lib/class/audiostate.dart
@@ -11,7 +11,7 @@ import 'package:audiofileplayer/audio_system.dart';
import 'package:tsacdop/local_storage/key_value_storage.dart';
import 'package:tsacdop/local_storage/sqflite_localpodcast.dart';
-enum AudioState { load, play, pause, complete, error, stop }
+//enum AudioState { load, play, pause, complete, error, stop }
class PlayHistory {
DBHelper dbHelper = DBHelper();
@@ -90,6 +90,14 @@ class AudioPlayer extends ChangeNotifier {
bool _remoteAudioLoading = false;
String _remoteErrorMessage;
double _seekSliderValue = 0.0;
+ int _lastPostion;
+ bool _skip = false;
+ bool _stopOnComplete = false;
+ Timer _stopTimer;
+ //Show stopwatch after user setting timer.
+ bool _showStopWatch = false;
+
+
final Logger _logger = Logger('audiofileplayer');
bool get backgroundAudioPlaying => _backgroundAudioPlaying;
@@ -99,16 +107,20 @@ class AudioPlayer extends ChangeNotifier {
double get seekSliderValue => _seekSliderValue;
String get remoteErrorMessage => _remoteErrorMessage;
bool get playerRunning => _playerRunning;
- int _lastPostion;
int get lastPositin => _lastPostion;
Playlist get queue => _queue;
-
EpisodeBrief get episode => _episode;
+ bool get stopOnComplete => _stopOnComplete;
+ bool get showStopWatch => _showStopWatch;
+
+
+ set setStopOnComplete(bool boo) {
+ _stopOnComplete = boo;
+ }
loadPlaylist() async {
await _queue.getPlaylist();
_lastPostion = await storage.getInt();
- print(_lastPostion);
}
episodeLoad(EpisodeBrief episode) async {
@@ -134,22 +146,27 @@ class AudioPlayer extends ChangeNotifier {
_backgroundAudioPlaying = false;
await _queue.getPlaylist();
_episode = _queue.playlist.first;
+ _skip = true;
await _play(_episode);
_playerRunning = true;
notifyListeners();
}
playNext() async {
+ storage.saveInt(0);
+ _lastPostion = 0;
PlayHistory history = PlayHistory(_episode.title, _episode.enclosureUrl,
backgroundAudioDuration, seekSliderValue);
await dbHelper.saveHistory(history);
await _queue.delFromPlaylist(_episode);
- if (_queue.playlist.length > 0) {
+ if (_queue.playlist.length > 0 && !_stopOnComplete) {
playlistLoad();
} else {
+ _stopOnComplete = false;
_backgroundAudioPlaying = false;
_remoteAudioLoading = false;
_playerRunning = false;
+ _disposeAudio();
notifyListeners();
}
}
@@ -170,7 +187,7 @@ class AudioPlayer extends ChangeNotifier {
_pauseBackgroundAudio();
notifyListeners();
PlayHistory history = PlayHistory(_episode.title, _episode.enclosureUrl,
- backgroundAudioDuration, seekSliderValue);
+ backgroundAudioPosition, seekSliderValue);
await dbHelper.saveHistory(history);
}
@@ -191,16 +208,42 @@ class AudioPlayer extends ChangeNotifier {
_backgroundAudio.seek(positionSeconds);
AudioSystem.instance.setPlaybackState(true, positionSeconds);
}
-
+ //Set sleep time
+ sleepTimer(int mins) {
+ _showStopWatch = true;
+ notifyListeners();
+ _stopTimer = Timer(Duration(minutes: mins),(){
+ _stopOnComplete = false;
+ _backgroundAudioPlaying = false;
+ _remoteAudioLoading = false;
+ _playerRunning = false;
+ _showStopWatch = false;
+ _disposeAudio();
+ notifyListeners();
+ });
+ }
+//Cancel sleep timer
+ cancelTimer(){
+ _stopTimer.cancel();
+ _showStopWatch = false;
+ notifyListeners();
+ }
+
+ _disposeAudio() {
+ pauseAduio();
+ AudioSystem.instance?.stopBackgroundDisplay();
+ AudioSystem.instance?.removeMediaEventListener(_mediaEventListener);
+ _backgroundAudio?.dispose();
+ }
+
@override
dispose() {
- pauseAduio();
- AudioSystem.instance.removeMediaEventListener(_mediaEventListener);
- _backgroundAudio?.dispose();
+ _disposeAudio();
super.dispose();
}
_play(EpisodeBrief episodeBrief) async {
+ AudioSystem.instance.addMediaEventListener(_mediaEventListener);
String url = _queue.playlist.first.enclosureUrl;
_getFile(url).then((result) {
result == 'NotDownload'
@@ -225,6 +268,42 @@ class AudioPlayer extends ChangeNotifier {
return ByteData.view(audio.buffer);
}
+ onDuration(double durationSeconds) {
+ _backgroundAudioDurationSeconds = durationSeconds;
+ _remoteAudioLoading = false;
+ _backgroundAudioPlaying = true;
+ if (_skip) {
+ _forwardBackgroundAudio(_lastPostion.toDouble());
+ _backgroundAudioPositionSeconds = _lastPostion.toDouble();
+ }
+ _skip = false;
+ _setNotification(true);
+ notifyListeners();
+ }
+
+ onPosition(double positionSeconds) {
+ if (_backgroundAudioPositionSeconds < _backgroundAudioDurationSeconds) {
+ _seekSliderValue =
+ _backgroundAudioPositionSeconds / _backgroundAudioDurationSeconds;
+ _backgroundAudioPositionSeconds = positionSeconds;
+ notifyListeners();
+ } else {
+ _seekSliderValue = 1;
+ _backgroundAudioPositionSeconds = _backgroundAudioDurationSeconds;
+ notifyListeners();
+ }
+ _lastPostion = positionSeconds.toInt();
+ storage.saveInt(_lastPostion);
+ }
+
+ onError(String message) {
+ _remoteErrorMessage = message;
+ _backgroundAudio.dispose();
+ _backgroundAudio = null;
+ _backgroundAudioPlaying = false;
+ _remoteAudioLoading = false;
+ }
+
void _initbackgroundAudioPlayerLocal(String path) {
_remoteErrorMessage = null;
_remoteAudioLoading = true;
@@ -232,35 +311,14 @@ class AudioPlayer extends ChangeNotifier {
_backgroundAudio?.pause();
_backgroundAudioPositionSeconds = 0;
_setNotification(false);
- _backgroundAudio =
- Audio.loadFromByteData(audio, onDuration: (double durationSeconds) {
- _backgroundAudioDurationSeconds = durationSeconds;
- _remoteAudioLoading = false;
- _backgroundAudioPlaying = true;
- _setNotification(true);
- notifyListeners();
- }, onPosition: (double positionSeconds) {
- if (_backgroundAudioPositionSeconds < _backgroundAudioDurationSeconds) {
- _seekSliderValue =
- _backgroundAudioPositionSeconds / _backgroundAudioDurationSeconds;
- _backgroundAudioPositionSeconds = positionSeconds;
- notifyListeners();
- } else {
- _seekSliderValue = 1;
- _backgroundAudioPositionSeconds = _backgroundAudioDurationSeconds;
- notifyListeners();
- }
- storage.saveInt(positionSeconds.toInt());
- }, onError: (String message) {
- _remoteErrorMessage = message;
- _backgroundAudio.dispose();
- _backgroundAudio = null;
- _backgroundAudioPlaying = false;
- _remoteAudioLoading = false;
- }, onComplete: () {
- playNext();
- }, looping: false, playInBackground: true)
- ..play();
+ _backgroundAudio = Audio.loadFromByteData(audio,
+ onDuration: (double durationSeconds) => onDuration(durationSeconds),
+ onPosition: (double positionSeconds) => onPosition(positionSeconds),
+ onError: (String message) => onError(message),
+ onComplete: () => playNext(),
+ looping: false,
+ playInBackground: true)
+ ..play();
}
void _initbackgroundAudioPlayer(String url) {
@@ -270,35 +328,14 @@ class AudioPlayer extends ChangeNotifier {
_backgroundAudio?.pause();
_backgroundAudioPositionSeconds = 0;
_setNotification(false);
- _backgroundAudio =
- Audio.loadFromRemoteUrl(url, onDuration: (double durationSeconds) {
- _backgroundAudioDurationSeconds = durationSeconds;
- _remoteAudioLoading = false;
- _backgroundAudioPlaying = true;
- _setNotification(true);
- notifyListeners();
- }, onPosition: (double positionSeconds) {
- if (_backgroundAudioPositionSeconds < _backgroundAudioDurationSeconds) {
- _seekSliderValue =
- _backgroundAudioPositionSeconds / _backgroundAudioDurationSeconds;
- _backgroundAudioPositionSeconds = positionSeconds;
- notifyListeners();
- } else {
- _seekSliderValue = 1;
- _backgroundAudioPositionSeconds = _backgroundAudioDurationSeconds;
- notifyListeners();
- }
- storage.saveInt(positionSeconds.toInt());
- }, onError: (String message) {
- _remoteErrorMessage = message;
- _backgroundAudio.dispose();
- _backgroundAudio = null;
- _backgroundAudioPlaying = false;
- _remoteAudioLoading = false;
- }, onComplete: () {
- playNext();
- }, looping: false, playInBackground: true)
- ..resume();
+ _backgroundAudio = Audio.loadFromRemoteUrl(url,
+ onDuration: (double durationSeconds) => onDuration(durationSeconds),
+ onPosition: (double positionSeconds) => onPosition(positionSeconds),
+ onError: (String message) => onError(message),
+ onComplete: () => playNext(),
+ looping: false,
+ playInBackground: true)
+ ..resume();
}
void _mediaEventListener(MediaEvent mediaEvent) {
@@ -341,7 +378,7 @@ class AudioPlayer extends ChangeNotifier {
}
}
- Future _setNotification(bool b) async {
+ Future _setNotification(bool boo) async {
final Uint8List imageBytes =
File('${_episode.imagePath}').readAsBytesSync();
AudioSystem.instance.setMetadata(AudioMetadata(
@@ -351,7 +388,7 @@ class AudioPlayer extends ChangeNotifier {
genre: "Podcast",
durationSeconds: _backgroundAudioDurationSeconds,
artBytes: imageBytes));
- AudioSystem.instance.setPlaybackState(b, _backgroundAudioPositionSeconds);
+ AudioSystem.instance.setPlaybackState(boo, _backgroundAudioPositionSeconds);
AudioSystem.instance.setAndroidNotificationButtons([
AndroidMediaButtonType.pause,
_forwardButton,
diff --git a/lib/class/importompl.dart b/lib/class/importompl.dart
index e35ee13..ad05b61 100644
--- a/lib/class/importompl.dart
+++ b/lib/class/importompl.dart
@@ -10,6 +10,7 @@ class ImportOmpl extends ChangeNotifier{
set rssTitle(String title){
_rssTitle = title;
+ notifyListeners();
}
ImportState get importState => _importState;
diff --git a/lib/class/podcast_group.dart b/lib/class/podcast_group.dart
index 85df4d7..711cca8 100644
--- a/lib/class/podcast_group.dart
+++ b/lib/class/podcast_group.dart
@@ -45,6 +45,15 @@ class PodcastGroup {
}
}
+ Color getColor() {
+ if (color != '#000000') {
+ int colorInt = int.parse('FF' + color.toUpperCase(), radix: 16);
+ return Color(colorInt).withOpacity(1.0);
+ } else {
+ return Colors.blue[400];
+ }
+ }
+
List _podcasts;
List get podcasts => _podcasts;
@@ -102,15 +111,25 @@ class GroupList extends ChangeNotifier {
}
Future delGroup(PodcastGroup podcastGroup) async {
- _groups.remove(podcastGroup);
+ _isLoading = true;
notifyListeners();
+ podcastGroup.podcastList.forEach((podcast) {
+ if (!_groups.first.podcastList.contains(podcast)) {
+ _groups[0].podcastList.insert(0, podcast);
+ }
+ });
_saveGroup();
+ _groups.remove(podcastGroup);
+ await _groups[0].getPodcasts();
+ _isLoading = false;
+ notifyListeners();
}
- void updateGroup(PodcastGroup podcastGroup) {
+ updateGroup(PodcastGroup podcastGroup) async{
var oldGroup = _groups.firstWhere((it) => it.id == podcastGroup.id);
var index = _groups.indexOf(oldGroup);
_groups.replaceRange(index, index + 1, [podcastGroup]);
+ await podcastGroup.getPodcasts();
notifyListeners();
_saveGroup();
}
@@ -137,6 +156,7 @@ class GroupList extends ChangeNotifier {
return result;
}
+ //Change podcast groups
changeGroup(String id, List list) async {
_isLoading = true;
notifyListeners();
@@ -154,15 +174,16 @@ class GroupList extends ChangeNotifier {
notifyListeners();
}
+ //Unsubscribe podcast
removePodcast(String id) async {
_isLoading = true;
notifyListeners();
_groups.forEach((group) async {
- group.podcastList.remove(id);
+ group.podcastList.remove(id);
});
_saveGroup();
await dbHelper.delPodcastLocal(id);
- await Future.forEach(_groups, (group) async {
+ await Future.forEach(_groups, (group) async {
await group.getPodcasts();
});
_isLoading = false;
diff --git a/lib/home/appbar/about.dart b/lib/home/appbar/about.dart
index 4b6df86..45b511f 100644
--- a/lib/home/appbar/about.dart
+++ b/lib/home/appbar/about.dart
@@ -29,7 +29,7 @@ class AboutApp extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
- Icon(icons, color: Colors.grey[700]),
+ Icon(icons, color: Theme.of(context).accentColor),
Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
),
diff --git a/lib/home/appbar/addpodcast.dart b/lib/home/appbar/addpodcast.dart
index 974b2f6..6319f67 100644
--- a/lib/home/appbar/addpodcast.dart
+++ b/lib/home/appbar/addpodcast.dart
@@ -10,10 +10,8 @@ import 'package:provider/provider.dart';
import 'package:path_provider/path_provider.dart';
import 'package:image/image.dart' as img;
import 'package:fluttertoast/fluttertoast.dart';
-import 'package:tsacdop/class/audiostate.dart';
import 'package:tsacdop/class/fireside_data.dart';
import 'package:uuid/uuid.dart';
-import 'package:tuple/tuple.dart';
import 'package:tsacdop/class/importompl.dart';
import 'package:tsacdop/class/podcast_group.dart';
@@ -32,30 +30,9 @@ class MyHomePage extends StatefulWidget {
class _MyHomePageState extends State {
final _MyHomePageDelegate _delegate = _MyHomePageDelegate();
final GlobalKey _scaffoldKey = GlobalKey();
- bool _loadPlay;
-
- static String _stringForSeconds(int seconds) {
- if (seconds == null) return null;
- return '${(seconds ~/ 60)}:${(seconds.truncate() % 60).toString().padLeft(2, '0')}';
- }
-
- @override
- void initState() {
- super.initState();
- _loadPlay = false;
- _getPlaylist();
- }
-
- _getPlaylist() async {
- await Provider.of(context, listen: false).loadPlaylist();
- setState(() {
- _loadPlay = true;
- });
- }
-
+
@override
Widget build(BuildContext context) {
- var audio = Provider.of(context, listen: false);
return AnnotatedRegion(
value: SystemUiOverlayStyle(
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
@@ -78,44 +55,14 @@ class _MyHomePageState extends State {
},
),
title: Image(
- image: AssetImage('assets/text.png'),
+ image: Theme.of(context).brightness == Brightness.light
+ ? AssetImage('assets/text.png') : AssetImage('assets/text_light.png'),
height: 30,
),
actions: [
PopupMenu(),
],
),
- floatingActionButton: Selector>(
- selector: (_, audio) => Tuple3(audio.playerRunning, audio.queue, audio.lastPositin),
- builder: (_, data, __) => !_loadPlay
- ? Center()
- : data.item1 || data.item2.playlist.length == 0
- ? Center()
- : FloatingActionButton.extended(
- tooltip: 'Play from playlist',
- highlightElevation: 2,
- hoverElevation: 2,
- onPressed: () => audio.playlistLoad(),
- elevation: 1,
- backgroundColor: Theme.of(context).accentColor,
- label: Text(_stringForSeconds(data.item3), style: TextStyle(color: Colors.white)),
- icon: Stack(
- alignment: Alignment.center,
- children: [
- CircleAvatar(
- radius: 15,
- backgroundImage: FileImage(File(
- "${data.item2.playlist.first.imagePath}")),
- ),
- Container(
- height: 30.0,
- decoration: BoxDecoration(
- shape: BoxShape.circle,
- color: Colors.black38),
- ),
- ],
- )),
- ),
body: Home(),
),
),
@@ -163,7 +110,8 @@ class _MyHomePageDelegate extends SearchDelegate {
child: Container(
padding: EdgeInsets.only(top: 400),
child: Image(
- image: AssetImage('assets/listennotes.png'),
+ image: Theme.of(context).brightness == Brightness.light
+ ? AssetImage('assets/listennotes.png') : AssetImage('assets/listennotes_light.png'),
height: 20,
),
));
diff --git a/lib/home/appbar/popupmenu.dart b/lib/home/appbar/popupmenu.dart
index d7cf4d5..0953f57 100644
--- a/lib/home/appbar/popupmenu.dart
+++ b/lib/home/appbar/popupmenu.dart
@@ -49,6 +49,7 @@ class PopupMenu extends StatelessWidget {
Widget build(BuildContext context) {
ImportOmpl importOmpl = Provider.of(context, listen: false);
GroupList groupList = Provider.of(context, listen: false);
+
_refreshAll() async {
var dbHelper = DBHelper();
List podcastList = await dbHelper.getPodcastLocalAll();
diff --git a/lib/home/audioplayer.dart b/lib/home/audioplayer.dart
index d4fdd7d..99d6108 100644
--- a/lib/home/audioplayer.dart
+++ b/lib/home/audioplayer.dart
@@ -1,3 +1,4 @@
+import 'dart:async';
import 'dart:io';
import 'dart:math' as math;
@@ -25,12 +26,118 @@ class _PlayerWidgetState extends State {
return '${(seconds ~/ 60)}:${(seconds.truncate() % 60).toString().padLeft(2, '0')}';
}
+ List minsToSelect = [1, 5, 10, 15, 20, 25, 30, 45, 60, 70, 80, 90, 99];
+ //Show playlist widget.
bool _showlist;
+ //Show timer choose widget.
+ bool _showTimer;
+ //Store selected timer mins.
+ int _minSelected;
+ //Left time after user setting timer.
+ int _timeLeft;
+ Timer _timer;
@override
void initState() {
super.initState();
_showlist = false;
+ _showTimer = false;
+ _minSelected = 5;
+ _timeLeft = 0;
+ }
+
+ setTimer() {
+ _timeLeft = _minSelected;
+ _timer = Timer.periodic(Duration(minutes: 1), (timer) {
+ setState(() {
+ if(_timeLeft < 1){
+ _timer.cancel();
+ } else{
+ _timeLeft = _timeLeft - 1;
+ }
+ });
+ });
+ }
+
+ Widget _sleepTimer(BuildContext context) {
+ var audio = Provider.of(context);
+ return Container(
+ height: 50,
+ margin: EdgeInsets.all(10.0),
+ padding: EdgeInsets.symmetric(horizontal: 10.0),
+ decoration: BoxDecoration(
+ color: Theme.of(context).scaffoldBackgroundColor,
+ borderRadius: BorderRadius.all(Radius.circular(10.0)),
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Expanded(
+ child: SingleChildScrollView(
+ scrollDirection: Axis.horizontal,
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: minsToSelect
+ .map((e) => InkWell(
+ onTap: () => setState(() => _minSelected = e),
+ child: AnimatedContainer(
+ duration: Duration(milliseconds: 300),
+ curve: Curves.elasticOut,
+ margin: EdgeInsets.symmetric(horizontal: 10.0),
+ decoration: BoxDecoration(
+ color: (e == _minSelected)
+ ? Theme.of(context).accentColor
+ : Colors.grey[400],
+ shape: BoxShape.circle,
+ ),
+ alignment: Alignment.center,
+ height: (e == _minSelected) ? 40 : 30,
+ width: (e == _minSelected) ? 40 : 30,
+ child: Text(e.toString(),
+ style: TextStyle(
+ color: (e == _minSelected)
+ ? Colors.white
+ : Colors.black)),
+ ),
+ ))
+ .toList(),
+ ),
+ ),
+ ),
+ Container(
+ width: 100,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ Material(
+ color: Colors.transparent,
+ child: IconButton(
+ icon: Icon(Icons.clear),
+ onPressed: () {
+ setState(() => _showTimer = false);
+ },
+ ),
+ ),
+ Material(
+ color: Colors.transparent,
+ child: IconButton(
+ icon: Icon(Icons.done),
+ onPressed: () {
+ setState(() {
+ _showTimer = false;
+ });
+ audio.sleepTimer(_minSelected);
+ setTimer();
+ },
+ ),
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ );
}
Widget _expandedPanel(BuildContext context) {
@@ -104,13 +211,16 @@ class _PlayerWidgetState extends State {
padding: EdgeInsets.only(left: 30, right: 30),
child: SliderTheme(
data: SliderTheme.of(context).copyWith(
- activeTrackColor: Colors.blue[100],
+ activeTrackColor: Theme.of(context)
+ .accentColor
+ .withOpacity(0.5),
inactiveTrackColor: Colors.grey[300],
trackHeight: 3.0,
- thumbColor: Colors.blue[400],
+ thumbColor: Theme.of(context).accentColor,
thumbShape: RoundSliderThumbShape(
enabledThumbRadius: 6.0),
- overlayColor: Colors.blue.withAlpha(32),
+ overlayColor:
+ Theme.of(context).accentColor.withAlpha(32),
overlayShape:
RoundSliderOverlayShape(overlayRadius: 14.0),
),
@@ -167,113 +277,192 @@ class _PlayerWidgetState extends State {
child: Selector(
selector: (_, audio) => audio.backgroundAudioPlaying,
builder: (_, backplay, __) {
- return Row(
- mainAxisSize: MainAxisSize.min,
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- IconButton(
- padding: EdgeInsets.symmetric(horizontal: 30.0),
- onPressed: backplay
- ? () => audio.forwardAudio(-10)
- : null,
- iconSize: 32.0,
- icon: Icon(Icons.replay_10),
- color: Theme.of(context).tabBarTheme.labelColor),
- backplay
- ? IconButton(
- padding:
- EdgeInsets.symmetric(horizontal: 30.0),
- onPressed: backplay
- ? () {
- audio.pauseAduio();
- }
- : null,
- iconSize: 40.0,
- icon: Icon(Icons.pause_circle_filled),
- color:
- Theme.of(context).tabBarTheme.labelColor)
- : IconButton(
- padding:
- EdgeInsets.symmetric(horizontal: 30.0),
- onPressed: backplay
- ? null
- : () {
- audio.resumeAudio();
- },
- iconSize: 40.0,
- icon: Icon(Icons.play_circle_filled),
- color:
- Theme.of(context).tabBarTheme.labelColor),
- IconButton(
- padding: EdgeInsets.symmetric(horizontal: 30.0),
- onPressed: backplay
- ? () => audio.forwardAudio(30)
- : null,
- iconSize: 32.0,
- icon: Icon(Icons.forward_30),
- color: Theme.of(context).tabBarTheme.labelColor),
- ],
+ return Material(
+ color: Colors.transparent,
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ IconButton(
+ padding: EdgeInsets.symmetric(horizontal: 30.0),
+ onPressed: backplay
+ ? () => audio.forwardAudio(-10)
+ : null,
+ iconSize: 32.0,
+ icon: Icon(Icons.replay_10),
+ color:
+ Theme.of(context).tabBarTheme.labelColor),
+ backplay
+ ? IconButton(
+ padding:
+ EdgeInsets.symmetric(horizontal: 30.0),
+ onPressed: backplay
+ ? () {
+ audio.pauseAduio();
+ }
+ : null,
+ iconSize: 40.0,
+ icon: Icon(Icons.pause_circle_filled),
+ color: Theme.of(context)
+ .tabBarTheme
+ .labelColor)
+ : IconButton(
+ padding:
+ EdgeInsets.symmetric(horizontal: 30.0),
+ onPressed: backplay
+ ? null
+ : () {
+ audio.resumeAudio();
+ },
+ iconSize: 40.0,
+ icon: Icon(Icons.play_circle_filled),
+ color: Theme.of(context)
+ .tabBarTheme
+ .labelColor),
+ IconButton(
+ padding: EdgeInsets.symmetric(horizontal: 30.0),
+ onPressed: backplay
+ ? () => audio.forwardAudio(30)
+ : null,
+ iconSize: 32.0,
+ icon: Icon(Icons.forward_30),
+ color:
+ Theme.of(context).tabBarTheme.labelColor),
+ ],
+ ),
);
},
),
),
Spacer(),
- Container(
- height: 50.0,
- margin: EdgeInsets.all(10.0),
- decoration: BoxDecoration(
- color: Theme.of(context).scaffoldBackgroundColor,
- borderRadius: BorderRadius.all(Radius.circular(10.0)),
- ),
- child: Selector(
- selector: (_, audio) => audio.episode,
- builder: (_, episode, __) {
- return Row(
- mainAxisAlignment: MainAxisAlignment.start,
- mainAxisSize: MainAxisSize.min,
- children: [
- Padding(
- padding: EdgeInsets.all(5.0),
- ),
- Container(
- height: 30.0,
- width: 30.0,
- child: CircleAvatar(
- backgroundImage:
- FileImage(File("${episode.imagePath}")),
- ),
- ),
- Spacer(),
- Material(
- color: Colors.transparent,
- child: IconButton(
- onPressed: () => Navigator.push(
- context,
- SlideUptRoute(
- page: EpisodeDetail(
- episodeItem: episode,
- heroTag: 'playpanel')),
- ),
- icon: Icon(Icons.info),
- ),
- ),
- Material(
- color: Colors.transparent,
- child: InkWell(
- borderRadius: BorderRadius.only(
- topRight: Radius.circular(10.0),
- bottomRight: Radius.circular(10.0)),
- child: Container(
- height: 50.0,
- width: 50.0,
- child: Icon(Icons.keyboard_arrow_up)),
- onTap: () => setState(() => _showlist = true)),
- ),
- ],
- );
- },
- ),
- ),
+ !_showTimer
+ // Setting sleep timer
+ ? Container(
+ height: 50.0,
+ margin: EdgeInsets.all(10.0),
+ decoration: BoxDecoration(
+ color: Theme.of(context).scaffoldBackgroundColor,
+ borderRadius: BorderRadius.all(Radius.circular(10.0)),
+ ),
+ child: Selector>(
+ selector: (_, audio) => Tuple3(audio.episode,
+ audio.stopOnComplete, audio.showStopWatch),
+ builder: (_, data, __) {
+ return Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Padding(
+ padding: EdgeInsets.all(5.0),
+ ),
+ Container(
+ height: 30.0,
+ width: 30.0,
+ child: CircleAvatar(
+ backgroundImage: FileImage(
+ File("${data.item1.imagePath}")),
+ ),
+ ),
+ Spacer(),
+ Material(
+ color: Colors.transparent,
+ child: !data.item3
+ ? PopupMenuButton(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.all(
+ Radius.circular(10))),
+ elevation: 1,
+ tooltip: 'Sleep Timer',
+ icon: Icon(
+ Icons.brightness_2,
+ color: data.item2
+ ? Theme.of(context).accentColor
+ : Theme.of(context)
+ .iconTheme
+ .color,
+ ),
+ itemBuilder: (context) => [
+ PopupMenuItem(
+ value: 1,
+ child: Text(
+ 'End of this episode')),
+ PopupMenuItem(
+ value: 2,
+ child: Text('Timer'),
+ ),
+ ],
+ onSelected: (value) {
+ if (value == 1) {
+ audio.setStopOnComplete = true;
+ } else if (value == 2) {
+ setState(() => _showTimer = true);
+ }
+ })
+ : PopupMenuButton(
+ tooltip: 'Time Left',
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.all(
+ Radius.circular(10))),
+ elevation: 1,
+ icon: Container(
+ alignment: Alignment.center,
+ height: 25,
+ width: 25,
+ decoration: BoxDecoration(
+ shape: BoxShape.circle,
+ color:
+ Theme.of(context).accentColor,
+ ),
+ child: Text(
+ _timeLeft.toString(),
+ style: TextStyle(
+ color: Colors.white)),
+ ),
+ itemBuilder: (context) => [
+ PopupMenuItem(
+ value: 1,
+ child: Text('Cancel')),
+ ],
+ onSelected: (value) {
+ audio.cancelTimer();
+ _timer.cancel();
+ setState(() => _timeLeft = 0);
+ },
+ ),
+ ),
+ Material(
+ color: Colors.transparent,
+ child: IconButton(
+ onPressed: () => Navigator.push(
+ context,
+ SlideUptRoute(
+ page: EpisodeDetail(
+ episodeItem: data.item1,
+ heroTag: 'playpanel')),
+ ),
+ icon: Icon(Icons.info),
+ ),
+ ),
+ Material(
+ color: Colors.transparent,
+ child: InkWell(
+ borderRadius: BorderRadius.only(
+ topRight: Radius.circular(10.0),
+ bottomRight: Radius.circular(10.0)),
+ child: Container(
+ height: 50.0,
+ width: 50.0,
+ child: Icon(Icons.keyboard_arrow_up)),
+ onTap: () =>
+ setState(() => _showlist = true)),
+ ),
+ ],
+ );
+ },
+ ),
+ )
+ : _sleepTimer(context),
]),
),
Container(
@@ -283,8 +472,8 @@ class _PlayerWidgetState extends State {
height: _showlist ? 300 : 0,
width: MediaQuery.of(context).size.width,
alignment: Alignment.center,
- margin: EdgeInsets.all(20),
- padding: EdgeInsets.only(bottom: 10.0),
+ // margin: EdgeInsets.all(20),
+ //padding: EdgeInsets.only(bottom: 10.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10.0)),
color: Theme.of(context).scaffoldBackgroundColor,
diff --git a/lib/home/home.dart b/lib/home/home.dart
index dfd5e85..0cd1b39 100644
--- a/lib/home/home.dart
+++ b/lib/home/home.dart
@@ -1,15 +1,45 @@
+import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'package:tuple/tuple.dart';
import 'hometab.dart';
import 'package:tsacdop/home/appbar/importompl.dart';
import 'package:tsacdop/home/audioplayer.dart';
+import 'package:tsacdop/class/audiostate.dart';
import 'homescroll.dart';
-class Home extends StatelessWidget {
+class Home extends StatefulWidget {
+ @override
+ _HomeState createState() => _HomeState();
+}
+
+class _HomeState extends State {
+ bool _loadPlay;
+
+ static String _stringForSeconds(int seconds) {
+ if (seconds == null) return null;
+ return '${(seconds ~/ 60)}:${(seconds.truncate() % 60).toString().padLeft(2, '0')}';
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ _loadPlay = false;
+ _getPlaylist();
+ }
+
+ _getPlaylist() async {
+ await Provider.of(context, listen: false).loadPlaylist();
+ setState(() {
+ _loadPlay = true;
+ });
+ }
@override
Widget build(BuildContext context) {
+ var audio = Provider.of(context, listen: false);
return Stack(children: [
Column(
mainAxisAlignment: MainAxisAlignment.start,
@@ -22,8 +52,70 @@ class Home extends StatelessWidget {
),
],
),
- Container(
- child: PlayerWidget()),
+ AnimatedPositioned(
+ duration: Duration(milliseconds: 2000),
+ curve: Curves.elasticOut,
+ bottom: 50,
+ right: _loadPlay ? 5 : -25,
+ child: Container(
+ child: Selector>(
+ selector: (_, audio) =>
+ Tuple3(audio.playerRunning, audio.queue, audio.lastPositin),
+ builder: (_, data, __) => !_loadPlay
+ ? Center()
+ : data.item1 || data.item2.playlist.length == 0
+ ? Center()
+ : InkWell(
+ onTap: () => audio.playlistLoad(),
+ child: Stack(
+ alignment: Alignment.centerLeft,
+ children: [
+ Container(
+ padding: EdgeInsets.only(left: 45, right: 10.0),
+ alignment: Alignment.centerRight,
+ decoration: BoxDecoration(
+ color: Theme.of(context).accentColor,
+ borderRadius: BorderRadius.only(
+ topLeft: Radius.circular(20.0),
+ bottomLeft: Radius.circular(20.0),
+ bottomRight: Radius.circular(10.0),
+ topRight: Radius.circular(10.0)),
+ boxShadow: [
+ BoxShadow(
+ color: Theme.of(context).brightness ==
+ Brightness.light
+ ? Colors.grey[400]
+ : Colors.grey[800],
+ blurRadius: 4,
+ offset: Offset(1, 1)),
+ ]),
+ height: 40,
+ child: Text(_stringForSeconds(data.item3) + '...',
+ style: TextStyle(color: Colors.white)),
+ ),
+ CircleAvatar(
+ radius: 20,
+ backgroundImage: FileImage(File(
+ "${data.item2.playlist.first.imagePath}")),
+ ),
+ Container(
+ height: 40.0,
+ width: 40,
+ decoration: BoxDecoration(
+ shape: BoxShape.circle,
+ color: Colors.black12),
+ child: Icon(
+ Icons.play_arrow,
+ color: Colors.white,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ),
+ Container(child: PlayerWidget()),
]);
}
}
diff --git a/lib/home/homescroll.dart b/lib/home/homescroll.dart
index e167918..0570783 100644
--- a/lib/home/homescroll.dart
+++ b/lib/home/homescroll.dart
@@ -303,7 +303,7 @@ class _PodcastPreviewState extends State {
@override
Widget build(BuildContext context) {
Color _c = (Theme.of(context).brightness == Brightness.light)
- ? widget.podcastLocal.primaryColor.colorizedark()
+ ? widget.podcastLocal.primaryColor.colorizedark()
: widget.podcastLocal.primaryColor.colorizeLight();
return Column(
children: [
@@ -374,9 +374,41 @@ class ShowEpisode extends StatelessWidget {
final List podcast;
final PodcastLocal podcastLocal;
ShowEpisode({Key key, this.podcast, this.podcastLocal}) : super(key: key);
+
@override
Widget build(BuildContext context) {
double _width = MediaQuery.of(context).size.width;
+ _showPopupMenu(Offset offset) async {
+ print(offset.dx);
+ double left = offset.dx;
+ double top = offset.dy;
+ await showMenu(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.all(Radius.circular(10))),
+ context: context,
+ position: RelativeRect.fromLTRB(left, top, _width - left, 0),
+ items: [
+ PopupMenuItem(
+ child: Row(
+ children: [
+ Icon(Icons.play_circle_outline),
+ Padding(padding: EdgeInsets.symmetric(horizontal: 2),),
+ Text('Play')
+ ],
+ ),
+ ),
+ PopupMenuItem(child: Row(
+ children: [
+ Icon(Icons.favorite_border),
+ Padding(padding: EdgeInsets.symmetric(horizontal: 2),),
+ Text('Like')
+ ],
+ )),
+ ],
+ elevation: 8.0,
+ );
+ }
+
return CustomScrollView(
physics: const AlwaysScrollableScrollPhysics(),
primary: false,
@@ -392,11 +424,12 @@ class ShowEpisode extends StatelessWidget {
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
- Color _c =
- (Theme.of(context).brightness == Brightness.light)
- ? podcastLocal.primaryColor.colorizedark()
- : podcastLocal.primaryColor.colorizeLight();
- return InkWell(
+ Color _c = (Theme.of(context).brightness == Brightness.light)
+ ? podcastLocal.primaryColor.colorizedark()
+ : podcastLocal.primaryColor.colorizeLight();
+ return GestureDetector(
+ onLongPressStart: (details) => _showPopupMenu(Offset(
+ details.globalPosition.dx, details.globalPosition.dy)),
onTap: () {
Navigator.push(
context,
diff --git a/lib/local_storage/key_value_storage.dart b/lib/local_storage/key_value_storage.dart
index 5dc6a27..2911626 100644
--- a/lib/local_storage/key_value_storage.dart
+++ b/lib/local_storage/key_value_storage.dart
@@ -34,7 +34,6 @@ class KeyValueStorage {
Future saveInt(int setting) async{
SharedPreferences prefs = await SharedPreferences.getInstance();
- print(setting.toString());
return prefs.setInt(key, setting);
}
diff --git a/lib/local_storage/sqflite_localpodcast.dart b/lib/local_storage/sqflite_localpodcast.dart
index d20d3c1..83858f3 100644
--- a/lib/local_storage/sqflite_localpodcast.dart
+++ b/lib/local_storage/sqflite_localpodcast.dart
@@ -1,10 +1,8 @@
import 'package:sqflite/sqflite.dart';
import 'dart:async';
-import 'dart:io' as io;
import 'package:path/path.dart';
import 'package:intl/intl.dart';
import 'package:flutter_downloader/flutter_downloader.dart';
-import 'package:path_provider/path_provider.dart';
import 'package:dio/dio.dart';
import 'package:tsacdop/class/podcastlocal.dart';
import 'package:tsacdop/class/audiostate.dart';
@@ -20,8 +18,8 @@ class DBHelper {
}
initDb() async {
- io.Directory documentsDirectory = await getApplicationDocumentsDirectory();
- String path = join(documentsDirectory.path, "podcasts.db");
+ var documentsDirectory = await getDatabasesPath();
+ String path = join(documentsDirectory, "podcasts.db");
Database theDb = await openDatabase(path, version: 1, onCreate: _onCreate);
return theDb;
}
diff --git a/lib/main.dart b/lib/main.dart
index 80c831c..3aad67a 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -32,15 +32,12 @@ Future main() async {
callbackDispatcher,
isInDebugMode: true,
);
- Workmanager.registerPeriodicTask("update", "simplePeriodicTask",
- frequency: Duration(hours: 1),
- initialDelay: Duration(seconds: 10),
+ Workmanager.registerPeriodicTask("2", "update_podcasts",
+ frequency: Duration(minutes: 1),
+ initialDelay: Duration(seconds: 5),
constraints: Constraints(
networkType: NetworkType.connected,
- requiresBatteryNotLow: true,
- requiresCharging: false,
- requiresDeviceIdle: true,
- requiresStorageNotLow: true));
+ ));
await FlutterDownloader.initialize();
await SystemChrome.setPreferredOrientations(
@@ -55,7 +52,7 @@ void callbackDispatcher() {
await dbHelper.updatePodcastRss(podcastLocal);
print('Refresh ' + podcastLocal.title);
});
- return Future.value(true);
+ return true;
});
}
diff --git a/lib/podcasts/podcastgroup.dart b/lib/podcasts/podcastgroup.dart
index 4358034..e3cc80a 100644
--- a/lib/podcasts/podcastgroup.dart
+++ b/lib/podcasts/podcastgroup.dart
@@ -1,10 +1,13 @@
import 'dart:io';
+import 'dart:math' as math;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
+import 'package:flutter_colorpicker/flutter_colorpicker.dart';
+
import 'package:tsacdop/class/podcast_group.dart';
import 'package:tsacdop/class/podcastlocal.dart';
import 'package:tsacdop/podcasts/podcastdetail.dart';
@@ -18,97 +21,460 @@ class PodcastGroupList extends StatefulWidget {
_PodcastGroupListState createState() => _PodcastGroupListState();
}
-class _PodcastGroupListState extends State {
- bool _loadSave;
+class _PodcastGroupListState extends State
+ with SingleTickerProviderStateMixin {
+ bool _showSetting;
+ AnimationController _controller;
+ Animation _animation;
+ double _fraction;
@override
void initState() {
super.initState();
- _loadSave = false;
+ _showSetting = false;
+ _fraction = 0;
+ _controller = AnimationController(
+ duration: const Duration(milliseconds: 500), vsync: this);
+ _animation = Tween(begin: 0.0, end: 1.0).animate(_controller)
+ ..addListener(() {
+ if (mounted)
+ setState(() {
+ _fraction = _animation.value;
+ });
+ });
+ _controller.addStatusListener((status) {
+ if (status == AnimationStatus.completed) {
+ _controller.stop();
+ } else if (status == AnimationStatus.dismissed) {
+ _controller.stop();
+ }
+ });
+ }
+
+ @override
+ void dispose() {
+ _controller.dispose();
+ super.dispose();
}
Widget _saveButton(BuildContext context) {
var podcastList = widget.group.podcasts;
- var _groupList = Provider.of(context);
- return Container(
- child: InkWell(
- child: AnimatedContainer(
- duration: Duration(milliseconds: 800),
- width: _loadSave ? 70 : 0,
- height: 60,
- decoration: BoxDecoration(
- color: Colors.blue,
- shape: BoxShape.circle,
- boxShadow: [
- BoxShadow(
- color: Colors.grey[700],
- blurRadius: 5,
- offset: Offset(1, 1),
- ),
- ]),
- alignment: Alignment.center,
- child: Text(
- 'Save',
- style: TextStyle(color: Colors.white),
- maxLines: 1,
- )),
- onTap: () async {
- await _groupList.saveOrder(widget.group, podcastList);
- Fluttertoast.showToast(
- msg: 'Setting Saved',
- gravity: ToastGravity.BOTTOM,
- );
- setState(() {
- _loadSave = false;
- });
- },
+ var _groupList = Provider.of(context, listen: false);
+ return Transform(
+ alignment: FractionalOffset(0.5, 0.5),
+ transform: Matrix4.rotationY(math.pi * _fraction),
+ child: Container(
+ child: InkWell(
+ child: Container(
+ width: 50,
+ height: 50,
+ decoration: BoxDecoration(
+ color: _fraction > 0.5 ? Colors.red : widget.group.getColor(),
+ shape: BoxShape.circle,
+ boxShadow: [
+ BoxShadow(
+ color: Colors.grey[700],
+ blurRadius: 5,
+ offset: Offset(1, 1),
+ ),
+ ]),
+ alignment: Alignment.center,
+ child: Icon(
+ _fraction > 0.5 ? Icons.save : Icons.settings,
+ color: Colors.white,
+ )),
+ onTap: () async {
+ if (_fraction == 0) {
+ setState(() {
+ _showSetting = true;
+ });
+ } else {
+ await _groupList.saveOrder(widget.group, podcastList);
+ Fluttertoast.showToast(
+ msg: 'Setting Saved',
+ gravity: ToastGravity.BOTTOM,
+ );
+ _controller.reverse();
+ }
+ },
+ ),
),
);
}
@override
Widget build(BuildContext context) {
+ var groupList = Provider.of(context, listen: false);
return widget.group.podcastList.length == 0
? Container(
color: Theme.of(context).primaryColor,
)
- : Container(
- color: Theme.of(context).primaryColor,
- child: Stack(
- children: [
- ReorderableListView(
- onReorder: (int oldIndex, int newIndex) {
- setState(() {
- if (newIndex > oldIndex) {
- newIndex -= 1;
- }
- final PodcastLocal podcast =
- widget.group.podcasts.removeAt(oldIndex);
- widget.group.podcasts.insert(newIndex, podcast);
- _loadSave = true;
- });
- },
- children: widget.group.podcasts
- .map((PodcastLocal podcastLocal) {
- return Container(
- decoration:
- BoxDecoration(color: Theme.of(context).primaryColor),
- key: ObjectKey(podcastLocal.title),
- child: PodcastCard(
- podcastLocal: podcastLocal,
- group: widget.group,
+ : Stack(
+ children: [
+ Container(
+ color: Theme.of(context).primaryColor,
+ child: Stack(
+ children: [
+ ReorderableListView(
+ onReorder: (int oldIndex, int newIndex) {
+ setState(() {
+ if (newIndex > oldIndex) {
+ newIndex -= 1;
+ }
+ final PodcastLocal podcast =
+ widget.group.podcasts.removeAt(oldIndex);
+ widget.group.podcasts.insert(newIndex, podcast);
+ _controller.forward();
+ });
+ },
+ children: widget.group.podcasts
+ .map((PodcastLocal podcastLocal) {
+ return Container(
+ decoration: BoxDecoration(
+ color: Theme.of(context).primaryColor),
+ key: ObjectKey(podcastLocal.title),
+ child: PodcastCard(
+ podcastLocal: podcastLocal,
+ group: widget.group,
+ ),
+ );
+ }).toList(),
+ ),
+ Positioned(
+ bottom: 30,
+ right: 30,
+ child: _saveButton(context),
+ ),
+ ],
+ ),
+ ),
+ _showSetting
+ ? Positioned.fill(
+ child: GestureDetector(
+ onTap: () => setState(() => _showSetting = false),
+ child: Container(
+ color: Theme.of(context)
+ .scaffoldBackgroundColor
+ .withOpacity(0.5),
+ ),
),
- );
- }).toList(),
- ),
- AnimatedPositioned(
- duration: Duration(seconds: 1),
- bottom: 30,
- right: _loadSave ? 50 : 0,
- child: _saveButton(context),
- ),
- ],
- ),
+ )
+ : Center(),
+ _showSetting
+ ? Container(
+ alignment: Alignment.bottomCenter,
+ child: Container(
+ height: 150.0,
+ alignment: Alignment.center,
+ decoration: BoxDecoration(
+ color: Theme.of(context).primaryColor,
+ boxShadow: [
+ BoxShadow(
+ offset: Offset(0, -1),
+ blurRadius: 4,
+ color: Theme.of(context).brightness ==
+ Brightness.light
+ ? Colors.grey[400]
+ : Colors.grey[800],
+ ),
+ ],
+ ),
+ child: SingleChildScrollView(
+ scrollDirection: Axis.vertical,
+ child: Container(
+ height: 150,
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ // mainAxisSize: MainAxisSize.min,
+ children: [
+ Material(
+ color: Colors.transparent,
+ child: InkWell(
+ onTap: () {
+ setState(() => _showSetting = false);
+ showGeneralDialog(
+ context: context,
+ barrierDismissible: true,
+ barrierLabel:
+ MaterialLocalizations.of(context)
+ .modalBarrierDismissLabel,
+ barrierColor: Colors.black54,
+ transitionDuration:
+ const Duration(milliseconds: 200),
+ pageBuilder: (BuildContext context,
+ Animation animaiton,
+ Animation
+ secondaryAnimation) =>
+ AnnotatedRegion<
+ SystemUiOverlayStyle>(
+ value: SystemUiOverlayStyle(
+ statusBarIconBrightness:
+ Brightness.light,
+ systemNavigationBarColor:
+ Theme.of(context)
+ .brightness ==
+ Brightness.light
+ ? Color.fromRGBO(
+ 113,
+ 113,
+ 113,
+ 1)
+ : Color.fromRGBO(
+ 15, 15, 15, 1),
+ statusBarColor: Theme.of(
+ context)
+ .brightness ==
+ Brightness.light
+ ? Color.fromRGBO(
+ 113, 113, 113, 1)
+ : Color.fromRGBO(
+ 5, 5, 5, 1),
+ ),
+ child: SafeArea(
+ child: AlertDialog(
+ elevation: 1,
+ titlePadding:
+ EdgeInsets.only(
+ top: 20,
+ left: 40,
+ right: 200,
+ bottom: 20),
+ shape: RoundedRectangleBorder(
+ borderRadius:
+ BorderRadius.all(
+ Radius.circular(
+ 10.0))),
+ title:
+ Text('Choose a color'),
+ content:
+ SingleChildScrollView(
+ child: MaterialPicker(
+ onColorChanged:
+ (value) {
+ PodcastGroup newGroup =
+ PodcastGroup(
+ widget
+ .group.name,
+ color: value
+ .toString()
+ .substring(
+ 10,
+ 16),
+ id: widget
+ .group.id,
+ podcastList:
+ widget
+ .group
+ .podcastList);
+ groupList.updateGroup(
+ newGroup);
+ Navigator.of(context)
+ .pop();
+ },
+ pickerColor:
+ Colors.blue,
+ ),
+ ),
+ ))));
+ },
+ child: Container(
+ height: 50.0,
+ padding:
+ EdgeInsets.symmetric(horizontal: 20),
+ child: Row(
+ children: [
+ Icon(Icons.colorize),
+ Padding(
+ padding: EdgeInsets.symmetric(
+ horizontal: 5.0),
+ ),
+ Text('Change Color'),
+ ],
+ ),
+ ),
+ ),
+ ),
+ Material(
+ color: Colors.transparent,
+ child: InkWell(
+ onTap: () {
+ setState(() => _showSetting = false);
+ widget.group.name == 'Home'
+ ? Fluttertoast.showToast(
+ msg:
+ 'Home group is not supported',
+ gravity: ToastGravity.BOTTOM,
+ )
+ : showGeneralDialog(
+ context: context,
+ barrierDismissible: true,
+ barrierLabel:
+ MaterialLocalizations.of(
+ context)
+ .modalBarrierDismissLabel,
+ barrierColor: Colors.black54,
+ transitionDuration:
+ const Duration(
+ milliseconds: 200),
+ pageBuilder: (BuildContext
+ context,
+ Animation animaiton,
+ Animation
+ secondaryAnimation) =>
+ RenameGroup(
+ group: widget.group,
+ ));
+ },
+ child: Container(
+ height: 50.0,
+ padding:
+ EdgeInsets.symmetric(horizontal: 20),
+ child: Row(
+ children: [
+ Icon(Icons.text_fields),
+ Padding(
+ padding: EdgeInsets.symmetric(
+ horizontal: 5.0),
+ ),
+ Text('Rename'),
+ ],
+ ),
+ ),
+ ),
+ ),
+ Material(
+ color: Colors.transparent,
+ child: InkWell(
+ onTap: () {
+ setState(() => _showSetting = false);
+ widget.group.name == 'Home'
+ ? Fluttertoast.showToast(
+ msg:
+ 'Home group is not supported',
+ gravity: ToastGravity.BOTTOM,
+ )
+ : showGeneralDialog(
+ context: context,
+ barrierDismissible: true,
+ barrierLabel:
+ MaterialLocalizations.of(
+ context)
+ .modalBarrierDismissLabel,
+ barrierColor: Colors.black54,
+ transitionDuration:
+ const Duration(
+ milliseconds: 200),
+ pageBuilder: (BuildContext
+ context,
+ Animation animaiton,
+ Animation
+ secondaryAnimation) =>
+ AnnotatedRegion<
+ SystemUiOverlayStyle>(
+ value: SystemUiOverlayStyle(
+ statusBarIconBrightness:
+ Brightness.light,
+ systemNavigationBarColor:
+ Theme.of(context)
+ .brightness ==
+ Brightness
+ .light
+ ? Color.fromRGBO(
+ 113,
+ 113,
+ 113,
+ 1)
+ : Color.fromRGBO(
+ 15,
+ 15,
+ 15,
+ 1),
+ statusBarColor: Theme.of(
+ context)
+ .brightness ==
+ Brightness.light
+ ? Color.fromRGBO(
+ 113, 113, 113, 1)
+ : Color.fromRGBO(
+ 5, 5, 5, 1),
+ ),
+ child: SafeArea(
+ child: AlertDialog(
+ elevation: 1,
+ shape: RoundedRectangleBorder(
+ borderRadius:
+ BorderRadius.all(
+ Radius.circular(
+ 10.0))),
+ titlePadding:
+ EdgeInsets.only(
+ top: 20,
+ left: 20,
+ right: 200,
+ bottom: 20),
+ title: Text(
+ 'Delete confirm'),
+ content: Text(
+ 'Are you sure you want to delete this group? Podcasts will be moved to Home group.'),
+ actions: [
+ FlatButton(
+ onPressed: () =>
+ Navigator.of(
+ context)
+ .pop(),
+ child: Text(
+ 'CANCEL',
+ style: TextStyle(
+ color: Colors
+ .grey[
+ 600]),
+ ),
+ ),
+ FlatButton(
+ onPressed: () {
+ groupList.delGroup(
+ widget.group);
+ Navigator.of(
+ context)
+ .pop();
+ },
+ child: Text(
+ 'CONFIRM',
+ style: TextStyle(
+ color: Colors
+ .red),
+ ),
+ )
+ ],
+ ),
+ ),
+ ));
+ },
+ child: Container(
+ height: 50,
+ padding:
+ EdgeInsets.symmetric(horizontal: 20),
+ child: Row(
+ children: [
+ Icon(Icons.delete_outline),
+ Padding(
+ padding: EdgeInsets.symmetric(
+ horizontal: 5.0),
+ ),
+ Text('Delete'),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ )
+ : Center(),
+ ],
);
}
}
@@ -330,7 +696,11 @@ class _PodcastCardState extends State {
});
}),
_buttonOnMenu(Icon(Icons.notifications), () {}),
- _buttonOnMenu(Icon(Icons.remove_circle), () {
+ _buttonOnMenu(
+ Icon(
+ Icons.delete,
+ color: Colors.red,
+ ), () {
showGeneralDialog(
context: context,
barrierDismissible: true,
@@ -375,7 +745,11 @@ class _PodcastCardState extends State {
FlatButton(
onPressed: () =>
Navigator.of(context).pop(),
- child: Text('CANCEL', style: TextStyle(color: Colors.grey[600]),),
+ child: Text(
+ 'CANCEL',
+ style: TextStyle(
+ color: Colors.grey[600]),
+ ),
),
FlatButton(
onPressed: () {
@@ -404,3 +778,120 @@ class _PodcastCardState extends State {
);
}
}
+
+class RenameGroup extends StatefulWidget {
+ final PodcastGroup group;
+ RenameGroup({this.group, Key key}) : super(key: key);
+ @override
+ _RenameGroupState createState() => _RenameGroupState();
+}
+
+class _RenameGroupState extends State {
+ TextEditingController _controller;
+ String _newName;
+ int _error;
+
+ @override
+ void initState() {
+ super.initState();
+ _error = 0;
+ _controller = TextEditingController();
+ }
+
+ @override
+ void dispose() {
+ _controller.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ var groupList = Provider.of(context, listen: false);
+ List list = groupList.groups.map((e) => e.name).toList();
+ return AnnotatedRegion(
+ value: SystemUiOverlayStyle(
+ statusBarIconBrightness: Brightness.light,
+ systemNavigationBarColor:
+ Theme.of(context).brightness == Brightness.light
+ ? Color.fromRGBO(113, 113, 113, 1)
+ : Color.fromRGBO(5, 5, 5, 1),
+ statusBarColor: Theme.of(context).brightness == Brightness.light
+ ? Color.fromRGBO(113, 113, 113, 1)
+ : Color.fromRGBO(15, 15, 15, 1),
+ ),
+ child: SafeArea(
+ child: AlertDialog(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.all(Radius.circular(10))),
+ elevation: 1,
+ contentPadding: EdgeInsets.symmetric(horizontal: 20),
+ titlePadding:
+ EdgeInsets.only(top: 20, left: 20, right: 200, bottom: 20),
+ actionsPadding: EdgeInsets.all(0),
+ actions: [
+ FlatButton(
+ onPressed: () => Navigator.of(context).pop(),
+ child: Text(
+ 'CANCEL',
+ style: TextStyle(color: Colors.grey[600]),
+ ),
+ ),
+ FlatButton(
+ onPressed: () async {
+ if (list.contains(_newName)) {
+ setState(() => _error = 1);
+ } else {
+ PodcastGroup newGroup = PodcastGroup(_newName,
+ color: widget.group.color,
+ id: widget.group.id,
+ podcastList: widget.group.podcastList);
+ groupList.updateGroup(newGroup);
+ Navigator.of(context).pop();
+ }
+ },
+ child: Text('DONE',
+ style: TextStyle(color: Theme.of(context).accentColor)),
+ )
+ ],
+ title: Text('Create new group'),
+ content: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ TextField(
+ decoration: InputDecoration(
+ contentPadding: EdgeInsets.symmetric(horizontal: 10),
+ hintText: 'New Group',
+ hintStyle: TextStyle(fontSize: 18),
+ filled: true,
+ focusedBorder: UnderlineInputBorder(
+ borderSide: BorderSide(
+ color: Theme.of(context).accentColor, width: 2.0),
+ ),
+ enabledBorder: UnderlineInputBorder(
+ borderSide: BorderSide(
+ color: Theme.of(context).accentColor, width: 2.0),
+ ),
+ ),
+ cursorRadius: Radius.circular(2),
+ autofocus: true,
+ maxLines: 1,
+ controller: _controller,
+ onChanged: (value) {
+ _newName = value;
+ },
+ ),
+ Container(
+ alignment: Alignment.centerLeft,
+ child: (_error == 1)
+ ? Text(
+ 'Group existed',
+ style: TextStyle(color: Colors.red[400]),
+ )
+ : Center(),
+ ),
+ ],
+ ),
+ ),
+ ));
+ }
+}
diff --git a/lib/podcasts/podcastlist.dart b/lib/podcasts/podcastlist.dart
index 26808fb..aa31da8 100644
--- a/lib/podcasts/podcastlist.dart
+++ b/lib/podcasts/podcastlist.dart
@@ -46,6 +46,9 @@ class _AboutPodcastState extends State {
Widget build(BuildContext context) {
var _groupList = Provider.of(context, listen: false);
return AlertDialog(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.all(Radius.circular(10.0))),
+ titlePadding: EdgeInsets.only(top: 20, left: 20, right: 200, bottom: 20),
actions: [
FlatButton(
padding: EdgeInsets.all(10.0),
@@ -99,7 +102,7 @@ class _PodcastListState extends State {
statusBarColor: Theme.of(context).primaryColor,
),
child: SafeArea(
- child: Scaffold(
+ child: Scaffold(
appBar: AppBar(
title: Text('Podcasts'),
centerTitle: true,
@@ -116,7 +119,8 @@ class _PodcastListState extends State {
SliverPadding(
padding: const EdgeInsets.all(10.0),
sliver: SliverGrid(
- gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
+ gridDelegate:
+ SliverGridDelegateWithFixedCrossAxisCount(
childAspectRatio: 0.8,
crossAxisCount: 3,
),
@@ -133,12 +137,43 @@ class _PodcastListState extends State {
);
},
onLongPress: () {
- showDialog(
- context: context,
- builder: (BuildContext context) =>
- AboutPodcast(
- podcastLocal: snapshot.data[index]),
- ).then((_) => setState(() {}));
+ showGeneralDialog(
+ context: context,
+ barrierDismissible: true,
+ barrierLabel:
+ MaterialLocalizations.of(context)
+ .modalBarrierDismissLabel,
+ barrierColor: Colors.black54,
+ transitionDuration:
+ const Duration(milliseconds: 200),
+ pageBuilder: (BuildContext context,
+ Animation animaiton,
+ Animation secondaryAnimation) =>
+ AnnotatedRegion(
+ value: SystemUiOverlayStyle(
+ statusBarIconBrightness:
+ Brightness.light,
+ systemNavigationBarColor:
+ Theme.of(context)
+ .brightness ==
+ Brightness.light
+ ? Color.fromRGBO(
+ 113, 113, 113, 1)
+ : Color.fromRGBO(
+ 15, 15, 15, 1),
+ statusBarColor: Theme.of(context)
+ .brightness ==
+ Brightness.light
+ ? Color.fromRGBO(
+ 113, 113, 113, 1)
+ : Color.fromRGBO(5, 5, 5, 1),
+ ),
+ child: SafeArea(
+ child: AboutPodcast(
+ podcastLocal:
+ snapshot.data[index]),
+ ),
+ ));
},
child: Container(
alignment: Alignment.center,
diff --git a/lib/podcasts/podcastmanage.dart b/lib/podcasts/podcastmanage.dart
index a86dba0..0f90252 100644
--- a/lib/podcasts/podcastmanage.dart
+++ b/lib/podcasts/podcastmanage.dart
@@ -20,12 +20,6 @@ class _PodcastManageState extends State {
));
}
- @override
- void initState() {
- super.initState();
- }
-
- @override
Widget build(BuildContext context) {
return AnnotatedRegion(
value: SystemUiOverlayStyle(
@@ -34,85 +28,85 @@ class _PodcastManageState extends State {
statusBarColor: Theme.of(context).primaryColor,
),
child: SafeArea(
- child: SafeArea(
- child: Scaffold(
- appBar: AppBar(
- centerTitle: true,
- title: Text('Groups'),
- actions: [
- IconButton(
- onPressed: () => showGeneralDialog(
- context: context,
- barrierDismissible: true,
- barrierLabel: MaterialLocalizations.of(context)
- .modalBarrierDismissLabel,
- barrierColor: Colors.black54,
- transitionDuration: const Duration(milliseconds: 200),
- pageBuilder: (BuildContext context, Animation animaiton,
- Animation secondaryAnimation) =>
- AddGroup()),
- icon: Icon(Icons.add)),
- OrderMenu(),
- ],
- ),
- body: Consumer(builder: (_, groupList, __) {
- bool _isLoading = groupList.isLoading;
- List _groups = groupList.groups;
- return _isLoading
- ? Center()
- : DefaultTabController(
- length: _groups.length,
- child: Column(
- mainAxisAlignment: MainAxisAlignment.start,
- mainAxisSize: MainAxisSize.min,
- children: [
- Container(
- height: 50,
- padding: EdgeInsets.symmetric(horizontal: 10.0),
- alignment: Alignment.centerLeft,
- child: TabBar(
- // labelColor: Colors.black,
- // unselectedLabelColor: Colors.grey[500],
- labelPadding: EdgeInsets.all(5.0),
- indicator: getIndicator(),
- isScrollable: true,
- tabs: _groups.map((group) {
- return Tab(
+ child: Scaffold(
+ appBar: AppBar(
+ centerTitle: true,
+ title: Text('Groups'),
+ actions: [
+ IconButton(
+ onPressed: () => showGeneralDialog(
+ context: context,
+ barrierDismissible: true,
+ barrierLabel: MaterialLocalizations.of(context)
+ .modalBarrierDismissLabel,
+ barrierColor: Colors.black54,
+ transitionDuration: const Duration(milliseconds: 200),
+ pageBuilder: (BuildContext context, Animation animaiton,
+ Animation secondaryAnimation) =>
+ AddGroup()),
+ icon: Icon(Icons.add)),
+ OrderMenu(),
+ ],
+ ),
+ body: Consumer(builder: (_, groupList, __) {
+ bool _isLoading = groupList.isLoading;
+ List _groups = groupList.groups;
+ return _isLoading
+ ? Center()
+ : DefaultTabController(
+ length: _groups.length,
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Container(
+ height: 50,
+ padding: EdgeInsets.symmetric(horizontal: 10.0),
+ alignment: Alignment.centerLeft,
+ child: TabBar(
+ labelColor: Colors.white,
+ unselectedLabelColor: Colors.black,
+ labelPadding: EdgeInsets.all(5.0),
+ indicator: getIndicator(),
+ isScrollable: true,
+ tabs: _groups.map((group) {
+ return Tab(
child: Container(
height: 30.0,
- padding: EdgeInsets.symmetric(
- horizontal: 10.0),
+ padding:
+ EdgeInsets.symmetric(horizontal: 10.0),
alignment: Alignment.center,
decoration: BoxDecoration(
- color: Theme.of(context).brightness ==
- Brightness.light
- ? Theme.of(context).primaryColorDark
- : Colors.grey[800],
- borderRadius: BorderRadius.all(
- Radius.circular(15)),
+ color: group.getColor(),
+ // Theme.of(context).brightness ==
+ // Brightness.light
+ // ? Theme.of(context).primaryColorDark
+ // : Colors.grey[800],
+ borderRadius:
+ BorderRadius.all(Radius.circular(15)),
),
child: Text(
group.name,
)),
);
+
+ }).toList(),
+ ),
+ ),
+ Expanded(
+ child: Container(
+ child: TabBarView(
+ children: _groups.map((group) {
+ return Container(
+ key: ObjectKey(group),
+ child: PodcastGroupList(group: group));
}).toList(),
),
),
- Expanded(
- child: Container(
- child: TabBarView(
- children: _groups.map((group) {
- return Container(
- key: ObjectKey(group),
- child: PodcastGroupList(group: group));
- }).toList(),
- ),
- ),
- )
- ],
- ));
- }),
- ),
+ )
+ ],
+ ));
+ }),
),
),
);
@@ -214,7 +208,8 @@ class _AddGroupState extends State {
Navigator.of(context).pop();
}
},
- child: Text('DONE',style: TextStyle(color: Theme.of(context).accentColor)),
+ child: Text('DONE',
+ style: TextStyle(color: Theme.of(context).accentColor)),
)
],
title: Text('Create new group'),
@@ -228,10 +223,12 @@ class _AddGroupState extends State {
hintStyle: TextStyle(fontSize: 18),
filled: true,
focusedBorder: UnderlineInputBorder(
- borderSide: BorderSide(color: Theme.of(context).accentColor, width: 2.0),
+ borderSide: BorderSide(
+ color: Theme.of(context).accentColor, width: 2.0),
),
enabledBorder: UnderlineInputBorder(
- borderSide: BorderSide(color: Theme.of(context).accentColor, width: 2.0),
+ borderSide: BorderSide(
+ color: Theme.of(context).accentColor, width: 2.0),
),
),
cursorRadius: Radius.circular(2),
diff --git a/pubspec.lock b/pubspec.lock
deleted file mode 100644
index a0c0c69..0000000
--- a/pubspec.lock
+++ /dev/null
@@ -1,481 +0,0 @@
-# Generated by pub
-# See https://dart.dev/tools/pub/glossary#lockfile
-packages:
- archive:
- dependency: transitive
- description:
- name: archive
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "2.0.11"
- args:
- dependency: transitive
- description:
- name: args
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.5.2"
- async:
- dependency: transitive
- description:
- name: async
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "2.4.0"
- audiofileplayer:
- dependency: "direct dev"
- description:
- name: audiofileplayer
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.1.1"
- boolean_selector:
- dependency: transitive
- description:
- name: boolean_selector
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.0.5"
- cached_network_image:
- dependency: "direct dev"
- description:
- name: cached_network_image
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "2.0.0"
- charcode:
- dependency: transitive
- description:
- name: charcode
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.1.2"
- collection:
- dependency: transitive
- description:
- name: collection
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.14.11"
- color_thief_flutter:
- dependency: "direct dev"
- description:
- name: color_thief_flutter
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.0.2"
- convert:
- dependency: transitive
- description:
- name: convert
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "2.1.1"
- crypto:
- dependency: transitive
- description:
- name: crypto
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "2.1.3"
- csslib:
- dependency: transitive
- description:
- name: csslib
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "0.16.1"
- cupertino_icons:
- dependency: "direct main"
- description:
- name: cupertino_icons
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "0.1.3"
- dio:
- dependency: "direct dev"
- description:
- name: dio
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "3.0.9"
- file_picker:
- dependency: "direct dev"
- description:
- name: file_picker
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.4.3+2"
- flutter:
- dependency: "direct main"
- description: flutter
- source: sdk
- version: "0.0.0"
- flutter_cache_manager:
- dependency: transitive
- description:
- name: flutter_cache_manager
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.1.3"
- flutter_colorpicker:
- dependency: "direct dev"
- description:
- name: flutter_colorpicker
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "0.3.2"
- flutter_downloader:
- dependency: "direct dev"
- description:
- name: flutter_downloader
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.4.1"
- flutter_html:
- dependency: "direct dev"
- description:
- name: flutter_html
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "0.11.1"
- flutter_test:
- dependency: "direct dev"
- description: flutter
- source: sdk
- version: "0.0.0"
- flutter_web_plugins:
- dependency: transitive
- description: flutter
- source: sdk
- version: "0.0.0"
- fluttertoast:
- dependency: "direct dev"
- description:
- name: fluttertoast
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "3.1.3"
- font_awesome_flutter:
- dependency: "direct dev"
- description:
- name: font_awesome_flutter
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "8.7.0"
- google_fonts:
- dependency: "direct dev"
- description:
- name: google_fonts
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "0.3.9"
- html:
- dependency: transitive
- description:
- name: html
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "0.14.0+3"
- http:
- dependency: transitive
- description:
- name: http
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "0.12.0+4"
- http_parser:
- dependency: transitive
- description:
- name: http_parser
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "3.1.3"
- image:
- dependency: "direct dev"
- description:
- name: image
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "2.1.4"
- intl:
- dependency: "direct dev"
- description:
- name: intl
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "0.16.1"
- json_annotation:
- dependency: "direct dev"
- description:
- name: json_annotation
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "3.0.1"
- logging:
- dependency: transitive
- description:
- name: logging
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "0.11.4"
- marquee:
- dependency: "direct dev"
- description:
- name: marquee
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.3.1"
- matcher:
- dependency: transitive
- description:
- name: matcher
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "0.12.6"
- meta:
- dependency: transitive
- description:
- name: meta
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.1.8"
- nested:
- dependency: transitive
- description:
- name: nested
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "0.0.4"
- path:
- dependency: transitive
- description:
- name: path
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.6.4"
- path_provider:
- dependency: "direct dev"
- description:
- name: path_provider
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.6.1"
- pedantic:
- dependency: transitive
- description:
- name: pedantic
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.8.0+1"
- permission_handler:
- dependency: "direct dev"
- description:
- name: permission_handler
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "4.2.0+hotfix.3"
- petitparser:
- dependency: transitive
- description:
- name: petitparser
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "2.4.0"
- platform:
- dependency: transitive
- description:
- name: platform
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "2.2.1"
- plugin_platform_interface:
- dependency: transitive
- description:
- name: plugin_platform_interface
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.0.2"
- provider:
- dependency: "direct dev"
- description:
- name: provider
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "4.0.4"
- quantize_dart:
- dependency: transitive
- description:
- name: quantize_dart
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.0.3"
- quiver:
- dependency: transitive
- description:
- name: quiver
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "2.0.5"
- shared_preferences:
- dependency: "direct dev"
- description:
- name: shared_preferences
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "0.5.6+2"
- shared_preferences_macos:
- dependency: transitive
- description:
- name: shared_preferences_macos
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "0.0.1+6"
- shared_preferences_platform_interface:
- dependency: transitive
- description:
- name: shared_preferences_platform_interface
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.0.3"
- shared_preferences_web:
- dependency: transitive
- description:
- name: shared_preferences_web
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "0.1.2+4"
- sky_engine:
- dependency: transitive
- description: flutter
- source: sdk
- version: "0.0.99"
- source_span:
- dependency: transitive
- description:
- name: source_span
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.5.5"
- sqflite:
- dependency: "direct dev"
- description:
- name: sqflite
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.2.1"
- stack_trace:
- dependency: transitive
- description:
- name: stack_trace
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.9.3"
- stream_channel:
- dependency: transitive
- description:
- name: stream_channel
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "2.0.0"
- string_scanner:
- dependency: transitive
- description:
- name: string_scanner
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.0.5"
- synchronized:
- dependency: transitive
- description:
- name: synchronized
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "2.2.0"
- term_glyph:
- dependency: transitive
- description:
- name: term_glyph
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.1.0"
- test_api:
- dependency: transitive
- description:
- name: test_api
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "0.2.11"
- tuple:
- dependency: "direct dev"
- description:
- name: tuple
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.0.3"
- typed_data:
- dependency: transitive
- description:
- name: typed_data
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.1.6"
- url_launcher:
- dependency: "direct dev"
- description:
- name: url_launcher
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "5.4.2"
- url_launcher_macos:
- dependency: transitive
- description:
- name: url_launcher_macos
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "0.0.1+4"
- url_launcher_platform_interface:
- dependency: transitive
- description:
- name: url_launcher_platform_interface
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.0.6"
- url_launcher_web:
- dependency: transitive
- description:
- name: url_launcher_web
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "0.1.1+1"
- uuid:
- dependency: "direct dev"
- description:
- name: uuid
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "2.0.4"
- vector_math:
- dependency: transitive
- description:
- name: vector_math
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "2.0.8"
- workmanager:
- dependency: "direct dev"
- description:
- name: workmanager
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "0.2.0"
- xml:
- dependency: "direct dev"
- description:
- name: xml
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "3.5.0"
-sdks:
- dart: ">=2.6.0 <3.0.0"
- flutter: ">=1.12.13+hotfix.4 <2.0.0"
diff --git a/pubspec.yaml b/pubspec.yaml
index ca634bd..73282e7 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -32,18 +32,18 @@ dev_dependencies:
flutter_html: ^0.11.1
path_provider: ^1.6.1
color_thief_flutter: ^1.0.1
- provider: ^4.0.1
- google_fonts: ^0.3.2
+ provider: ^4.0.4
+ google_fonts: ^0.3.9
dio: ^3.0.9
- file_picker: ^1.2.0
+ file_picker: ^1.4.3+2
xml: ^3.5.0
marquee: ^1.3.1
audiofileplayer: ^1.1.1
flutter_downloader: ^1.4.1
- permission_handler: ^4.2.0+hotfix.3
+ permission_handler: ^4.3.0
fluttertoast: ^3.1.3
intl: ^0.16.1
- url_launcher: ^5.4.1
+ url_launcher: ^5.4.2
image: ^2.1.4
shared_preferences: ^0.5.6+1
uuid: ^2.0.4
@@ -52,6 +52,7 @@ dev_dependencies:
workmanager: ^0.2.0
font_awesome_flutter: ^8.7.0
flutter_colorpicker: ^0.3.2
+ lazy_loading_list: ^1.0.0+1