parent
0a0e0a45f5
commit
5dc490f83f
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
|
@ -126,7 +126,7 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
bool _stopOnComplete = false;
|
||||
Timer _stopTimer;
|
||||
int _timeLeft = 0;
|
||||
bool _showStopWatch = false;
|
||||
bool _startSleepTimer = false;
|
||||
double _switchValue = 0;
|
||||
bool _autoPlay = true;
|
||||
DateTime _current;
|
||||
|
@ -144,7 +144,7 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
bool get queueUpdate => _queueUpdate;
|
||||
EpisodeBrief get episode => _episode;
|
||||
bool get stopOnComplete => _stopOnComplete;
|
||||
bool get showStopWatch => _showStopWatch;
|
||||
bool get startSleepTimer => _startSleepTimer;
|
||||
bool get autoPlay => _autoPlay;
|
||||
int get timeLeft => _timeLeft;
|
||||
double get switchValue => _switchValue;
|
||||
|
@ -165,8 +165,7 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
_queueUpdate = false;
|
||||
await AudioService.connect();
|
||||
bool running = await AudioService.running;
|
||||
if (running) {
|
||||
}
|
||||
if (running) {}
|
||||
}
|
||||
|
||||
loadPlaylist() async {
|
||||
|
@ -217,13 +216,13 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
await AudioService.connect();
|
||||
}
|
||||
await AudioService.start(
|
||||
backgroundTaskEntrypoint: _audioPlayerTaskEntrypoint,
|
||||
androidNotificationChannelName: 'Tsacdop',
|
||||
notificationColor: 0xFF4d91be,
|
||||
androidNotificationIcon: 'drawable/ic_notification',
|
||||
enableQueue: true,
|
||||
androidStopOnRemoveTask: true,
|
||||
androidStopForegroundOnPause: true);
|
||||
backgroundTaskEntrypoint: _audioPlayerTaskEntrypoint,
|
||||
androidNotificationChannelName: 'Tsacdop',
|
||||
notificationColor: 0xFF4d91be,
|
||||
androidNotificationIcon: 'drawable/ic_notification',
|
||||
enableQueue: true,
|
||||
androidStopOnRemoveTask: true,
|
||||
);
|
||||
_playerRunning = true;
|
||||
if (_autoPlay) {
|
||||
await Future.forEach(_queue.playlist, (episode) async {
|
||||
|
@ -312,7 +311,7 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
}
|
||||
notifyListeners();
|
||||
}
|
||||
if (_audioState == BasicPlaybackState.stopped) {
|
||||
if (_audioState == BasicPlaybackState.stopped || _playerRunning == false) {
|
||||
timer.cancel();
|
||||
}
|
||||
});
|
||||
|
@ -325,6 +324,7 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
_seekSliderValue = 0;
|
||||
_episode = _queue.playlist.first;
|
||||
_playerRunning = true;
|
||||
_queueUpdate = !_queueUpdate;
|
||||
notifyListeners();
|
||||
_startAudioService(_lastPostion ?? 0);
|
||||
}
|
||||
|
@ -397,9 +397,9 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
int pos = _backgroundAudioPosition + s * 1000;
|
||||
AudioService.seekTo(pos);
|
||||
}
|
||||
|
||||
seekTo(int position) async{
|
||||
if (_audioState != BasicPlaybackState.connecting &&
|
||||
|
||||
seekTo(int position) async {
|
||||
if (_audioState != BasicPlaybackState.connecting &&
|
||||
_audioState != BasicPlaybackState.none)
|
||||
await AudioService.seekTo(position);
|
||||
}
|
||||
|
@ -417,9 +417,9 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
}
|
||||
}
|
||||
|
||||
//Set sleep time
|
||||
//Set sleep timer
|
||||
sleepTimer(int mins) {
|
||||
_showStopWatch = true;
|
||||
_startSleepTimer= true;
|
||||
_switchValue = 1;
|
||||
notifyListeners();
|
||||
_timeLeft = mins * 60;
|
||||
|
@ -432,12 +432,14 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
notifyListeners();
|
||||
}
|
||||
});
|
||||
_stopTimer = Timer(Duration(minutes: mins), () {
|
||||
_stopTimer = Timer(Duration(minutes: mins), () {
|
||||
_stopOnComplete = false;
|
||||
_showStopWatch = false;
|
||||
_startSleepTimer= false;
|
||||
_switchValue = 0;
|
||||
_playerRunning = false;
|
||||
notifyListeners();
|
||||
AudioService.stop();
|
||||
notifyListeners();
|
||||
AudioService.disconnect();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -445,7 +447,7 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
cancelTimer() {
|
||||
_stopTimer.cancel();
|
||||
_timeLeft = 0;
|
||||
_showStopWatch = false;
|
||||
_startSleepTimer= false;
|
||||
_switchValue = 0;
|
||||
notifyListeners();
|
||||
}
|
||||
|
|
|
@ -16,13 +16,16 @@ import 'package:flutter_linkify/flutter_linkify.dart';
|
|||
import 'package:tsacdop/class/audiostate.dart';
|
||||
import 'package:tsacdop/class/episodebrief.dart';
|
||||
import 'package:tsacdop/local_storage/sqflite_localpodcast.dart';
|
||||
import 'package:tsacdop/util/context_extension.dart';
|
||||
import 'episodedownload.dart';
|
||||
|
||||
class EpisodeDetail extends StatefulWidget {
|
||||
final EpisodeBrief episodeItem;
|
||||
final String heroTag;
|
||||
final bool hide;
|
||||
EpisodeDetail({this.episodeItem, this.heroTag = '',this.hide = false, Key key}) : super(key: key);
|
||||
EpisodeDetail(
|
||||
{this.episodeItem, this.heroTag = '', this.hide = false, Key key})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
_EpisodeDetailState createState() => _EpisodeDetailState();
|
||||
|
@ -38,7 +41,8 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
|||
Future getSDescription(String url) async {
|
||||
var dbHelper = DBHelper();
|
||||
_description = (await dbHelper.getDescription(url))
|
||||
.replaceAll(RegExp(r'\s?<p>(<br>)?</p>\s?'), '').replaceAll('\r', '');
|
||||
.replaceAll(RegExp(r'\s?<p>(<br>)?</p>\s?'), '')
|
||||
.replaceAll('\r', '');
|
||||
if (mounted)
|
||||
setState(() {
|
||||
_loaddes = true;
|
||||
|
@ -93,7 +97,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
|||
child: Scaffold(
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
appBar: AppBar(
|
||||
// title: Text(widget.episodeItem.feedTitle),
|
||||
// title: Text(widget.episodeItem.feedTitle),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: Stack(
|
||||
|
@ -197,13 +201,12 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
|||
padding: EdgeInsets.only(top: 5.0),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
//physics: AlwaysScrollableScrollPhysics(),
|
||||
controller: _controller,
|
||||
child: _loaddes
|
||||
? (_description.contains('<'))
|
||||
? Html(
|
||||
padding:
|
||||
EdgeInsets.only(left: 20.0, right: 20, bottom: 10),
|
||||
padding: EdgeInsets.only(
|
||||
left: 20.0, right: 20, bottom: 10),
|
||||
defaultTextStyle: TextStyle(height: 1.8),
|
||||
data: _description,
|
||||
linkStyle: TextStyle(
|
||||
|
@ -215,24 +218,48 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
|||
},
|
||||
useRichText: true,
|
||||
)
|
||||
: Container(
|
||||
padding:
|
||||
EdgeInsets.only(left: 20.0, right: 20.0, bottom: 10.0),
|
||||
alignment: Alignment.topLeft,
|
||||
child: SelectableLinkify(
|
||||
onOpen: (link) {
|
||||
_launchUrl(link.url);
|
||||
},
|
||||
text: _description,
|
||||
style: TextStyle(
|
||||
height: 1.8,
|
||||
),
|
||||
linkStyle: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
decoration: TextDecoration.underline,
|
||||
),
|
||||
),
|
||||
)
|
||||
: _description.length > 0
|
||||
? Container(
|
||||
padding: EdgeInsets.only(
|
||||
left: 20.0,
|
||||
right: 20.0,
|
||||
bottom: 10.0),
|
||||
alignment: Alignment.topLeft,
|
||||
child: SelectableLinkify(
|
||||
onOpen: (link) {
|
||||
_launchUrl(link.url);
|
||||
},
|
||||
text: _description,
|
||||
style: TextStyle(
|
||||
height: 1.8,
|
||||
),
|
||||
linkStyle: TextStyle(
|
||||
color:
|
||||
Theme.of(context).accentColor,
|
||||
decoration:
|
||||
TextDecoration.underline,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Container(
|
||||
height: context.width,
|
||||
alignment: Alignment.center,
|
||||
child: Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Image(
|
||||
image: AssetImage(
|
||||
'assets/shownote.png'),
|
||||
height: 100.0,
|
||||
),
|
||||
Padding(padding: EdgeInsets.all(5.0)),
|
||||
Text(
|
||||
'Still no shownote received\n for this episode.', textAlign: TextAlign.center,
|
||||
style: TextStyle(color: context.textTheme.bodyText1.color.withOpacity(0.5))),
|
||||
],
|
||||
),
|
||||
)
|
||||
: Center(),
|
||||
),
|
||||
),
|
||||
|
@ -259,10 +286,9 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
|||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: MenuBar(
|
||||
episodeItem: widget.episodeItem,
|
||||
heroTag: widget.heroTag,
|
||||
hide: widget.hide
|
||||
),
|
||||
episodeItem: widget.episodeItem,
|
||||
heroTag: widget.heroTag,
|
||||
hide: widget.hide),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -279,7 +305,8 @@ class MenuBar extends StatefulWidget {
|
|||
final EpisodeBrief episodeItem;
|
||||
final String heroTag;
|
||||
final bool hide;
|
||||
MenuBar({this.episodeItem, this.heroTag, this.hide, Key key}) : super(key: key);
|
||||
MenuBar({this.episodeItem, this.heroTag, this.hide, Key key})
|
||||
: super(key: key);
|
||||
@override
|
||||
_MenuBarState createState() => _MenuBarState();
|
||||
}
|
||||
|
@ -349,10 +376,11 @@ class _MenuBarState extends State<MenuBar> {
|
|||
height: 30.0,
|
||||
width: 30.0,
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
child: widget.hide ? Center() :
|
||||
CircleAvatar(
|
||||
backgroundImage:
|
||||
FileImage(File("${widget.episodeItem.imagePath}"))),
|
||||
child: widget.hide
|
||||
? Center()
|
||||
: CircleAvatar(
|
||||
backgroundImage:
|
||||
FileImage(File("${widget.episodeItem.imagePath}"))),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -72,20 +72,19 @@ class AboutApp extends StatelessWidget {
|
|||
image: AssetImage('assets/logo.png'),
|
||||
height: 80,
|
||||
),
|
||||
Text('Version: 0.1.5'),
|
||||
Text('Version: 0.1.6'),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 50),
|
||||
height: 50,
|
||||
child: Text(
|
||||
'Tsacdop is a podcast player developed in flutter, a simple, beautiful, and easy-use application.',
|
||||
'Tsacdop is a podcast player developed in flutter, a simply beautiful, and friendly app.',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(5.0),
|
||||
padding: EdgeInsets.all(10.0),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.only(top: 20.0, bottom: 10.0),
|
||||
|
@ -113,7 +112,7 @@ class AboutApp extends StatelessWidget {
|
|||
'https://twitter.com/shimenmen'),
|
||||
_listItem(
|
||||
context,
|
||||
'Stone Gate',
|
||||
'Medium',
|
||||
LineIcons.medium,
|
||||
'https://medium.com/@stonegate'),
|
||||
],
|
||||
|
|
|
@ -71,10 +71,10 @@ class MyRoundSliderThumpShape extends SliderComponentShape {
|
|||
begin: _disabledThumbRadius,
|
||||
end: enabledThumbRadius,
|
||||
);
|
||||
final ColorTween colorTween = ColorTween(
|
||||
begin: sliderTheme.disabledThumbColor,
|
||||
end: sliderTheme.thumbColor,
|
||||
);
|
||||
// final ColorTween colorTween = ColorTween(
|
||||
// begin: sliderTheme.disabledThumbColor,
|
||||
// end: sliderTheme.thumbColor,
|
||||
// );
|
||||
|
||||
canvas.drawCircle(
|
||||
center,
|
||||
|
@ -157,7 +157,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
var audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
|
||||
return Selector<AudioPlayerNotifier, Tuple3<bool, int, double>>(
|
||||
selector: (_, audio) =>
|
||||
Tuple3(audio.showStopWatch, audio.timeLeft, audio.switchValue),
|
||||
Tuple3(audio.startSleepTimer, audio.timeLeft, audio.switchValue),
|
||||
builder: (_, data, __) {
|
||||
return Container(
|
||||
height: 300,
|
||||
|
@ -547,17 +547,14 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
Spacer(),
|
||||
Selector<AudioPlayerNotifier, Tuple3<EpisodeBrief, bool, bool>>(
|
||||
selector: (_, audio) => Tuple3(
|
||||
audio.episode, audio.stopOnComplete, audio.showStopWatch),
|
||||
audio.episode, audio.stopOnComplete, audio.startSleepTimer),
|
||||
builder: (_, data, __) {
|
||||
return Container(
|
||||
padding: EdgeInsets.all(12.0),
|
||||
padding: EdgeInsets.all(5.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.all(5.0),
|
||||
),
|
||||
Container(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
|
@ -568,7 +565,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
),
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 5.0),
|
||||
width: 200,
|
||||
width: 150,
|
||||
child: Text(
|
||||
data.item1.feedTitle,
|
||||
maxLines: 1,
|
||||
|
@ -578,6 +575,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
Spacer(),
|
||||
LastPosition(),
|
||||
IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
onPressed: () => Navigator.push(
|
||||
context,
|
||||
SlideUptRoute(
|
||||
|
@ -1007,8 +1005,9 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
builder: (_, audioplay, __) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Spacer(),
|
||||
audioplay == BasicPlaybackState.playing
|
||||
? InkWell(
|
||||
onTap:
|
||||
|
@ -1032,7 +1031,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
padding: EdgeInsets.symmetric(vertical: 10.0),
|
||||
child: Container(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
|
@ -1214,7 +1213,7 @@ class _ImageRotateState extends State<ImageRotate>
|
|||
return Transform.rotate(
|
||||
angle: 2 * math.pi * _value,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
padding: EdgeInsets.symmetric(vertical: 10.0),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(15.0)),
|
||||
child: Container(
|
||||
|
|
|
@ -482,8 +482,8 @@ class ShowEpisode extends StatelessWidget {
|
|||
padding: const EdgeInsets.all(5.0),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
childAspectRatio: 1.0,
|
||||
crossAxisCount: 3,
|
||||
childAspectRatio: 1.5,
|
||||
crossAxisCount: 2,
|
||||
mainAxisSpacing: 6.0,
|
||||
crossAxisSpacing: 6.0,
|
||||
),
|
||||
|
@ -529,15 +529,6 @@ class ShowEpisode extends StatelessWidget {
|
|||
);
|
||||
},
|
||||
child: Container(
|
||||
// decoration: BoxDecoration(
|
||||
// border: Border.all(
|
||||
// color: Theme.of(context).brightness ==
|
||||
// Brightness.light
|
||||
// ? Theme.of(context).primaryColor
|
||||
// : Theme.of(context).scaffoldBackgroundColor,
|
||||
// width: 0.0,
|
||||
// ),
|
||||
// ),
|
||||
padding: EdgeInsets.all(10.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
|
@ -560,7 +551,7 @@ class ShowEpisode extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
Spacer(),
|
||||
episodes[index].isNew == 1
|
||||
episodes[index].isNew == 1
|
||||
? Text(
|
||||
'New',
|
||||
style: TextStyle(
|
||||
|
@ -579,8 +570,8 @@ class ShowEpisode extends StatelessWidget {
|
|||
child: Text(
|
||||
episodes[index].title,
|
||||
style: TextStyle(
|
||||
fontSize: _width / 32,
|
||||
),
|
||||
//fontSize: _width / 32,
|
||||
),
|
||||
maxLines: 4,
|
||||
overflow: TextOverflow.fade,
|
||||
),
|
||||
|
@ -588,17 +579,37 @@ class ShowEpisode extends StatelessWidget {
|
|||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Container(
|
||||
alignment: Alignment.bottomLeft,
|
||||
child: Text(
|
||||
episodes[index].dateToString(),
|
||||
//podcast[index].pubDate.substring(4, 16),
|
||||
style: TextStyle(
|
||||
fontSize: _width / 35,
|
||||
color: _c,
|
||||
fontStyle: FontStyle.italic,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
alignment: Alignment.bottomLeft,
|
||||
child: Text(
|
||||
episodes[index].dateToString(),
|
||||
//podcast[index].pubDate.substring(4, 16),
|
||||
style: TextStyle(
|
||||
fontSize: _width / 35,
|
||||
color: _c,
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
episodes[index].duration != 0
|
||||
? Container(
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
(episodes[index].duration)
|
||||
.toString() +
|
||||
'mins',
|
||||
style: TextStyle(
|
||||
fontSize: _width / 35,
|
||||
// color: _c,
|
||||
// fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Center(),
|
||||
],
|
||||
)),
|
||||
],
|
||||
),
|
||||
|
@ -608,7 +619,7 @@ class ShowEpisode extends StatelessWidget {
|
|||
),
|
||||
);
|
||||
},
|
||||
childCount: (episodes.length > 3) ? 3 : episodes.length,
|
||||
childCount: (episodes.length > 2) ? 2 : episodes.length,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -88,121 +88,142 @@ class _PlaylistPageState extends State<PlaylistPage> {
|
|||
height: _topHeight,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
height: _topHeight,
|
||||
padding: EdgeInsets.only(
|
||||
left: 70,
|
||||
),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
text: _topHeight > 90 ? 'Playlist\n' : '',
|
||||
style: TextStyle(
|
||||
color:
|
||||
Theme.of(context).textTheme.bodyText1.color,
|
||||
fontSize: 30,
|
||||
),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: episodes.length.toString(),
|
||||
style: GoogleFonts.cairo(
|
||||
textStyle: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
fontSize: 30,
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Container(
|
||||
height: _topHeight,
|
||||
padding: EdgeInsets.only(
|
||||
left: 60,
|
||||
),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
text: _topHeight > 90 ? 'Playlist\n' : '',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.color,
|
||||
fontSize: 30,
|
||||
),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: episodes.length.toString(),
|
||||
style: GoogleFonts.cairo(
|
||||
textStyle: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: episodes.length < 2
|
||||
? ' episode '
|
||||
: ' episodes ',
|
||||
style: TextStyle(
|
||||
TextSpan(
|
||||
text: episodes.length < 2
|
||||
? 'episode'
|
||||
: 'episodes',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
fontSize: 15,
|
||||
)),
|
||||
TextSpan(
|
||||
text:
|
||||
_sumPlaylistLength(episodes).toString(),
|
||||
style: GoogleFonts.cairo(
|
||||
textStyle: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
fontSize: 20,
|
||||
fontSize: 25,
|
||||
)),
|
||||
TextSpan(
|
||||
text: _sumPlaylistLength(episodes).toString(),
|
||||
style: GoogleFonts.cairo(
|
||||
textStyle: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
fontSize: 30,
|
||||
)),
|
||||
),
|
||||
TextSpan(
|
||||
text: ' mins',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
fontSize: 20,
|
||||
)),
|
||||
],
|
||||
),
|
||||
TextSpan(
|
||||
text: 'mins',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
fontSize: 15,
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
Container(
|
||||
padding: EdgeInsets.only(
|
||||
right: 20,
|
||||
),
|
||||
child: data.item2
|
||||
? _topHeight < 90
|
||||
? Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
CircleAvatar(
|
||||
radius: 12,
|
||||
backgroundImage: FileImage(File(
|
||||
"${episodes.first.imagePath}")),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 15),
|
||||
child: SizedBox(
|
||||
width: 20,
|
||||
height: 15,
|
||||
child: WaveLoader()),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
CircleAvatar(
|
||||
radius: 15,
|
||||
//backgroundColor: _c.withOpacity(0.5),
|
||||
backgroundImage: FileImage(File(
|
||||
"${episodes.first.imagePath}")),
|
||||
),
|
||||
Container(
|
||||
width: 150,
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
episodes.first.title,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.fade,
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(5.0),
|
||||
margin: EdgeInsets.only(right: 20.0, bottom: 5.0),
|
||||
decoration: data.item2 ? BoxDecoration(
|
||||
color: context.brightness == Brightness.dark ? Colors.grey[800] : Colors.grey[200],
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(10.0)),
|
||||
) :
|
||||
BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Colors.transparent
|
||||
),
|
||||
child: data.item2
|
||||
? _topHeight < 90
|
||||
? Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
CircleAvatar(
|
||||
radius: 12,
|
||||
backgroundImage: FileImage(File(
|
||||
"${episodes.first.imagePath}")),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 15),
|
||||
child: SizedBox(
|
||||
width: 20,
|
||||
height: 15,
|
||||
child: WaveLoader()),
|
||||
),
|
||||
],
|
||||
)
|
||||
: IconButton(
|
||||
icon: Icon(Icons.play_circle_filled,
|
||||
size: 40,
|
||||
color: Theme.of(context).accentColor),
|
||||
onPressed: () => audio.playlistLoad(),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 15),
|
||||
child: SizedBox(
|
||||
width: 20,
|
||||
height: 15,
|
||||
child: WaveLoader()),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
CircleAvatar(
|
||||
radius: 15,
|
||||
//backgroundColor: _c.withOpacity(0.5),
|
||||
backgroundImage: FileImage(File(
|
||||
"${episodes.first.imagePath}")),
|
||||
),
|
||||
Container(
|
||||
width: 150,
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
episodes.first.title,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.fade,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 15),
|
||||
child: SizedBox(
|
||||
width: 20,
|
||||
height: 15,
|
||||
child: WaveLoader()),
|
||||
),
|
||||
],
|
||||
)
|
||||
: IconButton(
|
||||
padding: EdgeInsets.all(0),
|
||||
alignment: Alignment.center,
|
||||
icon: Icon(Icons.play_circle_filled,
|
||||
size: 40,
|
||||
color: Theme.of(context).accentColor),
|
||||
onPressed: () {
|
||||
audio.playlistLoad();
|
||||
// setState(() {});
|
||||
}),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -286,6 +307,7 @@ class _DismissibleContainerState extends State<DismissibleContainer> {
|
|||
var audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
|
||||
return AnimatedContainer(
|
||||
duration: Duration(milliseconds: 300),
|
||||
alignment: Alignment.center,
|
||||
height: _delete ? 0 : 95.0,
|
||||
child: _delete
|
||||
? Container(
|
||||
|
|
|
@ -195,12 +195,12 @@ class DBHelper {
|
|||
return result;
|
||||
}
|
||||
|
||||
Future<List<PlayHistory>> getPlayHistory() async {
|
||||
Future<List<PlayHistory>> getPlayHistory(int top) async {
|
||||
var dbClient = await database;
|
||||
List<Map> list = await dbClient.rawQuery(
|
||||
"""SELECT title, enclosure_url, seconds, seek_value, add_date FROM PlayHistory
|
||||
ORDER BY add_date DESC
|
||||
""");
|
||||
ORDER BY add_date DESC LIMIT ?
|
||||
""",[top]);
|
||||
List<PlayHistory> playHistory = [];
|
||||
list.forEach((record) {
|
||||
playHistory.add(PlayHistory(record['title'], record['enclosure_url'],
|
||||
|
|
|
@ -173,7 +173,7 @@ class _PodcastDetailState extends State<PodcastDetail> {
|
|||
void initState() {
|
||||
super.initState();
|
||||
_loadMore = false;
|
||||
_top = 33;
|
||||
_top = 99;
|
||||
_controller = ScrollController();
|
||||
}
|
||||
|
||||
|
|
|
@ -13,16 +13,26 @@ class PlayedHistory extends StatefulWidget {
|
|||
|
||||
class _PlayedHistoryState extends State<PlayedHistory>
|
||||
with SingleTickerProviderStateMixin {
|
||||
Future<List<PlayHistory>> getPlayHistory() async {
|
||||
Future<List<PlayHistory>> getPlayHistory(int top) async {
|
||||
DBHelper dbHelper = DBHelper();
|
||||
List<PlayHistory> playHistory;
|
||||
playHistory = await dbHelper.getPlayHistory();
|
||||
playHistory = await dbHelper.getPlayHistory(top);
|
||||
await Future.forEach(playHistory, (playHistory) async {
|
||||
await playHistory.getEpisode();
|
||||
});
|
||||
return playHistory;
|
||||
}
|
||||
|
||||
_loadMoreData() async {
|
||||
// await Future.delayed(Duration(seconds: 3));
|
||||
if (mounted)
|
||||
setState(() {
|
||||
_top = _top + 100;
|
||||
});
|
||||
}
|
||||
|
||||
int _top = 100;
|
||||
|
||||
Future<List<SubHistory>> getSubHistory() async {
|
||||
DBHelper dbHelper = DBHelper();
|
||||
return await dbHelper.getSubHistory();
|
||||
|
@ -126,94 +136,109 @@ class _PlayedHistoryState extends State<PlayedHistory>
|
|||
},
|
||||
body: TabBarView(controller: _controller, children: <Widget>[
|
||||
FutureBuilder<List<PlayHistory>>(
|
||||
future: getPlayHistory(),
|
||||
future: getPlayHistory(_top),
|
||||
builder: (context, snapshot) {
|
||||
double _width = MediaQuery.of(context).size.width;
|
||||
return snapshot.hasData
|
||||
? ListView.builder(
|
||||
shrinkWrap: true,
|
||||
scrollDirection: Axis.vertical,
|
||||
itemCount: snapshot.data.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return Container(
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
ListTile(
|
||||
title: Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.start,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
DateFormat.yMd().add_jm().format(
|
||||
snapshot.data[index].playdate),
|
||||
style: TextStyle(
|
||||
color: const Color(0xff67727d),
|
||||
fontSize: 15,
|
||||
fontStyle: FontStyle.italic),
|
||||
),
|
||||
Text(
|
||||
snapshot.data[index].title,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: Container(
|
||||
width: _width,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Icon(
|
||||
Icons.timelapse,
|
||||
color: Colors.grey[400],
|
||||
),
|
||||
Container(
|
||||
height: 2,
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: Colors.grey[400],
|
||||
width: 2.0))),
|
||||
width: _width *
|
||||
snapshot.data[index]
|
||||
.seekValue <
|
||||
(_width - 120)
|
||||
? _width *
|
||||
snapshot
|
||||
.data[index].seekValue
|
||||
: _width - 120,
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 2),
|
||||
),
|
||||
Container(
|
||||
width: 50,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.accentColor,
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(10))),
|
||||
padding: EdgeInsets.all(2),
|
||||
child: Text(
|
||||
_stringForSeconds(
|
||||
snapshot.data[index].seconds),
|
||||
? NotificationListener<ScrollNotification>(
|
||||
onNotification: (ScrollNotification scrollInfo) {
|
||||
if (scrollInfo.metrics.pixels ==
|
||||
scrollInfo.metrics.maxScrollExtent &&
|
||||
snapshot.data.length == _top)
|
||||
_loadMoreData();
|
||||
return true;
|
||||
},
|
||||
child: ListView.builder(
|
||||
//shrinkWrap: true,
|
||||
scrollDirection: Axis.vertical,
|
||||
itemCount: snapshot.data.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return Container(
|
||||
color:
|
||||
Theme.of(context).scaffoldBackgroundColor,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
ListTile(
|
||||
title: Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.start,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
DateFormat.yMd().add_jm().format(
|
||||
snapshot
|
||||
.data[index].playdate),
|
||||
style: TextStyle(
|
||||
color: Colors.white),
|
||||
color:
|
||||
const Color(0xff67727d),
|
||||
fontSize: 15,
|
||||
fontStyle: FontStyle.italic),
|
||||
),
|
||||
Text(
|
||||
snapshot.data[index].title,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: Container(
|
||||
width: _width,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Icon(
|
||||
Icons.timelapse,
|
||||
color: Colors.grey[400],
|
||||
),
|
||||
Container(
|
||||
height: 2,
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: Colors
|
||||
.grey[400],
|
||||
width: 2.0))),
|
||||
width: _width *
|
||||
snapshot.data[index]
|
||||
.seekValue <
|
||||
(_width - 120)
|
||||
? _width *
|
||||
snapshot.data[index]
|
||||
.seekValue
|
||||
: _width - 120,
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 2),
|
||||
),
|
||||
Container(
|
||||
width: 50,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.accentColor,
|
||||
borderRadius:
|
||||
BorderRadius.all(
|
||||
Radius.circular(
|
||||
10))),
|
||||
padding: EdgeInsets.all(2),
|
||||
child: Text(
|
||||
_stringForSeconds(snapshot
|
||||
.data[index].seconds),
|
||||
style: TextStyle(
|
||||
color: Colors.white),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
// Divider(height: 2),
|
||||
],
|
||||
),
|
||||
// Divider(height: 2),
|
||||
],
|
||||
),
|
||||
);
|
||||
})
|
||||
);
|
||||
}),
|
||||
)
|
||||
: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
|
|
|
@ -41,5 +41,8 @@ List<Libries> plugins = [
|
|||
Libries('audio_service', mit, 'https://pub.dev/packages/audio_service'),
|
||||
Libries('just_audio', apacheLicense, 'https://pub.dev/packages/just_audio'),
|
||||
Libries('line_icons', gpl, 'https://pub.dev/packages/line_icons'),
|
||||
Libries('flutter_file_dialog', bsd, 'https://pub.dev/packages/flutter_file_dialog')
|
||||
Libries('flutter_file_dialog', bsd, 'https://pub.dev/packages/flutter_file_dialog'),
|
||||
Libries('flutter_linkify', mit, 'https://pub.dev/packages/flutter_linkify'),
|
||||
Libries('extended_nested_scroll_view', mit, 'https://pub.dev/packages/extended_nested_scroll_view'),
|
||||
Libries('connectivity', bsd, 'https://pub.dev/packages/connectivity'),
|
||||
];
|
|
@ -195,7 +195,7 @@ class Settings extends StatelessWidget {
|
|||
EdgeInsets.symmetric(horizontal: 25.0),
|
||||
leading: Icon(LineIcons.map_signs_solid),
|
||||
title: Text('Changelog'),
|
||||
subtitle: Text('List of chagnes'),
|
||||
subtitle: Text('List of changes'),
|
||||
),
|
||||
Divider(height: 2),
|
||||
ListTile(
|
||||
|
@ -213,7 +213,7 @@ class Settings extends StatelessWidget {
|
|||
Divider(height: 2),
|
||||
ListTile(
|
||||
onTap: () => _launchUrl(
|
||||
'mailto:<xijieyin@gmail.com>?subject=Tsacdop Feedback'),
|
||||
'mailto:<tsacdop.app@gmail.com>?subject=Tsacdop Feedback'),
|
||||
contentPadding:
|
||||
EdgeInsets.symmetric(horizontal: 25.0),
|
||||
leading: Icon(LineIcons.bug_solid),
|
||||
|
|
|
@ -58,7 +58,7 @@ class StorageSetting extends StatelessWidget {
|
|||
EdgeInsets.only(left: 80.0, right: 25),
|
||||
title: Text('Ask before using cellular data'),
|
||||
subtitle: Text(
|
||||
'Ask to confirem when using cellular data to download episodes.'),
|
||||
'Ask to confirm when using cellular data to download episodes.'),
|
||||
trailing: Selector<SettingState, bool>(
|
||||
selector: (_, settings) =>
|
||||
settings.downloadUsingData,
|
||||
|
|
|
@ -8,4 +8,5 @@ extension ContextExtension on BuildContext{
|
|||
Brightness get brightness => Theme.of(this).brightness;
|
||||
double get width => MediaQuery.of(this).size.width;
|
||||
double get height => MediaQuery.of(this).size.width;
|
||||
TextTheme get textTheme => Theme.of(this).textTheme;
|
||||
}
|
|
@ -1,4 +1,7 @@
|
|||
//Fork from https://github.com/divyanshub024/day_night_switch
|
||||
//Copyright https://github.com/divyanshub024
|
||||
//Apache License 2.0 https://github.com/divyanshub024/day_night_switch/blob/master/LICENSE
|
||||
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
|
|
|
@ -104,7 +104,7 @@ class EpisodeGrid extends StatelessWidget {
|
|||
const EdgeInsets.only(top: 5.0, bottom: 5.0, left: 15.0, right: 15.0),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
childAspectRatio: 1.0,
|
||||
childAspectRatio: 1,
|
||||
crossAxisCount: 3,
|
||||
mainAxisSpacing: 6.0,
|
||||
crossAxisSpacing: 6.0,
|
||||
|
@ -213,7 +213,7 @@ class EpisodeGrid extends StatelessWidget {
|
|||
child: Text(
|
||||
episodes[index].title,
|
||||
style: TextStyle(
|
||||
fontSize: _width / 32,
|
||||
// fontSize: _width / 32,
|
||||
),
|
||||
maxLines: 4,
|
||||
overflow: TextOverflow.fade,
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
Forked from https://github.com/witochandra/webfeed
|
||||
Forked from https://github.com/witochandra/webfeed
|
||||
Copyright https://github.com/witochandra ALL RIGHT RESERVED
|
||||
Mit License https://github.com/witochandra/webfeed/blob/master/LICENSE
|
|
@ -11,7 +11,7 @@ description: An easy-use podacasts player.
|
|||
# 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: 0.1.5
|
||||
version: 0.1.6
|
||||
|
||||
environment:
|
||||
sdk: ">=2.6.0 <3.0.0"
|
||||
|
@ -56,7 +56,6 @@ dev_dependencies:
|
|||
just_audio:
|
||||
git:
|
||||
url: https://github.com/stonega/just_audio.git
|
||||
rxdart: ^0.23.1
|
||||
line_icons:
|
||||
git:
|
||||
url: https://github.com/galonsos/line_icons.git
|
||||
|
|
Loading…
Reference in New Issue