Update to flutter2.0.
This commit is contained in:
parent
61312ab36a
commit
e0d7a8d60f
|
@ -34,7 +34,6 @@ import 'download_list.dart';
|
|||
import 'home_groups.dart';
|
||||
import 'home_menu.dart';
|
||||
import 'import_opml.dart';
|
||||
import 'playlist.dart';
|
||||
import 'search_podcast.dart';
|
||||
|
||||
class Home extends StatefulWidget {
|
||||
|
@ -479,15 +478,6 @@ class __PlaylistButtonState extends State<_PlaylistButton> {
|
|||
builder: (context) => PlaylistHome(),
|
||||
),
|
||||
);
|
||||
} else if (value == 2) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => PlaylistPage(
|
||||
initPage: InitPage.history,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
|
|
|
@ -1,786 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:line_icons/line_icons.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
import '../local_storage/sqflite_localpodcast.dart';
|
||||
import '../state/audio_state.dart';
|
||||
import '../type/episodebrief.dart';
|
||||
import '../type/play_histroy.dart';
|
||||
import '../type/playlist.dart';
|
||||
import '../util/extension_helper.dart';
|
||||
import '../widgets/custom_widget.dart';
|
||||
|
||||
enum InitPage { playlist, history }
|
||||
|
||||
class PlaylistPage extends StatefulWidget {
|
||||
final InitPage initPage;
|
||||
PlaylistPage({this.initPage, Key key}) : super(key: key);
|
||||
@override
|
||||
_PlaylistPageState createState() => _PlaylistPageState();
|
||||
}
|
||||
|
||||
class _PlaylistPageState extends State<PlaylistPage> {
|
||||
final textstyle = TextStyle(fontSize: 15.0, color: Colors.black);
|
||||
var _loadList;
|
||||
int _sumPlaylistLength(List<EpisodeBrief> episodes) {
|
||||
var sum = 0;
|
||||
if (episodes.length == 0) {
|
||||
return sum;
|
||||
} else {
|
||||
for (var episode in episodes) {
|
||||
sum += episode.duration ~/ 60;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
|
||||
Future<double> _getListenTime() async {
|
||||
var dbHelper = DBHelper();
|
||||
var listenTime = await dbHelper.listenMins(0);
|
||||
return listenTime;
|
||||
}
|
||||
|
||||
bool _loadHistory = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.initPage == InitPage.playlist) {
|
||||
_loadList = _ReorderablePlaylist();
|
||||
} else {
|
||||
_loadHistory = true;
|
||||
_loadList = _HistoryList();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = context.s;
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
systemNavigationBarIconBrightness:
|
||||
Theme.of(context).accentColorBrightness,
|
||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
||||
),
|
||||
child: Scaffold(
|
||||
backgroundColor: context.primaryColor,
|
||||
appBar: AppBar(
|
||||
elevation: 0,
|
||||
backgroundColor: context.accentColor.withAlpha(70),
|
||||
leading: CustomBackButton(),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Selector<AudioPlayerNotifier,
|
||||
Tuple3<Playlist, bool, EpisodeBrief>>(
|
||||
selector: (_, audio) =>
|
||||
Tuple3(audio.playlist, audio.playerRunning, audio.episode),
|
||||
builder: (_, data, __) {
|
||||
var episodes = data.item1.episodes;
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
color: context.accentColor.withAlpha(70),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Container(
|
||||
height: 100,
|
||||
padding: EdgeInsets.only(
|
||||
left: 60,
|
||||
),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
_loadHistory
|
||||
? s.settingsHistory
|
||||
: s.homeMenuPlaylist,
|
||||
style: TextStyle(
|
||||
color: context.textColor,
|
||||
fontSize: 30,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 5),
|
||||
IconButton(
|
||||
icon: _loadHistory
|
||||
? Icon(Icons.playlist_play)
|
||||
: Icon(Icons.history),
|
||||
onPressed: () => setState(() {
|
||||
_loadHistory = !_loadHistory;
|
||||
if (_loadHistory) {
|
||||
_loadList = _HistoryList();
|
||||
} else {
|
||||
_loadList =
|
||||
_ReorderablePlaylist();
|
||||
}
|
||||
}))
|
||||
],
|
||||
),
|
||||
_loadHistory
|
||||
? FutureBuilder<double>(
|
||||
future: _getListenTime(),
|
||||
initialData: 0.0,
|
||||
builder: (context, snapshot) =>
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
text: 'Today ',
|
||||
style: GoogleFonts.cairo(
|
||||
textStyle: TextStyle(
|
||||
color: context.accentColor,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text:
|
||||
'${snapshot.data.toStringAsFixed(0)} ',
|
||||
style: GoogleFonts.cairo(
|
||||
textStyle: TextStyle(
|
||||
color: context.accentColor,
|
||||
fontSize: 25,
|
||||
)),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'mins',
|
||||
style: TextStyle(
|
||||
color: context.accentColor,
|
||||
fontSize: 15,
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
: RichText(
|
||||
text: TextSpan(
|
||||
text: episodes.length.toString(),
|
||||
style: GoogleFonts.cairo(
|
||||
textStyle: TextStyle(
|
||||
color:
|
||||
Theme.of(context).accentColor,
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: episodes.length < 2
|
||||
? 'episode'
|
||||
: 'episodes',
|
||||
style: TextStyle(
|
||||
color: context.accentColor,
|
||||
fontSize: 15,
|
||||
)),
|
||||
TextSpan(
|
||||
text: _sumPlaylistLength(episodes)
|
||||
.toString(),
|
||||
style: GoogleFonts.cairo(
|
||||
textStyle: TextStyle(
|
||||
color: context.accentColor,
|
||||
fontSize: 25,
|
||||
)),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'mins',
|
||||
style: TextStyle(
|
||||
color: context.accentColor,
|
||||
fontSize: 15,
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
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.circular(10.0),
|
||||
)
|
||||
: BoxDecoration(color: Colors.transparent),
|
||||
child: data.item2
|
||||
? Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
CircleAvatar(
|
||||
radius: 15,
|
||||
backgroundImage:
|
||||
data.item3.avatarImage),
|
||||
Container(
|
||||
width: 150,
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
data.item3.title,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.fade,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 15),
|
||||
child: SizedBox(
|
||||
width: 20,
|
||||
height: 15,
|
||||
child: WaveLoader(
|
||||
color: context.accentColor,
|
||||
)),
|
||||
),
|
||||
],
|
||||
)
|
||||
: IconButton(
|
||||
icon: Icon(Icons.play_circle_filled,
|
||||
size: 40, color: context.accentColor),
|
||||
onPressed: () {
|
||||
//audio.playlistLoad();
|
||||
// setState(() {});
|
||||
}),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
color: context.primaryColor,
|
||||
child: AnimatedSwitcher(
|
||||
duration: Duration(milliseconds: 300),
|
||||
child: _loadList),
|
||||
)),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ReorderablePlaylist extends StatefulWidget {
|
||||
_ReorderablePlaylist({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
__ReorderablePlaylistState createState() => __ReorderablePlaylistState();
|
||||
}
|
||||
|
||||
class __ReorderablePlaylistState extends State<_ReorderablePlaylist> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
|
||||
return Selector<AudioPlayerNotifier, Tuple2<Playlist, bool>>(
|
||||
selector: (_, audio) => Tuple2(audio.queue, audio.playerRunning),
|
||||
builder: (_, data, __) {
|
||||
var episodes = data.item1.episodes;
|
||||
return ReorderableListView(
|
||||
onReorder: (oldIndex, newIndex) {
|
||||
if (newIndex > oldIndex) {
|
||||
newIndex -= 1;
|
||||
}
|
||||
audio.reorderPlaylist(oldIndex, newIndex);
|
||||
setState(() {});
|
||||
},
|
||||
scrollDirection: Axis.vertical,
|
||||
children: data.item2
|
||||
? episodes.map<Widget>((episode) {
|
||||
if (episode.enclosureUrl != episodes.first.enclosureUrl) {
|
||||
return _DismissibleContainer(
|
||||
episode: episode,
|
||||
onRemove: (value) => setState(() {}),
|
||||
key: ValueKey(episode.enclosureUrl),
|
||||
);
|
||||
} else {
|
||||
return Container(
|
||||
key: ValueKey('sd'),
|
||||
);
|
||||
}
|
||||
}).toList()
|
||||
: episodes
|
||||
.map<Widget>((episode) => _DismissibleContainer(
|
||||
episode: episode,
|
||||
onRemove: (value) => setState(() {}),
|
||||
key: ValueKey(episode.enclosureUrl),
|
||||
))
|
||||
.toList());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class _DismissibleContainer extends StatefulWidget {
|
||||
final EpisodeBrief episode;
|
||||
final ValueChanged<bool> onRemove;
|
||||
_DismissibleContainer({this.episode, this.onRemove, Key key})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
__DismissibleContainerState createState() => __DismissibleContainerState();
|
||||
}
|
||||
|
||||
class __DismissibleContainerState extends State<_DismissibleContainer> {
|
||||
bool _delete;
|
||||
Widget _episodeTag(String text, Color color) {
|
||||
if (text == '') {
|
||||
return Center();
|
||||
}
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: color, borderRadius: BorderRadius.circular(15.0)),
|
||||
height: 25.0,
|
||||
margin: EdgeInsets.only(right: 10.0),
|
||||
padding: EdgeInsets.symmetric(horizontal: 8.0),
|
||||
alignment: Alignment.center,
|
||||
child: Text(text, style: TextStyle(fontSize: 14.0, color: Colors.black)),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_delete = false;
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
|
||||
final s = context.s;
|
||||
final c = widget.episode.backgroudColor(context);
|
||||
return AnimatedContainer(
|
||||
duration: Duration(milliseconds: 300),
|
||||
curve: Curves.easeInSine,
|
||||
alignment: Alignment.center,
|
||||
height: _delete ? 0 : 90.0,
|
||||
child: _delete
|
||||
? Container(
|
||||
color: Colors.transparent,
|
||||
)
|
||||
: Dismissible(
|
||||
key: ValueKey('${widget.episode.enclosureUrl}t'),
|
||||
background: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle, color: Colors.red),
|
||||
padding: EdgeInsets.all(5),
|
||||
alignment: Alignment.center,
|
||||
child: Icon(
|
||||
LineIcons.alternateTrash,
|
||||
color: Colors.white,
|
||||
size: 15,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle, color: Colors.red),
|
||||
padding: EdgeInsets.all(5),
|
||||
alignment: Alignment.center,
|
||||
child: Icon(
|
||||
LineIcons.alternateTrash,
|
||||
color: Colors.white,
|
||||
size: 15,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
height: 30,
|
||||
color: context.accentColor,
|
||||
),
|
||||
onDismissed: (direction) async {
|
||||
setState(() {
|
||||
_delete = true;
|
||||
});
|
||||
var index = await audio.delFromPlaylist(widget.episode);
|
||||
widget.onRemove(true);
|
||||
final episodeRemove = widget.episode;
|
||||
Scaffold.of(context).removeCurrentSnackBar();
|
||||
Scaffold.of(context).showSnackBar(SnackBar(
|
||||
behavior: SnackBarBehavior.floating,
|
||||
backgroundColor: Colors.grey[800],
|
||||
content: Text(s.toastRemovePlaylist,
|
||||
style: TextStyle(color: Colors.white)),
|
||||
action: SnackBarAction(
|
||||
textColor: context.accentColor,
|
||||
label: s.undo,
|
||||
onPressed: () async {
|
||||
await audio.addToPlaylistAt(episodeRemove, index);
|
||||
widget.onRemove(false);
|
||||
}),
|
||||
));
|
||||
},
|
||||
child: SizedBox(
|
||||
height: 90.0,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 8),
|
||||
onTap: () async {
|
||||
await audio.episodeLoad(widget.episode);
|
||||
widget.onRemove(true);
|
||||
},
|
||||
title: Container(
|
||||
padding: EdgeInsets.fromLTRB(0, 5.0, 20.0, 5.0),
|
||||
child: Text(
|
||||
widget.episode.title,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
leading: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(Icons.unfold_more, color: c),
|
||||
CircleAvatar(
|
||||
backgroundColor: c.withOpacity(0.5),
|
||||
backgroundImage: widget.episode.avatarImage),
|
||||
],
|
||||
),
|
||||
subtitle: Container(
|
||||
padding: EdgeInsets.only(top: 5, bottom: 5),
|
||||
height: 35,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
if (widget.episode.explicit == 1)
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.red[800],
|
||||
shape: BoxShape.circle),
|
||||
height: 25.0,
|
||||
width: 25.0,
|
||||
margin: EdgeInsets.only(right: 10.0),
|
||||
alignment: Alignment.center,
|
||||
child: Text('E',
|
||||
style: TextStyle(color: Colors.white))),
|
||||
if (widget.episode.duration != 0)
|
||||
_episodeTag(
|
||||
widget.episode.duration == 0
|
||||
? ''
|
||||
: s.minsCount(
|
||||
widget.episode.duration ~/ 60),
|
||||
Colors.cyan[300]),
|
||||
if (widget.episode.enclosureLength != null)
|
||||
_episodeTag(
|
||||
widget.episode.enclosureLength == 0
|
||||
? ''
|
||||
: '${(widget.episode.enclosureLength) ~/ 1000000}MB',
|
||||
Colors.lightBlue[300]),
|
||||
],
|
||||
),
|
||||
),
|
||||
//trailing: Icon(Icons.menu),
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
height: 2,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _HistoryList extends StatefulWidget {
|
||||
_HistoryList({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
__HistoryListState createState() => __HistoryListState();
|
||||
}
|
||||
|
||||
class __HistoryListState extends State<_HistoryList> {
|
||||
var dbHelper = DBHelper();
|
||||
bool _loadMore = false;
|
||||
Future _getData;
|
||||
|
||||
Future<List<PlayHistory>> getPlayRecords(int top) async {
|
||||
List<PlayHistory> playHistory;
|
||||
playHistory = await dbHelper.getPlayRecords(top);
|
||||
for (var record in playHistory) {
|
||||
await record.getEpisode();
|
||||
}
|
||||
return playHistory;
|
||||
}
|
||||
|
||||
Future<void> _loadMoreData() async {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_loadMore = true;
|
||||
});
|
||||
}
|
||||
await Future.delayed(Duration(milliseconds: 500));
|
||||
_top = _top + 20;
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_getData = getPlayRecords(_top);
|
||||
_loadMore = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
int _top;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_top = 20;
|
||||
_getData = getPlayRecords(_top);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = context.s;
|
||||
final audio = context.watch<AudioPlayerNotifier>();
|
||||
return FutureBuilder<List<PlayHistory>>(
|
||||
future: _getData,
|
||||
builder: (context, snapshot) {
|
||||
return snapshot.hasData
|
||||
? NotificationListener<ScrollNotification>(
|
||||
onNotification: (scrollInfo) {
|
||||
if (scrollInfo.metrics.pixels ==
|
||||
scrollInfo.metrics.maxScrollExtent &&
|
||||
snapshot.data.length == _top) {
|
||||
if (!_loadMore) {
|
||||
_loadMoreData();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.vertical,
|
||||
itemCount: snapshot.data.length + 1,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == snapshot.data.length) {
|
||||
return SizedBox(
|
||||
height: 2,
|
||||
child: _loadMore
|
||||
? LinearProgressIndicator()
|
||||
: Center());
|
||||
} else {
|
||||
final seekValue = snapshot.data[index].seekValue;
|
||||
final seconds = snapshot.data[index].seconds;
|
||||
final date = snapshot
|
||||
.data[index].playdate.millisecondsSinceEpoch;
|
||||
final episode = snapshot.data[index].episode;
|
||||
final c = episode?.backgroudColor(context);
|
||||
return episode == null
|
||||
? Center()
|
||||
: SizedBox(
|
||||
height: 90.0,
|
||||
child: Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.fromLTRB(
|
||||
24, 8, 20, 8),
|
||||
onTap: () => audio.episodeLoad(
|
||||
episode,
|
||||
startPosition: seekValue < 0.9
|
||||
? (seconds * 1000).toInt()
|
||||
: 0),
|
||||
leading: CircleAvatar(
|
||||
backgroundColor:
|
||||
c?.withOpacity(0.5),
|
||||
backgroundImage:
|
||||
episode.avatarImage),
|
||||
title: Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: 5.0),
|
||||
child: Text(
|
||||
snapshot.data[index].title,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
subtitle: SizedBox(
|
||||
height: 40,
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.start,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
if (seekValue < 0.9)
|
||||
Padding(
|
||||
padding:
|
||||
EdgeInsets.symmetric(
|
||||
vertical: 5.0),
|
||||
child: Material(
|
||||
color:
|
||||
Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
audio.episodeLoad(
|
||||
episode,
|
||||
startPosition:
|
||||
(seconds *
|
||||
1000)
|
||||
.toInt());
|
||||
},
|
||||
borderRadius:
|
||||
BorderRadius
|
||||
.circular(20),
|
||||
child: Stack(
|
||||
children: [
|
||||
ShaderMask(
|
||||
shaderCallback:
|
||||
(bounds) {
|
||||
return LinearGradient(
|
||||
begin: Alignment
|
||||
.centerLeft,
|
||||
colors: <
|
||||
Color>[
|
||||
Colors
|
||||
.cyan[600]
|
||||
.withOpacity(0.8),
|
||||
Colors
|
||||
.white70
|
||||
],
|
||||
stops: [
|
||||
seekValue,
|
||||
seekValue
|
||||
],
|
||||
tileMode:
|
||||
TileMode
|
||||
.mirror,
|
||||
).createShader(
|
||||
bounds);
|
||||
},
|
||||
child:
|
||||
Container(
|
||||
height: 25,
|
||||
alignment:
|
||||
Alignment
|
||||
.center,
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal:
|
||||
20),
|
||||
decoration:
|
||||
BoxDecoration(
|
||||
borderRadius:
|
||||
BorderRadius.circular(
|
||||
20.0),
|
||||
color: context
|
||||
.accentColor,
|
||||
),
|
||||
child: Text(
|
||||
seconds
|
||||
.toTime,
|
||||
style: TextStyle(
|
||||
color:
|
||||
Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
]),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
child: Selector<
|
||||
AudioPlayerNotifier,
|
||||
List<EpisodeBrief>>(
|
||||
selector: (_, audio) =>
|
||||
audio.queue.episodes,
|
||||
builder: (_, data, __) {
|
||||
return data.contains(
|
||||
episode)
|
||||
? IconButton(
|
||||
icon: Icon(
|
||||
Icons
|
||||
.playlist_add_check,
|
||||
color: context
|
||||
.accentColor),
|
||||
onPressed:
|
||||
() async {
|
||||
audio.delFromPlaylist(
|
||||
episode);
|
||||
Fluttertoast
|
||||
.showToast(
|
||||
msg: s
|
||||
.toastRemovePlaylist,
|
||||
gravity:
|
||||
ToastGravity
|
||||
.BOTTOM,
|
||||
);
|
||||
})
|
||||
: IconButton(
|
||||
icon: Icon(
|
||||
Icons
|
||||
.playlist_add,
|
||||
color: Colors
|
||||
.grey[
|
||||
700]),
|
||||
onPressed:
|
||||
() async {
|
||||
audio.addToPlaylist(
|
||||
episode);
|
||||
Fluttertoast
|
||||
.showToast(
|
||||
msg: s
|
||||
.toastAddPlaylist,
|
||||
gravity:
|
||||
ToastGravity
|
||||
.BOTTOM,
|
||||
);
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
Text(
|
||||
date.toDate(context),
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Divider(height: 1)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}),
|
||||
)
|
||||
: Center(
|
||||
child: SizedBox(
|
||||
height: 25,
|
||||
width: 25,
|
||||
child: CircularProgressIndicator()),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -7,10 +7,10 @@ import 'package:file_picker/file_picker.dart';
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_media_metadata/flutter_media_metadata.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:image/image.dart' as img;
|
||||
import 'package:line_icons/line_icons.dart';
|
||||
import 'package:media_metadata_retriever/media_metadata_retriever.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
@ -952,7 +952,7 @@ class __NewPlaylistState extends State<_NewPlaylist> {
|
|||
}
|
||||
|
||||
Future<EpisodeBrief> _getEpisodeFromFile(String path) async {
|
||||
var metadataRetriever = MediaMetadataRetriever();
|
||||
var metadataRetriever = MetadataRetriever();
|
||||
final fileLength = File(path).statSync().size;
|
||||
final pubDate = DateTime.now().millisecondsSinceEpoch;
|
||||
var primaryColor;
|
||||
|
|
|
@ -408,6 +408,7 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
_seekSliderValue = 0;
|
||||
_episode = episodeNew;
|
||||
_playerRunning = true;
|
||||
_playlist = _queue;
|
||||
notifyListeners();
|
||||
_startAudioService(_queue, position: startPosition);
|
||||
}
|
||||
|
|
|
@ -1247,7 +1247,7 @@ class _MyDropdownButtonState<T> extends State<MyDropdownButton<T>>
|
|||
padding: _kMenuItemPadding.resolve(textDirection),
|
||||
selectedIndex: _selectedIndex ?? 0,
|
||||
elevation: widget.elevation,
|
||||
theme: Theme.of(context, shadowThemeOnly: true),
|
||||
theme: Theme.of(context),
|
||||
style: _textStyle,
|
||||
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
|
||||
itemHeight: widget.itemHeight,
|
||||
|
@ -1317,7 +1317,7 @@ class _MyDropdownButtonState<T> extends State<MyDropdownButton<T>>
|
|||
widget.onChanged != null;
|
||||
|
||||
Orientation _getOrientation(BuildContext context) {
|
||||
var result = MediaQuery.of(context, nullOk: true)?.orientation;
|
||||
var result = MediaQuery.of(context)?.orientation;
|
||||
if (result == null) {
|
||||
// If there's no MediaQuery, then use the window aspect to determine
|
||||
// orientation.
|
||||
|
|
|
@ -358,7 +358,7 @@ Future<T> _showMenu<T>({
|
|||
initialValue: initialValue,
|
||||
elevation: elevation,
|
||||
semanticLabel: label,
|
||||
theme: Theme.of(context, shadowThemeOnly: true),
|
||||
theme: Theme.of(context),
|
||||
popupMenuTheme: PopupMenuTheme.of(context),
|
||||
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
|
||||
shape: shape,
|
||||
|
|
48
pubspec.yaml
48
pubspec.yaml
|
@ -11,53 +11,44 @@ dependencies:
|
|||
sdk: flutter
|
||||
flutter_localizations:
|
||||
sdk: flutter
|
||||
auto_animated: ^2.1.0
|
||||
auto_animated: ^3.0.0
|
||||
audio_session: ^0.0.9
|
||||
cached_network_image: ^2.3.3
|
||||
cached_network_image: ^2.5.1
|
||||
color_thief_flutter: ^1.0.2
|
||||
confetti: ^0.5.4+1
|
||||
cookie_jar: ^1.0.1
|
||||
cupertino_icons: ^1.0.0
|
||||
connectivity: ^2.0.2
|
||||
convert: ^2.1.1
|
||||
crypto: ^2.1.5
|
||||
device_info: ^0.4.2+8
|
||||
confetti: ^0.5.5
|
||||
cupertino_icons: ^1.0.2
|
||||
connectivity: ^3.0.2
|
||||
crypto: ^3.0.0
|
||||
device_info: ^2.0.0
|
||||
dio: ^3.0.10
|
||||
dio_cookie_manager: ^1.0.0
|
||||
extended_nested_scroll_view: ^1.0.1
|
||||
effective_dart: ^1.3.0
|
||||
extended_nested_scroll_view: ^3.0.0
|
||||
effective_dart: ^1.3.1
|
||||
equatable: ^1.2.5
|
||||
feature_discovery: ^0.13.0
|
||||
feature_discovery: ^0.13.0+2
|
||||
file_picker: ^2.1.4
|
||||
flutter_html: ^0.11.1
|
||||
fluttertoast: ^4.0.1
|
||||
flutter_isolate: ^1.0.0+14
|
||||
flutter_linkify: ^4.0.2
|
||||
flutter_file_dialog: ^1.0.0
|
||||
flutter_cache_manager: ^1.4.0
|
||||
flare_flutter: ^2.0.6
|
||||
fl_chart: ^0.12.2
|
||||
line_icons: ^1.3.2
|
||||
marquee: ^1.6.1
|
||||
media_metadata_retriever:
|
||||
git:
|
||||
url: https://github.com/stonega/media_metadata_retriever.git
|
||||
google_fonts: ^1.1.1
|
||||
image: ^2.1.19
|
||||
intl: ^0.16.1
|
||||
flutter_media_metadata: ^0.0.3+2
|
||||
marquee: ^1.7.0
|
||||
google_fonts: ^2.0.0
|
||||
image: ^3.0.1
|
||||
intl: ^0.17.0
|
||||
json_serializable: ^3.5.1
|
||||
json_annotation: ^3.1.1
|
||||
path_provider: ^1.6.24
|
||||
permission_handler: ^5.0.1
|
||||
provider: ^4.3.2
|
||||
rxdart: ^0.24.1
|
||||
sqflite: ^1.3.2+1
|
||||
shared_preferences: ^0.5.12
|
||||
state_notifier: ^0.6.0
|
||||
tuple: ^1.0.3
|
||||
url_launcher: ^5.7.10
|
||||
uuid: ^2.2.2
|
||||
xml: ^4.2.0
|
||||
workmanager: ^0.2.3
|
||||
wc_flutter_share: ^0.2.2
|
||||
flutter_downloader:
|
||||
|
@ -77,6 +68,15 @@ dependencies:
|
|||
url: https://github.com/stonega/webfeed.git
|
||||
|
||||
dependency_overrides:
|
||||
path_provider: ^2.0.1
|
||||
http_parser: ^4.0.0
|
||||
cookie_jar: ^2.0.0
|
||||
uuid: ^3.0.1
|
||||
http: ^0.13.0
|
||||
flutter_cache_manager: ^2.1.2
|
||||
shared_preferences: 2.0.0
|
||||
convert: ^3.0.0
|
||||
xml: ^5.0.2
|
||||
linkify:
|
||||
git:
|
||||
url: https://github.com/stonega/linkify.git
|
||||
|
|
Loading…
Reference in New Issue