1
0
mirror of https://github.com/stonega/tsacdop synced 2025-02-03 08:57:33 +01:00

Change player widget UI

Change homepage to nested scroll
This commit is contained in:
stonegate 2020-03-25 23:33:48 +08:00
parent be5de73ddc
commit 97ec6a59e4
18 changed files with 1036 additions and 739 deletions

View File

@ -9,7 +9,8 @@ jobs:
steps: steps:
- checkout - checkout
- run: flutter upgrade - run: cd /home/cirrus/sdks/flutter && git remote add origin https://github.com/flutter/flutter
- run: flutter upgrade && cd /home/cirrus/project/tsacdop
- run: - run:
name: Run Flutter doctor name: Run Flutter doctor
command: flutter doctor command: flutter doctor

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<classpath> <classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-10/"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/> <classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/> <classpathentry kind="output" path="bin/default"/>
</classpath> </classpath>

View File

@ -155,11 +155,7 @@ class AudioPlayerNotifier extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
// set setStopOnComplete(bool boo) { set autoPlaySwitch(bool boo) {
// _stopOnComplete = boo;
//}
set autoPlaySwitch(bool boo) {
_autoPlay = boo; _autoPlay = boo;
notifyListeners(); notifyListeners();
} }
@ -168,6 +164,9 @@ class AudioPlayerNotifier extends ChangeNotifier {
void addListener(VoidCallback listener) async { void addListener(VoidCallback listener) async {
super.addListener(listener); super.addListener(listener);
await AudioService.connect(); await AudioService.connect();
if(await AudioService.running){
AudioService.stop();
}
} }
loadPlaylist() async { loadPlaylist() async {
@ -515,7 +514,7 @@ class AudioPlayerTask extends BackgroundAudioTask {
_skipState = BasicPlaybackState.skippingToNext; _skipState = BasicPlaybackState.skippingToNext;
await _audioPlayer.setUrl(mediaItem.id); await _audioPlayer.setUrl(mediaItem.id);
print(mediaItem.id); print(mediaItem.id);
Duration duration = await _audioPlayer.durationFuture; Duration duration = await _audioPlayer.durationFuture ?? 0;
AudioServiceBackground.setMediaItem( AudioServiceBackground.setMediaItem(
mediaItem.copyWith(duration: duration.inMilliseconds)); mediaItem.copyWith(duration: duration.inMilliseconds));
_skipState = null; _skipState = null;

View File

@ -12,6 +12,7 @@ class PodcastLocal {
final String description; final String description;
final int upateCount; final int upateCount;
final int episodeCount;
PodcastLocal( PodcastLocal(
this.title, this.title,
this.imageUrl, this.imageUrl,
@ -25,6 +26,7 @@ class PodcastLocal {
{ {
this.description ='', this.description ='',
this.upateCount = 0, this.upateCount = 0,
this.episodeCount = 0
} }
); );
} }

View File

@ -197,13 +197,13 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
padding: EdgeInsets.only(top: 5.0), padding: EdgeInsets.only(top: 5.0),
child: SingleChildScrollView( child: SingleChildScrollView(
scrollDirection: Axis.vertical, scrollDirection: Axis.vertical,
physics: AlwaysScrollableScrollPhysics(), //physics: AlwaysScrollableScrollPhysics(),
controller: _controller, controller: _controller,
child: _loaddes child: _loaddes
? (_description.contains('<')) ? (_description.contains('<'))
? Html( ? Html(
padding: padding:
EdgeInsets.symmetric(horizontal: 20.0), EdgeInsets.only(left: 20.0, right: 20, bottom: 10),
defaultTextStyle: TextStyle(height: 1.8), defaultTextStyle: TextStyle(height: 1.8),
data: _description, data: _description,
linkStyle: TextStyle( linkStyle: TextStyle(
@ -217,7 +217,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
) )
: Container( : Container(
padding: padding:
EdgeInsets.symmetric(horizontal: 20.0), EdgeInsets.only(left: 20.0, right: 20.0, bottom: 10.0),
alignment: Alignment.topLeft, alignment: Alignment.topLeft,
child: SelectableLinkify( child: SelectableLinkify(
onOpen: (link) { onOpen: (link) {

View File

@ -72,7 +72,7 @@ class AboutApp extends StatelessWidget {
image: AssetImage('assets/logo.png'), image: AssetImage('assets/logo.png'),
height: 80, height: 80,
), ),
Text('Version: 0.1.4'), Text('Version: 0.1.5'),
], ],
), ),
), ),

View File

@ -18,10 +18,10 @@ import 'package:tsacdop/class/podcast_group.dart';
import 'package:tsacdop/class/searchpodcast.dart'; import 'package:tsacdop/class/searchpodcast.dart';
import 'package:tsacdop/class/podcastlocal.dart'; import 'package:tsacdop/class/podcastlocal.dart';
import 'package:tsacdop/local_storage/sqflite_localpodcast.dart'; import 'package:tsacdop/local_storage/sqflite_localpodcast.dart';
import 'package:tsacdop/home/home.dart';
import 'package:tsacdop/home/appbar/popupmenu.dart'; import 'package:tsacdop/home/appbar/popupmenu.dart';
import 'package:tsacdop/webfeed/webfeed.dart'; import 'package:tsacdop/webfeed/webfeed.dart';
import 'package:tsacdop/.env.dart'; import 'package:tsacdop/.env.dart';
import '../nested_home.dart';
class MyHomePage extends StatefulWidget { class MyHomePage extends StatefulWidget {
@override @override

View File

@ -5,9 +5,9 @@ import 'dart:math' as math;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:marquee/marquee.dart'; import 'package:marquee/marquee.dart';
import 'package:line_icons/line_icons.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
import 'package:audio_service/audio_service.dart'; import 'package:audio_service/audio_service.dart';
import 'package:flutter_neumorphic/flutter_neumorphic.dart';
import 'package:tsacdop/class/episodebrief.dart'; import 'package:tsacdop/class/episodebrief.dart';
import 'package:tsacdop/class/audiostate.dart'; import 'package:tsacdop/class/audiostate.dart';
@ -17,7 +17,6 @@ import 'package:tsacdop/util/pageroute.dart';
import 'package:tsacdop/util/colorize.dart'; import 'package:tsacdop/util/colorize.dart';
import 'package:tsacdop/util/day_night_switch.dart'; import 'package:tsacdop/util/day_night_switch.dart';
//Custom slider
class MyRectangularTrackShape extends RectangularSliderTrackShape { class MyRectangularTrackShape extends RectangularSliderTrackShape {
Rect getPreferredRect({ Rect getPreferredRect({
@required RenderBox parentBox, @required RenderBox parentBox,
@ -83,14 +82,28 @@ class MyRoundSliderThumpShape extends SliderComponentShape {
..style = PaintingStyle.fill ..style = PaintingStyle.fill
..strokeWidth = 2, ..strokeWidth = 2,
); );
// Path _path = Path();
// _path.moveTo(center.dx - 12, center.dy + 10);
// _path.lineTo(center.dx - 12, center.dy - 12);
// _path.lineTo(center.dx -12, center.dy - 12);
// canvas.drawShadow(_path, Colors.black, 4, false);
// Path _pathLight = Path();
// _pathLight.moveTo(center.dx + 12, center.dy - 12);
// _pathLight.lineTo(center.dx + 12, center.dy + 10);
//// _pathLight.lineTo(center.dx - 12, center.dy + 10);
// canvas.drawShadow(_pathLight, Colors.black, 4, true);
canvas.drawRect( canvas.drawRect(
Rect.fromLTRB( Rect.fromLTRB(
center.dx - 10, center.dy + 10, center.dx + 10, center.dy - 10), center.dx - 10, center.dy + 10, center.dx + 10, center.dy - 10),
Paint() Paint()
..color = colorTween.evaluate(enableAnimation) ..color = Colors.white
..style = PaintingStyle.fill ..style = PaintingStyle.fill
..strokeWidth = 10, ..strokeWidth = 10,
); );
canvas.drawLine( canvas.drawLine(
Offset(center.dx - 5, center.dy - 2), Offset(center.dx - 5, center.dy - 2),
Offset(center.dx + 5, center.dy + 2), Offset(center.dx + 5, center.dy + 2),
@ -113,6 +126,22 @@ class _PlayerWidgetState extends State<PlayerWidget> {
return '${(seconds ~/ 60)}:${(seconds.truncate() % 60).toString().padLeft(2, '0')}'; return '${(seconds ~/ 60)}:${(seconds.truncate() % 60).toString().padLeft(2, '0')}';
} }
List<BoxShadow> _customShadow = [
BoxShadow(blurRadius: 26, offset: Offset(-6, -6), color: Colors.white),
BoxShadow(
blurRadius: 8,
offset: Offset(2, 2),
color: Colors.grey[600].withOpacity(0.4))
];
List<BoxShadow> _customShadowNight = [
BoxShadow(
blurRadius: 6,
offset: Offset(-1, -1),
color: Colors.grey[100].withOpacity(0.3)),
BoxShadow(blurRadius: 8, offset: Offset(2, 2), color: Colors.black)
];
List minsToSelect = [1, 5, 10, 15, 20, 25, 30, 45, 60, 70, 80, 90, 99]; List minsToSelect = [1, 5, 10, 15, 20, 25, 30, 45, 60, 70, 80, 90, 99];
int _minSelected; int _minSelected;
@ -137,7 +166,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
height: 300, height: 300,
color: data.item3 > 0 color: data.item3 > 0
? Colors.black.withOpacity(data.item3) ? Colors.black.withOpacity(data.item3)
: Theme.of(context).scaffoldBackgroundColor, : Theme.of(context).primaryColor,
child: Stack( child: Stack(
children: <Widget>[ children: <Widget>[
Column( Column(
@ -149,54 +178,60 @@ class _PlayerWidgetState extends State<PlayerWidget> {
), ),
SingleChildScrollView( SingleChildScrollView(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
child: Row( child: Padding(
crossAxisAlignment: CrossAxisAlignment.center, padding: EdgeInsets.symmetric(vertical: 20),
children: minsToSelect child: Row(
.map((e) => InkWell( crossAxisAlignment: CrossAxisAlignment.center,
onTap: () => setState(() => _minSelected = e), children: minsToSelect
child: Stack( .map((e) => InkWell(
alignment: Alignment.center, onTap: () => setState(() => _minSelected = e),
children: <Widget>[ child: Stack(
AnimatedContainer( alignment: Alignment.center,
duration: Duration(milliseconds: 300), children: <Widget>[
curve: Curves.elasticOut, Container(
margin: EdgeInsets.symmetric( margin: EdgeInsets.symmetric(
horizontal: 10.0), horizontal: 10.0),
decoration: BoxDecoration( decoration: BoxDecoration(
boxShadow: [ boxShadow: !(e == _minSelected ||
BoxShadow( data.item3 > 0)
color: Colors.grey[800], ? (Theme.of(context).brightness ==
blurRadius: 0, Brightness.dark)
offset: Offset(0, 0)), ? _customShadowNight
], : _customShadow
color: (e == _minSelected) : [
? Theme.of(context).accentColor BoxShadow(
: Theme.of(context).primaryColorDark, color: Colors.black,
shape: BoxShape.circle, blurRadius: 0,
offset: Offset(0, 0)),
],
color: (e == _minSelected)
? Theme.of(context).accentColor
: Theme.of(context).primaryColor,
shape: BoxShape.circle,
),
alignment: Alignment.center,
height: 30,
width: 30,
child: Text(e.toString(),
style: TextStyle(
fontWeight: FontWeight.bold,
color: (e == _minSelected)
? Colors.white
: null)),
), ),
alignment: Alignment.center, Container(
height: (e == _minSelected) ? 40 : 30, height: 30 * data.item3,
width: (e == _minSelected) ? 40 : 30, width: 30 * data.item3,
child: Text(e.toString(), decoration: BoxDecoration(
style: TextStyle( color: Colors.black
fontWeight: FontWeight.bold, .withOpacity(data.item3),
color: Colors.white)), shape: BoxShape.circle),
), ),
Container( ],
height: (e == _minSelected) ),
? 40 * data.item3 ))
: 30 * data.item3, .toList(),
width: (e == _minSelected) ),
? 40 * data.item3
: 30 * data.item3,
decoration: BoxDecoration(
color: Colors.black,
shape: BoxShape.circle),
),
],
),
))
.toList(),
), ),
), ),
Container( Container(
@ -209,7 +244,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
value: data.item1, value: data.item1,
sunColor: Colors.yellow[700], sunColor: Colors.yellow[700],
moonColor: Colors.grey[600], moonColor: Colors.grey[600],
dayColor: Colors.grey[300], dayColor: Theme.of(context).primaryColorDark,
nightColor: Colors.black, nightColor: Colors.black,
onDrag: (value) => audio.setSwitchValue = value, onDrag: (value) => audio.setSwitchValue = value,
onChanged: (value) { onChanged: (value) {
@ -231,15 +266,13 @@ class _PlayerWidgetState extends State<PlayerWidget> {
alignment: Alignment.center, alignment: Alignment.center,
height: 25, height: 25,
width: 100, width: 100,
decoration: BoxDecoration( decoration: BoxDecoration(),
// color: Theme.of(context).accentColor,
),
child: Text(_stringForSeconds(data.item2.toDouble()), child: Text(_stringForSeconds(data.item2.toDouble()),
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 20, fontSize: 20,
color: Colors.white, color:
)), (data.item3 > 0) ? Colors.white : null)),
), ),
], ],
), ),
@ -247,7 +280,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
], ],
), ),
Positioned( Positioned(
bottom: 60 + 20 * data.item3, bottom: 50 + 20 * data.item3,
left: MediaQuery.of(context).size.width / 2 - 100, left: MediaQuery.of(context).size.width / 2 - 100,
width: 200, width: 200,
child: Container( child: Container(
@ -302,7 +335,10 @@ class _PlayerWidgetState extends State<PlayerWidget> {
padding: EdgeInsets.only(top: 10, left: 10, right: 10), padding: EdgeInsets.only(top: 10, left: 10, right: 10),
child: SliderTheme( child: SliderTheme(
data: SliderTheme.of(context).copyWith( data: SliderTheme.of(context).copyWith(
activeTrackColor: Colors.grey[400], activeTrackColor:
Theme.of(context).brightness == Brightness.dark
? Colors.black38
: Colors.grey[400],
inactiveTrackColor: inactiveTrackColor:
Theme.of(context).primaryColorDark, Theme.of(context).primaryColorDark,
trackHeight: 20.0, trackHeight: 20.0,
@ -315,7 +351,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
overlayColor: overlayColor:
Theme.of(context).accentColor.withAlpha(32), Theme.of(context).accentColor.withAlpha(32),
overlayShape: overlayShape:
RoundSliderOverlayShape(overlayRadius: 14.0), RoundSliderOverlayShape(overlayRadius: 4.0),
), ),
child: Slider( child: Slider(
value: data.seekSliderValue, value: data.seekSliderValue,
@ -387,32 +423,68 @@ class _PlayerWidgetState extends State<PlayerWidget> {
iconSize: 32.0, iconSize: 32.0,
icon: Icon(Icons.replay_10), icon: Icon(Icons.replay_10),
color: Colors.grey[500]), color: Colors.grey[500]),
backplay == BasicPlaybackState.playing Container(
? IconButton( margin: EdgeInsets.symmetric(horizontal: 30),
padding: EdgeInsets.symmetric(horizontal: 30.0), height: 60,
onPressed: width: 60,
backplay == BasicPlaybackState.playing decoration: BoxDecoration(
? () { color: Theme.of(context).primaryColor,
audio.pauseAduio(); shape: BoxShape.circle,
} border: Border.all(
: null, color: Theme.of(context).brightness ==
iconSize: 60.0, Brightness.dark
icon: Icon( ? Colors.black12
LineIcons.pause_circle, : Colors.white10,
size: 40, width: 1),
boxShadow: Theme.of(context).brightness ==
Brightness.dark
? _customShadowNight
: _customShadow),
child: backplay == BasicPlaybackState.playing
? Material(
color: Colors.transparent,
child: InkWell(
borderRadius:
BorderRadius.all(Radius.circular(30)),
onTap:
backplay == BasicPlaybackState.playing
? () {
audio.pauseAduio();
}
: null,
child: SizedBox(
height: 60,
width: 60,
child: Icon(
Icons.pause,
size: 40,
),
),
),
)
: Material(
color: Colors.transparent,
child: InkWell(
borderRadius:
BorderRadius.all(Radius.circular(30)),
onTap:
backplay == BasicPlaybackState.playing
? null
: () {
audio.resumeAudio();
},
child: SizedBox(
height: 60,
width: 60,
child: Icon(
Icons.play_arrow,
size: 40,
color: Theme.of(context).accentColor,
),
),
),
), ),
color: Colors.grey[500]) ),
: IconButton(
padding: EdgeInsets.symmetric(horizontal: 30.0),
onPressed:
backplay == BasicPlaybackState.playing
? null
: () {
audio.resumeAudio();
},
iconSize: 60.0,
icon: Icon(LineIcons.play_circle, size: 40),
color: Colors.grey[500]),
IconButton( IconButton(
padding: EdgeInsets.symmetric(horizontal: 30.0), padding: EdgeInsets.symmetric(horizontal: 30.0),
onPressed: backplay == BasicPlaybackState.playing onPressed: backplay == BasicPlaybackState.playing
@ -497,6 +569,11 @@ class _PlayerWidgetState extends State<PlayerWidget> {
FileImage(File("${data.item1.imagePath}")), FileImage(File("${data.item1.imagePath}")),
), ),
), ),
Container(
padding: EdgeInsets.symmetric(horizontal: 5.0),
width: 200,
child: Text(data.item1.feedTitle, maxLines: 1, overflow: TextOverflow.fade,),
),
Spacer(), Spacer(),
IconButton( IconButton(
onPressed: () => Navigator.push( onPressed: () => Navigator.push(
@ -530,105 +607,127 @@ class _PlayerWidgetState extends State<PlayerWidget> {
//padding: EdgeInsets.only(bottom: 10.0), //padding: EdgeInsets.only(bottom: 10.0),
decoration: BoxDecoration( decoration: BoxDecoration(
// borderRadius: BorderRadius.all(Radius.circular(10.0)), // borderRadius: BorderRadius.all(Radius.circular(10.0)),
color: Theme.of(context).scaffoldBackgroundColor, color: Theme.of(context).primaryColor,
), ),
child: Column( child: Selector<AudioPlayerNotifier, List<EpisodeBrief>>(
mainAxisAlignment: MainAxisAlignment.start, selector: (_, audio) => audio.queue.playlist,
mainAxisSize: MainAxisSize.min, builder: (_, playlist, __) {
children: <Widget>[ return ListView.builder(
SingleChildScrollView( shrinkWrap: true,
scrollDirection: Axis.vertical, scrollDirection: Axis.vertical,
child: Container( itemCount: playlist.length,
height: 50, itemBuilder: (BuildContext context, int index) {
padding: EdgeInsets.symmetric(horizontal: 20.0), print(playlist.length);
alignment: Alignment.center, if (index == 0) {
child: Row( return Container(
mainAxisAlignment: MainAxisAlignment.center, height: 60,
mainAxisSize: MainAxisSize.min, padding: EdgeInsets.symmetric(horizontal: 20.0),
children: <Widget>[ alignment: Alignment.center,
Text( child: Row(
'NEXT TO PLAY', mainAxisAlignment: MainAxisAlignment.center,
style: TextStyle( mainAxisSize: MainAxisSize.min,
color: Theme.of(context).accentColor, children: <Widget>[
fontWeight: FontWeight.bold), Text(
'Playlist',
style: TextStyle(
color: Theme.of(context).accentColor,
fontWeight: FontWeight.bold,
fontSize: 16),
),
Spacer(),
Container(
alignment: Alignment.center,
child: Container(
alignment: Alignment.center,
height: 40,
width: 80,
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius:
BorderRadius.all(Radius.circular(20)),
border: Border.all(
color: Theme.of(context).brightness ==
Brightness.dark
? Colors.black12
: Colors.white10,
width: 1),
boxShadow: Theme.of(context).brightness ==
Brightness.dark
? _customShadowNight
: _customShadow),
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius:
BorderRadius.all(Radius.circular(20)),
onTap: () => audio.playNext(),
child: SizedBox(
height: 40,
width: 80,
child: Icon(
Icons.skip_next,
size: 30,
),
),
),
),
),
),
],
), ),
Spacer(), );
], } else {
), return Column(
), children: <Widget>[
), Material(
Expanded( color: Colors.transparent,
child: Selector<AudioPlayerNotifier, List<EpisodeBrief>>( child: InkWell(
selector: (_, audio) => audio.queue.playlist, onTap: () {
builder: (_, playlist, __) { audio.episodeLoad(playlist[index]);
return ListView.builder( },
shrinkWrap: true, child: Container(
scrollDirection: Axis.vertical, height: 60,
itemCount: playlist.length, padding: EdgeInsets.symmetric(horizontal: 10),
itemBuilder: (BuildContext context, int index) { alignment: Alignment.centerLeft,
print(playlist.length); child: Row(
return index == 0 mainAxisAlignment: MainAxisAlignment.center,
? Center() crossAxisAlignment: CrossAxisAlignment.center,
: Column( mainAxisSize: MainAxisSize.min,
children: <Widget>[ children: <Widget>[
Material( Container(
color: Colors.transparent, padding: EdgeInsets.all(10.0),
child: InkWell( child: ClipRRect(
onTap: () { borderRadius:
audio.episodeLoad(playlist[index]); BorderRadius.all(Radius.circular(15.0)),
},
child: Container( child: Container(
height: 60, height: 30.0,
padding: width: 30.0,
EdgeInsets.symmetric(horizontal: 10), child: Image.file(File(
alignment: Alignment.centerLeft, "${playlist[index].imagePath}"))),
// decoration: BoxDecoration( ),
// color: Theme.of(context) ),
// .scaffoldBackgroundColor, Expanded(
// ), child: Container(
child: Row( alignment: Alignment.centerLeft,
mainAxisAlignment: child: Text(
MainAxisAlignment.center, playlist[index].title,
crossAxisAlignment: maxLines: 1,
CrossAxisAlignment.center, overflow: TextOverflow.ellipsis,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
padding: EdgeInsets.all(10.0),
child: ClipRRect(
borderRadius: BorderRadius.all(
Radius.circular(15.0)),
child: Container(
height: 30.0,
width: 30.0,
child: Image.file(File(
"${playlist[index].imagePath}"))),
),
),
Expanded(
child: Container(
alignment: Alignment.centerLeft,
child: Text(
playlist[index].title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
),
],
),
), ),
), ),
), ),
Divider(height: 2),
], ],
); ),
}, ),
),
),
Divider(height: 2),
],
); );
}, }
), },
), );
], },
), ),
), ),
); );

View File

@ -1,28 +0,0 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'hometab.dart';
import 'package:tsacdop/home/appbar/importompl.dart';
import 'package:tsacdop/home/audioplayer.dart';
import 'home_groups.dart';
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Stack(children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Import(),
Container(child: ScrollPodcasts()),
Expanded(
child: MainTab(),
),
],
),
Container(child: PlayerWidget()),
]);
}
}

View File

@ -43,100 +43,105 @@ class _ScrollPodcastsState extends State<ScrollPodcasts> {
height: (_width - 20) / 3 + 140, height: (_width - 20) / 3 + 140,
) )
: groups[_groupIndex].podcastList.length == 0 : groups[_groupIndex].podcastList.length == 0
? Column( ? Container(
mainAxisAlignment: MainAxisAlignment.start, height: (_width - 20) / 3 + 140,
mainAxisSize: MainAxisSize.min, child: Column(
children: <Widget>[ mainAxisAlignment: MainAxisAlignment.start,
GestureDetector( mainAxisSize: MainAxisSize.min,
onVerticalDragEnd: (event) { children: <Widget>[
if (event.primaryVelocity > 200) { GestureDetector(
if (groups.length == 1) { onVerticalDragEnd: (event) {
Fluttertoast.showToast( if (event.primaryVelocity > 200) {
msg: 'Add some groups', if (groups.length == 1) {
gravity: ToastGravity.BOTTOM, Fluttertoast.showToast(
); msg: 'Add some groups',
} else { gravity: ToastGravity.BOTTOM,
if (mounted) );
} else {
if (mounted)
setState(() {
(_groupIndex != 0)
? _groupIndex--
: _groupIndex = groups.length - 1;
});
}
} else if (event.primaryVelocity < -200) {
if (groups.length == 1) {
Fluttertoast.showToast(
msg: 'Add some groups',
gravity: ToastGravity.BOTTOM,
);
} else {
setState(() { setState(() {
(_groupIndex != 0) (_groupIndex < groups.length - 1)
? _groupIndex-- ? _groupIndex++
: _groupIndex = groups.length - 1; : _groupIndex = 0;
}); });
}
} }
} else if (event.primaryVelocity < -200) { },
if (groups.length == 1) { child: Column(
Fluttertoast.showToast( children: <Widget>[
msg: 'Add some groups', Container(
gravity: ToastGravity.BOTTOM, child: Row(
); children: <Widget>[
} else { Container(
setState(() { padding: EdgeInsets.symmetric(
(_groupIndex < groups.length - 1) horizontal: 15.0),
? _groupIndex++ child: Text(
: _groupIndex = 0; groups[_groupIndex].name,
}); style: Theme.of(context)
} .textTheme
} .bodyText1
}, .copyWith(
child: Column( color: Theme.of(context)
children: <Widget>[ .accentColor),
Container( )),
child: Row( Spacer(),
children: <Widget>[ Container(
Container( height: 30,
padding: EdgeInsets.symmetric( padding:
horizontal: 15.0), EdgeInsets.symmetric(horizontal: 15),
child: Text( alignment: Alignment.bottomRight,
groups[_groupIndex].name, child: InkWell(
style: Theme.of(context) onTap: () {
.textTheme Navigator.push(
.bodyText1 context,
.copyWith( SlideLeftRoute(
color: Theme.of(context) page: PodcastManage()),
.accentColor), );
)), },
Spacer(), child: Container(
Container( height: 30,
height: 30, padding: EdgeInsets.all(5.0),
padding: child: Text(
EdgeInsets.symmetric(horizontal: 15), 'See All',
alignment: Alignment.bottomRight, style: Theme.of(context)
child: InkWell( .textTheme
onTap: () { .bodyText1
Navigator.push( .copyWith(
context, color: Theme.of(context)
SlideLeftRoute(page: PodcastManage()), .accentColor),
); )),
}, ),
child: Container(
height: 30,
padding: EdgeInsets.all(5.0),
child: Text(
'See All',
style: Theme.of(context)
.textTheme
.bodyText1
.copyWith(
color: Theme.of(context)
.accentColor),
)),
), ),
), ],
], ),
), ),
), Container(
Container( height: 70,
height: 70, color:
color: Theme.of(context).scaffoldBackgroundColor, Theme.of(context).scaffoldBackgroundColor,
), ),
], ],
)), )),
Container( Container(
height: (_width - 20) / 3 + 40, height: (_width - 20) / 3 + 40,
color: Theme.of(context).primaryColor, color: Theme.of(context).primaryColor,
margin: EdgeInsets.symmetric(horizontal: 15), margin: EdgeInsets.symmetric(horizontal: 15),
), ),
], ],
),
) )
: DefaultTabController( : DefaultTabController(
length: groups[_groupIndex].podcastList.length, length: groups[_groupIndex].podcastList.length,
@ -194,7 +199,7 @@ class _ScrollPodcastsState extends State<ScrollPodcasts> {
)), )),
Spacer(), Spacer(),
Container( Container(
height: 30, height: 30.0,
padding: padding:
EdgeInsets.symmetric(horizontal: 15), EdgeInsets.symmetric(horizontal: 15),
alignment: Alignment.bottomRight, alignment: Alignment.bottomRight,
@ -223,7 +228,6 @@ class _ScrollPodcastsState extends State<ScrollPodcasts> {
), ),
), ),
Container( Container(
// color: Colors.white10,
height: 70, height: 70,
width: _width, width: _width,
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,

View File

@ -1,33 +1,31 @@
import 'dart:io'; import 'dart:io';
import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart' hide NestedScrollView;
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:tsacdop/local_storage/key_value_storage.dart'; import 'package:tsacdop/home/playlist.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
import 'package:tsacdop/class/audiostate.dart'; import 'package:tsacdop/class/audiostate.dart';
import 'package:tsacdop/class/episodebrief.dart'; import 'package:tsacdop/class/episodebrief.dart';
import 'package:tsacdop/home/playlist.dart'; import 'package:tsacdop/local_storage/key_value_storage.dart';
import 'package:tsacdop/local_storage/sqflite_localpodcast.dart'; import 'package:tsacdop/local_storage/sqflite_localpodcast.dart';
import 'package:tsacdop/util/episodegrid.dart'; import 'package:tsacdop/util/episodegrid.dart';
import 'package:tsacdop/util/mypopupmenu.dart'; import 'package:tsacdop/util/mypopupmenu.dart';
class MainTab extends StatefulWidget { import 'package:tsacdop/home/appbar/importompl.dart';
import 'package:tsacdop/home/audioplayer.dart';
import 'home_groups.dart';
class Home extends StatefulWidget {
@override @override
_MainTabState createState() => _MainTabState(); _HomeState createState() => _HomeState();
} }
class _MainTabState extends State<MainTab> with TickerProviderStateMixin { class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
TabController _controller; TabController _controller;
bool _loadPlay; Decoration _getIndicator(BuildContext context) {
static String _stringForSeconds(int seconds) {
if (seconds == null) return null;
return '${(seconds ~/ 60)}:${(seconds.truncate() % 60).toString().padLeft(2, '0')}';
}
Decoration getIndicator(BuildContext context) {
return UnderlineTabIndicator( return UnderlineTabIndicator(
borderSide: BorderSide(color: Theme.of(context).accentColor, width: 2), borderSide: BorderSide(color: Theme.of(context).accentColor, width: 3),
insets: EdgeInsets.only( insets: EdgeInsets.only(
left: 10.0, left: 10.0,
right: 10.0, right: 10.0,
@ -35,6 +33,147 @@ class _MainTabState extends State<MainTab> with TickerProviderStateMixin {
)); ));
} }
@override
void initState() {
super.initState();
_controller = TabController(length: 3, vsync: this);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
double top = 0;
@override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
double height = (width - 20) / 3 + 140;
return SafeArea(
child: Stack(
children: <Widget>[
Column(
children: <Widget>[
Import(),
Expanded(
child: NestedScrollView(
headerSliverBuilder:
(BuildContext context, bool innerBoxScrolled) {
return <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return SizedBox(
height: height,
width: width,
child: ScrollPodcasts(),
);
},
childCount: 1,
),
),
SliverPersistentHeader(
delegate: _SliverAppBarDelegate(
TabBar(
indicator: _getIndicator(context),
isScrollable: true,
indicatorSize: TabBarIndicatorSize.tab,
controller: _controller,
tabs: <Widget>[
Tab(
child: Text('Recent Update'),
),
Tab(
child: Text('Favorite'),
),
Tab(
child: Text('Download'),
)
],
),
),
pinned: true,
),
];
},
body: TabBarView(
controller: _controller,
children: <Widget>[
_RecentUpdate(),
_MyFavorite(),
_MyDownload(),
],
),
),
),
Selector<AudioPlayerNotifier, bool>(
selector: (_, audio) => audio.playerRunning,
builder: (_, data, __) {
return Padding(
padding: EdgeInsets.only(bottom: data ? 60.0 : 0),
);
}),
],
),
Container(child: PlayerWidget()),
],
),
);
}
}
class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
_SliverAppBarDelegate(this._tabBar);
final TabBar _tabBar;
@override
double get minExtent => _tabBar.preferredSize.height + 2;
@override
double get maxExtent => _tabBar.preferredSize.height + 2;
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return Container(
color: Theme.of(context).scaffoldBackgroundColor,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
_tabBar,
Spacer(),
PlaylistButton(),
],
),
Container(height: 2, color: Theme.of(context).primaryColorDark),
],
),
);
}
@override
bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
return true;
}
}
class PlaylistButton extends StatefulWidget {
PlaylistButton({Key key}) : super(key: key);
@override
PlaylistButtonState createState() => PlaylistButtonState();
}
class PlaylistButtonState extends State<PlaylistButton> {
bool _loadPlay;
static String _stringForSeconds(int seconds) {
if (seconds == null) return null;
return '${(seconds ~/ 60)}:${(seconds.truncate() % 60).toString().padLeft(2, '0')}';
}
_getPlaylist() async { _getPlaylist() async {
await Provider.of<AudioPlayerNotifier>(context, listen: false) await Provider.of<AudioPlayerNotifier>(context, listen: false)
.loadPlaylist(); .loadPlaylist();
@ -43,7 +182,15 @@ class _MainTabState extends State<MainTab> with TickerProviderStateMixin {
}); });
} }
Widget playlist(BuildContext context) { @override
void initState() {
super.initState();
_loadPlay = false;
_getPlaylist();
}
@override
Widget build(BuildContext context) {
var audio = Provider.of<AudioPlayerNotifier>(context, listen: false); var audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
return MyPopupMenuButton<int>( return MyPopupMenuButton<int>(
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
@ -163,86 +310,14 @@ class _MainTabState extends State<MainTab> with TickerProviderStateMixin {
}, },
); );
} }
@override
void initState() {
super.initState();
_controller = TabController(length: 3, vsync: this);
_loadPlay = false;
_getPlaylist();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Row(
children: <Widget>[
Container(
padding: EdgeInsets.symmetric(horizontal: 10.0),
height: 50,
alignment: Alignment.bottomLeft,
child: TabBar(
indicatorSize: TabBarIndicatorSize.tab,
isScrollable: true,
labelPadding: EdgeInsets.all(10.0),
controller: _controller,
indicator: getIndicator(context),
tabs: <Widget>[
Text(
'Recent Update',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(
'Favorites',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(
'Downloads',
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
),
Spacer(),
playlist(context),
],
),
Container(height: 2, color: Theme.of(context).primaryColorDark),
Expanded(
child: Container(
child: TabBarView(
controller: _controller,
children: <Widget>[
Container(
child: RecentUpdate()),
Container(
child: MyFavorite()),
Container(
child: MyDownload()),
],
),
),
),
],
);
}
} }
class RecentUpdate extends StatefulWidget { class _RecentUpdate extends StatefulWidget {
@override @override
_RecentUpdateState createState() => _RecentUpdateState(); _RecentUpdateState createState() => _RecentUpdateState();
} }
class _RecentUpdateState extends State<RecentUpdate> { class _RecentUpdateState extends State<_RecentUpdate> {
int _updateCount = 0; int _updateCount = 0;
Future<List<EpisodeBrief>> _getRssItem(int top) async { Future<List<EpisodeBrief>> _getRssItem(int top) async {
var dbHelper = DBHelper(); var dbHelper = DBHelper();
@ -252,34 +327,24 @@ class _RecentUpdateState extends State<RecentUpdate> {
return episodes; return episodes;
} }
ScrollController _controller; _loadMoreEpisode() async {
if (mounted) setState(() => _loadMore = true);
await Future.delayed(Duration(seconds: 3));
if (mounted)
setState(() {
_top = _top + 33;
_loadMore = false;
});
}
int _top; int _top;
bool _loadMore; bool _loadMore;
_scrollListener() async {
if (_controller.offset == _controller.position.maxScrollExtent) {
if (mounted) setState(() => _loadMore = true);
await Future.delayed(Duration(seconds: 3));
if (mounted)
setState(() {
_top = _top + 33;
_loadMore = false;
});
}
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_loadMore = false; _loadMore = false;
_top = 33; _top = 33;
_controller = ScrollController();
_controller.addListener(_scrollListener);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
} }
@override @override
@ -289,14 +354,92 @@ class _RecentUpdateState extends State<RecentUpdate> {
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error); if (snapshot.hasError) print(snapshot.error);
return (snapshot.hasData) return (snapshot.hasData)
? CustomScrollView( ? NotificationListener<ScrollNotification>(
controller: _controller, onNotification: (ScrollNotification scrollInfo) {
physics: const AlwaysScrollableScrollPhysics(), if (scrollInfo.metrics.pixels ==
primary: false, scrollInfo.metrics.maxScrollExtent &&
slivers: <Widget>[ snapshot.data.length == _top) _loadMoreEpisode();
return true;
},
child: CustomScrollView(
key: PageStorageKey<String>('update'),
physics: const AlwaysScrollableScrollPhysics(),
slivers: <Widget>[
EpisodeGrid(
episodes: snapshot.data,
updateCount: _updateCount,
),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return _loadMore
? Container(
height: 2, child: LinearProgressIndicator())
: Center();
},
childCount: 1,
),
),
]),
)
: Center(child: CircularProgressIndicator());
},
);
}
}
class _MyFavorite extends StatefulWidget {
@override
_MyFavoriteState createState() => _MyFavoriteState();
}
class _MyFavoriteState extends State<_MyFavorite> {
Future<List<EpisodeBrief>> _getLikedRssItem(_top) async {
var dbHelper = DBHelper();
List<EpisodeBrief> episodes = await dbHelper.getLikedRssItem(_top);
return episodes;
}
_loadMoreEpisode() async {
if (mounted) setState(() => _loadMore = true);
await Future.delayed(Duration(seconds: 3));
if (mounted)
setState(() {
_top = _top + 33;
_loadMore = false;
});
}
int _top;
bool _loadMore;
@override
void initState() {
super.initState();
_loadMore = false;
_top = 33;
}
@override
Widget build(BuildContext context) {
return FutureBuilder<List<EpisodeBrief>>(
future: _getLikedRssItem(_top),
builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
return (snapshot.hasData)
? NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification scrollInfo) {
if (scrollInfo.metrics.pixels ==
scrollInfo.metrics.maxScrollExtent &&
snapshot.data.length == _top) _loadMoreEpisode();
return true;
},
child: CustomScrollView(
key: PageStorageKey<String>('favorite'),
physics: const AlwaysScrollableScrollPhysics(),
slivers: <Widget>[
EpisodeGrid( EpisodeGrid(
podcast: snapshot.data, episodes: snapshot.data,
updateCount: _updateCount,
), ),
SliverList( SliverList(
delegate: SliverChildBuilderDelegate( delegate: SliverChildBuilderDelegate(
@ -309,40 +452,8 @@ class _RecentUpdateState extends State<RecentUpdate> {
childCount: 1, childCount: 1,
), ),
), ),
]) ],
: Center(child: CircularProgressIndicator()); ),
},
);
}
}
class MyFavorite extends StatefulWidget {
@override
_MyFavoriteState createState() => _MyFavoriteState();
}
class _MyFavoriteState extends State<MyFavorite> {
Future<List<EpisodeBrief>> _getLikedRssItem() async {
var dbHelper = DBHelper();
List<EpisodeBrief> episodes = await dbHelper.getLikedRssItem();
return episodes;
}
@override
Widget build(BuildContext context) {
return FutureBuilder<List<EpisodeBrief>>(
future: _getLikedRssItem(),
builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
return (snapshot.hasData)
? CustomScrollView(
physics: const AlwaysScrollableScrollPhysics(),
primary: false,
slivers: <Widget>[
EpisodeGrid(
podcast: snapshot.data,
)
],
) )
: Center(child: CircularProgressIndicator()); : Center(child: CircularProgressIndicator());
}, },
@ -350,12 +461,12 @@ class _MyFavoriteState extends State<MyFavorite> {
} }
} }
class MyDownload extends StatefulWidget { class _MyDownload extends StatefulWidget {
@override @override
_MyDownloadState createState() => _MyDownloadState(); _MyDownloadState createState() => _MyDownloadState();
} }
class _MyDownloadState extends State<MyDownload> { class _MyDownloadState extends State<_MyDownload> {
Future<List<EpisodeBrief>> _getDownloadedRssItem() async { Future<List<EpisodeBrief>> _getDownloadedRssItem() async {
var dbHelper = DBHelper(); var dbHelper = DBHelper();
List<EpisodeBrief> episodes = await dbHelper.getDownloadedRssItem(); List<EpisodeBrief> episodes = await dbHelper.getDownloadedRssItem();
@ -374,7 +485,7 @@ class _MyDownloadState extends State<MyDownload> {
primary: false, primary: false,
slivers: <Widget>[ slivers: <Widget>[
EpisodeGrid( EpisodeGrid(
podcast: snapshot.data, episodes: snapshot.data,
showDownload: true, showDownload: true,
) )
], ],

View File

@ -49,7 +49,7 @@ class _PlaylistPageState extends State<PlaylistPage> {
ScrollController _controller; ScrollController _controller;
_scrollListener() { _scrollListener() {
double value = _controller.offset; double value = _controller.offset;
setState(() => _topHeight = (100 - value) > 0 ? 100 - value : 0); setState(() => _topHeight = (100 - value) > 60 ? 100 - value : 60);
} }
double _topHeight; double _topHeight;
@ -58,12 +58,12 @@ class _PlaylistPageState extends State<PlaylistPage> {
void initState() { void initState() {
super.initState(); super.initState();
_topHeight = 100; _topHeight = 100;
_controller = ScrollController(); _controller = ScrollController()..addListener(_scrollListener);
_controller.addListener(_scrollListener);
} }
@override @override
void dispose() { void dispose() {
_controller.removeListener(_scrollListener);
_controller.dispose(); _controller.dispose();
super.dispose(); super.dispose();
} }
@ -81,7 +81,7 @@ class _PlaylistPageState extends State<PlaylistPage> {
child: Scaffold( child: Scaffold(
backgroundColor: Theme.of(context).primaryColor, backgroundColor: Theme.of(context).primaryColor,
appBar: AppBar( appBar: AppBar(
title: _topHeight == 0 ? Text('Playlist') : Center(), title: _topHeight == 60 ? Text('Playlist') : Center(),
elevation: 0, elevation: 0,
backgroundColor: Theme.of(context).primaryColor, backgroundColor: Theme.of(context).primaryColor,
), ),
@ -95,56 +95,89 @@ class _PlaylistPageState extends State<PlaylistPage> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
Transform.scale( Container(
alignment: Alignment.topLeft, height: _topHeight,
scale: _topHeight / 100, child: Row(
child: Container( children: <Widget>[
height: _topHeight, Container(
padding: EdgeInsets.only( height: _topHeight,
bottom: (_topHeight - 60) > 0 ? _topHeight - 60 : 0, padding: EdgeInsets.only(
left: 60), left: 70,
alignment: Alignment.bottomLeft,
child: RichText(
text: TextSpan(
text: 'Total ',
style: TextStyle(
color: Theme.of(context).accentColor,
fontSize: 20,
), ),
children: <TextSpan>[ alignment: Alignment.centerLeft,
TextSpan( child: RichText(
text: data.item1.length.toString(), text: TextSpan(
style: TextStyle( text: _topHeight > 90 ? 'Playlist\n' : '',
color: Theme.of(context).accentColor, style: TextStyle(
fontSize: 40, color:
)), Theme.of(context).textTheme.bodyText1.color,
TextSpan( fontSize: 30,
text: data.item1.length < 2 ),
? ' episode' children: <TextSpan>[
: ' episodes ', TextSpan(
style: TextStyle( text: data.item1.length.toString(),
color: Theme.of(context).accentColor, style: GoogleFonts.cairo(
fontSize: 20, textStyle: TextStyle(
)), color: Theme.of(context).accentColor,
TextSpan( fontSize: 30,
text: _sumPlaylistLength(data.item1).toString(), ),
style: GoogleFonts.teko( ),
textStyle: TextStyle( ),
color: Theme.of(context).accentColor, TextSpan(
fontSize: 60, text: data.item1.length < 2
)), ? ' episode '
: ' episodes ',
style: TextStyle(
color: Theme.of(context).accentColor,
fontSize: 20,
)),
TextSpan(
text:
_sumPlaylistLength(data.item1).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: 20,
)),
],
), ),
), Spacer(),
_topHeight > 65
? Center()
: Container(
padding: EdgeInsets.only(
right: 20, bottom: 80 - _topHeight),
child: data.item2
? Padding(
padding: EdgeInsets.only(right: 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(),
),
),
],
), ),
), ),
Divider(
height: 3,
),
Expanded( Expanded(
child: AnimatedList( child: AnimatedList(
controller: _controller, controller: _controller,
@ -224,15 +257,19 @@ class _PlaylistPageState extends State<PlaylistPage> {
trailing: index == 0 trailing: index == 0
? data.item2 ? data.item2
? Padding( ? Padding(
padding: const EdgeInsets.only( padding: EdgeInsets.only(
right: 12.0), right: 15, top: 20),
child: SizedBox( child: SizedBox(
width: 20, width: 20,
height: 15, height: 15,
child: WaveLoader()), child: WaveLoader()),
) )
: IconButton( : IconButton(
icon: Icon(Icons.play_arrow), icon: Icon(
Icons.play_arrow,
color: Theme.of(context)
.accentColor,
),
onPressed: () => onPressed: () =>
audio.playlistLoad()) audio.playlistLoad())
: Transform.rotate( : Transform.rotate(

View File

@ -54,6 +54,8 @@ class DBHelper {
list = await dbClient.rawQuery( list = await dbClient.rawQuery(
'SELECT id, title, imageUrl, rssUrl, primaryColor, author, imagePath , provider, link ,update_count FROM PodcastLocal WHERE id = ?', 'SELECT id, title, imageUrl, rssUrl, primaryColor, author, imagePath , provider, link ,update_count FROM PodcastLocal WHERE id = ?',
[s]); [s]);
int count = Sqflite.firstIntValue(await dbClient.rawQuery(
'SELECT COUNT(*) FROM Episodes WHERE feed_id = ?', [s]));
podcastLocal.add(PodcastLocal( podcastLocal.add(PodcastLocal(
list.first['title'], list.first['title'],
list.first['imageUrl'], list.first['imageUrl'],
@ -64,7 +66,8 @@ class DBHelper {
list.first['imagePath'], list.first['imagePath'],
list.first['provider'], list.first['provider'],
list.first['link'], list.first['link'],
upateCount: list.first['update_count'])); upateCount: list.first['update_count'],
episodeCount: count));
}); });
return podcastLocal; return podcastLocal;
} }
@ -398,13 +401,6 @@ class DBHelper {
} else { } else {
for (int i = 0; i < (result - count); i++) { for (int i = 0; i < (result - count); i++) {
print(feed.items[i].title); print(feed.items[i].title);
// if (feed.items[i].itunes.summary != null) {
// feed.items[i].itunes.summary.contains('<')
// ? description = feed.items[i].itunes.summary
// : description = feed.items[i].description;
// } else {
// description = feed.items[i].description;
// }
description = _getDescription( description = _getDescription(
feed.items[i].content.value ?? '', feed.items[i].content.value ?? '',
feed.items[i].description ?? '', feed.items[i].description ?? '',
@ -444,11 +440,11 @@ class DBHelper {
}); });
} }
} }
return result - count; return (result - count) < 0 ? 0 : (result - count);
} }
} }
Future<List<EpisodeBrief>> getRssItem(String id) async { Future<List<EpisodeBrief>> getRssItem(String id, int i) async {
var dbClient = await database; var dbClient = await database;
List<EpisodeBrief> episodes = []; List<EpisodeBrief> episodes = [];
List<Map> list = await dbClient List<Map> list = await dbClient
@ -456,7 +452,7 @@ class DBHelper {
E.milliseconds, P.imagePath, P.title as feedTitle, E.duration, E.explicit, E.liked, E.milliseconds, P.imagePath, P.title as feedTitle, E.duration, E.explicit, E.liked,
E.downloaded, P.primaryColor , E.media_id E.downloaded, P.primaryColor , E.media_id
FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
WHERE P.id = ? ORDER BY E.milliseconds DESC""", [id]); WHERE P.id = ? ORDER BY E.milliseconds DESC LIMIT ?""", [id, i]);
for (int x = 0; x < list.length; x++) { for (int x = 0; x < list.length; x++) {
episodes.add(EpisodeBrief( episodes.add(EpisodeBrief(
list[x]['title'], list[x]['title'],
@ -557,14 +553,14 @@ class DBHelper {
return episodes; return episodes;
} }
Future<List<EpisodeBrief>> getLikedRssItem() async { Future<List<EpisodeBrief>> getLikedRssItem(int i) async {
var dbClient = await database; var dbClient = await database;
List<EpisodeBrief> episodes = List(); List<EpisodeBrief> episodes = List();
List<Map> list = await dbClient.rawQuery( List<Map> list = await dbClient.rawQuery(
"""SELECT E.title, E.enclosure_url, E.enclosure_length, E.milliseconds, P.imagePath, """SELECT E.title, E.enclosure_url, E.enclosure_length, E.milliseconds, P.imagePath,
P.title as feed_title, E.duration, E.explicit, E.liked, E.downloaded, P.title as feed_title, E.duration, E.explicit, E.liked, E.downloaded,
P.primaryColor, E.media_id FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id P.primaryColor, E.media_id FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
WHERE E.liked = 1 ORDER BY E.milliseconds DESC LIMIT 99"""); WHERE E.liked = 1 ORDER BY E.milliseconds DESC LIMIT ?""",[i]);
for (int x = 0; x < list.length; x++) { for (int x = 0; x < list.length; x++) {
episodes.add(EpisodeBrief( episodes.add(EpisodeBrief(
list[x]['title'], list[x]['title'],

View File

@ -5,9 +5,11 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:html/parser.dart'; import 'package:html/parser.dart';
import 'package:tsacdop/class/audiostate.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
import 'package:flutter_linkify/flutter_linkify.dart'; import 'package:flutter_linkify/flutter_linkify.dart';
import 'package:provider/provider.dart';
import 'package:cached_network_image/cached_network_image.dart'; import 'package:cached_network_image/cached_network_image.dart';
import 'package:tsacdop/class/podcastlocal.dart'; import 'package:tsacdop/class/podcastlocal.dart';
@ -45,9 +47,10 @@ class _PodcastDetailState extends State<PodcastDetail> {
if (mounted) setState(() {}); if (mounted) setState(() {});
} }
Future<List<EpisodeBrief>> _getRssItem(PodcastLocal podcastLocal) async { Future<List<EpisodeBrief>> _getRssItem(
PodcastLocal podcastLocal, int i) async {
var dbHelper = DBHelper(); var dbHelper = DBHelper();
List<EpisodeBrief> episodes = await dbHelper.getRssItem(podcastLocal.id); List<EpisodeBrief> episodes = await dbHelper.getRssItem(podcastLocal.id, i);
if (podcastLocal.provider.contains('fireside')) { if (podcastLocal.provider.contains('fireside')) {
FiresideData data = FiresideData(podcastLocal.id, podcastLocal.link); FiresideData data = FiresideData(podcastLocal.id, podcastLocal.link);
await data.getData(); await data.getData();
@ -156,7 +159,25 @@ class _PodcastDetailState extends State<PodcastDetail> {
); );
} }
double top = 0; double _topHeight = 0;
ScrollController _controller;
int _top;
bool _loadMore;
@override
void initState() {
super.initState();
_loadMore = false;
_top = 33;
_controller = ScrollController();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -178,177 +199,239 @@ class _PodcastDetailState extends State<PodcastDetail> {
onRefresh: () => _updateRssItem(widget.podcastLocal), onRefresh: () => _updateRssItem(widget.podcastLocal),
child: Stack( child: Stack(
children: <Widget>[ children: <Widget>[
FutureBuilder<List<EpisodeBrief>>( Column(
future: _getRssItem(widget.podcastLocal), mainAxisAlignment: MainAxisAlignment.start,
builder: (context, snapshot) { mainAxisSize: MainAxisSize.min,
if (snapshot.hasError) print(snapshot.error); crossAxisAlignment: CrossAxisAlignment.start,
return (snapshot.hasData) children: <Widget>[
? CustomScrollView( Expanded(
physics: const AlwaysScrollableScrollPhysics(), child: FutureBuilder<List<EpisodeBrief>>(
primary: true, future: _getRssItem(widget.podcastLocal, _top),
slivers: <Widget>[ builder: (context, snapshot) {
SliverAppBar( if (snapshot.hasError) print(snapshot.error);
brightness: Brightness.dark, return (snapshot.hasData)
actions: <Widget>[ ? CustomScrollView(
PopupMenuButton<String>( controller: _controller
shape: RoundedRectangleBorder( ..addListener(() async {
borderRadius: BorderRadius.all( if (_controller.offset ==
Radius.circular(10))), _controller
elevation: 2, .position.maxScrollExtent &&
tooltip: 'Menu', snapshot.data.length == _top) {
itemBuilder: (context) => [ if (mounted)
widget.podcastLocal.link != null setState(() => _loadMore = true);
? PopupMenuItem( await Future.delayed(
value: widget.podcastLocal.link, Duration(seconds: 3));
if (mounted)
setState(() {
_top = _top + 33;
_loadMore = false;
});
}
}),
physics: const ClampingScrollPhysics(),
//primary: true,
slivers: <Widget>[
SliverAppBar(
brightness: Brightness.dark,
actions: <Widget>[
PopupMenuButton<String>(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(10))),
elevation: 2,
tooltip: 'Menu',
itemBuilder: (context) => [
widget.podcastLocal.link != null
? PopupMenuItem(
value: widget
.podcastLocal.link,
child: Container(
padding: EdgeInsets.only(
left: 10),
child: Row(
children: <Widget>[
Icon(Icons.link,
color: Theme.of(
context)
.tabBarTheme
.labelColor),
Padding(
padding: EdgeInsets
.symmetric(
horizontal:
5.0),
),
Text('Visit Site'),
],
),
),
)
: Center(),
PopupMenuItem(
value: widget.podcastLocal.rssUrl,
child: Container( child: Container(
padding: padding:
EdgeInsets.only(left: 10), EdgeInsets.only(left: 10),
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
Icon(Icons.link, Icon(
color: Theme.of(context) Icons.rss_feed,
.tabBarTheme color: Theme.of(context)
.labelColor), .tabBarTheme
.labelColor,
),
Padding( Padding(
padding: padding:
EdgeInsets.symmetric( EdgeInsets.symmetric(
horizontal: 5.0), horizontal: 5.0),
), ),
Text('Visit Site'), Text('View Rss Feed'),
], ],
), ),
), ),
) ),
: Center(), ],
PopupMenuItem( onSelected: (url) {
value: widget.podcastLocal.rssUrl, _launchUrl(url);
child: Container( },
padding: EdgeInsets.only(left: 10), )
child: Row( ],
elevation: 0,
iconTheme: IconThemeData(
color: Colors.white,
),
expandedHeight: 150 +
MediaQuery.of(context).padding.top,
backgroundColor: _color,
floating: true,
pinned: true,
flexibleSpace: LayoutBuilder(builder:
(BuildContext context,
BoxConstraints constraints) {
_topHeight = constraints.biggest.height;
return FlexibleSpaceBar(
background: Stack(
children: <Widget>[ children: <Widget>[
Icon( Container(
Icons.rss_feed, margin: EdgeInsets.only(
color: Theme.of(context) top: 120 +
.tabBarTheme MediaQuery.of(context)
.labelColor, .padding
.top),
padding: EdgeInsets.only(
left: 80, right: 120),
color: Colors.white10,
alignment: Alignment.centerLeft,
child: Column(
mainAxisAlignment:
MainAxisAlignment.start,
mainAxisSize:
MainAxisSize.min,
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
widget.podcastLocal
.author ??
'',
maxLines: 1,
overflow: TextOverflow
.ellipsis,
style: TextStyle(
color:
Colors.white)),
widget.podcastLocal.provider
.isNotEmpty
? Text(
'Hosted on ' +
widget
.podcastLocal
.provider,
maxLines: 1,
style: TextStyle(
color: Colors
.white),
)
: Center(),
],
),
), ),
Padding( Container(
padding: EdgeInsets.symmetric( alignment:
horizontal: 5.0), Alignment.centerRight,
padding:
EdgeInsets.only(right: 10),
child: SizedBox(
height: 120,
child: Image.file(File(
"${widget.podcastLocal.imagePath}")),
),
),
Container(
alignment: Alignment.center,
child: podcastInfo(context),
), ),
Text('View Rss Feed'),
], ],
), ),
), title: _topHeight <
), 70 +
], MediaQuery.of(context)
onSelected: (url) { .padding
_launchUrl(url); .top
}, ? Text(widget.podcastLocal.title,
)
],
elevation: 0,
iconTheme: IconThemeData(
color: Colors.white,
),
expandedHeight:
150 + MediaQuery.of(context).padding.top,
backgroundColor: _color,
floating: true,
pinned: true,
flexibleSpace: LayoutBuilder(builder:
(BuildContext context,
BoxConstraints constraints) {
top = constraints.biggest.height;
return FlexibleSpaceBar(
background: Stack(
children: <Widget>[
Container(
margin: EdgeInsets.only(
top: 120 +
MediaQuery.of(context)
.padding
.top),
padding: EdgeInsets.only(
left: 80, right: 120),
color: Colors.white10,
alignment: Alignment.centerLeft,
child: Column(
mainAxisAlignment:
MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
widget.podcastLocal.author ??
'',
maxLines: 1, maxLines: 1,
overflow: overflow:
TextOverflow.ellipsis, TextOverflow.ellipsis,
style: TextStyle( style: TextStyle(
color: Colors.white)), color: Colors.white))
widget.podcastLocal.provider : Center(),
.isNotEmpty );
? Text( }),
'Hosted on ' +
widget.podcastLocal
.provider,
maxLines: 1,
style: TextStyle(
color: Colors.white),
)
: Center(),
],
),
),
Container(
alignment: Alignment.centerRight,
padding: EdgeInsets.only(right: 10),
child: SizedBox(
height: 120,
child: Image.file(File(
"${widget.podcastLocal.imagePath}")),
),
),
Container(
alignment: Alignment.center,
child: podcastInfo(context),
),
],
), ),
title: top < SliverList(
70 + delegate: SliverChildBuilderDelegate(
MediaQuery.of(context) (BuildContext context, int index) {
.padding return hostsList(context, hosts);
.top },
? Text(widget.podcastLocal.title, childCount: 1,
maxLines: 1, ),
overflow: TextOverflow.ellipsis, ),
style: EpisodeGrid(
TextStyle(color: Colors.white)) episodes: snapshot.data,
: Center(), showFavorite: true,
); showNumber: true,
}), updateCount:
), widget.podcastLocal.upateCount,
SliverList( episodeCount:
delegate: SliverChildBuilderDelegate( widget.podcastLocal.episodeCount,
(BuildContext context, int index) { ),
return hostsList(context, hosts); SliverList(
}, delegate: SliverChildBuilderDelegate(
childCount: 1, (BuildContext context, int index) {
), return _loadMore
), ? Container(
EpisodeGrid( height: 2,
podcast: snapshot.data, child:
showFavorite: true, LinearProgressIndicator())
showNumber: true, : Center();
updateCount: widget.podcastLocal.upateCount, },
), childCount: 1,
], ),
) ),
: Center(child: CircularProgressIndicator()); ],
}, )
: Center(child: CircularProgressIndicator());
},
),
),
Selector<AudioPlayerNotifier, bool>(
selector: (_, audio) => audio.playerRunning,
builder: (_, data, __) {
return Padding(
padding: EdgeInsets.only(bottom: data ? 60.0 : 0),
);
}),
],
), ),
Container(child: PlayerWidget()), Container(child: PlayerWidget()),
], ],

View File

@ -5,6 +5,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_downloader/flutter_downloader.dart'; import 'package:flutter_downloader/flutter_downloader.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:line_icons/line_icons.dart'; import 'package:line_icons/line_icons.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:tsacdop/class/episodebrief.dart'; import 'package:tsacdop/class/episodebrief.dart';
import 'package:tsacdop/local_storage/sqflite_localpodcast.dart'; import 'package:tsacdop/local_storage/sqflite_localpodcast.dart';
@ -123,22 +124,24 @@ class _DownloadsManageState extends State<DownloadsManage> {
), ),
Container( Container(
height: 100.0, height: 100.0,
padding: EdgeInsets.only(bottom: 40, left: 60), padding: EdgeInsets.only(bottom: 20, left: 60),
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: RichText( child: RichText(
text: TextSpan( text: TextSpan(
text: 'Total ', text: 'Total ',
style: TextStyle( style: TextStyle(
color: Theme.of(context).accentColor, color: Theme.of(context).accentColor,
fontSize: 20, fontSize: 20,
), ),
children: <TextSpan>[ children: <TextSpan>[
TextSpan( TextSpan(
text: _fileNum.toString(), text: _fileNum.toString(),
style: TextStyle( style: GoogleFonts.cairo(
color: Theme.of(context).accentColor, textStyle: TextStyle(
fontSize: 40, color: Theme.of(context).accentColor,
)), fontSize: 40,
)),
),
TextSpan( TextSpan(
text: _fileNum < 2 ? ' episode' : ' episodes ', text: _fileNum < 2 ? ' episode' : ' episodes ',
style: TextStyle( style: TextStyle(
@ -146,11 +149,13 @@ class _DownloadsManageState extends State<DownloadsManage> {
fontSize: 20, fontSize: 20,
)), )),
TextSpan( TextSpan(
text: (_size ~/ 1000000).toString(), text: (_size ~/ 1000000).toString(),
style: TextStyle( style: GoogleFonts.cairo(
color: Theme.of(context).accentColor, textStyle: TextStyle(
fontSize: 60, color: Theme.of(context).accentColor,
)), fontSize: 50,
)),
),
TextSpan( TextSpan(
text: ' Mb', text: ' Mb',
style: TextStyle( style: TextStyle(

View File

@ -196,7 +196,7 @@ class _RenderSwitch extends RenderToggleable {
..onEnd = _handleDragEnd ..onEnd = _handleDragEnd
..dragStartBehavior = dragStartBehavior; ..dragStartBehavior = dragStartBehavior;
} }
ImageProvider get activeThumbImage => _activeThumbImage; ImageProvider get activeThumbImage => _activeThumbImage;
ImageProvider _activeThumbImage; ImageProvider _activeThumbImage;
set activeThumbImage(ImageProvider value) { set activeThumbImage(ImageProvider value) {
@ -285,7 +285,9 @@ class _RenderSwitch extends RenderToggleable {
positionController.value += delta; positionController.value += delta;
break; break;
} }
positionController.addListener(() {onDrag(positionController.value);}); positionController.addListener(() {
onDrag(positionController.value);
});
} }
} }
@ -297,8 +299,6 @@ class _RenderSwitch extends RenderToggleable {
reactionController.reverse(); reactionController.reverse();
} }
@override @override
void handleEvent(PointerEvent event, BoxHitTestEntry entry) { void handleEvent(PointerEvent event, BoxHitTestEntry entry) {
assert(debugHandleEvent(event, entry)); assert(debugHandleEvent(event, entry));
@ -309,7 +309,7 @@ class _RenderSwitch extends RenderToggleable {
Color _cachedThumbColor; Color _cachedThumbColor;
ImageProvider _cachedThumbImage; ImageProvider _cachedThumbImage;
BoxPainter _cachedThumbPainter; BoxPainter _cachedThumbPainter;
BoxDecoration _createDefaultThumbDecoration( BoxDecoration _createDefaultThumbDecoration(
Color color, ImageProvider image) { Color color, ImageProvider image) {
return BoxDecoration( return BoxDecoration(
@ -335,9 +335,7 @@ class _RenderSwitch extends RenderToggleable {
super.describeSemanticsConfiguration(config); super.describeSemanticsConfiguration(config);
config.isToggled = value == true; config.isToggled = value == true;
} }
@override @override
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
final Canvas canvas = context.canvas; final Canvas canvas = context.canvas;
@ -413,7 +411,7 @@ class _RenderSwitch extends RenderToggleable {
); );
var starPaint = Paint() var starPaint = Paint()
..strokeWidth = 4 + (6 * (1 - currentValue)) ..strokeWidth = 2 + (6 * (1 - currentValue))
..strokeCap = StrokeCap.round ..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke ..style = PaintingStyle.stroke
..color = Color.fromARGB((255 * currentValue).floor(), 255, 255, 255); ..color = Color.fromARGB((255 * currentValue).floor(), 255, 255, 255);
@ -450,14 +448,14 @@ class _RenderSwitch extends RenderToggleable {
_isPainting = false; _isPainting = false;
} }
canvas.drawLine( canvas.drawLine(
Offset(offset.dx + _kSwitchWidth * 0.3, offset.dy + _kSwitchHeight * 0.5), Offset(offset.dx + _kSwitchWidth * 0.3, offset.dy + _kSwitchHeight * 0.5),
Offset( Offset(
offset.dx + offset.dx +
(_kSwitchWidth * 0.3) + (_kSwitchWidth * 0.3) +
(_kSwitchWidth / 2 * (1 - currentValue)), (_kSwitchWidth / 2 * (1 - currentValue)),
offset.dy + _kSwitchHeight * 0.5), offset.dy + _kSwitchHeight * 0.5),
linePaint, linePaint,
); );
} }
} }

View File

@ -17,20 +17,22 @@ import 'package:tsacdop/episodes/episodedetail.dart';
import 'package:tsacdop/util/colorize.dart'; import 'package:tsacdop/util/colorize.dart';
class EpisodeGrid extends StatelessWidget { class EpisodeGrid extends StatelessWidget {
final List<EpisodeBrief> podcast; final List<EpisodeBrief> episodes;
final bool showFavorite; final bool showFavorite;
final bool showDownload; final bool showDownload;
final bool showNumber; final bool showNumber;
final int updateCount; final int updateCount;
final String heroTag; final String heroTag;
final int episodeCount;
EpisodeGrid( EpisodeGrid(
{Key key, {Key key,
@required this.podcast, @required this.episodes,
this.heroTag = '', this.heroTag = '',
this.showDownload = false, this.showDownload = false,
this.showFavorite = false, this.showFavorite = false,
this.showNumber = false, this.showNumber = false,
this.updateCount = 0}) this.updateCount = 0,
this.episodeCount = 0})
: super(key: key); : super(key: key);
@override @override
@ -115,14 +117,14 @@ class EpisodeGrid extends StatelessWidget {
delegate: SliverChildBuilderDelegate( delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) { (BuildContext context, int index) {
Color _c = (Theme.of(context).brightness == Brightness.light) Color _c = (Theme.of(context).brightness == Brightness.light)
? podcast[index].primaryColor.colorizedark() ? episodes[index].primaryColor.colorizedark()
: podcast[index].primaryColor.colorizeLight(); : episodes[index].primaryColor.colorizeLight();
return Selector<AudioPlayerNotifier, return Selector<AudioPlayerNotifier,
Tuple2<EpisodeBrief, List<String>>>( Tuple2<EpisodeBrief, List<String>>>(
selector: (_, audio) => Tuple2(audio?.episode, selector: (_, audio) => Tuple2(audio?.episode,
audio.queue.playlist.map((e) => e.enclosureUrl).toList()), audio.queue.playlist.map((e) => e.enclosureUrl).toList()),
builder: (_, data, __) => OpenContainerWrapper( builder: (_, data, __) => OpenContainerWrapper(
episode: podcast[index], episode: episodes[index],
closedBuilder: (context, action, boo) => Container( closedBuilder: (context, action, boo) => Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5.0)), borderRadius: BorderRadius.all(Radius.circular(5.0)),
@ -143,21 +145,11 @@ class EpisodeGrid extends StatelessWidget {
details.globalPosition.dx, details.globalPosition.dy), details.globalPosition.dx, details.globalPosition.dy),
onLongPress: () => _showPopupMenu( onLongPress: () => _showPopupMenu(
_offset, _offset,
podcast[index], episodes[index],
context, context,
data.item1 == podcast[index], data.item1 == episodes[index],
data.item2.contains(podcast[index].enclosureUrl)), data.item2.contains(episodes[index].enclosureUrl)),
onTap: action, onTap: action,
// {
// Navigator.push(
// context,
// ScaleRoute(
// page: EpisodeDetail(
// episodeItem: podcast[index],
// heroTag: heroTag,
// )),
// )
// },
child: Container( child: Container(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
decoration: BoxDecoration( decoration: BoxDecoration(
@ -187,7 +179,7 @@ class EpisodeGrid extends StatelessWidget {
backgroundColor: backgroundColor:
_c.withOpacity(0.5), _c.withOpacity(0.5),
backgroundImage: FileImage(File( backgroundImage: FileImage(File(
"${podcast[index].imagePath}")), "${episodes[index].imagePath}")),
), ),
), ),
Spacer(), Spacer(),
@ -205,7 +197,7 @@ class EpisodeGrid extends StatelessWidget {
? Container( ? Container(
alignment: Alignment.topRight, alignment: Alignment.topRight,
child: Text( child: Text(
(podcast.length - index).toString(), (episodeCount- index).toString(),
style: GoogleFonts.teko( style: GoogleFonts.teko(
textStyle: TextStyle( textStyle: TextStyle(
fontSize: _width / 24, fontSize: _width / 24,
@ -224,7 +216,7 @@ class EpisodeGrid extends StatelessWidget {
alignment: Alignment.topLeft, alignment: Alignment.topLeft,
padding: EdgeInsets.only(top: 2.0), padding: EdgeInsets.only(top: 2.0),
child: Text( child: Text(
podcast[index].title, episodes[index].title,
style: TextStyle( style: TextStyle(
fontSize: _width / 32, fontSize: _width / 32,
), ),
@ -240,7 +232,7 @@ class EpisodeGrid extends StatelessWidget {
Align( Align(
alignment: Alignment.bottomLeft, alignment: Alignment.bottomLeft,
child: Text( child: Text(
podcast[index].dateToString(), episodes[index].dateToString(),
style: TextStyle( style: TextStyle(
fontSize: _width / 35, fontSize: _width / 35,
color: _c, color: _c,
@ -250,7 +242,7 @@ class EpisodeGrid extends StatelessWidget {
Spacer(), Spacer(),
showDownload showDownload
? DownloadIcon( ? DownloadIcon(
episodeBrief: podcast[index]) episodeBrief: episodes[index])
: Center(), : Center(),
Padding( Padding(
padding: EdgeInsets.all(1), padding: EdgeInsets.all(1),
@ -258,7 +250,7 @@ class EpisodeGrid extends StatelessWidget {
showFavorite showFavorite
? Container( ? Container(
alignment: Alignment.bottomRight, alignment: Alignment.bottomRight,
child: (podcast[index].liked == 0) child: (episodes[index].liked == 0)
? Center() ? Center()
: IconTheme( : IconTheme(
data: IconThemeData(size: 15), data: IconThemeData(size: 15),
@ -281,7 +273,7 @@ class EpisodeGrid extends StatelessWidget {
), ),
); );
}, },
childCount: podcast.length, childCount: episodes.length,
), ),
), ),
); );

View File

@ -11,7 +11,7 @@ description: An easy-use podacasts player.
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at # Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 0.1.4 version: 0.1.5
environment: environment:
sdk: ">=2.6.0 <3.0.0" sdk: ">=2.6.0 <3.0.0"
@ -51,7 +51,7 @@ dev_dependencies:
workmanager: ^0.2.2 workmanager: ^0.2.2
flutter_colorpicker: ^0.3.2 flutter_colorpicker: ^0.3.2
app_settings: ^3.0.1 app_settings: ^3.0.1
fl_chart: ^0.8.3 fl_chart: ^0.8.7
audio_service: ^0.6.2 audio_service: ^0.6.2
just_audio: ^0.1.3 just_audio: ^0.1.3
rxdart: ^0.23.1 rxdart: ^0.23.1
@ -60,8 +60,6 @@ dev_dependencies:
url: https://github.com/galonsos/line_icons.git url: https://github.com/galonsos/line_icons.git
flutter_file_dialog: ^0.0.5 flutter_file_dialog: ^0.0.5
flutter_linkify: ^3.1.0 flutter_linkify: ^3.1.0
animations: ^1.0.0+5
# For information on the generic Dart part of this file, see the # For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec # following page: https://www.dartlang.org/tools/pub/pubspec