modified: lib/class/settingstate.dart
modified: lib/episodes/episodedetail.dart modified: lib/home/appbar/about.dart modified: lib/home/appbar/addpodcast.dart modified: lib/home/appbar/importompl.dart modified: lib/home/appbar/popupmenu.dart modified: lib/home/audio_player.dart modified: lib/home/audiopanel.dart modified: lib/home/homescroll.dart modified: lib/home/hometab.dart modified: lib/local_storage/key_value_storage.dart modified: lib/main.dart modified: lib/podcasts/podcastdetail.dart modified: lib/podcasts/podcastgroup.dart modified: lib/podcasts/podcastlist.dart modified: lib/podcasts/podcastmanage.dart modified: lib/util/episodegrid.dart
This commit is contained in:
parent
9d4bbc895a
commit
7ba0552717
|
@ -1,13 +1,30 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
//two types podcast update, backhome nedd to back to default grooup.
|
||||
enum Update {backhome, justupdate}
|
||||
class SettingState extends ChangeNotifier{
|
||||
Update _subscribeupdate;
|
||||
Update get subscribeupdate => _subscribeupdate;
|
||||
set subscribeUpdate(Update s){
|
||||
_subscribeupdate = s;
|
||||
import 'package:tsacdop/local_storage/key_value_storage.dart';
|
||||
|
||||
class SettingState extends ChangeNotifier {
|
||||
KeyValueStorage storage = KeyValueStorage('themes');
|
||||
int _theme;
|
||||
|
||||
int get theme => _theme;
|
||||
void setTheme(int theme) {
|
||||
_theme = theme;
|
||||
notifyListeners();
|
||||
_saveTheme(theme);
|
||||
}
|
||||
|
||||
@override
|
||||
void addListener(VoidCallback listener) {
|
||||
super.addListener(listener);
|
||||
_getTheme();
|
||||
}
|
||||
|
||||
_getTheme() async {
|
||||
_theme = await storage.getTheme();
|
||||
}
|
||||
|
||||
_saveTheme(theme) async {
|
||||
await storage.saveTheme(theme);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:io';
|
|||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_html/flutter_html.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
@ -15,8 +16,7 @@ import 'episodedownload.dart';
|
|||
class EpisodeDetail extends StatefulWidget {
|
||||
final EpisodeBrief episodeItem;
|
||||
final String heroTag;
|
||||
EpisodeDetail({this.episodeItem, this.heroTag, Key key})
|
||||
: super(key: key);
|
||||
EpisodeDetail({this.episodeItem, this.heroTag, Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_EpisodeDetailState createState() => _EpisodeDetailState();
|
||||
|
@ -53,119 +53,130 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.grey[100],
|
||||
appBar: AppBar(
|
||||
title: Text(widget.episodeItem.feedTitle),
|
||||
elevation: 0.0,
|
||||
centerTitle: true,
|
||||
backgroundColor: Colors.grey[100],
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
||||
statusBarColor: Theme.of(context).primaryColor,
|
||||
),
|
||||
body: Container(
|
||||
color: Colors.grey[100],
|
||||
padding: EdgeInsets.all(10.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12.0),
|
||||
alignment: Alignment.topLeft,
|
||||
child: Text(
|
||||
widget.episodeItem.title,
|
||||
style: Theme.of(context).textTheme.headline5,
|
||||
child: SafeArea(
|
||||
child: Scaffold(
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
appBar: AppBar(
|
||||
title: Text(widget.episodeItem.feedTitle),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: Container(
|
||||
color: Theme.of(context).primaryColor,
|
||||
padding: EdgeInsets.all(10.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12.0),
|
||||
alignment: Alignment.topLeft,
|
||||
child: Text(
|
||||
widget.episodeItem.title,
|
||||
style: Theme.of(context).textTheme.headline5,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
padding: EdgeInsets.symmetric(horizontal: 12.0),
|
||||
height: 30.0,
|
||||
child: Text(
|
||||
'Published ' +
|
||||
DateFormat.yMMMd().format(
|
||||
DateTime.fromMillisecondsSinceEpoch(
|
||||
widget.episodeItem.pubDate)),
|
||||
style: TextStyle(color: Colors.blue[500])),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.all(12.0),
|
||||
height: 50.0,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
(widget.episodeItem.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)))
|
||||
: Center(),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.cyan[300],
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(15.0))),
|
||||
height: 30.0,
|
||||
margin: EdgeInsets.only(right: 10.0),
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.0),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
(widget.episodeItem.duration).toString() +
|
||||
'mins',
|
||||
style: textstyle),
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.lightBlue[300],
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(15.0))),
|
||||
height: 30.0,
|
||||
margin: EdgeInsets.only(right: 10.0),
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.0),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
((widget.episodeItem.enclosureLength) ~/
|
||||
1000000)
|
||||
.toString() +
|
||||
'MB',
|
||||
style: textstyle),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 12.0, right: 12.0, top: 5.0),
|
||||
child: SingleChildScrollView(
|
||||
child: _loaddes
|
||||
? (widget.episodeItem.description.contains('<'))
|
||||
? Html(
|
||||
data: widget.episodeItem.description,
|
||||
onLinkTap: (url) {
|
||||
_launchUrl(url);
|
||||
},
|
||||
useRichText: true,
|
||||
)
|
||||
: Container(
|
||||
alignment: Alignment.topLeft,
|
||||
child: Text(widget.episodeItem.description))
|
||||
: Center(),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
padding: EdgeInsets.symmetric(horizontal: 12.0),
|
||||
height: 30.0,
|
||||
child: Text(
|
||||
'Published ' +
|
||||
DateFormat.yMMMd().format( DateTime.fromMillisecondsSinceEpoch(widget.episodeItem.pubDate)),
|
||||
style: TextStyle(color: Colors.blue[500])),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.all(12.0),
|
||||
height: 50.0,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
(widget.episodeItem.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)))
|
||||
: Center(),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.cyan[300],
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(15.0))),
|
||||
height: 30.0,
|
||||
margin: EdgeInsets.only(right: 10.0),
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.0),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
(widget.episodeItem.duration).toString() + 'mins',
|
||||
style: textstyle),
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.lightBlue[300],
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(15.0))),
|
||||
height: 30.0,
|
||||
margin: EdgeInsets.only(right: 10.0),
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.0),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
((widget.episodeItem.enclosureLength) ~/ 1000000)
|
||||
.toString() +
|
||||
'MB',
|
||||
style: textstyle),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 12.0, right: 12.0, top: 5.0),
|
||||
child: SingleChildScrollView(
|
||||
child: _loaddes
|
||||
? (widget.episodeItem.description.contains('<'))
|
||||
? Html(
|
||||
data: widget.episodeItem.description,
|
||||
onLinkTap: (url) {
|
||||
_launchUrl(url);
|
||||
},
|
||||
useRichText: true,
|
||||
)
|
||||
: Container(
|
||||
alignment: Alignment.topLeft,
|
||||
child: Text(widget.episodeItem.description))
|
||||
: Center(),
|
||||
),
|
||||
),
|
||||
),
|
||||
MenuBar(
|
||||
episodeItem: widget.episodeItem,
|
||||
heroTag: widget.heroTag,
|
||||
MenuBar(
|
||||
episodeItem: widget.episodeItem,
|
||||
heroTag: widget.heroTag,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -175,8 +186,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
|||
class MenuBar extends StatefulWidget {
|
||||
final EpisodeBrief episodeItem;
|
||||
final String heroTag;
|
||||
MenuBar({this.episodeItem, this.heroTag, Key key})
|
||||
: super(key: key);
|
||||
MenuBar({this.episodeItem, this.heroTag, Key key}) : super(key: key);
|
||||
@override
|
||||
_MenuBarState createState() => _MenuBarState();
|
||||
}
|
||||
|
@ -224,114 +234,113 @@ class _MenuBarState extends State<MenuBar> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final audioplay = Provider.of<AudioPlay>(context);
|
||||
return Container(
|
||||
height: 50.0,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.all(Radius.circular(10.0)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
(widget.episodeItem.title == audioplay.episode?.title &&
|
||||
audioplay.audioState == AudioState.play)
|
||||
? ImageRotate(
|
||||
title: widget.episodeItem.feedTitle,
|
||||
path: widget.episodeItem.imagePath,
|
||||
)
|
||||
: Hero(
|
||||
tag: widget.episodeItem.enclosureUrl + widget.heroTag,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(15.0)),
|
||||
child: Container(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
color: Colors.white,
|
||||
child: Image.file(File(
|
||||
"${widget.episodeItem.imagePath}")),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
(_like == 0 && !_liked)
|
||||
? _buttonOnMenu(
|
||||
Icon(
|
||||
Icons.favorite_border,
|
||||
color: Colors.grey[700],
|
||||
),
|
||||
() => saveLiked(widget.episodeItem.enclosureUrl))
|
||||
: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
LoveOpen(),
|
||||
_buttonOnMenu(
|
||||
Icon(
|
||||
Icons.favorite,
|
||||
color: Colors.red,
|
||||
),
|
||||
() => setUnliked(widget.episodeItem.enclosureUrl)),
|
||||
],
|
||||
),
|
||||
DownloadButton(episodeBrief: widget.episodeItem),
|
||||
_buttonOnMenu(Icon(Icons.playlist_add, color: Colors.grey[700]),
|
||||
() {
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Not support yet',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
/*TODO*/
|
||||
}),
|
||||
Spacer(),
|
||||
(widget.episodeItem.title != audioplay.episode?.title)
|
||||
? Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight: Radius.circular(5.0),
|
||||
bottomRight: Radius.circular(5.0)),
|
||||
onTap: () {
|
||||
audioplay.episodeLoad = widget.episodeItem;
|
||||
},
|
||||
return Container(
|
||||
height: 50.0,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
borderRadius: BorderRadius.all(Radius.circular(10.0)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
(widget.episodeItem.title == audioplay.episode?.title &&
|
||||
audioplay.audioState == AudioState.play)
|
||||
? ImageRotate(
|
||||
title: widget.episodeItem.feedTitle,
|
||||
path: widget.episodeItem.imagePath,
|
||||
)
|
||||
: Hero(
|
||||
tag: widget.episodeItem.enclosureUrl + widget.heroTag,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(15.0)),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
height: 50.0,
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.0),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Text('Play Now',
|
||||
style: TextStyle(
|
||||
color: Colors.blue,
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.bold,
|
||||
)),
|
||||
Icon(
|
||||
Icons.play_arrow,
|
||||
color: Colors.blue,
|
||||
),
|
||||
],
|
||||
),
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
child:
|
||||
Image.file(File("${widget.episodeItem.imagePath}")),
|
||||
),
|
||||
),
|
||||
)
|
||||
: (widget.episodeItem.title == audioplay.episode?.title &&
|
||||
audioplay.audioState == AudioState.play)
|
||||
? Container(
|
||||
padding: EdgeInsets.only(right: 30),
|
||||
child: SizedBox(
|
||||
width: 20, height: 15, child: WaveLoader()))
|
||||
: Container(
|
||||
padding: EdgeInsets.only(right: 30),
|
||||
child: SizedBox(
|
||||
width: 20,
|
||||
height: 15,
|
||||
child: LineLoader(),
|
||||
),
|
||||
),
|
||||
(_like == 0 && !_liked)
|
||||
? _buttonOnMenu(
|
||||
Icon(
|
||||
Icons.favorite_border,
|
||||
color: Colors.grey[700],
|
||||
),
|
||||
() => saveLiked(widget.episodeItem.enclosureUrl))
|
||||
: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
LoveOpen(),
|
||||
_buttonOnMenu(
|
||||
Icon(
|
||||
Icons.favorite,
|
||||
color: Colors.red,
|
||||
),
|
||||
() => setUnliked(widget.episodeItem.enclosureUrl)),
|
||||
],
|
||||
),
|
||||
DownloadButton(episodeBrief: widget.episodeItem),
|
||||
_buttonOnMenu(Icon(Icons.playlist_add, color: Colors.grey[700]), () {
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Not support yet',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
/*TODO*/
|
||||
}),
|
||||
Spacer(),
|
||||
(widget.episodeItem.title != audioplay.episode?.title)
|
||||
? Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight: Radius.circular(5.0),
|
||||
bottomRight: Radius.circular(5.0)),
|
||||
onTap: () {
|
||||
audioplay.episodeLoad = widget.episodeItem;
|
||||
},
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
height: 50.0,
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.0),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Text('Play Now',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.bold,
|
||||
)),
|
||||
Icon(
|
||||
Icons.play_arrow,
|
||||
color: Theme.of(context).accentColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: (widget.episodeItem.title == audioplay.episode?.title &&
|
||||
audioplay.audioState == AudioState.play)
|
||||
? Container(
|
||||
padding: EdgeInsets.only(right: 30),
|
||||
child:
|
||||
SizedBox(width: 20, height: 15, child: WaveLoader()))
|
||||
: Container(
|
||||
padding: EdgeInsets.only(right: 30),
|
||||
child: SizedBox(
|
||||
width: 20,
|
||||
height: 15,
|
||||
child: LineLoader(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,31 +1,37 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class AboutApp extends StatelessWidget {
|
||||
TextSpan buildTextSpan() {
|
||||
return TextSpan(children: [
|
||||
TextSpan(text: 'Tsacdop\n',style: TextStyle(fontSize: 20)),
|
||||
TextSpan(text: 'Tsacdop\n', style: TextStyle(fontSize: 20)),
|
||||
TextSpan(
|
||||
text:
|
||||
'Tsacdop is a podcast client developed by flutter, is a simple, easy-use player.\n'),
|
||||
TextSpan(
|
||||
text:
|
||||
'Github https://github.com/stonga/tsacdop .\n'),
|
||||
TextSpan(text: 'Github https://github.com/stonga/tsacdop .\n'),
|
||||
]);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.grey[100],
|
||||
title: Text('Tsacdop'),
|
||||
centerTitle: true,
|
||||
elevation: 0,
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.all(20),
|
||||
alignment: Alignment.topLeft,
|
||||
child: Text.rich(buildTextSpan()),
|
||||
));
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
||||
statusBarColor: Theme.of(context).primaryColor,
|
||||
),
|
||||
child: SafeArea(
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Tsacdop'),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.all(20),
|
||||
alignment: Alignment.topLeft,
|
||||
child: Text.rich(buildTextSpan()),
|
||||
)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,35 +34,35 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||
Widget build(BuildContext context) {
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
systemNavigationBarColor: Colors.grey[100],
|
||||
statusBarColor: Colors.green,
|
||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
||||
statusBarColor: Theme.of(context).primaryColor,
|
||||
),
|
||||
child: Scaffold(
|
||||
key: _scaffoldKey,
|
||||
appBar: AppBar(
|
||||
elevation: 0,
|
||||
centerTitle: true,
|
||||
backgroundColor: Colors.grey[100],
|
||||
brightness: Brightness.light,
|
||||
leading: IconButton(
|
||||
tooltip: 'Add',
|
||||
icon: const Icon(Icons.add_circle_outline),
|
||||
onPressed: () async {
|
||||
await showSearch<int>(
|
||||
context: context,
|
||||
delegate: _delegate,
|
||||
);
|
||||
},
|
||||
child: SafeArea(
|
||||
child: Scaffold(
|
||||
key: _scaffoldKey,
|
||||
appBar: AppBar(
|
||||
centerTitle: true,
|
||||
leading: IconButton(
|
||||
tooltip: 'Add',
|
||||
icon: const Icon(Icons.add_circle_outline),
|
||||
onPressed: () async {
|
||||
await showSearch<int>(
|
||||
context: context,
|
||||
delegate: _delegate,
|
||||
);
|
||||
},
|
||||
),
|
||||
title: Image(
|
||||
image: AssetImage('assets/text.png'),
|
||||
height: 30,
|
||||
),
|
||||
actions: <Widget>[
|
||||
PopupMenu(),
|
||||
],
|
||||
),
|
||||
title: Image(
|
||||
image: AssetImage('assets/text.png'),
|
||||
height: 30,
|
||||
),
|
||||
actions: <Widget>[
|
||||
PopupMenu(),
|
||||
],
|
||||
body: Home(),
|
||||
),
|
||||
body: Home(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -83,6 +83,9 @@ class _MyHomePageDelegate extends SearchDelegate<int> {
|
|||
var searchResult = SearchPodcast.fromJson(searchResultMap);
|
||||
return searchResult.results;
|
||||
}
|
||||
|
||||
@override
|
||||
ThemeData appBarTheme(BuildContext context) => Theme.of(context);
|
||||
|
||||
@override
|
||||
Widget buildLeading(BuildContext context) {
|
||||
|
@ -327,7 +330,7 @@ class _SearchResultState extends State<SearchResult> {
|
|||
? !_adding
|
||||
? OutlineButton(
|
||||
child: Text('Subscribe',
|
||||
style: TextStyle(color: Colors.blue)),
|
||||
style: TextStyle(color: Theme.of(context).accentColor)),
|
||||
onPressed: () {
|
||||
importOmpl.rssTitle = widget.onlinePodcast.title;
|
||||
savePodcast(widget.onlinePodcast.rss);
|
||||
|
@ -351,7 +354,7 @@ class _SearchResultState extends State<SearchResult> {
|
|||
? Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[300],
|
||||
color: Theme.of(context).primaryColorDark,
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight: Radius.circular(15.0),
|
||||
bottomLeft: Radius.circular(15.0),
|
||||
|
|
|
@ -7,7 +7,7 @@ class Import extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
return Consumer<ImportOmpl>(
|
||||
builder: (context, importOmpl, _) => Container(
|
||||
color: Colors.grey[300],
|
||||
color: Theme.of(context).primaryColorDark,
|
||||
child: importOmpl.importState == ImportState.start
|
||||
? Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:dio/dio.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tsacdop/class/podcast_group.dart';
|
||||
import 'package:tsacdop/class/settingstate.dart';
|
||||
import 'package:xml/xml.dart' as xml;
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
@ -47,6 +48,7 @@ class PopupMenu extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
ImportOmpl importOmpl = Provider.of<ImportOmpl>(context, listen: false);
|
||||
GroupList groupList = Provider.of<GroupList>(context, listen: false);
|
||||
SettingState setting = Provider.of<SettingState>(context);
|
||||
_refreshAll() async {
|
||||
var dbHelper = DBHelper();
|
||||
List<PodcastLocal> podcastList = await dbHelper.getPodcastLocalAll();
|
||||
|
@ -113,16 +115,15 @@ class PopupMenu extends StatelessWidget {
|
|||
await Future.delayed(Duration(seconds: 5));
|
||||
importOmpl.importState = ImportState.stop;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
importOmpl.importState = ImportState.error;
|
||||
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Network error, Subscribe failed',
|
||||
gravity: ToastGravity.TOP,
|
||||
);
|
||||
await Future.delayed(Duration(seconds: 5));
|
||||
importOmpl.importState = ImportState.stop;
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Network error, Subscribe failed',
|
||||
gravity: ToastGravity.TOP,
|
||||
);
|
||||
await Future.delayed(Duration(seconds: 5));
|
||||
importOmpl.importState = ImportState.stop;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,10 +145,11 @@ class PopupMenu extends StatelessWidget {
|
|||
for (int i = 0; i < total.length; i++) {
|
||||
if (total[i].xmlUrl != null) {
|
||||
importOmpl.rssTitle = total[i].text;
|
||||
try{await saveOmpl(total[i].xmlUrl);}
|
||||
catch (e){
|
||||
print(e.toString());
|
||||
}
|
||||
try {
|
||||
await saveOmpl(total[i].xmlUrl);
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
}
|
||||
print(total[i].text);
|
||||
}
|
||||
}
|
||||
|
@ -183,17 +185,23 @@ class PopupMenu extends StatelessWidget {
|
|||
),
|
||||
PopupMenuItem(
|
||||
value: 3,
|
||||
child: setting.theme != 2 ? Text('Night Mode') : Text('Light Mode'),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: 4,
|
||||
child: Text('About'),
|
||||
),
|
||||
],
|
||||
onSelected: (value) {
|
||||
if (value == 3) {
|
||||
if (value == 4) {
|
||||
Navigator.push(
|
||||
context, MaterialPageRoute(builder: (context) => AboutApp()));
|
||||
} else if (value == 2) {
|
||||
_getFilePath();
|
||||
} else if (value == 1) {
|
||||
_refreshAll();
|
||||
} else if (value == 3) {
|
||||
setting.theme != 2 ? setting.setTheme(2) : setting.setTheme(1);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
|
@ -65,9 +65,10 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
_remoteAudioLoading = true;
|
||||
Provider.of<AudioPlay>(context, listen: false).audioState = AudioState.load;
|
||||
|
||||
if (_backgroundAudioPlaying == true)
|
||||
{ _backgroundAudio?.pause();
|
||||
AudioSystem.instance.stopBackgroundDisplay();}
|
||||
if (_backgroundAudioPlaying == true) {
|
||||
_backgroundAudio?.pause();
|
||||
AudioSystem.instance.stopBackgroundDisplay();
|
||||
}
|
||||
_backgroundAudio?.dispose();
|
||||
_backgroundAudio = Audio.loadFromRemoteUrl(url,
|
||||
onDuration: (double durationSeconds) {
|
||||
|
@ -118,9 +119,10 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
_remoteAudioLoading = true;
|
||||
ByteData audio = getAudio(path);
|
||||
Provider.of<AudioPlay>(context, listen: false).audioState = AudioState.load;
|
||||
if (_backgroundAudioPlaying == true)
|
||||
{_backgroundAudio?.pause();
|
||||
AudioSystem.instance.stopBackgroundDisplay();}
|
||||
if (_backgroundAudioPlaying == true) {
|
||||
_backgroundAudio?.pause();
|
||||
AudioSystem.instance.stopBackgroundDisplay();
|
||||
}
|
||||
_backgroundAudio?.dispose();
|
||||
_backgroundAudio = Audio.loadFromByteData(audio,
|
||||
onDuration: (double durationSeconds) {
|
||||
|
@ -192,11 +194,6 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
setState(() {
|
||||
this.url = url;
|
||||
episode = Provider.of<AudioPlay>(context).episode;
|
||||
var color = json.decode(episode?.primaryColor);
|
||||
(color[0] > 200 && color[1] > 200 && color[2] > 200)
|
||||
? _c = Color.fromRGBO(
|
||||
(255 - color[0]), 255 - color[1], 255 - color[2], 1.0)
|
||||
: _c = Color.fromRGBO(color[0], color[1], color[2], 1.0);
|
||||
_backgroundAudioPlaying = true;
|
||||
_isLoading = true;
|
||||
_getFile(url).then((result) {
|
||||
|
@ -270,11 +267,10 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
'playnow', likeButtonId, 'ic_stat_play_circle_filled');
|
||||
|
||||
Future<void> _setNotification() async {
|
||||
final Uint8List imageBytes =
|
||||
File('${episode.imagePath}').readAsBytesSync();
|
||||
final Uint8List imageBytes = File('${episode.imagePath}').readAsBytesSync();
|
||||
AudioSystem.instance.setMetadata(AudioMetadata(
|
||||
title: episode.title,
|
||||
artist:episode.feedTitle,
|
||||
artist: episode.feedTitle,
|
||||
album: episode.feedTitle,
|
||||
genre: "Podcast",
|
||||
durationSeconds: _backgroundAudioDurationSeconds,
|
||||
|
@ -309,8 +305,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
Provider.of<AudioPlay>(context, listen: false).audioState =
|
||||
AudioState.play;
|
||||
});
|
||||
final Uint8List imageBytes =
|
||||
File('${episode.imagePath}').readAsBytesSync();
|
||||
final Uint8List imageBytes = File('${episode.imagePath}').readAsBytesSync();
|
||||
AudioSystem.instance.setMetadata(AudioMetadata(
|
||||
title: episode.title,
|
||||
artist: episode.feedTitle,
|
||||
|
@ -383,9 +378,9 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
AudioSystem.instance.setPlaybackState(true, forwardposition);
|
||||
}
|
||||
|
||||
Widget _expandedPanel() => Container(
|
||||
Widget _expandedPanel(BuildContext context) => Container(
|
||||
height: 300,
|
||||
color: Colors.grey[100],
|
||||
color: Theme.of(context).primaryColor,
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
|
@ -459,7 +454,8 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
color: const Color(0xFFFF0000)))
|
||||
: Text(
|
||||
_remoteAudioLoading ? 'Buffring...' : '',
|
||||
style: TextStyle(color: Colors.blue),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).accentColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -474,6 +470,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
height: 100,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
|
@ -484,7 +481,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
: null,
|
||||
iconSize: 32.0,
|
||||
icon: Icon(Icons.replay_10),
|
||||
color: Colors.black),
|
||||
color: Theme.of(context).tabBarTheme.labelColor),
|
||||
),
|
||||
_backgroundAudioPlaying
|
||||
? Material(
|
||||
|
@ -498,7 +495,8 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
: null,
|
||||
iconSize: 40.0,
|
||||
icon: Icon(Icons.pause_circle_filled),
|
||||
color: Colors.black),
|
||||
color:
|
||||
Theme.of(context).tabBarTheme.labelColor),
|
||||
)
|
||||
: Material(
|
||||
color: Colors.transparent,
|
||||
|
@ -511,7 +509,8 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
},
|
||||
iconSize: 40.0,
|
||||
icon: Icon(Icons.play_circle_filled),
|
||||
color: Colors.black),
|
||||
color:
|
||||
Theme.of(context).tabBarTheme.labelColor),
|
||||
),
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
|
@ -522,7 +521,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
: null,
|
||||
iconSize: 32.0,
|
||||
icon: Icon(Icons.forward_30),
|
||||
color: Colors.black),
|
||||
color: Theme.of(context).tabBarTheme.labelColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -533,7 +532,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
margin: EdgeInsets.symmetric(vertical: 10.0),
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.0),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
borderRadius: BorderRadius.all(Radius.circular(10.0)),
|
||||
),
|
||||
child: Row(
|
||||
|
@ -545,12 +544,9 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(15.0)),
|
||||
child: Container(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
color: Colors.white,
|
||||
child: Image.file(
|
||||
File("${episode.imagePath}"))
|
||||
),
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: Image.file(File("${episode.imagePath}"))),
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
|
@ -565,138 +561,158 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
))
|
||||
]),
|
||||
);
|
||||
Widget _miniPanel(double width) => Container(
|
||||
height: 60,
|
||||
color: Colors.grey[100],
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
SizedBox(
|
||||
height: 2,
|
||||
child: LinearProgressIndicator(
|
||||
value: _seekSliderValue,
|
||||
backgroundColor: Colors.grey[100],
|
||||
valueColor: AlwaysStoppedAnimation<Color>(_c),
|
||||
)),
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 15, right: 10),
|
||||
alignment: Alignment.center,
|
||||
Widget _miniPanel(double width, BuildContext context) {
|
||||
var color = json.decode(episode?.primaryColor);
|
||||
if (color) {
|
||||
if (Theme.of(context).brightness == Brightness.light) {
|
||||
_c = (color[0] > 200 && color[1] > 200 && color[2] > 200)
|
||||
? Color.fromRGBO(
|
||||
(255 - color[0]), 255 - color[1], 255 - color[2], 1.0)
|
||||
: Color.fromRGBO(color[0], color[1], color[2], 1.0);
|
||||
} else {
|
||||
_c = (color[0] < 50 && color[1] < 50 && color[2] < 50)
|
||||
? Color.fromRGBO(
|
||||
(255 - color[0]), 255 - color[1], 255 - color[2], 1.0)
|
||||
: Color.fromRGBO(color[0], color[1], color[2], 1.0);
|
||||
}
|
||||
}
|
||||
return Container(
|
||||
height: 60,
|
||||
color: Theme.of(context).primaryColor,
|
||||
child:
|
||||
Column(mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[
|
||||
SizedBox(
|
||||
height: 2,
|
||||
child: LinearProgressIndicator(
|
||||
value: _seekSliderValue,
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(_c),
|
||||
)),
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 15, right: 10),
|
||||
alignment: Alignment.center,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
flex: 4,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 5),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: (episode.title.length > 55)
|
||||
? Marquee(
|
||||
text: episode.title,
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
scrollAxis: Axis.vertical,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
blankSpace: 30.0,
|
||||
velocity: 50.0,
|
||||
pauseAfterRound: Duration(seconds: 1),
|
||||
startPadding: 30.0,
|
||||
accelerationDuration: Duration(seconds: 1),
|
||||
accelerationCurve: Curves.linear,
|
||||
decelerationDuration: Duration(milliseconds: 500),
|
||||
decelerationCurve: Curves.easeOut,
|
||||
)
|
||||
: Text(
|
||||
episode.title,
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
maxLines: 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||
alignment: Alignment.center,
|
||||
child: _remoteAudioLoading
|
||||
? Text(
|
||||
'Buffring...',
|
||||
style:
|
||||
TextStyle(color: Theme.of(context).accentColor),
|
||||
)
|
||||
: Row(
|
||||
children: <Widget>[
|
||||
Text(
|
||||
_stringForSeconds(
|
||||
_backgroundAudioDurationSeconds -
|
||||
_backgroundAudioPositionSeconds) ??
|
||||
'',
|
||||
style: TextStyle(color: _c),
|
||||
),
|
||||
Text(
|
||||
' Left',
|
||||
style: TextStyle(color: _c),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
flex: 4,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 5),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: (episode.title.length > 55)
|
||||
? Marquee(
|
||||
text: episode.title,
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
scrollAxis: Axis.vertical,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
blankSpace: 30.0,
|
||||
velocity: 50.0,
|
||||
pauseAfterRound: Duration(seconds: 1),
|
||||
startPadding: 30.0,
|
||||
accelerationDuration: Duration(seconds: 1),
|
||||
accelerationCurve: Curves.linear,
|
||||
decelerationDuration:
|
||||
Duration(milliseconds: 500),
|
||||
decelerationCurve: Curves.easeOut,
|
||||
)
|
||||
: Text(
|
||||
episode.title,
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
maxLines: 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||
alignment: Alignment.center,
|
||||
child: _remoteAudioLoading
|
||||
? Text(
|
||||
'Buffring...',
|
||||
style: TextStyle(color: Colors.blue),
|
||||
)
|
||||
: Row(
|
||||
children: <Widget>[
|
||||
Text(
|
||||
_stringForSeconds(
|
||||
_backgroundAudioDurationSeconds -
|
||||
_backgroundAudioPositionSeconds) ??
|
||||
'',
|
||||
style: TextStyle(color: _c),
|
||||
),
|
||||
Text(
|
||||
' Left',
|
||||
style: TextStyle(color: _c),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
_backgroundAudioPlaying
|
||||
? Material(
|
||||
color: Colors.transparent,
|
||||
child: IconButton(
|
||||
onPressed: _backgroundAudioPlaying
|
||||
? () {
|
||||
_pauseBackgroundAudio();
|
||||
}
|
||||
: null,
|
||||
iconSize: 25.0,
|
||||
icon: Icon(Icons.pause_circle_filled),
|
||||
color: Colors.black),
|
||||
)
|
||||
: Material(
|
||||
color: Colors.transparent,
|
||||
child: IconButton(
|
||||
onPressed: _backgroundAudioPlaying
|
||||
? null
|
||||
: () {
|
||||
_resumeBackgroundAudio();
|
||||
},
|
||||
iconSize: 25.0,
|
||||
icon: Icon(Icons.play_circle_filled),
|
||||
color: Colors.black),
|
||||
),
|
||||
Material(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
_backgroundAudioPlaying
|
||||
? Material(
|
||||
color: Colors.transparent,
|
||||
child: IconButton(
|
||||
onPressed: _backgroundAudioPlaying
|
||||
? () => _forwardBackgroundAudio(30)
|
||||
? () {
|
||||
_pauseBackgroundAudio();
|
||||
}
|
||||
: null,
|
||||
iconSize: 25.0,
|
||||
icon: Icon(Icons.forward_30),
|
||||
color: Colors.black),
|
||||
icon: Icon(Icons.pause_circle_filled),
|
||||
color:
|
||||
Theme.of(context).tabBarTheme.labelColor),
|
||||
)
|
||||
: Material(
|
||||
color: Colors.transparent,
|
||||
child: IconButton(
|
||||
onPressed: _backgroundAudioPlaying
|
||||
? null
|
||||
: () {
|
||||
_resumeBackgroundAudio();
|
||||
},
|
||||
iconSize: 25.0,
|
||||
icon: Icon(Icons.play_circle_filled),
|
||||
color:
|
||||
Theme.of(context).tabBarTheme.labelColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child: IconButton(
|
||||
onPressed: _backgroundAudioPlaying
|
||||
? () => _forwardBackgroundAudio(30)
|
||||
: null,
|
||||
iconSize: 25.0,
|
||||
icon: Icon(Icons.forward_30),
|
||||
color: Theme.of(context).tabBarTheme.labelColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
]),
|
||||
);
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
double _width = MediaQuery.of(context).size.width;
|
||||
|
||||
return !_isLoading
|
||||
? Center()
|
||||
: AudioPanel(
|
||||
miniPanel: _miniPanel(_width), expandedPanel: _expandedPanel());
|
||||
miniPanel: _miniPanel(_width, context),
|
||||
expandedPanel: _expandedPanel(context));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ class _AudioPanelState extends State<AudioPanel>
|
|||
child: GestureDetector(
|
||||
onTap: () => _backToMini(),
|
||||
child: Container(
|
||||
color: Colors.white.withOpacity(0.5),
|
||||
color: Theme.of(context).scaffoldBackgroundColor.withOpacity(0.5),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
@ -64,7 +64,7 @@ class _AudioPanelState extends State<AudioPanel>
|
|||
: (_animation.value <= minSize) ? minSize : _animation.value,
|
||||
child: _animation.value < minSize + 30
|
||||
? Container(
|
||||
color: Colors.grey[100],
|
||||
color: Theme.of(context).primaryColor,
|
||||
child: Opacity(
|
||||
opacity: _animation.value > minSize
|
||||
? (minSize + 30 - _animation.value) / 40
|
||||
|
@ -75,7 +75,7 @@ class _AudioPanelState extends State<AudioPanel>
|
|||
),
|
||||
)
|
||||
: Container(
|
||||
color: Colors.grey[100],
|
||||
color: Theme.of(context).primaryColor,
|
||||
child: SingleChildScrollView(
|
||||
child: Opacity(
|
||||
opacity: _animation.value < (maxSize - 50)
|
||||
|
|
|
@ -87,9 +87,10 @@ class _ScrollPodcastsState extends State<ScrollPodcasts> {
|
|||
EdgeInsets.symmetric(horizontal: 15.0),
|
||||
child: Text(
|
||||
groups[_groupIndex].name,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.red[300]),
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.copyWith(color: Colors.red[300]),
|
||||
)),
|
||||
Spacer(),
|
||||
Container(
|
||||
|
@ -104,21 +105,24 @@ class _ScrollPodcastsState extends State<ScrollPodcasts> {
|
|||
);
|
||||
},
|
||||
child: Container(
|
||||
height: 30,
|
||||
padding: EdgeInsets.all(5.0),
|
||||
child: Text('See All',
|
||||
style: TextStyle(
|
||||
color: Colors.red[300],
|
||||
fontWeight: FontWeight.bold,
|
||||
)),
|
||||
),
|
||||
height: 30,
|
||||
padding: EdgeInsets.all(5.0),
|
||||
child: Text(
|
||||
'See All',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.accentColor),
|
||||
)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
color: Colors.white10,
|
||||
// color: Colors.white10,
|
||||
height: 70,
|
||||
width: _width,
|
||||
alignment: Alignment.centerLeft,
|
||||
|
@ -153,14 +157,15 @@ class _ScrollPodcastsState extends State<ScrollPodcasts> {
|
|||
height: (_width - 20) / 3 + 40,
|
||||
margin: EdgeInsets.only(left: 10, right: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
),
|
||||
child: TabBarView(
|
||||
children: groups[_groupIndex]
|
||||
.podcasts
|
||||
.map<Widget>((PodcastLocal podcastLocal) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(color: Colors.grey[100]),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).primaryColor),
|
||||
margin: EdgeInsets.symmetric(horizontal: 5.0),
|
||||
key: ObjectKey(podcastLocal.title),
|
||||
child: PodcastPreview(
|
||||
|
@ -193,18 +198,21 @@ class _PodcastPreviewState extends State<PodcastPreview> {
|
|||
}
|
||||
|
||||
Color _c;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
var color = json.decode(widget.podcastLocal.primaryColor);
|
||||
(color[0] > 200 && color[1] > 200 && color[2] > 200)
|
||||
? _c = Color.fromRGBO(
|
||||
(255 - color[0]), 255 - color[1], 255 - color[2], 1.0)
|
||||
: _c = Color.fromRGBO(color[0], color[1], color[2], 1.0);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var color = json.decode(widget.podcastLocal.primaryColor);
|
||||
if (Theme.of(context).brightness == Brightness.light) {
|
||||
(color[0] > 200 && color[1] > 200 && color[2] > 200)
|
||||
? _c = Color.fromRGBO(
|
||||
(255 - color[0]), 255 - color[1], 255 - color[2], 1.0)
|
||||
: _c = Color.fromRGBO(color[0], color[1], color[2], 1.0);
|
||||
} else {
|
||||
(color[0] < 50 && color[1] < 50 && color[2] < 50)
|
||||
? _c = Color.fromRGBO(
|
||||
(255 - color[0]), 255 - color[1], 255 - color[2], 1.0)
|
||||
: _c = Color.fromRGBO(color[0], color[1], color[2], 1.0);
|
||||
}
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
|
@ -294,10 +302,18 @@ class ShowEpisode extends StatelessWidget {
|
|||
(BuildContext context, int index) {
|
||||
Color _c;
|
||||
var color = json.decode(podcast[index].primaryColor);
|
||||
(color[0] > 200 && color[1] > 200 && color[2] > 200)
|
||||
? _c = Color.fromRGBO(
|
||||
(255 - color[0]), 255 - color[1], 255 - color[2], 1.0)
|
||||
: _c = Color.fromRGBO(color[0], color[1], color[2], 1.0);
|
||||
|
||||
if (Theme.of(context).brightness == Brightness.light) {
|
||||
(color[0] > 200 && color[1] > 200 && color[2] > 200)
|
||||
? _c = Color.fromRGBO(
|
||||
(255 - color[0]), 255 - color[1], 255 - color[2], 1.0)
|
||||
: _c = Color.fromRGBO(color[0], color[1], color[2], 1.0);
|
||||
} else {
|
||||
(color[0] < 50 && color[1] < 50 && color[2] < 50)
|
||||
? _c = Color.fromRGBO(
|
||||
(255 - color[0]), 255 - color[1], 255 - color[2], 1.0)
|
||||
: _c = Color.fromRGBO(color[0], color[1], color[2], 1.0);
|
||||
}
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
|
@ -315,12 +331,12 @@ class ShowEpisode extends StatelessWidget {
|
|||
borderRadius: BorderRadius.all(Radius.circular(5.0)),
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
border: Border.all(
|
||||
color: Colors.grey[100],
|
||||
color: Theme.of(context).primaryColor,
|
||||
width: 3.0,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey[100],
|
||||
color: Theme.of(context).primaryColor,
|
||||
blurRadius: 1.0,
|
||||
spreadRadius: 0.5,
|
||||
),
|
||||
|
|
|
@ -12,11 +12,16 @@ class MainTab extends StatefulWidget {
|
|||
|
||||
class _MainTabState extends State<MainTab> with TickerProviderStateMixin {
|
||||
TabController _controller;
|
||||
Decoration getIndicator() {
|
||||
return const UnderlineTabIndicator(
|
||||
borderSide: BorderSide(color: Colors.red, width: 2),
|
||||
insets: EdgeInsets.only(left:10.0,right: 10.0, top:10.0,)
|
||||
);}
|
||||
Decoration getIndicator(BuildContext context) {
|
||||
return UnderlineTabIndicator(
|
||||
borderSide: BorderSide(color: Theme.of(context).accentColor, width: 2),
|
||||
insets: EdgeInsets.only(
|
||||
left: 10.0,
|
||||
right: 10.0,
|
||||
top: 10.0,
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
@ -41,17 +46,23 @@ class _MainTabState extends State<MainTab> with TickerProviderStateMixin {
|
|||
alignment: Alignment.centerLeft,
|
||||
child: TabBar(
|
||||
isScrollable: true,
|
||||
labelPadding:
|
||||
EdgeInsets.all(10.0),
|
||||
labelPadding: EdgeInsets.all(10.0),
|
||||
controller: _controller,
|
||||
labelColor: Colors.red,
|
||||
unselectedLabelColor: Colors.black,
|
||||
indicator: getIndicator(),
|
||||
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),),
|
||||
],
|
||||
Text(
|
||||
'Recent Update',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
Text(
|
||||
'Favorites',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
Text(
|
||||
'Downloads',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
|
@ -96,7 +107,13 @@ class _RecentUpdateState extends State<RecentUpdate> {
|
|||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) print(snapshot.error);
|
||||
return (snapshot.hasData)
|
||||
? EpisodeGrid(podcast: snapshot.data, showDownload: false, showFavorite: false, showNumber: false, heroTag: 'recent',)
|
||||
? EpisodeGrid(
|
||||
podcast: snapshot.data,
|
||||
showDownload: false,
|
||||
showFavorite: false,
|
||||
showNumber: false,
|
||||
heroTag: 'recent',
|
||||
)
|
||||
: Center(child: CircularProgressIndicator());
|
||||
},
|
||||
);
|
||||
|
@ -111,7 +128,7 @@ class MyFavorite extends StatefulWidget {
|
|||
class _MyFavoriteState extends State<MyFavorite> {
|
||||
Future<List<EpisodeBrief>> _getLikedRssItem() async {
|
||||
var dbHelper = DBHelper();
|
||||
List<EpisodeBrief> episodes =await dbHelper.getLikedRssItem();
|
||||
List<EpisodeBrief> episodes = await dbHelper.getLikedRssItem();
|
||||
return episodes;
|
||||
}
|
||||
|
||||
|
@ -122,26 +139,31 @@ class _MyFavoriteState extends State<MyFavorite> {
|
|||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) print(snapshot.error);
|
||||
return (snapshot.hasData)
|
||||
? EpisodeGrid(podcast: snapshot.data, showDownload: false, showFavorite: false, showNumber: false, heroTag: 'favorite',)
|
||||
? EpisodeGrid(
|
||||
podcast: snapshot.data,
|
||||
showDownload: false,
|
||||
showFavorite: false,
|
||||
showNumber: false,
|
||||
heroTag: 'favorite',
|
||||
)
|
||||
: Center(child: CircularProgressIndicator());
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MyDownload extends StatefulWidget {
|
||||
class MyDownload extends StatefulWidget {
|
||||
@override
|
||||
_MyDownloadState createState() => _MyDownloadState();
|
||||
}
|
||||
|
||||
|
||||
class _MyDownloadState extends State<MyDownload> {
|
||||
Future<List<EpisodeBrief>> _getDownloadedRssItem() async {
|
||||
var dbHelper = DBHelper();
|
||||
List<EpisodeBrief> episodes =await dbHelper.getDownloadedRssItem();
|
||||
List<EpisodeBrief> episodes = await dbHelper.getDownloadedRssItem();
|
||||
return episodes;
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder<List<EpisodeBrief>>(
|
||||
|
@ -149,10 +171,15 @@ class _MyDownloadState extends State<MyDownload> {
|
|||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) print(snapshot.error);
|
||||
return (snapshot.hasData)
|
||||
? EpisodeGrid(podcast: snapshot.data, showDownload: true, showFavorite: false, showNumber: false, heroTag: 'download',)
|
||||
? EpisodeGrid(
|
||||
podcast: snapshot.data,
|
||||
showDownload: true,
|
||||
showFavorite: false,
|
||||
showNumber: false,
|
||||
heroTag: 'download',
|
||||
)
|
||||
: Center(child: CircularProgressIndicator());
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,4 +31,15 @@ class KeyValueStorage {
|
|||
json.encode(
|
||||
{'groups': groupList.map((group) => group.toJson()).toList()}));
|
||||
}
|
||||
|
||||
Future<bool> saveTheme(int setting) async{
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
return prefs.setInt(key, setting);
|
||||
}
|
||||
|
||||
Future<int> getTheme() async{
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
if(prefs.getInt(key) == null) await prefs.setInt(key, 0);
|
||||
return prefs.getInt(key);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,14 +28,35 @@ void main() async {
|
|||
class MyApp extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
SystemChrome.setSystemUIOverlayStyle(
|
||||
SystemUiOverlayStyle(statusBarColor: Colors.grey[100]));
|
||||
var theme = Provider.of<SettingState>(context).theme;
|
||||
return MaterialApp(
|
||||
themeMode: theme == 0
|
||||
? ThemeMode.system
|
||||
: theme == 1 ? ThemeMode.dark : ThemeMode.light,
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'TsacDop',
|
||||
theme: ThemeData(
|
||||
primaryColor: Colors.white,
|
||||
accentColorBrightness: Brightness.dark,
|
||||
primaryColor: Colors.grey[100],
|
||||
accentColor: Colors.blue[400],
|
||||
primaryColorLight: Colors.white,
|
||||
primaryColorDark: Colors.grey[300],
|
||||
dialogBackgroundColor: Colors.white,
|
||||
backgroundColor: Colors.grey[100],
|
||||
appBarTheme: AppBarTheme(
|
||||
color: Colors.grey[100],
|
||||
elevation: 0,
|
||||
),
|
||||
textTheme: TextTheme(
|
||||
headline1: TextStyle(fontSize: 72.0, fontWeight: FontWeight.bold),
|
||||
bodyText2: TextStyle(fontSize: 15.0, fontWeight: FontWeight.normal),
|
||||
),
|
||||
tabBarTheme: TabBarTheme(
|
||||
labelColor: Colors.black,
|
||||
unselectedLabelColor: Colors.grey[400],
|
||||
),
|
||||
),
|
||||
darkTheme: ThemeData.dark(),
|
||||
home: MyHomePage(),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'dart:async';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:tsacdop/class/podcastlocal.dart';
|
||||
|
@ -21,48 +22,62 @@ class _PodcastDetailState extends State<PodcastDetail> {
|
|||
Future _updateRssItem(PodcastLocal podcastLocal) async {
|
||||
var dbHelper = DBHelper();
|
||||
final result = await dbHelper.updatePodcastRss(podcastLocal);
|
||||
result == 0 ?
|
||||
Fluttertoast.showToast(
|
||||
msg: 'No Update',
|
||||
gravity: ToastGravity.TOP,
|
||||
)
|
||||
: Fluttertoast.showToast(
|
||||
msg: 'Updated $result Episodes',
|
||||
gravity: ToastGravity.TOP,
|
||||
);
|
||||
if(mounted) setState(() {});
|
||||
result == 0
|
||||
? Fluttertoast.showToast(
|
||||
msg: 'No Update',
|
||||
gravity: ToastGravity.TOP,
|
||||
)
|
||||
: Fluttertoast.showToast(
|
||||
msg: 'Updated $result Episodes',
|
||||
gravity: ToastGravity.TOP,
|
||||
);
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
Future<List<EpisodeBrief>> _getRssItem(PodcastLocal podcastLocal) async {
|
||||
print(podcastLocal.id);
|
||||
var dbHelper = DBHelper();
|
||||
List<EpisodeBrief> episodes = await
|
||||
dbHelper.getRssItem(podcastLocal.id);
|
||||
List<EpisodeBrief> episodes = await dbHelper.getRssItem(podcastLocal.id);
|
||||
return episodes;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(widget.podcastLocal.title,),
|
||||
elevation: 0.0,
|
||||
backgroundColor: Colors.grey[100],
|
||||
centerTitle: true,
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
||||
statusBarColor: Theme.of(context).primaryColor,
|
||||
),
|
||||
child: SafeArea(
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
widget.podcastLocal.title,
|
||||
),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: RefreshIndicator(
|
||||
key: _refreshIndicatorKey,
|
||||
color: Colors.blue[500],
|
||||
onRefresh: () => _updateRssItem(widget.podcastLocal),
|
||||
child: FutureBuilder<List<EpisodeBrief>>(
|
||||
future: _getRssItem(widget.podcastLocal),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) print(snapshot.error);
|
||||
return (snapshot.hasData)
|
||||
? EpisodeGrid(
|
||||
podcast: snapshot.data,
|
||||
showDownload: true,
|
||||
showFavorite: true,
|
||||
showNumber: true,
|
||||
heroTag: 'podcast',
|
||||
)
|
||||
: Center(child: CircularProgressIndicator());
|
||||
},
|
||||
)),
|
||||
),
|
||||
body: RefreshIndicator(
|
||||
key: _refreshIndicatorKey,
|
||||
color: Colors.blue[500],
|
||||
onRefresh: () => _updateRssItem(widget.podcastLocal),
|
||||
child: FutureBuilder<List<EpisodeBrief>>(
|
||||
future: _getRssItem(widget.podcastLocal),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) print(snapshot.error);
|
||||
return (snapshot.hasData)
|
||||
? EpisodeGrid(podcast: snapshot.data, showDownload: true, showFavorite: true, showNumber: true, heroTag: 'podcast',)
|
||||
: Center(child: CircularProgressIndicator());
|
||||
},
|
||||
)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import 'dart:io';
|
|||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tsacdop/class/podcast_group.dart';
|
||||
|
@ -36,14 +37,15 @@ class _PodcastGroupListState extends State<PodcastGroupList> {
|
|||
width: _loadSave ? 70 : 0,
|
||||
height: 60,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue,
|
||||
shape: BoxShape.circle,
|
||||
boxShadow: [BoxShadow(
|
||||
color: Colors.grey[700],
|
||||
blurRadius: 5,
|
||||
offset: Offset(1, 1),
|
||||
),]
|
||||
),
|
||||
color: Colors.blue,
|
||||
shape: BoxShape.circle,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey[700],
|
||||
blurRadius: 5,
|
||||
offset: Offset(1, 1),
|
||||
),
|
||||
]),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
'Save',
|
||||
|
@ -68,10 +70,10 @@ class _PodcastGroupListState extends State<PodcastGroupList> {
|
|||
Widget build(BuildContext context) {
|
||||
return widget.group.podcastList.length == 0
|
||||
? Container(
|
||||
color: Colors.grey[100],
|
||||
color: Theme.of(context).primaryColor,
|
||||
)
|
||||
: Container(
|
||||
color: Colors.grey[100],
|
||||
color: Theme.of(context).primaryColor,
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
ReorderableListView(
|
||||
|
@ -89,7 +91,8 @@ class _PodcastGroupListState extends State<PodcastGroupList> {
|
|||
children: widget.group.podcasts
|
||||
.map<Widget>((PodcastLocal podcastLocal) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(color: Colors.grey[100]),
|
||||
decoration:
|
||||
BoxDecoration(color: Theme.of(context).primaryColor),
|
||||
key: ObjectKey(podcastLocal.title),
|
||||
child: PodcastCard(
|
||||
podcastLocal: podcastLocal,
|
||||
|
@ -147,10 +150,17 @@ class _PodcastCardState extends State<PodcastCard> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var color = json.decode(widget.podcastLocal.primaryColor);
|
||||
(color[0] > 200 && color[1] > 200 && color[2] > 200)
|
||||
? _c = Color.fromRGBO(
|
||||
(255 - color[0]), 255 - color[1], 255 - color[2], 1.0)
|
||||
: _c = Color.fromRGBO(color[0], color[1], color[2], 1.0);
|
||||
if (Theme.of(context).brightness == Brightness.light) {
|
||||
(color[0] > 200 && color[1] > 200 && color[2] > 200)
|
||||
? _c = Color.fromRGBO(
|
||||
(255 - color[0]), 255 - color[1], 255 - color[2], 1.0)
|
||||
: _c = Color.fromRGBO(color[0], color[1], color[2], 1.0);
|
||||
} else {
|
||||
(color[0] < 50 && color[1] < 50 && color[2] < 50)
|
||||
? _c = Color.fromRGBO(
|
||||
(255 - color[0]), 255 - color[1], 255 - color[2], 1.0)
|
||||
: _c = Color.fromRGBO(color[0], color[1], color[2], 1.0);
|
||||
}
|
||||
double _width = MediaQuery.of(context).size.width;
|
||||
var _groupList = Provider.of<GroupList>(context);
|
||||
_belongGroups = _groupList.getPodcastGroup(widget.podcastLocal.id);
|
||||
|
@ -219,27 +229,35 @@ class _PodcastCardState extends State<PodcastCard> {
|
|||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
child: AlertDialog(
|
||||
elevation: 2.0,
|
||||
title: Text('Remove confirm'),
|
||||
content: Text(
|
||||
'${widget.podcastLocal.title} will be removed from device.'),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text('CANCEL'),
|
||||
),
|
||||
FlatButton(
|
||||
onPressed: () {
|
||||
_groupList.removePodcast(widget.podcastLocal.id);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(
|
||||
'CONFIRM',
|
||||
style: TextStyle(color: Colors.red),
|
||||
child: AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
systemNavigationBarColor:
|
||||
Colors.black.withOpacity(0.5),
|
||||
statusBarColor: Colors.red,
|
||||
),
|
||||
child: AlertDialog(
|
||||
elevation: 2.0,
|
||||
title: Text('Remove confirm'),
|
||||
content: Text(
|
||||
'${widget.podcastLocal.title} will be removed from device.'),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text('CANCEL'),
|
||||
),
|
||||
)
|
||||
],
|
||||
FlatButton(
|
||||
onPressed: () {
|
||||
_groupList
|
||||
.removePodcast(widget.podcastLocal.id);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(
|
||||
'CONFIRM',
|
||||
style: TextStyle(color: Colors.red),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
));
|
||||
},
|
||||
),
|
||||
|
@ -251,10 +269,12 @@ class _PodcastCardState extends State<PodcastCard> {
|
|||
: Container(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[100],
|
||||
color: Theme.of(context).primaryColor,
|
||||
border: Border(
|
||||
bottom: BorderSide(color: Colors.grey[300]),
|
||||
top: BorderSide(color: Colors.grey[300]))),
|
||||
bottom: BorderSide(
|
||||
color: Theme.of(context).primaryColorDark),
|
||||
top: BorderSide(
|
||||
color: Theme.of(context).primaryColorDark))),
|
||||
height: 50,
|
||||
child: _addGroup
|
||||
? Row(
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter/rendering.dart';
|
||||
import 'dart:async';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_html/flutter_html.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tsacdop/class/podcast_group.dart';
|
||||
|
@ -52,7 +53,6 @@ class _AboutPodcastState extends State<AboutPodcast> {
|
|||
_groupList.removePodcast(widget.podcastLocal.id);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
color: Colors.grey[200],
|
||||
textColor: Colors.red,
|
||||
child: Text(
|
||||
'UNSUBSCRIBE',
|
||||
|
@ -83,7 +83,6 @@ class PodcastList extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _PodcastListState extends State<PodcastList> {
|
||||
|
||||
Future<List<PodcastLocal>> getPodcastLocal() async {
|
||||
var dbHelper = DBHelper();
|
||||
var podcastList = await dbHelper.getPodcastLocalAll();
|
||||
|
@ -93,109 +92,100 @@ class _PodcastListState extends State<PodcastList> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
double _width = MediaQuery.of(context).size.width;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Podcasts'),
|
||||
centerTitle: true,
|
||||
backgroundColor: Colors.grey[100],
|
||||
elevation: 0,
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
||||
statusBarColor: Theme.of(context).primaryColor,
|
||||
),
|
||||
body: Container(
|
||||
color: Colors.grey[100],
|
||||
child: FutureBuilder<List<PodcastLocal>>(
|
||||
future: getPodcastLocal(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return CustomScrollView(
|
||||
primary: false,
|
||||
slivers: <Widget>[
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
childAspectRatio: 0.8,
|
||||
crossAxisCount: 3,
|
||||
),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(BuildContext context, int index) {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
ScaleRoute(
|
||||
page: PodcastDetail(
|
||||
podcastLocal: snapshot.data[index],
|
||||
)),
|
||||
child: SafeArea(
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Podcasts'),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: Container(
|
||||
color: Theme.of(context).primaryColor,
|
||||
child: FutureBuilder<List<PodcastLocal>>(
|
||||
future: getPodcastLocal(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return CustomScrollView(
|
||||
primary: false,
|
||||
slivers: <Widget>[
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate:
|
||||
SliverGridDelegateWithFixedCrossAxisCount(
|
||||
childAspectRatio: 0.8,
|
||||
crossAxisCount: 3,
|
||||
),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(BuildContext context, int index) {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
ScaleRoute(
|
||||
page: PodcastDetail(
|
||||
podcastLocal: snapshot.data[index],
|
||||
)),
|
||||
);
|
||||
},
|
||||
onLongPress: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) =>
|
||||
AboutPodcast(
|
||||
podcastLocal: snapshot.data[index]),
|
||||
).then((_) => setState(() {}));
|
||||
},
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
height: 10.0,
|
||||
),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(_width / 8)),
|
||||
child: Container(
|
||||
height: _width / 4,
|
||||
width: _width / 4,
|
||||
child: Image.file(File(
|
||||
"${snapshot.data[index].imagePath}")),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.all(4.0),
|
||||
child: Text(
|
||||
snapshot.data[index].title,
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.bodyText1,
|
||||
maxLines: 2,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
onLongPress: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) => AboutPodcast(
|
||||
podcastLocal: snapshot.data[index]),
|
||||
).then((_) => setState(() {}));
|
||||
},
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
height: 10.0,
|
||||
),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(_width / 8)),
|
||||
child: Container(
|
||||
height: _width / 4,
|
||||
width: _width / 4,
|
||||
child: Image.file(File(
|
||||
"${snapshot.data[index].imagePath}")),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.all(4.0),
|
||||
child: Text(
|
||||
snapshot.data[index].title,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Colors.black.withOpacity(0.5),
|
||||
),
|
||||
maxLines: 2,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
childCount: snapshot.data.length,
|
||||
childCount: snapshot.data.length,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
return Text('NoData');
|
||||
},
|
||||
],
|
||||
);
|
||||
}
|
||||
return Text('NoData');
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Podcast extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.grey[100],
|
||||
elevation: 0,
|
||||
centerTitle: true,
|
||||
title: Text('Podcasts'),
|
||||
),
|
||||
body: Container(child: PodcastList()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tsacdop/class/podcast_group.dart';
|
||||
import 'package:tsacdop/podcasts/podcastgroup.dart';
|
||||
|
@ -26,86 +27,85 @@ class _PodcastManageState extends State<PodcastManage> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
elevation: 0,
|
||||
centerTitle: true,
|
||||
backgroundColor: Colors.grey[100],
|
||||
title: Text('Groups'),
|
||||
actions: <Widget>[
|
||||
OrderMenu(),
|
||||
],
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
||||
statusBarColor: Theme.of(context).primaryColor,
|
||||
),
|
||||
body: Consumer<GroupList>(builder: (_, groupList, __) {
|
||||
bool _isLoading = groupList.isLoading;
|
||||
List<PodcastGroup> _groups = groupList.groups;
|
||||
return _isLoading
|
||||
? Center()
|
||||
: DefaultTabController(
|
||||
length: _groups.length,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
child: SafeArea(
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
centerTitle: true,
|
||||
title: Text('Groups'),
|
||||
actions: <Widget>[
|
||||
IconButton(
|
||||
onPressed: () => showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) => AddGroup()),
|
||||
icon: Icon(Icons.add)),
|
||||
OrderMenu(),
|
||||
],
|
||||
),
|
||||
body: Consumer<GroupList>(builder: (_, groupList, __) {
|
||||
bool _isLoading = groupList.isLoading;
|
||||
List<PodcastGroup> _groups = groupList.groups;
|
||||
return _isLoading
|
||||
? Center()
|
||||
: DefaultTabController(
|
||||
length: _groups.length,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
flex: 4,
|
||||
child: Container(
|
||||
height: 50,
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.0),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: TabBar(
|
||||
labelColor: Colors.black,
|
||||
unselectedLabelColor: Colors.grey[500],
|
||||
labelPadding: EdgeInsets.all(5.0),
|
||||
indicator: getIndicator(),
|
||||
isScrollable: true,
|
||||
tabs: _groups.map<Tab>((group) {
|
||||
return Tab(
|
||||
child: Container(
|
||||
height: 30.0,
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 10.0),
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[300],
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(15)),
|
||||
),
|
||||
child: Text(
|
||||
group.name,
|
||||
)),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
Container(
|
||||
height: 50,
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.0),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: TabBar(
|
||||
// labelColor: Colors.black,
|
||||
// unselectedLabelColor: Colors.grey[500],
|
||||
labelPadding: EdgeInsets.all(5.0),
|
||||
indicator: getIndicator(),
|
||||
isScrollable: true,
|
||||
tabs: _groups.map<Tab>((group) {
|
||||
return Tab(
|
||||
child: Container(
|
||||
height: 30.0,
|
||||
padding:
|
||||
EdgeInsets.symmetric(horizontal: 10.0),
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).brightness ==
|
||||
Brightness.light
|
||||
? Theme.of(context).primaryColorDark
|
||||
: Colors.grey[800],
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(15)),
|
||||
),
|
||||
child: Text(
|
||||
group.name,
|
||||
)),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: IconButton(
|
||||
onPressed: () => showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) =>
|
||||
AddGroup()),
|
||||
icon: Icon(Icons.add)),
|
||||
),
|
||||
child: Container(
|
||||
child: TabBarView(
|
||||
children: _groups.map<Widget>((group) {
|
||||
return Container(
|
||||
key: ObjectKey(group),
|
||||
child: PodcastGroupList(group: group));
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
child: TabBarView(
|
||||
children: _groups.map<Widget>((group) {
|
||||
return Container(
|
||||
key: ObjectKey(group),
|
||||
child: PodcastGroupList(group: group));
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
));
|
||||
}),
|
||||
));
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -166,66 +166,72 @@ class _AddGroupState extends State<AddGroup> {
|
|||
Widget build(BuildContext context) {
|
||||
var groupList = Provider.of<GroupList>(context);
|
||||
List list = groupList.groups.map((e) => e.name).toList();
|
||||
return AlertDialog(
|
||||
elevation: 1,
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 20),
|
||||
titlePadding: EdgeInsets.only(top: 20, left: 20, right: 20, bottom: 20),
|
||||
actionsPadding: EdgeInsets.all(0),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(
|
||||
'CANCEL',
|
||||
style: TextStyle(color: Colors.grey[700]),
|
||||
),
|
||||
),
|
||||
FlatButton(
|
||||
onPressed: () async {
|
||||
if (list.contains(_newGroup)) {
|
||||
setState(() => _error = 1);
|
||||
} else {
|
||||
groupList.addGroup(PodcastGroup(_newGroup));
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
child: Text('DONE'),
|
||||
)
|
||||
],
|
||||
title: Text('Create new group'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
TextField(
|
||||
decoration: InputDecoration(
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 10),
|
||||
hintText: 'New Group',
|
||||
hintStyle: TextStyle(fontSize: 18),
|
||||
filled: true,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.white, width: 2.0),
|
||||
),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.blue, width: 2.0),
|
||||
),
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
systemNavigationBarColor: Colors.black.withOpacity(0.5),
|
||||
statusBarColor: Colors.red,
|
||||
),
|
||||
child: AlertDialog(
|
||||
elevation: 1,
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 20),
|
||||
titlePadding: EdgeInsets.only(top: 20, left: 20, right: 20, bottom: 20),
|
||||
actionsPadding: EdgeInsets.all(0),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(
|
||||
'CANCEL',
|
||||
style: TextStyle(color: Colors.grey[600]),
|
||||
),
|
||||
cursorRadius: Radius.circular(2),
|
||||
autofocus: true,
|
||||
maxLines: 1,
|
||||
controller: _controller,
|
||||
onChanged: (value) {
|
||||
_newGroup = value;
|
||||
),
|
||||
FlatButton(
|
||||
onPressed: () async {
|
||||
if (list.contains(_newGroup)) {
|
||||
setState(() => _error = 1);
|
||||
} else {
|
||||
groupList.addGroup(PodcastGroup(_newGroup));
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
),
|
||||
Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: (_error == 1)
|
||||
? Text(
|
||||
'Group existed',
|
||||
style: TextStyle(color: Colors.red[400]),
|
||||
)
|
||||
: Center(),
|
||||
),
|
||||
child: Text('DONE'),
|
||||
)
|
||||
],
|
||||
title: Text('Create new group'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
TextField(
|
||||
decoration: InputDecoration(
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 10),
|
||||
hintText: 'New Group',
|
||||
hintStyle: TextStyle(fontSize: 18),
|
||||
filled: true,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.blue, width: 2.0),
|
||||
),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.blue, width: 2.0),
|
||||
),
|
||||
),
|
||||
cursorRadius: Radius.circular(2),
|
||||
autofocus: true,
|
||||
maxLines: 1,
|
||||
controller: _controller,
|
||||
onChanged: (value) {
|
||||
_newGroup = value;
|
||||
},
|
||||
),
|
||||
Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: (_error == 1)
|
||||
? Text(
|
||||
'Group existed',
|
||||
style: TextStyle(color: Colors.red[400]),
|
||||
)
|
||||
: Center(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -45,10 +45,17 @@ class EpisodeGrid extends StatelessWidget {
|
|||
(BuildContext context, int index) {
|
||||
Color _c;
|
||||
var color = json.decode(podcast[index].primaryColor);
|
||||
(color[0] > 200 && color[1] > 200 && color[2] > 200)
|
||||
? _c = Color.fromRGBO(
|
||||
(255 - color[0]), 255 - color[1], 255 - color[2], 1.0)
|
||||
: _c = Color.fromRGBO(color[0], color[1], color[2], 1.0);
|
||||
if (Theme.of(context).brightness == Brightness.light) {
|
||||
(color[0] > 200 && color[1] > 200 && color[2] > 200)
|
||||
? _c = Color.fromRGBO(
|
||||
(255 - color[0]), 255 - color[1], 255 - color[2], 1.0)
|
||||
: _c = Color.fromRGBO(color[0], color[1], color[2], 1.0);
|
||||
} else {
|
||||
(color[0] < 50 && color[1] < 50 && color[2] < 50)
|
||||
? _c = Color.fromRGBO(
|
||||
(255 - color[0]), 255 - color[1], 255 - color[2], 1.0)
|
||||
: _c = Color.fromRGBO(color[0], color[1], color[2], 1.0);
|
||||
}
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
|
@ -67,13 +74,16 @@ class EpisodeGrid extends StatelessWidget {
|
|||
borderRadius: BorderRadius.all(Radius.circular(5.0)),
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
border: Border.all(
|
||||
color: Colors.grey[100],
|
||||
color:
|
||||
Theme.of(context).brightness == Brightness.light
|
||||
? Theme.of(context).primaryColor
|
||||
: Theme.of(context).scaffoldBackgroundColor,
|
||||
width: 3.0,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey[100],
|
||||
blurRadius: 1.0,
|
||||
color: Theme.of(context).primaryColor,
|
||||
blurRadius: 0.5,
|
||||
spreadRadius: 0.5,
|
||||
),
|
||||
]),
|
||||
|
|
Loading…
Reference in New Issue