feat: update setting pages to material you
This commit is contained in:
parent
e97a493135
commit
92dd3dd34e
|
@ -87,8 +87,8 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
||||||
final audio = context.watch<AudioPlayerNotifier>();
|
final audio = context.watch<AudioPlayerNotifier>();
|
||||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||||
value: SystemUiOverlayStyle(
|
value: SystemUiOverlayStyle(
|
||||||
statusBarColor: context.priamryContainer,
|
statusBarColor: widget.episodeItem!.cardColor(context),
|
||||||
systemNavigationBarColor: context.priamryContainer,
|
systemNavigationBarColor: widget.episodeItem!.cardColor(context),
|
||||||
systemNavigationBarContrastEnforced: false,
|
systemNavigationBarContrastEnforced: false,
|
||||||
systemNavigationBarIconBrightness: context.iconBrightness,
|
systemNavigationBarIconBrightness: context.iconBrightness,
|
||||||
statusBarBrightness: context.brightness,
|
statusBarBrightness: context.brightness,
|
||||||
|
@ -104,7 +104,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
backgroundColor: Theme.of(context).primaryColor,
|
backgroundColor: context.onPrimary,
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
|
@ -116,7 +116,8 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
||||||
headerSliverBuilder: (context, innerBoxScrolled) {
|
headerSliverBuilder: (context, innerBoxScrolled) {
|
||||||
return <Widget>[
|
return <Widget>[
|
||||||
SliverAppBar(
|
SliverAppBar(
|
||||||
backgroundColor: context.priamryContainer,
|
backgroundColor:
|
||||||
|
widget.episodeItem!.cardColor(context),
|
||||||
floating: true,
|
floating: true,
|
||||||
pinned: true,
|
pinned: true,
|
||||||
title: _showTitle
|
title: _showTitle
|
||||||
|
@ -296,8 +297,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
||||||
final height = kMinPlayerHeight[data.item2!.index];
|
final height = kMinPlayerHeight[data.item2!.index];
|
||||||
return Container(
|
return Container(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
padding:
|
padding: EdgeInsets.only(bottom: data.item1 ? height : 0),
|
||||||
EdgeInsets.only(bottom: data.item1 ? height : 0),
|
|
||||||
child: AnimatedContainer(
|
child: AnimatedContainer(
|
||||||
duration: Duration(milliseconds: 400),
|
duration: Duration(milliseconds: 400),
|
||||||
height: _showMenu ? 50 : 0,
|
height: _showMenu ? 50 : 0,
|
||||||
|
@ -310,13 +310,16 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
Selector<AudioPlayerNotifier, EpisodeBrief?>(
|
Selector<AudioPlayerNotifier, EpisodeBrief?>(
|
||||||
selector: (_, audio) => audio.episode,
|
selector: (_, audio) => audio.episode,
|
||||||
builder: (_, data, __) => Container(
|
builder: (_, data, __) => Container(
|
||||||
child: PlayerWidget(
|
child: PlayerWidget(
|
||||||
playerKey: _playerKey,
|
playerKey: _playerKey,
|
||||||
isPlayingPage: data == widget.episodeItem))),
|
isPlayingPage: data == widget.episodeItem),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -28,7 +28,7 @@ class MenuBarState extends State<MenuBar> {
|
||||||
return Container(
|
return Container(
|
||||||
height: 50.0,
|
height: 50.0,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: context.priamryContainer,
|
color: widget.episodeItem!.cardColor(context),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
@ -48,7 +48,6 @@ class MenuBarState extends State<MenuBar> {
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 30.0,
|
height: 30.0,
|
||||||
width: 30.0,
|
width: 30.0,
|
||||||
color: context.priamryContainer,
|
|
||||||
child: widget.hide!
|
child: widget.hide!
|
||||||
? Center()
|
? Center()
|
||||||
: CircleAvatar(
|
: CircleAvatar(
|
||||||
|
|
|
@ -7,100 +7,12 @@ import '../widgets/custom_widget.dart';
|
||||||
|
|
||||||
const String version = '0.6.0';
|
const String version = '0.6.0';
|
||||||
|
|
||||||
class AboutApp extends StatefulWidget {
|
class AboutApp extends StatelessWidget {
|
||||||
@override
|
|
||||||
_AboutAppState createState() => _AboutAppState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _AboutAppState extends State<AboutApp> {
|
|
||||||
ScrollController? _scrollController;
|
|
||||||
late bool _scroll;
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_scroll = false;
|
|
||||||
_scrollController = ScrollController()
|
|
||||||
..addListener(() {
|
|
||||||
if (_scrollController!.offset > 0 && !_scroll && mounted) {
|
|
||||||
setState(() => _scroll = true);
|
|
||||||
}
|
|
||||||
if (_scrollController!.offset <= 0 && _scroll && mounted) {
|
|
||||||
setState(() => _scroll = false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _listItem(
|
|
||||||
BuildContext context, String text, IconData icons, String url) =>
|
|
||||||
InkWell(
|
|
||||||
onTap: () => url.launchUrl,
|
|
||||||
child: Container(
|
|
||||||
height: 50.0,
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 20.0),
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: Border(
|
|
||||||
bottom: Divider.createBorderSide(context),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Icon(icons, color: Theme.of(context).accentColor),
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 10),
|
|
||||||
),
|
|
||||||
Text(text),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _translatorInfo(BuildContext context,
|
|
||||||
{required String name, String? flag}) =>
|
|
||||||
Container(
|
|
||||||
height: 50.0,
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 20.0),
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: Border(
|
|
||||||
bottom: Divider.createBorderSide(context),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Icon(LineIcons.user, color: Theme.of(context).accentColor),
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 10),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
name,
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.fade,
|
|
||||||
)),
|
|
||||||
if (flag != null)
|
|
||||||
ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(4),
|
|
||||||
child: Image(
|
|
||||||
image: AssetImage('assets/$flag.png'),
|
|
||||||
height: 20,
|
|
||||||
width: 30,
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
OverlayEntry _createOverlayEntry(TapDownDetails detail) {
|
OverlayEntry _createOverlayEntry(TapDownDetails detail) {
|
||||||
// RenderBox renderBox = context.findRenderObject();
|
// RenderBox renderBox = context.findRenderObject();
|
||||||
var offset = detail.globalPosition;
|
final offset = detail.globalPosition;
|
||||||
return OverlayEntry(
|
return OverlayEntry(
|
||||||
builder: (constext) => Positioned(
|
builder: (constext) => Positioned(
|
||||||
left: offset.dx - 5,
|
left: offset.dx - 5,
|
||||||
|
@ -118,23 +30,21 @@ class _AboutAppState extends State<AboutApp> {
|
||||||
final s = context.s;
|
final s = context.s;
|
||||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||||
value: SystemUiOverlayStyle(
|
value: SystemUiOverlayStyle(
|
||||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
statusBarColor: context.onPrimary,
|
||||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
statusBarIconBrightness: context.iconBrightness,
|
||||||
systemNavigationBarIconBrightness:
|
systemNavigationBarColor: context.onPrimary,
|
||||||
Theme.of(context).accentColorBrightness,
|
systemNavigationBarIconBrightness: context.iconBrightness,
|
||||||
),
|
),
|
||||||
|
child: SafeArea(
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
backgroundColor: Theme.of(context).primaryColor,
|
backgroundColor: context.onPrimary,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
|
backgroundColor: context.onPrimary,
|
||||||
title: Text(s.homeToprightMenuAbout),
|
title: Text(s.homeToprightMenuAbout),
|
||||||
|
scrolledUnderElevation: 1,
|
||||||
leading: CustomBackButton(),
|
leading: CustomBackButton(),
|
||||||
elevation: _scroll ? 1 : 0,
|
|
||||||
),
|
),
|
||||||
body: SafeArea(
|
body: SingleChildScrollView(
|
||||||
child: ScrollConfiguration(
|
|
||||||
behavior: NoGrowBehavior(),
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
controller: _scrollController,
|
|
||||||
scrollDirection: Axis.vertical,
|
scrollDirection: Axis.vertical,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(20.0),
|
padding: const EdgeInsets.all(20.0),
|
||||||
|
@ -170,12 +80,10 @@ class _AboutAppState extends State<AboutApp> {
|
||||||
children: [
|
children: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () =>
|
onPressed: () =>
|
||||||
'https://tsacdop.stonegate.me/#/privacy'
|
'https://tsacdop.stonegate.me/#/privacy'.launchUrl,
|
||||||
.launchUrl,
|
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
primary: context.accentColor,
|
primary: context.accentColor,
|
||||||
textStyle:
|
textStyle: TextStyle(fontWeight: FontWeight.bold)),
|
||||||
TextStyle(fontWeight: FontWeight.bold)),
|
|
||||||
child: Text(
|
child: Text(
|
||||||
s.privacyPolicy,
|
s.privacyPolicy,
|
||||||
),
|
),
|
||||||
|
@ -185,8 +93,7 @@ class _AboutAppState extends State<AboutApp> {
|
||||||
height: 4,
|
height: 4,
|
||||||
width: 4,
|
width: 4,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: context.accentColor,
|
color: context.accentColor, shape: BoxShape.circle),
|
||||||
shape: BoxShape.circle),
|
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () =>
|
onPressed: () =>
|
||||||
|
@ -194,8 +101,7 @@ class _AboutAppState extends State<AboutApp> {
|
||||||
.launchUrl,
|
.launchUrl,
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
primary: context.accentColor,
|
primary: context.accentColor,
|
||||||
textStyle:
|
textStyle: TextStyle(fontWeight: FontWeight.bold)),
|
||||||
TextStyle(fontWeight: FontWeight.bold)),
|
|
||||||
child: Text(s.changelog,
|
child: Text(s.changelog,
|
||||||
style: TextStyle(color: context.accentColor)),
|
style: TextStyle(color: context.accentColor)),
|
||||||
),
|
),
|
||||||
|
@ -209,10 +115,7 @@ class _AboutAppState extends State<AboutApp> {
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
_listItem(context, 'Twitter @tsacdop',
|
_listItem(context, 'Twitter @tsacdop',
|
||||||
LineIcons.twitter, 'https://twitter.com/tsacdop'),
|
LineIcons.twitter, 'https://twitter.com/tsacdop'),
|
||||||
_listItem(
|
_listItem(context, 'GitHub', LineIcons.alternateGithub,
|
||||||
context,
|
|
||||||
'GitHub',
|
|
||||||
LineIcons.alternateGithub,
|
|
||||||
'https://github.com/stonega/tsacdop'),
|
'https://github.com/stonega/tsacdop'),
|
||||||
_listItem(context, 'Telegram', LineIcons.telegram,
|
_listItem(context, 'Telegram', LineIcons.telegram,
|
||||||
'https://t.me/joinchat/Bk3LkRpTHy40QYC78PK7Qg'),
|
'https://t.me/joinchat/Bk3LkRpTHy40QYC78PK7Qg'),
|
||||||
|
@ -226,23 +129,29 @@ class _AboutAppState extends State<AboutApp> {
|
||||||
'https://www.buymeacoffee.com/stonegate'
|
'https://www.buymeacoffee.com/stonegate'
|
||||||
.launchUrl,
|
.launchUrl,
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
primary: context.accentColor),
|
primary: Color(0xffffdd00),
|
||||||
|
elevation: 0,
|
||||||
|
enableFeedback: false,
|
||||||
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 30.0,
|
height: 30.0,
|
||||||
padding:
|
padding: EdgeInsets.symmetric(horizontal: 4.0),
|
||||||
EdgeInsets.symmetric(horizontal: 4.0),
|
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text('Buy Me A Coffee',
|
Text(
|
||||||
|
'Buy Me A Coffee',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold)),
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
Image(
|
Image(
|
||||||
image: AssetImage(
|
image:
|
||||||
'assets/buymeacoffee.png'),
|
AssetImage('assets/buymeacoffee.png'),
|
||||||
height: 20,
|
height: 20,
|
||||||
fit: BoxFit.fitHeight,
|
fit: BoxFit.fitHeight,
|
||||||
),
|
),
|
||||||
|
@ -270,7 +179,7 @@ class _AboutAppState extends State<AboutApp> {
|
||||||
Text(
|
Text(
|
||||||
s.translators,
|
s.translators,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context).accentColor,
|
color: context.accentColor,
|
||||||
fontWeight: FontWeight.bold),
|
fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
SizedBox(width: 2),
|
SizedBox(width: 2),
|
||||||
|
@ -336,7 +245,73 @@ class _AboutAppState extends State<AboutApp> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _listItem(
|
||||||
|
BuildContext context, String text, IconData icons, String url) =>
|
||||||
|
InkWell(
|
||||||
|
onTap: () => url.launchUrl,
|
||||||
|
child: Container(
|
||||||
|
height: 50.0,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 20.0),
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
bottom: Divider.createBorderSide(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Icon(icons, color: context.accentColor),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
),
|
||||||
|
Text(text),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _translatorInfo(BuildContext context,
|
||||||
|
{required String name, String? flag}) =>
|
||||||
|
Container(
|
||||||
|
height: 50.0,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 20.0),
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
bottom: Divider.createBorderSide(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Icon(LineIcons.user, color: context.accentColor),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
name,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.fade,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (flag != null)
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(4),
|
||||||
|
child: Image(
|
||||||
|
image: AssetImage('assets/$flag.png'),
|
||||||
|
height: 20,
|
||||||
|
width: 30,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -120,8 +120,6 @@ class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
SafeArea(
|
SafeArea(
|
||||||
bottom: false,
|
bottom: false,
|
||||||
child: StretchingOverscrollIndicator(
|
|
||||||
axisDirection: AxisDirection.down,
|
|
||||||
child: NestedScrollView(
|
child: NestedScrollView(
|
||||||
innerScrollPositionKeyBuilder: () {
|
innerScrollPositionKeyBuilder: () {
|
||||||
return Key('tab${_controller!.index}');
|
return Key('tab${_controller!.index}');
|
||||||
|
@ -175,7 +173,8 @@ class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
|
||||||
textStyle: TextStyle(fontSize: 25)),
|
textStyle: TextStyle(fontSize: 25)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
featureDiscoveryOverlay(context,
|
featureDiscoveryOverlay(
|
||||||
|
context,
|
||||||
featureId: menuFeature,
|
featureId: menuFeature,
|
||||||
tapTarget: Icon(Icons.more_vert),
|
tapTarget: Icon(Icons.more_vert),
|
||||||
backgroundColor: Colors.cyan[500],
|
backgroundColor: Colors.cyan[500],
|
||||||
|
@ -186,7 +185,8 @@ class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
|
||||||
padding:
|
padding:
|
||||||
const EdgeInsets.only(right: 5.0),
|
const EdgeInsets.only(right: 5.0),
|
||||||
child: PopupMenu(),
|
child: PopupMenu(),
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -232,11 +232,17 @@ class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
NestedScrollViewInnerScrollPositionKeyWidget(
|
NestedScrollViewInnerScrollPositionKeyWidget(
|
||||||
Key('tab0'), _RecentUpdate()),
|
Key('tab0'),
|
||||||
|
_RecentUpdate(),
|
||||||
|
),
|
||||||
NestedScrollViewInnerScrollPositionKeyWidget(
|
NestedScrollViewInnerScrollPositionKeyWidget(
|
||||||
Key('tab1'), _MyFavorite()),
|
Key('tab1'),
|
||||||
|
_MyFavorite(),
|
||||||
|
),
|
||||||
NestedScrollViewInnerScrollPositionKeyWidget(
|
NestedScrollViewInnerScrollPositionKeyWidget(
|
||||||
Key('tab2'), _MyDownload()),
|
Key('tab2'),
|
||||||
|
_MyDownload(),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -252,8 +258,9 @@ class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Container(
|
||||||
|
child: PlayerWidget(playerKey: _playerKey),
|
||||||
),
|
),
|
||||||
Container(child: PlayerWidget(playerKey: _playerKey)),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -345,6 +352,7 @@ class __PlaylistButtonState extends State<_PlaylistButton> {
|
||||||
borderRadius: BorderRadius.all(Radius.circular(10))),
|
borderRadius: BorderRadius.all(Radius.circular(10))),
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
icon: Icon(Icons.playlist_play),
|
icon: Icon(Icons.playlist_play),
|
||||||
|
color: context.priamryContainer,
|
||||||
tooltip: s.menu,
|
tooltip: s.menu,
|
||||||
itemBuilder: (context) => [
|
itemBuilder: (context) => [
|
||||||
MyPopupMenuItem(
|
MyPopupMenuItem(
|
||||||
|
@ -1249,8 +1257,7 @@ class _MyDownloadState extends State<_MyDownload>
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(
|
setState(() => _hideListened = !_hideListened!);
|
||||||
() => _hideListened = !_hideListened!);
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1276,8 +1283,7 @@ class _MyDownloadState extends State<_MyDownload>
|
||||||
Icon(LineIcons.download,
|
Icon(LineIcons.download,
|
||||||
size: 80, color: Colors.grey[500]),
|
size: 80, color: Colors.grey[500]),
|
||||||
Padding(
|
Padding(
|
||||||
padding:
|
padding: EdgeInsets.symmetric(vertical: 10)),
|
||||||
EdgeInsets.symmetric(vertical: 10)),
|
|
||||||
Text(
|
Text(
|
||||||
s.noEpisodeDownload,
|
s.noEpisodeDownload,
|
||||||
style: TextStyle(color: Colors.grey[500]),
|
style: TextStyle(color: Colors.grey[500]),
|
||||||
|
@ -1295,7 +1301,8 @@ class _MyDownloadState extends State<_MyDownload>
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,11 +118,13 @@ class _ScrollPodcastsState extends State<ScrollPodcasts>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {
|
setState(
|
||||||
|
() {
|
||||||
(_groupIndex < groups.length - 1)
|
(_groupIndex < groups.length - 1)
|
||||||
? _groupIndex++
|
? _groupIndex++
|
||||||
: _groupIndex = 0;
|
: _groupIndex = 0;
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,13 +136,13 @@ class _ScrollPodcastsState extends State<ScrollPodcasts>
|
||||||
child: Row(
|
child: Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Padding(
|
Padding(
|
||||||
padding:
|
padding: EdgeInsets.symmetric(horizontal: 15.0),
|
||||||
EdgeInsets.symmetric(horizontal: 15.0),
|
|
||||||
child: Text(
|
child: Text(
|
||||||
groups[_groupIndex]!.name!,
|
groups[_groupIndex]!.name!,
|
||||||
style: context.textTheme.bodyText1!
|
style: context.textTheme.bodyText1!
|
||||||
.copyWith(color: context.accentColor),
|
.copyWith(color: context.accentColor),
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
Spacer(),
|
Spacer(),
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 15),
|
padding: EdgeInsets.symmetric(horizontal: 15),
|
||||||
|
@ -154,7 +156,8 @@ class _ScrollPodcastsState extends State<ScrollPodcasts>
|
||||||
.read<SettingState>()
|
.read<SettingState>()
|
||||||
.openAllPodcastDefalt!
|
.openAllPodcastDefalt!
|
||||||
? PodcastList()
|
? PodcastList()
|
||||||
: PodcastManage()),
|
: PodcastManage(),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -443,12 +446,14 @@ class _ScrollPodcastsState extends State<ScrollPodcasts>
|
||||||
width: 10,
|
width: 10,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.red,
|
color: Colors.red,
|
||||||
border: Border.all(color: context.primaryColor, width: 2),
|
border:
|
||||||
|
Border.all(color: context.primaryColor, width: 2),
|
||||||
shape: BoxShape.circle),
|
shape: BoxShape.circle),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: Center();
|
: Center();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class PodcastPreview extends StatefulWidget {
|
class PodcastPreview extends StatefulWidget {
|
||||||
|
@ -463,12 +468,6 @@ class PodcastPreview extends StatefulWidget {
|
||||||
class _PodcastPreviewState extends State<PodcastPreview> {
|
class _PodcastPreviewState extends State<PodcastPreview> {
|
||||||
Future? _getRssItem;
|
Future? _getRssItem;
|
||||||
|
|
||||||
Future<List<EpisodeBrief>> _getRssItemTop(PodcastLocal podcastLocal) async {
|
|
||||||
final dbHelper = DBHelper();
|
|
||||||
final episodes = await dbHelper.getRssItemTop(podcastLocal.id);
|
|
||||||
return episodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
@ -510,10 +509,12 @@ class _PodcastPreviewState extends State<PodcastPreview> {
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 4,
|
flex: 4,
|
||||||
child: Text(widget.podcastLocal!.title!,
|
child: Text(
|
||||||
|
widget.podcastLocal!.title!,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(fontWeight: FontWeight.bold, color: c)),
|
style: TextStyle(fontWeight: FontWeight.bold, color: c),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
@ -531,6 +532,12 @@ class _PodcastPreviewState extends State<PodcastPreview> {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<List<EpisodeBrief>> _getRssItemTop(PodcastLocal podcastLocal) async {
|
||||||
|
final dbHelper = DBHelper();
|
||||||
|
final episodes = await dbHelper.getRssItemTop(podcastLocal.id);
|
||||||
|
return episodes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ShowEpisode extends StatelessWidget {
|
class ShowEpisode extends StatelessWidget {
|
||||||
|
@ -539,121 +546,6 @@ class ShowEpisode extends StatelessWidget {
|
||||||
final DBHelper _dbHelper = DBHelper();
|
final DBHelper _dbHelper = DBHelper();
|
||||||
ShowEpisode({Key? key, this.episodes, this.podcastLocal}) : super(key: key);
|
ShowEpisode({Key? key, this.episodes, this.podcastLocal}) : super(key: key);
|
||||||
|
|
||||||
Future<tuple.Tuple5<int, bool, bool, bool, List<int>>> _initData(
|
|
||||||
EpisodeBrief episode) async {
|
|
||||||
final menuList = await _getEpisodeMenu();
|
|
||||||
final tapToOpen = await _getTapToOpenPopupMenu();
|
|
||||||
final listened = await _isListened(episode);
|
|
||||||
final liked = await _isLiked(episode);
|
|
||||||
final downloaded = await _isDownloaded(episode);
|
|
||||||
|
|
||||||
return tuple.Tuple5(listened, liked, downloaded, tapToOpen, menuList);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<int> _isListened(EpisodeBrief episode) async {
|
|
||||||
return await _dbHelper.isListened(episode.enclosureUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> _isLiked(EpisodeBrief episode) async {
|
|
||||||
return await _dbHelper.isLiked(episode.enclosureUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<List<int>> _getEpisodeMenu() async {
|
|
||||||
final popupMenuStorage = KeyValueStorage(episodePopupMenuKey);
|
|
||||||
final list = await popupMenuStorage.getMenu();
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> _isDownloaded(EpisodeBrief episode) async {
|
|
||||||
return await _dbHelper.isDownloaded(episode.enclosureUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> _getTapToOpenPopupMenu() async {
|
|
||||||
final tapToOpenPopupMenuStorage = KeyValueStorage(tapToOpenPopupMenuKey);
|
|
||||||
final boo = await tapToOpenPopupMenuStorage.getInt(defaultValue: 0);
|
|
||||||
return boo == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _markListened(EpisodeBrief episode) async {
|
|
||||||
var marked = await _dbHelper.checkMarked(episode);
|
|
||||||
if (!marked) {
|
|
||||||
final history = PlayHistory(episode.title, episode.enclosureUrl, 0, 1);
|
|
||||||
await _dbHelper.saveHistory(history);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _saveLiked(String url) async {
|
|
||||||
await _dbHelper.setLiked(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _setUnliked(String url) async {
|
|
||||||
await _dbHelper.setUniked(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _requestDownload(BuildContext context,
|
|
||||||
{EpisodeBrief? episode}) async {
|
|
||||||
final permissionReady = await _checkPermmison();
|
|
||||||
final downloadUsingData = await KeyValueStorage(downloadUsingDataKey)
|
|
||||||
.getBool(defaultValue: true, reverse: true);
|
|
||||||
final result = await Connectivity().checkConnectivity();
|
|
||||||
final usingData = result == ConnectivityResult.mobile;
|
|
||||||
var dataConfirm = true;
|
|
||||||
if (permissionReady) {
|
|
||||||
if (downloadUsingData && usingData) {
|
|
||||||
dataConfirm = await _useDataConfirm(context);
|
|
||||||
}
|
|
||||||
if (dataConfirm) {
|
|
||||||
Provider.of<DownloadState>(context, listen: false).startTask(episode!);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> _checkPermmison() async {
|
|
||||||
var permission = await Permission.storage.status;
|
|
||||||
if (permission != PermissionStatus.granted) {
|
|
||||||
var permissions = await [Permission.storage].request();
|
|
||||||
if (permissions[Permission.storage] == PermissionStatus.granted) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> _useDataConfirm(BuildContext context) async {
|
|
||||||
var ifUseData = false;
|
|
||||||
final s = context.s;
|
|
||||||
await generalDialog(
|
|
||||||
context,
|
|
||||||
title: Text(s.cellularConfirm),
|
|
||||||
content: Text(s.cellularConfirmDes),
|
|
||||||
actions: <Widget>[
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
s.cancel,
|
|
||||||
style: TextStyle(color: Colors.grey[600]),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
ifUseData = true;
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
s.confirm,
|
|
||||||
style: TextStyle(color: Colors.red),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
return ifUseData;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final width = context.width;
|
final width = context.width;
|
||||||
|
@ -669,7 +561,7 @@ class ShowEpisode extends StatelessWidget {
|
||||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
childAspectRatio: 1.5,
|
childAspectRatio: 1.5,
|
||||||
crossAxisCount: 2,
|
crossAxisCount: 2,
|
||||||
mainAxisSpacing: 6.0,
|
mainAxisSpacing: 8.0,
|
||||||
crossAxisSpacing: 6.0,
|
crossAxisSpacing: 6.0,
|
||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
@ -691,19 +583,17 @@ class ShowEpisode extends StatelessWidget {
|
||||||
final isDownloaded = snapshot.data!.item3;
|
final isDownloaded = snapshot.data!.item3;
|
||||||
final tapToOpen = snapshot.data!.item4;
|
final tapToOpen = snapshot.data!.item4;
|
||||||
final menuList = snapshot.data!.item5;
|
final menuList = snapshot.data!.item5;
|
||||||
return Container(
|
return Align(
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(5.0),
|
|
||||||
color: context.background,
|
|
||||||
),
|
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: FocusedMenuHolder(
|
child: FocusedMenuHolder(
|
||||||
blurSize: 0.0,
|
blurSize: 0.0,
|
||||||
menuItemExtent: 45,
|
menuItemExtent: 45,
|
||||||
menuBoxDecoration: BoxDecoration(
|
menuBoxDecoration: BoxDecoration(
|
||||||
color: Colors.transparent,
|
color: context.priamryContainer,
|
||||||
borderRadius:
|
borderRadius: BorderRadius.all(
|
||||||
BorderRadius.all(Radius.circular(15.0))),
|
Radius.circular(15.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
duration: Duration(milliseconds: 100),
|
duration: Duration(milliseconds: 100),
|
||||||
tapMode:
|
tapMode:
|
||||||
tapToOpen ? TapMode.onTap : TapMode.onLongPress,
|
tapToOpen ? TapMode.onTap : TapMode.onLongPress,
|
||||||
|
@ -716,10 +606,7 @@ class ShowEpisode extends StatelessWidget {
|
||||||
menuOffset: 6,
|
menuOffset: 6,
|
||||||
menuItems: <FocusedMenuItem>[
|
menuItems: <FocusedMenuItem>[
|
||||||
FocusedMenuItem(
|
FocusedMenuItem(
|
||||||
backgroundColor:
|
backgroundColor: context.priamryContainer,
|
||||||
context.brightness == Brightness.light
|
|
||||||
? context.primaryColor
|
|
||||||
: context.dialogBackgroundColor,
|
|
||||||
title: Text(data.item1 != episodes![index] ||
|
title: Text(data.item1 != episodes![index] ||
|
||||||
!data.item3
|
!data.item3
|
||||||
? s.play
|
? s.play
|
||||||
|
@ -736,10 +623,7 @@ class ShowEpisode extends StatelessWidget {
|
||||||
}),
|
}),
|
||||||
if (menuList.contains(1))
|
if (menuList.contains(1))
|
||||||
FocusedMenuItem(
|
FocusedMenuItem(
|
||||||
backgroundColor:
|
backgroundColor: context.priamryContainer,
|
||||||
context.brightness == Brightness.light
|
|
||||||
? context.primaryColor
|
|
||||||
: context.dialogBackgroundColor,
|
|
||||||
title: data.item2.contains(
|
title: data.item2.contains(
|
||||||
episodes![index].enclosureUrl)
|
episodes![index].enclosureUrl)
|
||||||
? Text(s.remove)
|
? Text(s.remove)
|
||||||
|
@ -766,10 +650,7 @@ class ShowEpisode extends StatelessWidget {
|
||||||
}),
|
}),
|
||||||
if (menuList.contains(2))
|
if (menuList.contains(2))
|
||||||
FocusedMenuItem(
|
FocusedMenuItem(
|
||||||
backgroundColor:
|
backgroundColor: context.priamryContainer,
|
||||||
context.brightness == Brightness.light
|
|
||||||
? context.primaryColor
|
|
||||||
: context.dialogBackgroundColor,
|
|
||||||
title:
|
title:
|
||||||
isLiked ? Text(s.unlike) : Text(s.like),
|
isLiked ? Text(s.unlike) : Text(s.like),
|
||||||
trailingIcon: Icon(LineIcons.heart,
|
trailingIcon: Icon(LineIcons.heart,
|
||||||
|
@ -795,10 +676,7 @@ class ShowEpisode extends StatelessWidget {
|
||||||
}),
|
}),
|
||||||
if (menuList.contains(3))
|
if (menuList.contains(3))
|
||||||
FocusedMenuItem(
|
FocusedMenuItem(
|
||||||
backgroundColor:
|
backgroundColor: context.priamryContainer,
|
||||||
context.brightness == Brightness.light
|
|
||||||
? context.primaryColor
|
|
||||||
: context.dialogBackgroundColor,
|
|
||||||
title: isListened > 0
|
title: isListened > 0
|
||||||
? Text(s.listened,
|
? Text(s.listened,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
@ -828,10 +706,7 @@ class ShowEpisode extends StatelessWidget {
|
||||||
}),
|
}),
|
||||||
if (menuList.contains(4))
|
if (menuList.contains(4))
|
||||||
FocusedMenuItem(
|
FocusedMenuItem(
|
||||||
backgroundColor:
|
backgroundColor: context.priamryContainer,
|
||||||
context.brightness == Brightness.light
|
|
||||||
? context.primaryColor
|
|
||||||
: context.dialogBackgroundColor,
|
|
||||||
title: isDownloaded
|
title: isDownloaded
|
||||||
? Text(s.downloaded,
|
? Text(s.downloaded,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
@ -850,10 +725,7 @@ class ShowEpisode extends StatelessWidget {
|
||||||
}),
|
}),
|
||||||
if (menuList.contains(5))
|
if (menuList.contains(5))
|
||||||
FocusedMenuItem(
|
FocusedMenuItem(
|
||||||
backgroundColor:
|
backgroundColor: context.priamryContainer,
|
||||||
context.brightness == Brightness.light
|
|
||||||
? context.primaryColor
|
|
||||||
: context.dialogBackgroundColor,
|
|
||||||
title: Text(s.playNext),
|
title: Text(s.playNext),
|
||||||
trailingIcon: Icon(
|
trailingIcon: Icon(
|
||||||
LineIcons.lightningBolt,
|
LineIcons.lightningBolt,
|
||||||
|
@ -865,7 +737,8 @@ class ShowEpisode extends StatelessWidget {
|
||||||
msg: s.playNextDes,
|
msg: s.playNextDes,
|
||||||
gravity: ToastGravity.BOTTOM,
|
gravity: ToastGravity.BOTTOM,
|
||||||
);
|
);
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
onPressed: () => Navigator.push(
|
onPressed: () => Navigator.push(
|
||||||
context,
|
context,
|
||||||
|
@ -878,6 +751,10 @@ class ShowEpisode extends StatelessWidget {
|
||||||
),
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.all(10.0),
|
padding: EdgeInsets.all(10.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: podcastLocal!.cardColor(context),
|
||||||
|
borderRadius: BorderRadius.circular(15.0),
|
||||||
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
|
@ -999,18 +876,18 @@ class ShowEpisode extends StatelessWidget {
|
||||||
),
|
),
|
||||||
if (episodes![index].enclosureLength !=
|
if (episodes![index].enclosureLength !=
|
||||||
null &&
|
null &&
|
||||||
episodes![index].enclosureLength !=
|
episodes![index].enclosureLength != 0)
|
||||||
0)
|
|
||||||
Container(
|
Container(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: Text(
|
child: Text(
|
||||||
'${episodes![index].enclosureLength! ~/ 1000000}MB',
|
'${episodes![index].enclosureLength! ~/ 1000000}MB',
|
||||||
style: TextStyle(
|
style:
|
||||||
fontSize: width / 35),
|
TextStyle(fontSize: width / 35),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1027,6 +904,121 @@ class ShowEpisode extends StatelessWidget {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<tuple.Tuple5<int, bool, bool, bool, List<int>>> _initData(
|
||||||
|
EpisodeBrief episode) async {
|
||||||
|
final menuList = await _getEpisodeMenu();
|
||||||
|
final tapToOpen = await _getTapToOpenPopupMenu();
|
||||||
|
final listened = await _isListened(episode);
|
||||||
|
final liked = await _isLiked(episode);
|
||||||
|
final downloaded = await _isDownloaded(episode);
|
||||||
|
|
||||||
|
return tuple.Tuple5(listened, liked, downloaded, tapToOpen, menuList);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int> _isListened(EpisodeBrief episode) async {
|
||||||
|
return await _dbHelper.isListened(episode.enclosureUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _isLiked(EpisodeBrief episode) async {
|
||||||
|
return await _dbHelper.isLiked(episode.enclosureUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<int>> _getEpisodeMenu() async {
|
||||||
|
final popupMenuStorage = KeyValueStorage(episodePopupMenuKey);
|
||||||
|
final list = await popupMenuStorage.getMenu();
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _isDownloaded(EpisodeBrief episode) async {
|
||||||
|
return await _dbHelper.isDownloaded(episode.enclosureUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _getTapToOpenPopupMenu() async {
|
||||||
|
final tapToOpenPopupMenuStorage = KeyValueStorage(tapToOpenPopupMenuKey);
|
||||||
|
final boo = await tapToOpenPopupMenuStorage.getInt(defaultValue: 0);
|
||||||
|
return boo == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _markListened(EpisodeBrief episode) async {
|
||||||
|
var marked = await _dbHelper.checkMarked(episode);
|
||||||
|
if (!marked) {
|
||||||
|
final history = PlayHistory(episode.title, episode.enclosureUrl, 0, 1);
|
||||||
|
await _dbHelper.saveHistory(history);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _saveLiked(String url) async {
|
||||||
|
await _dbHelper.setLiked(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _setUnliked(String url) async {
|
||||||
|
await _dbHelper.setUniked(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _requestDownload(BuildContext context,
|
||||||
|
{EpisodeBrief? episode}) async {
|
||||||
|
final permissionReady = await _checkPermmison();
|
||||||
|
final downloadUsingData = await KeyValueStorage(downloadUsingDataKey)
|
||||||
|
.getBool(defaultValue: true, reverse: true);
|
||||||
|
final result = await Connectivity().checkConnectivity();
|
||||||
|
final usingData = result == ConnectivityResult.mobile;
|
||||||
|
var dataConfirm = true;
|
||||||
|
if (permissionReady) {
|
||||||
|
if (downloadUsingData && usingData) {
|
||||||
|
dataConfirm = await _useDataConfirm(context);
|
||||||
|
}
|
||||||
|
if (dataConfirm) {
|
||||||
|
Provider.of<DownloadState>(context, listen: false).startTask(episode!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _checkPermmison() async {
|
||||||
|
var permission = await Permission.storage.status;
|
||||||
|
if (permission != PermissionStatus.granted) {
|
||||||
|
var permissions = await [Permission.storage].request();
|
||||||
|
if (permissions[Permission.storage] == PermissionStatus.granted) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _useDataConfirm(BuildContext context) async {
|
||||||
|
var ifUseData = false;
|
||||||
|
final s = context.s;
|
||||||
|
await generalDialog(
|
||||||
|
context,
|
||||||
|
title: Text(s.cellularConfirm),
|
||||||
|
content: Text(s.cellularConfirmDes),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
s.cancel,
|
||||||
|
style: TextStyle(color: Colors.grey[600]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
ifUseData = true;
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
s.confirm,
|
||||||
|
style: TextStyle(color: Colors.red),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
return ifUseData;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Circle Indicator
|
//Circle Indicator
|
||||||
|
|
|
@ -673,10 +673,10 @@ class _PodcastDetailState extends State<PodcastDetail> {
|
||||||
final s = context.s;
|
final s = context.s;
|
||||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||||
value: SystemUiOverlayStyle(
|
value: SystemUiOverlayStyle(
|
||||||
|
statusBarColor: color,
|
||||||
statusBarIconBrightness: Brightness.dark,
|
statusBarIconBrightness: Brightness.dark,
|
||||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
systemNavigationBarColor: context.primaryColor,
|
||||||
systemNavigationBarIconBrightness:
|
systemNavigationBarIconBrightness: context.iconBrightness,
|
||||||
Theme.of(context).accentColorBrightness,
|
|
||||||
),
|
),
|
||||||
child: WillPopScope(
|
child: WillPopScope(
|
||||||
onWillPop: () {
|
onWillPop: () {
|
||||||
|
|
|
@ -33,18 +33,233 @@ class DataBackup extends StatefulWidget {
|
||||||
|
|
||||||
class _DataBackupState extends State<DataBackup> {
|
class _DataBackupState extends State<DataBackup> {
|
||||||
final _gpodder = Gpodder();
|
final _gpodder = Gpodder();
|
||||||
var _syncing = false;
|
// var _syncing = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final s = context.s;
|
||||||
|
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||||
|
value: SystemUiOverlayStyle(
|
||||||
|
statusBarIconBrightness: context.iconBrightness,
|
||||||
|
systemNavigationBarColor: Theme.of(context).primaryColor,
|
||||||
|
systemNavigationBarIconBrightness: context.brightness,
|
||||||
|
),
|
||||||
|
child: Scaffold(
|
||||||
|
backgroundColor: context.onPrimary,
|
||||||
|
appBar: AppBar(
|
||||||
|
elevation: 0,
|
||||||
|
title: Text(s.settingsBackup),
|
||||||
|
leading: CustomBackButton(),
|
||||||
|
backgroundColor: context.primaryColor,
|
||||||
|
),
|
||||||
|
body: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 30.0,
|
||||||
|
padding: EdgeInsets.fromLTRB(70, 0, 70, 0),
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(s.subscribe,
|
||||||
|
style: context.textTheme.bodyText1!
|
||||||
|
.copyWith(color: context.accentColor)),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding:
|
||||||
|
EdgeInsets.only(left: 70.0, right: 20, top: 10, bottom: 10),
|
||||||
|
child: Text(s.subscribeExportDes),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(left: 70.0, right: 20),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
ButtonTheme(
|
||||||
|
height: 32,
|
||||||
|
child: OutlinedButton(
|
||||||
|
style: OutlinedButton.styleFrom(
|
||||||
|
side: BorderSide(color: Colors.green[700]!),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(100.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
LineIcons.save,
|
||||||
|
color: Colors.green[700],
|
||||||
|
size: context.textTheme.headline6!.fontSize,
|
||||||
|
),
|
||||||
|
SizedBox(width: 10),
|
||||||
|
Text(s.save,
|
||||||
|
style: TextStyle(color: Colors.green[700])),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
final file = await _exportOmpl(context);
|
||||||
|
await _saveFile(file);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
SizedBox(width: 10),
|
||||||
|
ButtonTheme(
|
||||||
|
height: 32,
|
||||||
|
child: OutlinedButton(
|
||||||
|
style: OutlinedButton.styleFrom(
|
||||||
|
side: BorderSide(color: Colors.blue[700]!),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(100.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.share,
|
||||||
|
size: context.textTheme.headline6!.fontSize,
|
||||||
|
color: Colors.blue[700],
|
||||||
|
),
|
||||||
|
SizedBox(width: 10),
|
||||||
|
Text(s.share,
|
||||||
|
style: TextStyle(color: Colors.blue[700])),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
var file = await _exportOmpl(context);
|
||||||
|
await _shareFile(file);
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 10.0),
|
||||||
|
child: Divider(height: 1),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 30.0,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 70),
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
s.settings,
|
||||||
|
style: context.textTheme.bodyText1!
|
||||||
|
.copyWith(color: context.accentColor),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding:
|
||||||
|
EdgeInsets.only(left: 70.0, right: 20, top: 10, bottom: 10),
|
||||||
|
child: Text(s.settingsExportDes),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(left: 70.0, right: 10),
|
||||||
|
child: Wrap(children: [
|
||||||
|
ButtonTheme(
|
||||||
|
height: 32,
|
||||||
|
child: OutlinedButton(
|
||||||
|
style: OutlinedButton.styleFrom(
|
||||||
|
side: BorderSide(color: Colors.green[700]!),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(100.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
LineIcons.save,
|
||||||
|
color: Colors.green[700],
|
||||||
|
size: context.textTheme.headline6!.fontSize,
|
||||||
|
),
|
||||||
|
SizedBox(width: 10),
|
||||||
|
Text(s.save,
|
||||||
|
style: TextStyle(color: Colors.green[700])),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
var file = await _exportSetting(context);
|
||||||
|
await _saveFile(file);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
SizedBox(width: 10),
|
||||||
|
ButtonTheme(
|
||||||
|
height: 32,
|
||||||
|
child: OutlinedButton(
|
||||||
|
style: OutlinedButton.styleFrom(
|
||||||
|
side: BorderSide(color: Colors.blue[700]!),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(100.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.share,
|
||||||
|
size: context.textTheme.headline6!.fontSize,
|
||||||
|
color: Colors.blue[700],
|
||||||
|
),
|
||||||
|
SizedBox(width: 10),
|
||||||
|
Text(s.share,
|
||||||
|
style: TextStyle(color: Colors.blue[700])),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
var file = await _exportSetting(context);
|
||||||
|
await _shareFile(file);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
SizedBox(width: 10),
|
||||||
|
ButtonTheme(
|
||||||
|
height: 32,
|
||||||
|
child: OutlinedButton(
|
||||||
|
style: OutlinedButton.styleFrom(
|
||||||
|
side: BorderSide(color: Colors.red[700]!),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(100.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
LineIcons.paperclip,
|
||||||
|
size: context.textTheme.headline6!.fontSize,
|
||||||
|
color: Colors.red[700],
|
||||||
|
),
|
||||||
|
SizedBox(width: 10),
|
||||||
|
Text(s.import,
|
||||||
|
style: TextStyle(color: Colors.red[700])),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
_getFilePath(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 10.0),
|
||||||
|
child: Divider(height: 1),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Future<File> _exportOmpl(BuildContext context) async {
|
Future<File> _exportOmpl(BuildContext context) async {
|
||||||
var groups = context.read<GroupList>().groups;
|
final groups = context.read<GroupList>().groups;
|
||||||
var opml = PodcastsBackup(groups).omplBuilder();
|
final opml = PodcastsBackup(groups).omplBuilder();
|
||||||
var tempdir = await getTemporaryDirectory();
|
final tempdir = await getTemporaryDirectory();
|
||||||
var now = DateTime.now();
|
final now = DateTime.now();
|
||||||
var datePlus = now.year.toString() +
|
final datePlus = now.year.toString() +
|
||||||
now.month.toString() +
|
now.month.toString() +
|
||||||
now.day.toString() +
|
now.day.toString() +
|
||||||
now.second.toString();
|
now.second.toString();
|
||||||
var file = File(path.join(tempdir.path, 'tsacdop_opml_$datePlus.xml'));
|
final file = File(path.join(tempdir.path, 'tsacdop_opml_$datePlus.xml'));
|
||||||
await file.writeAsString(opml.toXmlString());
|
await file.writeAsString(opml.toXmlString());
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
@ -147,27 +362,6 @@ class _DataBackupState extends State<DataBackup> {
|
||||||
return await storage.getStringList();
|
return await storage.getStringList();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _syncNow() async {
|
|
||||||
if (mounted) {
|
|
||||||
setState(() {
|
|
||||||
_syncing = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
final gpodder = Gpodder();
|
|
||||||
final status = await gpodder.getChanges();
|
|
||||||
|
|
||||||
if (status == 200) {
|
|
||||||
final groupList = context.read<GroupList>();
|
|
||||||
await gpodder.updateChange();
|
|
||||||
await groupList.gpodderSyncNow();
|
|
||||||
}
|
|
||||||
if (mounted) {
|
|
||||||
setState(() {
|
|
||||||
_syncing = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<List<int?>> _getSyncStatus() async {
|
Future<List<int?>> _getSyncStatus() async {
|
||||||
var dateTimeStorage = KeyValueStorage(gpodderSyncDateTimeKey);
|
var dateTimeStorage = KeyValueStorage(gpodderSyncDateTimeKey);
|
||||||
var statusStorage = KeyValueStorage(gpodderSyncStatusKey);
|
var statusStorage = KeyValueStorage(gpodderSyncStatusKey);
|
||||||
|
@ -175,353 +369,6 @@ class _DataBackupState extends State<DataBackup> {
|
||||||
final statusIndex = await statusStorage.getInt();
|
final statusIndex = await statusStorage.getInt();
|
||||||
return [syncDateTime, statusIndex];
|
return [syncDateTime, statusIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final s = context.s;
|
|
||||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
|
||||||
value: SystemUiOverlayStyle(
|
|
||||||
statusBarIconBrightness: context.iconBrightness,
|
|
||||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
|
||||||
systemNavigationBarIconBrightness: context.brightness,
|
|
||||||
),
|
|
||||||
child: Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
elevation: 0,
|
|
||||||
title: Text(s.settingsBackup),
|
|
||||||
leading: CustomBackButton(),
|
|
||||||
backgroundColor: context.primaryColor,
|
|
||||||
),
|
|
||||||
body: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.all(10.0),
|
|
||||||
),
|
|
||||||
FutureBuilder<List<String?>?>(
|
|
||||||
future: _getLoginInfo(),
|
|
||||||
initialData: [],
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
final loginInfo = snapshot.data!;
|
|
||||||
return Container(
|
|
||||||
height: 160,
|
|
||||||
width: double.infinity,
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Stack(
|
|
||||||
children: [
|
|
||||||
Hero(
|
|
||||||
tag: 'gpodder.net',
|
|
||||||
child: CircleAvatar(
|
|
||||||
minRadius: 40,
|
|
||||||
backgroundColor: context.primaryColor,
|
|
||||||
child: SizedBox(
|
|
||||||
height: 60,
|
|
||||||
width: 60,
|
|
||||||
child: Image.asset('assets/gpodder.png')),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (_syncing)
|
|
||||||
Positioned(
|
|
||||||
left: context.width / 2 - 40,
|
|
||||||
child: SizedBox(
|
|
||||||
height: 80,
|
|
||||||
width: 80,
|
|
||||||
child: CircularProgressIndicator(
|
|
||||||
strokeWidth: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (_syncing)
|
|
||||||
Positioned(
|
|
||||||
bottom: 39,
|
|
||||||
left: context.width / 2 - 12,
|
|
||||||
child: _OpenEye()),
|
|
||||||
if (_syncing)
|
|
||||||
Positioned(
|
|
||||||
bottom: 39,
|
|
||||||
left: context.width / 2 + 3,
|
|
||||||
child: _OpenEye()),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
loginInfo.isEmpty
|
|
||||||
? s.intergateWith('gpodder.net')
|
|
||||||
: s.loggedInAs(loginInfo.first!),
|
|
||||||
style: TextStyle(color: Colors.purple[700])),
|
|
||||||
ButtonTheme(
|
|
||||||
height: 32,
|
|
||||||
child: OutlinedButton(
|
|
||||||
style: OutlinedButton.styleFrom(
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(100.0),
|
|
||||||
side: BorderSide(color: Colors.purple[700]!)),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
LineIcons.user,
|
|
||||||
color: Colors.purple[700],
|
|
||||||
size: context.textTheme.headline6!.fontSize,
|
|
||||||
),
|
|
||||||
SizedBox(width: 10),
|
|
||||||
Text(loginInfo.isEmpty ? s.login : s.logout,
|
|
||||||
style:
|
|
||||||
TextStyle(color: Colors.purple[700])),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
if (loginInfo.isEmpty) {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => _LoginGpodder(),
|
|
||||||
fullscreenDialog: true));
|
|
||||||
} else {
|
|
||||||
_logout();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
FutureBuilder<List<String?>?>(
|
|
||||||
future: _getLoginInfo(),
|
|
||||||
initialData: [],
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
final loginInfo = snapshot.data!;
|
|
||||||
if (loginInfo.isNotEmpty) {
|
|
||||||
return ListTile(
|
|
||||||
contentPadding: const EdgeInsets.only(
|
|
||||||
left: 70.0, right: 20, top: 10, bottom: 10),
|
|
||||||
onTap: _syncNow,
|
|
||||||
title: Text(s.syncNow),
|
|
||||||
trailing: IconButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => _GpodderInfo()));
|
|
||||||
},
|
|
||||||
icon: Icon(LineIcons.infoCircle),
|
|
||||||
),
|
|
||||||
subtitle: FutureBuilder<List<int?>>(
|
|
||||||
future: _getSyncStatus(),
|
|
||||||
initialData: [0, 0],
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
final dateTime = snapshot.data![0]!;
|
|
||||||
final status = snapshot.data![1];
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'${s.lastUpdate}: ${dateTime.toDate(context)}'),
|
|
||||||
SizedBox(width: 8),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text('${s.status}: '),
|
|
||||||
_syncStauts(status),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return Center();
|
|
||||||
}),
|
|
||||||
// ListTile(
|
|
||||||
// onTap: () async {
|
|
||||||
// final subscribeWorker = context.read<GroupList>();
|
|
||||||
// await subscribeWorker.cancelWork();
|
|
||||||
// subscribeWorker.setWorkManager();
|
|
||||||
// },
|
|
||||||
// title: Text('reset'),
|
|
||||||
// ),
|
|
||||||
Divider(height: 1),
|
|
||||||
Container(
|
|
||||||
height: 30.0,
|
|
||||||
padding: EdgeInsets.fromLTRB(70, 0, 70, 0),
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: Text(s.subscribe,
|
|
||||||
style: context.textTheme.bodyText1!
|
|
||||||
.copyWith(color: context.accentColor)),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding:
|
|
||||||
EdgeInsets.only(left: 70.0, right: 20, top: 10, bottom: 10),
|
|
||||||
child: Text(s.subscribeExportDes),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.only(left: 70.0, right: 20),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
ButtonTheme(
|
|
||||||
height: 32,
|
|
||||||
child: OutlinedButton(
|
|
||||||
style: OutlinedButton.styleFrom(
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(100.0),
|
|
||||||
side: BorderSide(color: Colors.green[700]!)),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
LineIcons.save,
|
|
||||||
color: Colors.green[700],
|
|
||||||
size: context.textTheme.headline6!.fontSize,
|
|
||||||
),
|
|
||||||
SizedBox(width: 10),
|
|
||||||
Text(s.save,
|
|
||||||
style: TextStyle(color: Colors.green[700])),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
onPressed: () async {
|
|
||||||
var file = await _exportOmpl(context);
|
|
||||||
await _saveFile(file);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
SizedBox(width: 10),
|
|
||||||
ButtonTheme(
|
|
||||||
height: 32,
|
|
||||||
child: OutlinedButton(
|
|
||||||
style: OutlinedButton.styleFrom(
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(100.0),
|
|
||||||
side: BorderSide(color: Colors.blue[700]!)),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
Icons.share,
|
|
||||||
size: context.textTheme.headline6!.fontSize,
|
|
||||||
color: Colors.blue[700],
|
|
||||||
),
|
|
||||||
SizedBox(width: 10),
|
|
||||||
Text(s.share,
|
|
||||||
style: TextStyle(color: Colors.blue[700])),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
onPressed: () async {
|
|
||||||
var file = await _exportOmpl(context);
|
|
||||||
await _shareFile(file);
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Divider(height: 1),
|
|
||||||
Container(
|
|
||||||
height: 30.0,
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 70),
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: Text(s.settings,
|
|
||||||
style: context.textTheme.bodyText1!
|
|
||||||
.copyWith(color: Theme.of(context).accentColor)),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding:
|
|
||||||
EdgeInsets.only(left: 70.0, right: 20, top: 10, bottom: 10),
|
|
||||||
child: Text(s.settingsExportDes),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.only(left: 70.0, right: 10),
|
|
||||||
child: Wrap(children: [
|
|
||||||
ButtonTheme(
|
|
||||||
height: 32,
|
|
||||||
child: OutlinedButton(
|
|
||||||
style: OutlinedButton.styleFrom(
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(100.0),
|
|
||||||
side: BorderSide(color: Colors.green[700]!)),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
LineIcons.save,
|
|
||||||
color: Colors.green[700],
|
|
||||||
size: context.textTheme.headline6!.fontSize,
|
|
||||||
),
|
|
||||||
SizedBox(width: 10),
|
|
||||||
Text(s.save,
|
|
||||||
style: TextStyle(color: Colors.green[700])),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
onPressed: () async {
|
|
||||||
var file = await _exportSetting(context);
|
|
||||||
await _saveFile(file);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
SizedBox(width: 10),
|
|
||||||
ButtonTheme(
|
|
||||||
height: 32,
|
|
||||||
child: OutlinedButton(
|
|
||||||
style: OutlinedButton.styleFrom(
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(100.0),
|
|
||||||
side: BorderSide(color: Colors.blue[700]!)),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
Icons.share,
|
|
||||||
size: context.textTheme.headline6!.fontSize,
|
|
||||||
color: Colors.blue[700],
|
|
||||||
),
|
|
||||||
SizedBox(width: 10),
|
|
||||||
Text(s.share,
|
|
||||||
style: TextStyle(color: Colors.blue[700])),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
onPressed: () async {
|
|
||||||
var file = await _exportSetting(context);
|
|
||||||
await _shareFile(file);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
SizedBox(width: 10),
|
|
||||||
ButtonTheme(
|
|
||||||
height: 32,
|
|
||||||
child: OutlinedButton(
|
|
||||||
style: OutlinedButton.styleFrom(
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(100.0),
|
|
||||||
side: BorderSide(color: Colors.red[700]!)),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
LineIcons.paperclip,
|
|
||||||
size: context.textTheme.headline6!.fontSize,
|
|
||||||
color: Colors.red[700],
|
|
||||||
),
|
|
||||||
SizedBox(width: 10),
|
|
||||||
Text(s.import,
|
|
||||||
style: TextStyle(color: Colors.red[700])),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
_getFilePath(context);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
),
|
|
||||||
Divider(height: 1)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _OpenEye extends StatefulWidget {
|
class _OpenEye extends StatefulWidget {
|
||||||
|
@ -710,7 +557,6 @@ class __LoginGpodderState extends State<_LoginGpodder> {
|
||||||
context.s.settingsSyncing,
|
context.s.settingsSyncing,
|
||||||
style: TextStyle(color: Colors.white),
|
style: TextStyle(color: Colors.white),
|
||||||
);
|
);
|
||||||
break;
|
|
||||||
case LoginStatus.start:
|
case LoginStatus.start:
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
|
@ -725,7 +571,6 @@ class __LoginGpodderState extends State<_LoginGpodder> {
|
||||||
context.s.login,
|
context.s.login,
|
||||||
style: TextStyle(color: Colors.white),
|
style: TextStyle(color: Colors.white),
|
||||||
);
|
);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,86 +25,6 @@ class PlayedHistory extends StatefulWidget {
|
||||||
|
|
||||||
class _PlayedHistoryState extends State<PlayedHistory>
|
class _PlayedHistoryState extends State<PlayedHistory>
|
||||||
with SingleTickerProviderStateMixin {
|
with SingleTickerProviderStateMixin {
|
||||||
/// Get play history.
|
|
||||||
Future<List<PlayHistory>> _getPlayHistory(int top) async {
|
|
||||||
var dbHelper = DBHelper();
|
|
||||||
List<PlayHistory> playHistory;
|
|
||||||
playHistory = await dbHelper.getPlayHistory(top);
|
|
||||||
for (var record in playHistory) {
|
|
||||||
await record.getEpisode();
|
|
||||||
}
|
|
||||||
return playHistory;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _loadMore = false;
|
|
||||||
|
|
||||||
Future<void> _loadMoreData() async {
|
|
||||||
if (mounted) {
|
|
||||||
setState(() {
|
|
||||||
_loadMore = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
await Future.delayed(Duration(milliseconds: 500));
|
|
||||||
if (mounted) {
|
|
||||||
setState(() {
|
|
||||||
_top = _top + 10;
|
|
||||||
_loadMore = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int _top = 10;
|
|
||||||
|
|
||||||
Future<List<SubHistory>> getSubHistory() async {
|
|
||||||
var dbHelper = DBHelper();
|
|
||||||
return await dbHelper.getSubHistory();
|
|
||||||
}
|
|
||||||
|
|
||||||
TabController? _controller;
|
|
||||||
List<int> list = const [0, 1, 2, 3, 4, 5, 6];
|
|
||||||
|
|
||||||
Future<List<FlSpot>> getData() async {
|
|
||||||
var dbHelper = DBHelper();
|
|
||||||
var stats = <FlSpot>[];
|
|
||||||
|
|
||||||
for (var day in list) {
|
|
||||||
var mins = await dbHelper.listenMins(7 - day);
|
|
||||||
stats.add(FlSpot(day.toDouble(), mins));
|
|
||||||
}
|
|
||||||
return stats;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future recoverSub(BuildContext context, String url) async {
|
|
||||||
Fluttertoast.showToast(
|
|
||||||
msg: context.s.toastPodcastRecovering,
|
|
||||||
gravity: ToastGravity.BOTTOM,
|
|
||||||
);
|
|
||||||
var subscribeWorker = context.watch<GroupList>();
|
|
||||||
try {
|
|
||||||
var options = BaseOptions(
|
|
||||||
connectTimeout: 10000,
|
|
||||||
receiveTimeout: 10000,
|
|
||||||
);
|
|
||||||
var response = await Dio(options).get(url);
|
|
||||||
var p = RssFeed.parse(response.data);
|
|
||||||
var podcast = OnlinePodcast(
|
|
||||||
rss: url,
|
|
||||||
title: p.title,
|
|
||||||
publisher: p.author,
|
|
||||||
description: p.description,
|
|
||||||
image: p.itunes!.image!.href);
|
|
||||||
var item = SubscribeItem(podcast.rss, podcast.title,
|
|
||||||
imgUrl: podcast.image, group: 'Home');
|
|
||||||
subscribeWorker.setSubscribeItem(item);
|
|
||||||
} catch (e) {
|
|
||||||
developer.log(e.toString(), name: 'Recover podcast error');
|
|
||||||
Fluttertoast.showToast(
|
|
||||||
msg: context.s.toastRecoverFailed,
|
|
||||||
gravity: ToastGravity.BOTTOM,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
@ -122,13 +42,9 @@ class _PlayedHistoryState extends State<PlayedHistory>
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final s = context.s;
|
final s = context.s;
|
||||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||||
value: SystemUiOverlayStyle(
|
value: context.overlay,
|
||||||
statusBarIconBrightness: context.brightness,
|
|
||||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
|
||||||
systemNavigationBarIconBrightness: context.iconBrightness,
|
|
||||||
),
|
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
backgroundColor: context.primaryColor,
|
backgroundColor: context.onPrimary,
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: NestedScrollView(
|
child: NestedScrollView(
|
||||||
headerSliverBuilder: (context, innerBoxScrolled) {
|
headerSliverBuilder: (context, innerBoxScrolled) {
|
||||||
|
@ -389,6 +305,86 @@ class _PlayedHistoryState extends State<PlayedHistory>
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get play history.
|
||||||
|
Future<List<PlayHistory>> _getPlayHistory(int top) async {
|
||||||
|
var dbHelper = DBHelper();
|
||||||
|
List<PlayHistory> playHistory;
|
||||||
|
playHistory = await dbHelper.getPlayHistory(top);
|
||||||
|
for (var record in playHistory) {
|
||||||
|
await record.getEpisode();
|
||||||
|
}
|
||||||
|
return playHistory;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _loadMore = false;
|
||||||
|
|
||||||
|
Future<void> _loadMoreData() async {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_loadMore = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await Future.delayed(Duration(milliseconds: 500));
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_top = _top + 10;
|
||||||
|
_loadMore = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int _top = 10;
|
||||||
|
|
||||||
|
Future<List<SubHistory>> getSubHistory() async {
|
||||||
|
var dbHelper = DBHelper();
|
||||||
|
return await dbHelper.getSubHistory();
|
||||||
|
}
|
||||||
|
|
||||||
|
TabController? _controller;
|
||||||
|
List<int> list = const [0, 1, 2, 3, 4, 5, 6];
|
||||||
|
|
||||||
|
Future<List<FlSpot>> getData() async {
|
||||||
|
var dbHelper = DBHelper();
|
||||||
|
var stats = <FlSpot>[];
|
||||||
|
|
||||||
|
for (var day in list) {
|
||||||
|
var mins = await dbHelper.listenMins(7 - day);
|
||||||
|
stats.add(FlSpot(day.toDouble(), mins));
|
||||||
|
}
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future recoverSub(BuildContext context, String url) async {
|
||||||
|
Fluttertoast.showToast(
|
||||||
|
msg: context.s.toastPodcastRecovering,
|
||||||
|
gravity: ToastGravity.BOTTOM,
|
||||||
|
);
|
||||||
|
var subscribeWorker = context.watch<GroupList>();
|
||||||
|
try {
|
||||||
|
var options = BaseOptions(
|
||||||
|
connectTimeout: 10000,
|
||||||
|
receiveTimeout: 10000,
|
||||||
|
);
|
||||||
|
var response = await Dio(options).get(url);
|
||||||
|
var p = RssFeed.parse(response.data);
|
||||||
|
var podcast = OnlinePodcast(
|
||||||
|
rss: url,
|
||||||
|
title: p.title,
|
||||||
|
publisher: p.author,
|
||||||
|
description: p.description,
|
||||||
|
image: p.itunes!.image!.href);
|
||||||
|
var item = SubscribeItem(podcast.rss, podcast.title,
|
||||||
|
imgUrl: podcast.image, group: 'Home');
|
||||||
|
subscribeWorker.setSubscribeItem(item);
|
||||||
|
} catch (e) {
|
||||||
|
developer.log(e.toString(), name: 'Recover podcast error');
|
||||||
|
Fluttertoast.showToast(
|
||||||
|
msg: context.s.toastRecoverFailed,
|
||||||
|
gravity: ToastGravity.BOTTOM,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
||||||
|
|
|
@ -21,6 +21,246 @@ class LayoutSetting extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _LayoutSettingState extends State<LayoutSetting> {
|
class _LayoutSettingState extends State<LayoutSetting> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final s = context.s;
|
||||||
|
var audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
|
||||||
|
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||||
|
value: context.overlay,
|
||||||
|
child: Scaffold(
|
||||||
|
backgroundColor: context.onPrimary,
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(s.settingsLayout),
|
||||||
|
leading: CustomBackButton(),
|
||||||
|
elevation: 0,
|
||||||
|
backgroundColor: context.primaryColor,
|
||||||
|
),
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.all(10.0),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 30.0,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 70),
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(s.settingsPopupMenu,
|
||||||
|
style: context.textTheme.bodyText1!
|
||||||
|
.copyWith(color: context.accentColor)),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
onTap: () => Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => PopupMenuSetting())),
|
||||||
|
contentPadding: EdgeInsets.only(left: 70.0, right: 20),
|
||||||
|
title: Text(s.settingsPopupMenu),
|
||||||
|
subtitle: Text(s.settingsPopupMenuDes),
|
||||||
|
),
|
||||||
|
Divider(height: 1),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.all(10.0),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 30.0,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 70),
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
s.player,
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyText1!
|
||||||
|
.copyWith(color: context.accentColor),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
contentPadding: EdgeInsets.fromLTRB(70, 10, 10, 10),
|
||||||
|
title: Text(s.settingsPlayerHeight),
|
||||||
|
subtitle: Text(s.settingsPlayerHeightDes),
|
||||||
|
trailing: Selector<AudioPlayerNotifier, PlayerHeight?>(
|
||||||
|
selector: (_, audio) => audio.playerHeight,
|
||||||
|
builder: (_, data, __) => MyDropdownButton(
|
||||||
|
hint: Text(_getHeightString(data)),
|
||||||
|
underline: Center(),
|
||||||
|
elevation: 1,
|
||||||
|
value: data!.index,
|
||||||
|
items: <int>[0, 1, 2].map<DropdownMenuItem<int>>((e) {
|
||||||
|
return DropdownMenuItem<int>(
|
||||||
|
value: e,
|
||||||
|
child: Text(
|
||||||
|
_getHeightString(PlayerHeight.values[e])));
|
||||||
|
}).toList(),
|
||||||
|
onChanged: (dynamic index) =>
|
||||||
|
audio.setPlayerHeight = PlayerHeight.values[index]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (environment['apiKey'] != '') Divider(height: 1),
|
||||||
|
if (environment['apiKey'] != '')
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.all(10.0),
|
||||||
|
),
|
||||||
|
if (environment['apiKey'] != '')
|
||||||
|
Container(
|
||||||
|
height: 30.0,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 70),
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(s.search,
|
||||||
|
style: context.textTheme.bodyText1!
|
||||||
|
.copyWith(color: context.accentColor)),
|
||||||
|
),
|
||||||
|
if (environment['apiKey'] != '')
|
||||||
|
FutureBuilder<bool>(
|
||||||
|
future: _getHideDiscovery(),
|
||||||
|
initialData: false,
|
||||||
|
builder: (context, snapshot) => ListTile(
|
||||||
|
contentPadding: EdgeInsets.fromLTRB(70, 10, 10, 10),
|
||||||
|
onTap: () => _saveHideDiscovery(!snapshot.data!),
|
||||||
|
title: Text(s.hidePodcastDiscovery),
|
||||||
|
subtitle: Text(s.hidePodcastDiscoveryDes),
|
||||||
|
trailing: Transform.scale(
|
||||||
|
scale: 0.9,
|
||||||
|
child: Switch(
|
||||||
|
value: snapshot.data!,
|
||||||
|
onChanged: _saveHideDiscovery),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (environment['apiKey'] != '')
|
||||||
|
FutureBuilder(
|
||||||
|
future: _getSearchEngine(),
|
||||||
|
initialData: SearchEngine.listenNotes,
|
||||||
|
builder: (context, snapshot) => ListTile(
|
||||||
|
contentPadding: EdgeInsets.fromLTRB(70, 10, 10, 10),
|
||||||
|
title: Text(s.defaultSearchEngine),
|
||||||
|
subtitle: Text(s.defaultSearchEngineDes),
|
||||||
|
trailing: MyDropdownButton(
|
||||||
|
hint: Text(''),
|
||||||
|
underline: Center(),
|
||||||
|
elevation: 1,
|
||||||
|
value: snapshot.data,
|
||||||
|
items: [
|
||||||
|
DropdownMenuItem<SearchEngine>(
|
||||||
|
value: SearchEngine.podcastIndex,
|
||||||
|
child: Text('Podcastindex')),
|
||||||
|
DropdownMenuItem<SearchEngine>(
|
||||||
|
value: SearchEngine.listenNotes,
|
||||||
|
child: Text('ListenNotes')),
|
||||||
|
],
|
||||||
|
onChanged: (dynamic value) =>
|
||||||
|
_saveSearchEngine(value)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Divider(height: 1),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
Container(
|
||||||
|
height: 30.0,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 70),
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text('Default page',
|
||||||
|
style: context.textTheme.bodyText1!
|
||||||
|
.copyWith(color: context.accentColor)),
|
||||||
|
),
|
||||||
|
Selector<SettingState, bool?>(
|
||||||
|
selector: (_, setting) => setting.openPlaylistDefault,
|
||||||
|
builder: (_, data, __) {
|
||||||
|
return ListTile(
|
||||||
|
contentPadding: EdgeInsets.fromLTRB(70, 10, 10, 10),
|
||||||
|
onTap: () => context
|
||||||
|
.read<SettingState>()
|
||||||
|
.openPlaylistDefault = !data!,
|
||||||
|
title: Text('Open playlist page by default'),
|
||||||
|
subtitle: Text(
|
||||||
|
'Open playlist page instead of homepage by default'),
|
||||||
|
trailing: Transform.scale(
|
||||||
|
scale: 0.9,
|
||||||
|
child: Switch(
|
||||||
|
value: data!,
|
||||||
|
onChanged: (boo) => context
|
||||||
|
.read<SettingState>()
|
||||||
|
.openPlaylistDefault = boo),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Selector<SettingState, bool?>(
|
||||||
|
selector: (_, setting) => setting.openAllPodcastDefalt,
|
||||||
|
builder: (_, data, __) {
|
||||||
|
return ListTile(
|
||||||
|
contentPadding: EdgeInsets.fromLTRB(70, 10, 10, 10),
|
||||||
|
onTap: () => context
|
||||||
|
.read<SettingState>()
|
||||||
|
.openAllPodcastDefault = !data!,
|
||||||
|
title: Text('Open all podcasts page by default'),
|
||||||
|
subtitle: Text(
|
||||||
|
'Open all podcasts page instead of group page by default'),
|
||||||
|
trailing: Transform.scale(
|
||||||
|
scale: 0.9,
|
||||||
|
child: Switch(
|
||||||
|
value: data!,
|
||||||
|
onChanged: (boo) => context
|
||||||
|
.read<SettingState>()
|
||||||
|
.openAllPodcastDefault = boo),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Divider(height: 1),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
Container(
|
||||||
|
height: 30.0,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 70),
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
s.settingsDefaultGrid,
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyText1!
|
||||||
|
.copyWith(color: context.accentColor),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ListView(
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
shrinkWrap: true,
|
||||||
|
scrollDirection: Axis.vertical,
|
||||||
|
children: <Widget>[
|
||||||
|
FutureBuilder<bool>(
|
||||||
|
future: _hideListened(),
|
||||||
|
initialData: false,
|
||||||
|
builder: (context, snapshot) => ListTile(
|
||||||
|
contentPadding: EdgeInsets.only(left: 70, right: 10),
|
||||||
|
onTap: () => _saveHideListened(!snapshot.data!),
|
||||||
|
title: Text('Hide listened'),
|
||||||
|
subtitle: Text('Hide listened episodes by default'),
|
||||||
|
trailing: Transform.scale(
|
||||||
|
scale: 0.9,
|
||||||
|
child: Switch(
|
||||||
|
value: snapshot.data!,
|
||||||
|
onChanged: _saveHideListened),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
_setDefaultGridView(context,
|
||||||
|
text: s.settingsDefaultGridPodcast,
|
||||||
|
key: podcastLayoutKey),
|
||||||
|
_setDefaultGridView(context,
|
||||||
|
text: s.settingsDefaultGridRecent,
|
||||||
|
key: recentLayoutKey),
|
||||||
|
_setDefaultGridView(context,
|
||||||
|
text: s.settingsDefaultGridFavorite,
|
||||||
|
key: favLayoutKey),
|
||||||
|
_setDefaultGridView(context,
|
||||||
|
text: s.settingsDefaultGridDownload,
|
||||||
|
key: downloadLayoutKey),
|
||||||
|
]),
|
||||||
|
Divider(height: 1),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final _hideDiscoveyStorage = KeyValueStorage(hidePodcastDiscoveryKey);
|
final _hideDiscoveyStorage = KeyValueStorage(hidePodcastDiscoveryKey);
|
||||||
Future<Layout> _getLayout(String key) async {
|
Future<Layout> _getLayout(String key) async {
|
||||||
final keyValueStorage = KeyValueStorage(key);
|
final keyValueStorage = KeyValueStorage(key);
|
||||||
|
@ -38,8 +278,8 @@ class _LayoutSettingState extends State<LayoutSetting> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> _hideListened() async {
|
Future<bool> _hideListened() async {
|
||||||
var hideListenedStorage = KeyValueStorage(hideListenedKey);
|
final hideListenedStorage = KeyValueStorage(hideListenedKey);
|
||||||
var hideListened = await hideListenedStorage.getBool(defaultValue: false);
|
final hideListened = await hideListenedStorage.getBool(defaultValue: false);
|
||||||
return hideListened;
|
return hideListened;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,244 +421,4 @@ class _LayoutSettingState extends State<LayoutSetting> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final s = context.s;
|
|
||||||
var audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
|
|
||||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
|
||||||
value: SystemUiOverlayStyle(
|
|
||||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
|
||||||
systemNavigationBarColor: context.primaryColor,
|
|
||||||
systemNavigationBarIconBrightness:
|
|
||||||
Theme.of(context).accentColorBrightness,
|
|
||||||
),
|
|
||||||
child: Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(s.settingsLayout),
|
|
||||||
leading: CustomBackButton(),
|
|
||||||
elevation: 0,
|
|
||||||
backgroundColor: context.primaryColor,
|
|
||||||
),
|
|
||||||
body: SingleChildScrollView(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.all(10.0),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
height: 30.0,
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 70),
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: Text(s.settingsPopupMenu,
|
|
||||||
style: context.textTheme.bodyText1!
|
|
||||||
.copyWith(color: context.accentColor)),
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
onTap: () => Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => PopupMenuSetting())),
|
|
||||||
contentPadding: EdgeInsets.only(left: 70.0, right: 20),
|
|
||||||
title: Text(s.settingsPopupMenu),
|
|
||||||
subtitle: Text(s.settingsPopupMenuDes),
|
|
||||||
),
|
|
||||||
Divider(height: 1),
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.all(10.0),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
height: 30.0,
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 70),
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: Text(s.player,
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.bodyText1!
|
|
||||||
.copyWith(color: Theme.of(context).accentColor)),
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
contentPadding: EdgeInsets.fromLTRB(70, 10, 10, 10),
|
|
||||||
title: Text(s.settingsPlayerHeight),
|
|
||||||
subtitle: Text(s.settingsPlayerHeightDes),
|
|
||||||
trailing: Selector<AudioPlayerNotifier, PlayerHeight?>(
|
|
||||||
selector: (_, audio) => audio.playerHeight,
|
|
||||||
builder: (_, data, __) => MyDropdownButton(
|
|
||||||
hint: Text(_getHeightString(data)),
|
|
||||||
underline: Center(),
|
|
||||||
elevation: 1,
|
|
||||||
value: data!.index,
|
|
||||||
items: <int>[0, 1, 2].map<DropdownMenuItem<int>>((e) {
|
|
||||||
return DropdownMenuItem<int>(
|
|
||||||
value: e,
|
|
||||||
child: Text(
|
|
||||||
_getHeightString(PlayerHeight.values[e])));
|
|
||||||
}).toList(),
|
|
||||||
onChanged: (dynamic index) =>
|
|
||||||
audio.setPlayerHeight = PlayerHeight.values[index]),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (environment['apiKey'] != '') Divider(height: 1),
|
|
||||||
if (environment['apiKey'] != '')
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.all(10.0),
|
|
||||||
),
|
|
||||||
if (environment['apiKey'] != '')
|
|
||||||
Container(
|
|
||||||
height: 30.0,
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 70),
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: Text(s.search,
|
|
||||||
style: context.textTheme.bodyText1!
|
|
||||||
.copyWith(color: context.accentColor)),
|
|
||||||
),
|
|
||||||
if (environment['apiKey'] != '')
|
|
||||||
FutureBuilder<bool>(
|
|
||||||
future: _getHideDiscovery(),
|
|
||||||
initialData: false,
|
|
||||||
builder: (context, snapshot) => ListTile(
|
|
||||||
contentPadding: EdgeInsets.fromLTRB(70, 10, 10, 10),
|
|
||||||
onTap: () => _saveHideDiscovery(!snapshot.data!),
|
|
||||||
title: Text(s.hidePodcastDiscovery),
|
|
||||||
subtitle: Text(s.hidePodcastDiscoveryDes),
|
|
||||||
trailing: Transform.scale(
|
|
||||||
scale: 0.9,
|
|
||||||
child: Switch(
|
|
||||||
value: snapshot.data!,
|
|
||||||
onChanged: _saveHideDiscovery),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (environment['apiKey'] != '')
|
|
||||||
FutureBuilder(
|
|
||||||
future: _getSearchEngine(),
|
|
||||||
initialData: SearchEngine.listenNotes,
|
|
||||||
builder: (context, snapshot) => ListTile(
|
|
||||||
contentPadding: EdgeInsets.fromLTRB(70, 10, 10, 10),
|
|
||||||
title: Text(s.defaultSearchEngine),
|
|
||||||
subtitle: Text(s.defaultSearchEngineDes),
|
|
||||||
trailing: MyDropdownButton(
|
|
||||||
hint: Text(''),
|
|
||||||
underline: Center(),
|
|
||||||
elevation: 1,
|
|
||||||
value: snapshot.data,
|
|
||||||
items: [
|
|
||||||
DropdownMenuItem<SearchEngine>(
|
|
||||||
value: SearchEngine.podcastIndex,
|
|
||||||
child: Text('Podcastindex')),
|
|
||||||
DropdownMenuItem<SearchEngine>(
|
|
||||||
value: SearchEngine.listenNotes,
|
|
||||||
child: Text('ListenNotes')),
|
|
||||||
],
|
|
||||||
onChanged: (dynamic value) =>
|
|
||||||
_saveSearchEngine(value)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Divider(height: 1),
|
|
||||||
SizedBox(height: 20),
|
|
||||||
Container(
|
|
||||||
height: 30.0,
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 70),
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: Text('Default page',
|
|
||||||
style: context.textTheme.bodyText1!
|
|
||||||
.copyWith(color: context.accentColor)),
|
|
||||||
),
|
|
||||||
Selector<SettingState, bool?>(
|
|
||||||
selector: (_, setting) => setting.openPlaylistDefault,
|
|
||||||
builder: (_, data, __) {
|
|
||||||
return ListTile(
|
|
||||||
contentPadding: EdgeInsets.fromLTRB(70, 10, 10, 10),
|
|
||||||
onTap: () => context
|
|
||||||
.read<SettingState>()
|
|
||||||
.openPlaylistDefault = !data!,
|
|
||||||
title: Text('Open playlist page by default'),
|
|
||||||
subtitle: Text(
|
|
||||||
'Open playlist page instead of homepage by default'),
|
|
||||||
trailing: Transform.scale(
|
|
||||||
scale: 0.9,
|
|
||||||
child: Switch(
|
|
||||||
value: data!,
|
|
||||||
onChanged: (boo) => context
|
|
||||||
.read<SettingState>()
|
|
||||||
.openPlaylistDefault = boo),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Selector<SettingState, bool?>(
|
|
||||||
selector: (_, setting) => setting.openAllPodcastDefalt,
|
|
||||||
builder: (_, data, __) {
|
|
||||||
return ListTile(
|
|
||||||
contentPadding: EdgeInsets.fromLTRB(70, 10, 10, 10),
|
|
||||||
onTap: () => context
|
|
||||||
.read<SettingState>()
|
|
||||||
.openAllPodcastDefault = !data!,
|
|
||||||
title: Text('Open all podcasts page by default'),
|
|
||||||
subtitle: Text(
|
|
||||||
'Open all podcasts page instead of group page by default'),
|
|
||||||
trailing: Transform.scale(
|
|
||||||
scale: 0.9,
|
|
||||||
child: Switch(
|
|
||||||
value: data!,
|
|
||||||
onChanged: (boo) => context
|
|
||||||
.read<SettingState>()
|
|
||||||
.openAllPodcastDefault = boo),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Divider(height: 1),
|
|
||||||
SizedBox(height: 20),
|
|
||||||
Container(
|
|
||||||
height: 30.0,
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 70),
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: Text(s.settingsDefaultGrid,
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.bodyText1!
|
|
||||||
.copyWith(color: Theme.of(context).accentColor)),
|
|
||||||
),
|
|
||||||
ListView(
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
shrinkWrap: true,
|
|
||||||
scrollDirection: Axis.vertical,
|
|
||||||
children: <Widget>[
|
|
||||||
FutureBuilder<bool>(
|
|
||||||
future: _hideListened(),
|
|
||||||
initialData: false,
|
|
||||||
builder: (context, snapshot) => ListTile(
|
|
||||||
contentPadding: EdgeInsets.only(left: 70, right: 10),
|
|
||||||
onTap: () => _saveHideListened(!snapshot.data!),
|
|
||||||
title: Text('Hide listened'),
|
|
||||||
subtitle: Text('Hide listened episodes by default'),
|
|
||||||
trailing: Transform.scale(
|
|
||||||
scale: 0.9,
|
|
||||||
child: Switch(
|
|
||||||
value: snapshot.data!,
|
|
||||||
onChanged: _saveHideListened),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
_setDefaultGridView(context,
|
|
||||||
text: s.settingsDefaultGridPodcast,
|
|
||||||
key: podcastLayoutKey),
|
|
||||||
_setDefaultGridView(context,
|
|
||||||
text: s.settingsDefaultGridRecent,
|
|
||||||
key: recentLayoutKey),
|
|
||||||
_setDefaultGridView(context,
|
|
||||||
text: s.settingsDefaultGridFavorite,
|
|
||||||
key: favLayoutKey),
|
|
||||||
_setDefaultGridView(context,
|
|
||||||
text: s.settingsDefaultGridDownload,
|
|
||||||
key: downloadLayoutKey),
|
|
||||||
]),
|
|
||||||
Divider(height: 1),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,15 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
|
||||||
|
|
||||||
import '../util/extension_helper.dart';
|
import '../util/extension_helper.dart';
|
||||||
import '../widgets/custom_widget.dart';
|
import '../widgets/custom_widget.dart';
|
||||||
import 'licenses.dart';
|
import 'licenses.dart';
|
||||||
|
|
||||||
class Libries extends StatelessWidget {
|
class Libries extends StatelessWidget {
|
||||||
_launchUrl(String url) async {
|
|
||||||
if (await canLaunch(url)) {
|
|
||||||
await launch(url);
|
|
||||||
} else {
|
|
||||||
throw 'Could not launch $url';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||||
value: SystemUiOverlayStyle(
|
value: context.overlay,
|
||||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
|
||||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
|
||||||
systemNavigationBarIconBrightness:
|
|
||||||
Theme.of(context).accentColorBrightness,
|
|
||||||
),
|
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(context.s.settingsLibraries),
|
title: Text(context.s.settingsLibraries),
|
||||||
|
@ -50,14 +36,14 @@ class Libries extends StatelessWidget {
|
||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodyText1!
|
.bodyText1!
|
||||||
.copyWith(color: Theme.of(context).accentColor)),
|
.copyWith(color: context.accentColor)),
|
||||||
),
|
),
|
||||||
Column(
|
Column(
|
||||||
children: google.map<Widget>(
|
children: google.map<Widget>(
|
||||||
(e) {
|
(e) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
contentPadding: EdgeInsets.symmetric(horizontal: 80),
|
contentPadding: EdgeInsets.symmetric(horizontal: 80),
|
||||||
onTap: () => _launchUrl(e.link),
|
onTap: () => e.link.launchUrl,
|
||||||
title: Text(e.name),
|
title: Text(e.name),
|
||||||
subtitle: Text(e.license),
|
subtitle: Text(e.license),
|
||||||
);
|
);
|
||||||
|
@ -72,14 +58,14 @@ class Libries extends StatelessWidget {
|
||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodyText1!
|
.bodyText1!
|
||||||
.copyWith(color: Theme.of(context).accentColor)),
|
.copyWith(color: context.accentColor)),
|
||||||
),
|
),
|
||||||
Column(
|
Column(
|
||||||
children: fonts.map<Widget>(
|
children: fonts.map<Widget>(
|
||||||
(e) {
|
(e) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
contentPadding: EdgeInsets.symmetric(horizontal: 80),
|
contentPadding: EdgeInsets.symmetric(horizontal: 80),
|
||||||
onTap: () => _launchUrl(e.link),
|
onTap: () => e.link.launchUrl,
|
||||||
title: Text(e.name),
|
title: Text(e.name),
|
||||||
subtitle: Text(e.license),
|
subtitle: Text(e.license),
|
||||||
);
|
);
|
||||||
|
@ -94,14 +80,14 @@ class Libries extends StatelessWidget {
|
||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodyText1!
|
.bodyText1!
|
||||||
.copyWith(color: Theme.of(context).accentColor)),
|
.copyWith(color: context.accentColor)),
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: plugins.map<Widget>(
|
children: plugins.map<Widget>(
|
||||||
(e) {
|
(e) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
onTap: () => _launchUrl(e.link),
|
onTap: () => e.link.launchUrl,
|
||||||
contentPadding:
|
contentPadding:
|
||||||
EdgeInsets.symmetric(horizontal: 80),
|
EdgeInsets.symmetric(horizontal: 80),
|
||||||
title: Text(e.name),
|
title: Text(e.name),
|
||||||
|
|
|
@ -38,198 +38,15 @@ class PlaySetting extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PlaySettingState extends State<PlaySetting> {
|
class _PlaySettingState extends State<PlaySetting> {
|
||||||
String _volumeEffect(BuildContext context, int? i) {
|
|
||||||
final s = context.s;
|
|
||||||
if (i == 2000) {
|
|
||||||
return s.playerHeightShort;
|
|
||||||
} else if (i == 3000) {
|
|
||||||
return s.playerHeightMed;
|
|
||||||
}
|
|
||||||
return s.playerHeightTall;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> _getMarkListenedSkip() async {
|
|
||||||
final storage = KeyValueStorage(markListenedAfterSkipKey);
|
|
||||||
return storage.getBool(defaultValue: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _saveMarkListenedSkip(bool boo) async {
|
|
||||||
final storage = KeyValueStorage(markListenedAfterSkipKey);
|
|
||||||
await storage.saveBool(boo);
|
|
||||||
if (mounted) setState(() {});
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _modeWidget(BuildContext context) {
|
|
||||||
var settings = Provider.of<SettingState>(context, listen: false);
|
|
||||||
return Selector<SettingState, Tuple2<int?, int?>>(
|
|
||||||
selector: (_, settings) =>
|
|
||||||
Tuple2(settings.autoSleepTimerMode, settings.defaultSleepTimer),
|
|
||||||
builder: (_, data, __) => Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
InkWell(
|
|
||||||
onTap: () => settings.setAutoSleepTimerMode = 0,
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
bottomLeft: Radius.circular(5), topLeft: Radius.circular(5)),
|
|
||||||
child: Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: AnimatedContainer(
|
|
||||||
duration: Duration(milliseconds: 400),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: data.item1 == 0
|
|
||||||
? context.accentColor
|
|
||||||
: context.primaryColorDark,
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
bottomLeft: Radius.circular(5),
|
|
||||||
topLeft: Radius.circular(5)),
|
|
||||||
),
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Text(context.s.endOfEpisode,
|
|
||||||
style: TextStyle(
|
|
||||||
color: data.item1 == 0 ? Colors.white : null)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
InkWell(
|
|
||||||
onTap: () => settings.setAutoSleepTimerMode = 1,
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
bottomRight: Radius.circular(5),
|
|
||||||
topRight: Radius.circular(5)),
|
|
||||||
child: Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: AnimatedContainer(
|
|
||||||
duration: Duration(milliseconds: 400),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: data.item1 == 1
|
|
||||||
? context.accentColor
|
|
||||||
: context.primaryColorDark,
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
bottomRight: Radius.circular(5),
|
|
||||||
topRight: Radius.circular(5)),
|
|
||||||
),
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Text(context.s.minsCount(data.item2!),
|
|
||||||
style: TextStyle(
|
|
||||||
color: data.item1 == 1 ? Colors.white : null)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _scheduleWidget(BuildContext context) {
|
|
||||||
var settings = Provider.of<SettingState>(context, listen: false);
|
|
||||||
final s = context.s;
|
|
||||||
return Selector<SettingState, Tuple2<int?, int?>>(
|
|
||||||
selector: (_, settings) =>
|
|
||||||
Tuple2(settings.autoSleepTimerStart, settings.autoSleepTimerEnd),
|
|
||||||
builder: (_, data, __) => Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 10.0),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
InkWell(
|
|
||||||
onTap: () async {
|
|
||||||
var startTime = data.item1!;
|
|
||||||
final timeOfDay = await showCustomTimePicker(
|
|
||||||
context: context,
|
|
||||||
cancelText: s.cancel,
|
|
||||||
confirmText: s.confirm,
|
|
||||||
helpText: '',
|
|
||||||
initialTime: TimeOfDay(
|
|
||||||
hour: startTime ~/ 60, minute: startTime % 60));
|
|
||||||
if (timeOfDay != null) {
|
|
||||||
startTime = timeOfDay.hour * 60 + timeOfDay.minute;
|
|
||||||
if (startTime != data.item2) {
|
|
||||||
settings.setAutoSleepTimerStart = startTime;
|
|
||||||
} else {
|
|
||||||
Fluttertoast.showToast(
|
|
||||||
msg: s.toastTimeEqualEnd,
|
|
||||||
gravity: ToastGravity.BOTTOM,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
bottomLeft: Radius.circular(5), topLeft: Radius.circular(5)),
|
|
||||||
child: Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: context.primaryColorDark,
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
bottomLeft: Radius.circular(5),
|
|
||||||
topLeft: Radius.circular(5)),
|
|
||||||
),
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Text(s.from(data.item1!.toTime)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
InkWell(
|
|
||||||
onTap: () async {
|
|
||||||
var endTime = data.item2!;
|
|
||||||
final timeOfDay = await showCustomTimePicker(
|
|
||||||
context: context,
|
|
||||||
cancelText: s.cancel,
|
|
||||||
confirmText: s.confirm,
|
|
||||||
helpText: '',
|
|
||||||
initialTime:
|
|
||||||
TimeOfDay(hour: endTime ~/ 60, minute: endTime % 60));
|
|
||||||
if (timeOfDay != null) {
|
|
||||||
endTime = timeOfDay.hour * 60 + timeOfDay.minute;
|
|
||||||
if (endTime != data.item1) {
|
|
||||||
settings.setAutoSleepTimerEnd = endTime;
|
|
||||||
} else {
|
|
||||||
Fluttertoast.showToast(
|
|
||||||
msg: s.toastTimeEqualStart,
|
|
||||||
gravity: ToastGravity.BOTTOM,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
bottomRight: Radius.circular(5),
|
|
||||||
topRight: Radius.circular(5)),
|
|
||||||
child: Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: Container(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.black54,
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
bottomRight: Radius.circular(5),
|
|
||||||
topRight: Radius.circular(5))),
|
|
||||||
child: Text(s.to(data.item2!.toTime),
|
|
||||||
style: TextStyle(color: Colors.white)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var settings = context.watch<SettingState>();
|
final settings = context.watch<SettingState>();
|
||||||
var audio = context.watch<AudioPlayerNotifier>();
|
final audio = context.watch<AudioPlayerNotifier>();
|
||||||
final s = context.s;
|
final s = context.s;
|
||||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||||
value: SystemUiOverlayStyle(
|
value: context.overlay,
|
||||||
statusBarIconBrightness: context.brightness,
|
|
||||||
systemNavigationBarColor: context.primaryColor,
|
|
||||||
systemNavigationBarIconBrightness: context.iconBrightness,
|
|
||||||
),
|
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
|
backgroundColor: context.onPrimary,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(s.play),
|
title: Text(s.play),
|
||||||
leading: CustomBackButton(),
|
leading: CustomBackButton(),
|
||||||
|
@ -463,6 +280,186 @@ class _PlaySettingState extends State<PlaySetting> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _volumeEffect(BuildContext context, int? i) {
|
||||||
|
final s = context.s;
|
||||||
|
if (i == 2000) {
|
||||||
|
return s.playerHeightShort;
|
||||||
|
} else if (i == 3000) {
|
||||||
|
return s.playerHeightMed;
|
||||||
|
}
|
||||||
|
return s.playerHeightTall;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _getMarkListenedSkip() async {
|
||||||
|
final storage = KeyValueStorage(markListenedAfterSkipKey);
|
||||||
|
return storage.getBool(defaultValue: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _saveMarkListenedSkip(bool boo) async {
|
||||||
|
final storage = KeyValueStorage(markListenedAfterSkipKey);
|
||||||
|
await storage.saveBool(boo);
|
||||||
|
if (mounted) setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _modeWidget(BuildContext context) {
|
||||||
|
var settings = Provider.of<SettingState>(context, listen: false);
|
||||||
|
return Selector<SettingState, Tuple2<int?, int?>>(
|
||||||
|
selector: (_, settings) =>
|
||||||
|
Tuple2(settings.autoSleepTimerMode, settings.defaultSleepTimer),
|
||||||
|
builder: (_, data, __) => Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
InkWell(
|
||||||
|
onTap: () => settings.setAutoSleepTimerMode = 0,
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
bottomLeft: Radius.circular(5), topLeft: Radius.circular(5)),
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: AnimatedContainer(
|
||||||
|
duration: Duration(milliseconds: 400),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: data.item1 == 0
|
||||||
|
? context.accentColor
|
||||||
|
: context.primaryColorDark,
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
bottomLeft: Radius.circular(5),
|
||||||
|
topLeft: Radius.circular(5)),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(context.s.endOfEpisode,
|
||||||
|
style: TextStyle(
|
||||||
|
color: data.item1 == 0 ? Colors.white : null)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
InkWell(
|
||||||
|
onTap: () => settings.setAutoSleepTimerMode = 1,
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
bottomRight: Radius.circular(5),
|
||||||
|
topRight: Radius.circular(5)),
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: AnimatedContainer(
|
||||||
|
duration: Duration(milliseconds: 400),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: data.item1 == 1
|
||||||
|
? context.accentColor
|
||||||
|
: context.primaryColorDark,
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
bottomRight: Radius.circular(5),
|
||||||
|
topRight: Radius.circular(5)),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(context.s.minsCount(data.item2!),
|
||||||
|
style: TextStyle(
|
||||||
|
color: data.item1 == 1 ? Colors.white : null)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _scheduleWidget(BuildContext context) {
|
||||||
|
var settings = Provider.of<SettingState>(context, listen: false);
|
||||||
|
final s = context.s;
|
||||||
|
return Selector<SettingState, Tuple2<int?, int?>>(
|
||||||
|
selector: (_, settings) =>
|
||||||
|
Tuple2(settings.autoSleepTimerStart, settings.autoSleepTimerEnd),
|
||||||
|
builder: (_, data, __) => Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 10.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
InkWell(
|
||||||
|
onTap: () async {
|
||||||
|
var startTime = data.item1!;
|
||||||
|
final timeOfDay = await showCustomTimePicker(
|
||||||
|
context: context,
|
||||||
|
cancelText: s.cancel,
|
||||||
|
confirmText: s.confirm,
|
||||||
|
helpText: '',
|
||||||
|
initialTime: TimeOfDay(
|
||||||
|
hour: startTime ~/ 60, minute: startTime % 60));
|
||||||
|
if (timeOfDay != null) {
|
||||||
|
startTime = timeOfDay.hour * 60 + timeOfDay.minute;
|
||||||
|
if (startTime != data.item2) {
|
||||||
|
settings.setAutoSleepTimerStart = startTime;
|
||||||
|
} else {
|
||||||
|
Fluttertoast.showToast(
|
||||||
|
msg: s.toastTimeEqualEnd,
|
||||||
|
gravity: ToastGravity.BOTTOM,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
bottomLeft: Radius.circular(5), topLeft: Radius.circular(5)),
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: context.primaryColorDark,
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
bottomLeft: Radius.circular(5),
|
||||||
|
topLeft: Radius.circular(5)),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(s.from(data.item1!.toTime)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
InkWell(
|
||||||
|
onTap: () async {
|
||||||
|
var endTime = data.item2!;
|
||||||
|
final timeOfDay = await showCustomTimePicker(
|
||||||
|
context: context,
|
||||||
|
cancelText: s.cancel,
|
||||||
|
confirmText: s.confirm,
|
||||||
|
helpText: '',
|
||||||
|
initialTime:
|
||||||
|
TimeOfDay(hour: endTime ~/ 60, minute: endTime % 60));
|
||||||
|
if (timeOfDay != null) {
|
||||||
|
endTime = timeOfDay.hour * 60 + timeOfDay.minute;
|
||||||
|
if (endTime != data.item1) {
|
||||||
|
settings.setAutoSleepTimerEnd = endTime;
|
||||||
|
} else {
|
||||||
|
Fluttertoast.showToast(
|
||||||
|
msg: s.toastTimeEqualStart,
|
||||||
|
gravity: ToastGravity.BOTTOM,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
bottomRight: Radius.circular(5),
|
||||||
|
topRight: Radius.circular(5)),
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.black54,
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
bottomRight: Radius.circular(5),
|
||||||
|
topRight: Radius.circular(5))),
|
||||||
|
child: Text(s.to(data.item2!.toTime),
|
||||||
|
style: TextStyle(color: Colors.white)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _NotificationLayout extends StatefulWidget {
|
class _NotificationLayout extends StatefulWidget {
|
||||||
|
|
|
@ -71,20 +71,19 @@ class _SettingsState extends State<Settings> {
|
||||||
final s = context.s;
|
final s = context.s;
|
||||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||||
value: SystemUiOverlayStyle(
|
value: SystemUiOverlayStyle(
|
||||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
statusBarIconBrightness: context.brightness,
|
||||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
systemNavigationBarColor: context.onPrimary,
|
||||||
systemNavigationBarIconBrightness:
|
systemNavigationBarIconBrightness: context.iconBrightness,
|
||||||
Theme.of(context).accentColorBrightness,
|
|
||||||
),
|
),
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
|
backgroundColor: context.onPrimary,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(s.settings),
|
title: Text(s.settings),
|
||||||
leading: CustomBackButton(),
|
leading: CustomBackButton(),
|
||||||
elevation: _showTitle ? 1 : 0,
|
elevation: _showTitle ? 1 : 0,
|
||||||
backgroundColor: context.primaryColor,
|
backgroundColor: context.onPrimary,
|
||||||
),
|
),
|
||||||
body: SafeArea(
|
body: SingleChildScrollView(
|
||||||
child: SingleChildScrollView(
|
|
||||||
scrollDirection: Axis.vertical,
|
scrollDirection: Axis.vertical,
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
child: Column(
|
child: Column(
|
||||||
|
@ -142,10 +141,8 @@ class _SettingsState extends State<Settings> {
|
||||||
subtitle: Text(s.settingsSyncingDes)),
|
subtitle: Text(s.settingsSyncingDes)),
|
||||||
Divider(height: 1),
|
Divider(height: 1),
|
||||||
ListTile(
|
ListTile(
|
||||||
onTap: () => Navigator.push(
|
onTap: () => Navigator.push(context,
|
||||||
context,
|
MaterialPageRoute(builder: (context) => StorageSetting())),
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => StorageSetting())),
|
|
||||||
contentPadding: EdgeInsets.symmetric(horizontal: 25.0),
|
contentPadding: EdgeInsets.symmetric(horizontal: 25.0),
|
||||||
leading: Icon(LineIcons.save, color: Colors.green[700]),
|
leading: Icon(LineIcons.save, color: Colors.green[700]),
|
||||||
title: Text(s.settingStorage),
|
title: Text(s.settingStorage),
|
||||||
|
@ -218,9 +215,7 @@ class _SettingsState extends State<Settings> {
|
||||||
'https://github.com/stonega/tsacdop/issues'),
|
'https://github.com/stonega/tsacdop/issues'),
|
||||||
_feedbackItem(LineIcons.telegram, s.feedbackTelegram,
|
_feedbackItem(LineIcons.telegram, s.feedbackTelegram,
|
||||||
'https://t.me/joinchat/Bk3LkRpTHy40QYC78PK7Qg'),
|
'https://t.me/joinchat/Bk3LkRpTHy40QYC78PK7Qg'),
|
||||||
_feedbackItem(
|
_feedbackItem(LineIcons.envelopeOpenText, s.feedbackEmail,
|
||||||
LineIcons.envelopeOpenText,
|
|
||||||
s.feedbackEmail,
|
|
||||||
'mailto:<tsacdop.app@gmail.com>?subject=Tsacdop Feedback'),
|
'mailto:<tsacdop.app@gmail.com>?subject=Tsacdop Feedback'),
|
||||||
_feedbackItem(LineIcons.googlePlay, s.feedbackPlay,
|
_feedbackItem(LineIcons.googlePlay, s.feedbackPlay,
|
||||||
'https://play.google.com/store/apps/details?id=com.stonegate.tsacdop'),
|
'https://play.google.com/store/apps/details?id=com.stonegate.tsacdop'),
|
||||||
|
@ -261,8 +256,7 @@ class _SettingsState extends State<Settings> {
|
||||||
onTap: () => Navigator.push(
|
onTap: () => Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) =>
|
builder: (context) => SlideIntro(goto: Goto.settings))),
|
||||||
SlideIntro(goto: Goto.settings))),
|
|
||||||
contentPadding: EdgeInsets.symmetric(horizontal: 25.0),
|
contentPadding: EdgeInsets.symmetric(horizontal: 25.0),
|
||||||
leading: Icon(LineIcons.columns, color: Colors.blueGrey),
|
leading: Icon(LineIcons.columns, color: Colors.blueGrey),
|
||||||
title: Text(s.settingsAppIntro),
|
title: Text(s.settingsAppIntro),
|
||||||
|
@ -275,7 +269,6 @@ class _SettingsState extends State<Settings> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,75 +23,6 @@ class _StorageSettingState extends State<StorageSetting>
|
||||||
AnimationController? _controller;
|
AnimationController? _controller;
|
||||||
late Animation<double> _animation;
|
late Animation<double> _animation;
|
||||||
List<String>? _dirs;
|
List<String>? _dirs;
|
||||||
Future<void> _getCacheMax() async {
|
|
||||||
var cache =
|
|
||||||
await cacheStorage.getInt(defaultValue: (200 * 1024 * 1024).toInt());
|
|
||||||
if (cache == 0) {
|
|
||||||
await cacheStorage.saveInt((200 * 1024 * 1024).toInt());
|
|
||||||
cache = 200 * 1024 * 1024;
|
|
||||||
}
|
|
||||||
var value = cache ~/ (1024 * 1024);
|
|
||||||
if (value > 100) {
|
|
||||||
_controller = AnimationController(
|
|
||||||
vsync: this, duration: Duration(milliseconds: value * 2));
|
|
||||||
_animation = Tween<double>(begin: 100, end: value.toDouble()).animate(
|
|
||||||
CurvedAnimation(curve: Curves.easeOutQuart, parent: _controller!))
|
|
||||||
..addListener(() {
|
|
||||||
setState(() => _value = _animation.value);
|
|
||||||
});
|
|
||||||
_controller!.forward();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> _getAutoDownloadNetwork() async {
|
|
||||||
var storage = KeyValueStorage(autoDownloadNetworkKey);
|
|
||||||
var value = await storage.getBool(defaultValue: false);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<int?> _getAutoDeleteDays() async {
|
|
||||||
var storage = KeyValueStorage(autoDeleteKey);
|
|
||||||
var days = await storage.getInt();
|
|
||||||
if (days == 0) {
|
|
||||||
storage.saveInt(30);
|
|
||||||
return 30;
|
|
||||||
}
|
|
||||||
return days;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<int?> _getDownloadPasition() async {
|
|
||||||
final storage = KeyValueStorage(downloadPositionKey);
|
|
||||||
final index = await storage.getInt();
|
|
||||||
final externalDirs = await getExternalStorageDirectories();
|
|
||||||
_dirs = [for (var dir in externalDirs!) dir.path];
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> _getDelteAfterPlayed() async {
|
|
||||||
final storage = KeyValueStorage(deleteAfterPlayedKey);
|
|
||||||
return await storage.getBool(defaultValue: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _setAutoDeleteDays(int days) async {
|
|
||||||
var storage = KeyValueStorage(autoDeleteKey);
|
|
||||||
await storage.saveInt(days);
|
|
||||||
setState(() {});
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _setAudtDownloadNetwork(bool boo) async {
|
|
||||||
var storage = KeyValueStorage(autoDownloadNetworkKey);
|
|
||||||
await storage.saveBool(boo);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _setDownloadPosition(int? index) async {
|
|
||||||
final storage = KeyValueStorage(downloadPositionKey);
|
|
||||||
await storage.saveInt(index!);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _setDeleteAfterPlayed(bool? boo) async {
|
|
||||||
final storage = KeyValueStorage(deleteAfterPlayedKey);
|
|
||||||
await storage.saveBool(boo);
|
|
||||||
}
|
|
||||||
|
|
||||||
late double _value;
|
late double _value;
|
||||||
|
|
||||||
|
@ -113,13 +44,9 @@ class _StorageSettingState extends State<StorageSetting>
|
||||||
final s = context.s;
|
final s = context.s;
|
||||||
var settings = Provider.of<SettingState>(context, listen: false);
|
var settings = Provider.of<SettingState>(context, listen: false);
|
||||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||||
value: SystemUiOverlayStyle(
|
value: context.overlay,
|
||||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
|
||||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
|
||||||
systemNavigationBarIconBrightness:
|
|
||||||
Theme.of(context).accentColorBrightness,
|
|
||||||
),
|
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
|
backgroundColor: context.onPrimary,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(s.settingStorage),
|
title: Text(s.settingStorage),
|
||||||
leading: CustomBackButton(),
|
leading: CustomBackButton(),
|
||||||
|
@ -345,4 +272,74 @@ class _StorageSettingState extends State<StorageSetting>
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _getCacheMax() async {
|
||||||
|
var cache =
|
||||||
|
await cacheStorage.getInt(defaultValue: (200 * 1024 * 1024).toInt());
|
||||||
|
if (cache == 0) {
|
||||||
|
await cacheStorage.saveInt((200 * 1024 * 1024).toInt());
|
||||||
|
cache = 200 * 1024 * 1024;
|
||||||
|
}
|
||||||
|
var value = cache ~/ (1024 * 1024);
|
||||||
|
if (value > 100) {
|
||||||
|
_controller = AnimationController(
|
||||||
|
vsync: this, duration: Duration(milliseconds: value * 2));
|
||||||
|
_animation = Tween<double>(begin: 100, end: value.toDouble()).animate(
|
||||||
|
CurvedAnimation(curve: Curves.easeOutQuart, parent: _controller!))
|
||||||
|
..addListener(() {
|
||||||
|
setState(() => _value = _animation.value);
|
||||||
|
});
|
||||||
|
_controller!.forward();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _getAutoDownloadNetwork() async {
|
||||||
|
var storage = KeyValueStorage(autoDownloadNetworkKey);
|
||||||
|
var value = await storage.getBool(defaultValue: false);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int?> _getAutoDeleteDays() async {
|
||||||
|
var storage = KeyValueStorage(autoDeleteKey);
|
||||||
|
var days = await storage.getInt();
|
||||||
|
if (days == 0) {
|
||||||
|
storage.saveInt(30);
|
||||||
|
return 30;
|
||||||
|
}
|
||||||
|
return days;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int?> _getDownloadPasition() async {
|
||||||
|
final storage = KeyValueStorage(downloadPositionKey);
|
||||||
|
final index = await storage.getInt();
|
||||||
|
final externalDirs = await getExternalStorageDirectories();
|
||||||
|
_dirs = [for (var dir in externalDirs!) dir.path];
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _getDelteAfterPlayed() async {
|
||||||
|
final storage = KeyValueStorage(deleteAfterPlayedKey);
|
||||||
|
return await storage.getBool(defaultValue: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _setAutoDeleteDays(int days) async {
|
||||||
|
var storage = KeyValueStorage(autoDeleteKey);
|
||||||
|
await storage.saveInt(days);
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _setAudtDownloadNetwork(bool boo) async {
|
||||||
|
var storage = KeyValueStorage(autoDownloadNetworkKey);
|
||||||
|
await storage.saveBool(boo);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _setDownloadPosition(int? index) async {
|
||||||
|
final storage = KeyValueStorage(downloadPositionKey);
|
||||||
|
await storage.saveInt(index!);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _setDeleteAfterPlayed(bool? boo) async {
|
||||||
|
final storage = KeyValueStorage(deleteAfterPlayedKey);
|
||||||
|
await storage.saveBool(boo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,12 +14,7 @@ class SyncingSetting extends StatelessWidget {
|
||||||
final s = context.s;
|
final s = context.s;
|
||||||
var settings = Provider.of<SettingState>(context, listen: false);
|
var settings = Provider.of<SettingState>(context, listen: false);
|
||||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||||
value: SystemUiOverlayStyle(
|
value: context.overlay,
|
||||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
|
||||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
|
||||||
systemNavigationBarIconBrightness:
|
|
||||||
Theme.of(context).accentColorBrightness,
|
|
||||||
),
|
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(s.settingsSyncing),
|
title: Text(s.settingsSyncing),
|
||||||
|
|
|
@ -13,18 +13,14 @@ class ThemeSetting extends StatelessWidget {
|
||||||
final s = context.s;
|
final s = context.s;
|
||||||
var settings = Provider.of<SettingState>(context, listen: false);
|
var settings = Provider.of<SettingState>(context, listen: false);
|
||||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||||
value: SystemUiOverlayStyle(
|
value: context.overlay,
|
||||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
|
||||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
|
||||||
systemNavigationBarIconBrightness:
|
|
||||||
Theme.of(context).accentColorBrightness,
|
|
||||||
),
|
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
|
backgroundColor: context.onPrimary,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(s.settingsAppearance),
|
title: Text(s.settingsAppearance),
|
||||||
leading: CustomBackButton(),
|
leading: CustomBackButton(),
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
backgroundColor: Theme.of(context).primaryColor,
|
backgroundColor: context.onPrimary,
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
@ -37,18 +33,20 @@ class ThemeSetting extends StatelessWidget {
|
||||||
height: 30.0,
|
height: 30.0,
|
||||||
padding: EdgeInsets.symmetric(horizontal: 70),
|
padding: EdgeInsets.symmetric(horizontal: 70),
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: Text(s.settingsInterface,
|
child: Text(
|
||||||
|
s.settingsInterface,
|
||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodyText1!
|
.bodyText1!
|
||||||
.copyWith(color: Theme.of(context).accentColor)),
|
.copyWith(color: context.accentColor),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
onTap: () => showGeneralDialog(
|
onTap: () => showGeneralDialog(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
barrierLabel: MaterialLocalizations.of(context)
|
barrierLabel:
|
||||||
.modalBarrierDismissLabel,
|
MaterialLocalizations.of(context).modalBarrierDismissLabel,
|
||||||
barrierColor: Colors.black54,
|
barrierColor: Colors.black54,
|
||||||
transitionDuration: const Duration(milliseconds: 200),
|
transitionDuration: const Duration(milliseconds: 200),
|
||||||
pageBuilder: (context, animaiton, secondaryAnimation) =>
|
pageBuilder: (context, animaiton, secondaryAnimation) =>
|
||||||
|
@ -68,8 +66,7 @@ class ThemeSetting extends StatelessWidget {
|
||||||
),
|
),
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius:
|
borderRadius: BorderRadius.all(Radius.circular(10.0))),
|
||||||
BorderRadius.all(Radius.circular(10.0))),
|
|
||||||
title: Text(s.settingsTheme),
|
title: Text(s.settingsTheme),
|
||||||
content: SingleChildScrollView(
|
content: SingleChildScrollView(
|
||||||
scrollDirection: Axis.vertical,
|
scrollDirection: Axis.vertical,
|
||||||
|
@ -78,8 +75,7 @@ class ThemeSetting extends StatelessWidget {
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
ClipRRect(
|
ClipRRect(
|
||||||
borderRadius:
|
borderRadius: BorderRadius.all(Radius.circular(5)),
|
||||||
BorderRadius.all(Radius.circular(5)),
|
|
||||||
child: Material(
|
child: Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: RadioListTile(
|
child: RadioListTile(
|
||||||
|
@ -93,8 +89,7 @@ class ThemeSetting extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ClipRRect(
|
ClipRRect(
|
||||||
borderRadius:
|
borderRadius: BorderRadius.all(Radius.circular(5)),
|
||||||
BorderRadius.all(Radius.circular(5)),
|
|
||||||
child: Material(
|
child: Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: RadioListTile(
|
child: RadioListTile(
|
||||||
|
@ -108,8 +103,7 @@ class ThemeSetting extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ClipRRect(
|
ClipRRect(
|
||||||
borderRadius:
|
borderRadius: BorderRadius.all(Radius.circular(5)),
|
||||||
BorderRadius.all(Radius.circular(5)),
|
|
||||||
child: Material(
|
child: Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: RadioListTile(
|
child: RadioListTile(
|
||||||
|
@ -126,7 +120,8 @@ class ThemeSetting extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
contentPadding: EdgeInsets.symmetric(horizontal: 70.0),
|
contentPadding: EdgeInsets.symmetric(horizontal: 70.0),
|
||||||
// leading: Icon(Icons.colorize),
|
// leading: Icon(Icons.colorize),
|
||||||
title: Text(s.settingsTheme),
|
title: Text(s.settingsTheme),
|
||||||
|
@ -324,7 +319,8 @@ class __ColorPickerState extends State<_ColorPicker>
|
||||||
key: UniqueKey(),
|
key: UniqueKey(),
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
children: Colors.primaries
|
children: Colors.primaries
|
||||||
.map<Widget>((color) => ScrollConfiguration(
|
.map<Widget>(
|
||||||
|
(color) => ScrollConfiguration(
|
||||||
behavior: NoGrowBehavior(),
|
behavior: NoGrowBehavior(),
|
||||||
child: GridView.count(
|
child: GridView.count(
|
||||||
primary: false,
|
primary: false,
|
||||||
|
@ -351,8 +347,7 @@ class __ColorPickerState extends State<_ColorPicker>
|
||||||
: color == Colors.orange
|
: color == Colors.orange
|
||||||
? _accentList(Colors.orangeAccent)
|
? _accentList(Colors.orangeAccent)
|
||||||
: color == Colors.amber
|
: color == Colors.amber
|
||||||
? _accentList(
|
? _accentList(Colors.amberAccent)
|
||||||
Colors.amberAccent)
|
|
||||||
: color == Colors.yellow
|
: color == Colors.yellow
|
||||||
? _accentList(
|
? _accentList(
|
||||||
Colors.yellowAccent)
|
Colors.yellowAccent)
|
||||||
|
@ -360,8 +355,7 @@ class __ColorPickerState extends State<_ColorPicker>
|
||||||
? _accentList(
|
? _accentList(
|
||||||
Colors.limeAccent)
|
Colors.limeAccent)
|
||||||
: color ==
|
: color ==
|
||||||
Colors
|
Colors.lightGreen
|
||||||
.lightGreen
|
|
||||||
? _accentList(Colors
|
? _accentList(Colors
|
||||||
.lightGreenAccent)
|
.lightGreenAccent)
|
||||||
: color ==
|
: color ==
|
||||||
|
@ -377,7 +371,8 @@ class __ColorPickerState extends State<_ColorPicker>
|
||||||
: color ==
|
: color ==
|
||||||
Colors
|
Colors
|
||||||
.cyan
|
.cyan
|
||||||
? _accentList(Colors
|
? _accentList(
|
||||||
|
Colors
|
||||||
.cyanAccent)
|
.cyanAccent)
|
||||||
: color ==
|
: color ==
|
||||||
Colors.lightBlue
|
Colors.lightBlue
|
||||||
|
@ -393,7 +388,8 @@ class __ColorPickerState extends State<_ColorPicker>
|
||||||
: []
|
: []
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
))
|
),
|
||||||
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -150,6 +150,7 @@ class SettingState extends ChangeNotifier {
|
||||||
color: Colors.grey[100],
|
color: Colors.grey[100],
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
titleTextStyle: TextStyle(color: Colors.black),
|
titleTextStyle: TextStyle(color: Colors.black),
|
||||||
|
scrolledUnderElevation: 1,
|
||||||
iconTheme: IconThemeData(color: Colors.black),
|
iconTheme: IconThemeData(color: Colors.black),
|
||||||
systemOverlayStyle: SystemUiOverlayStyle.dark),
|
systemOverlayStyle: SystemUiOverlayStyle.dark),
|
||||||
textTheme: TextTheme(
|
textTheme: TextTheme(
|
||||||
|
@ -259,6 +260,7 @@ class SettingState extends ChangeNotifier {
|
||||||
appBarTheme: AppBarTheme(
|
appBarTheme: AppBarTheme(
|
||||||
color: Colors.grey[900],
|
color: Colors.grey[900],
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
|
scrolledUnderElevation: 0,
|
||||||
systemOverlayStyle: SystemUiOverlayStyle.light),
|
systemOverlayStyle: SystemUiOverlayStyle.light),
|
||||||
buttonTheme: ButtonThemeData(height: 32),
|
buttonTheme: ButtonThemeData(height: 32),
|
||||||
dialogBackgroundColor: _realDark! ? Colors.grey[900] : null,
|
dialogBackgroundColor: _realDark! ? Colors.grey[900] : null,
|
||||||
|
|
|
@ -80,6 +80,14 @@ class EpisodeBrief extends Equatable {
|
||||||
: primaryColor!.colorizeLight();
|
: primaryColor!.colorizeLight();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Color cardColor(BuildContext context) {
|
||||||
|
final schema = ColorScheme.fromSeed(
|
||||||
|
seedColor: primaryColor!.colorizedark(),
|
||||||
|
brightness: context.brightness,
|
||||||
|
);
|
||||||
|
return schema.primaryContainer;
|
||||||
|
}
|
||||||
|
|
||||||
EpisodeBrief copyWith({
|
EpisodeBrief copyWith({
|
||||||
String? mediaId,
|
String? mediaId,
|
||||||
}) =>
|
}) =>
|
||||||
|
|
|
@ -42,12 +42,13 @@ class PodcastLocal extends Equatable {
|
||||||
this.description = '',
|
this.description = '',
|
||||||
this.updateCount = 0,
|
this.updateCount = 0,
|
||||||
this.episodeCount = 0,
|
this.episodeCount = 0,
|
||||||
}) : assert(rssUrl != null);
|
});
|
||||||
|
|
||||||
ImageProvider get avatarImage {
|
ImageProvider get avatarImage {
|
||||||
return (File(imagePath!).existsSync()
|
return (File(imagePath!).existsSync()
|
||||||
? FileImage(File(imagePath!))
|
? FileImage(File(imagePath!))
|
||||||
: const AssetImage('assets/avatar_backup.png')) as ImageProvider<Object>;
|
: const AssetImage('assets/avatar_backup.png'))
|
||||||
|
as ImageProvider<Object>;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color backgroudColor(BuildContext context) {
|
Color backgroudColor(BuildContext context) {
|
||||||
|
@ -56,9 +57,26 @@ class PodcastLocal extends Equatable {
|
||||||
: primaryColor!.colorizeLight();
|
: primaryColor!.colorizeLight();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Color cardColor(BuildContext context) {
|
||||||
|
final schema = ColorScheme.fromSeed(
|
||||||
|
seedColor: primaryColor!.colorizedark(),
|
||||||
|
brightness: context.brightness,
|
||||||
|
);
|
||||||
|
return schema.primaryContainer;
|
||||||
|
}
|
||||||
|
|
||||||
PodcastLocal copyWith({int? updateCount, int? episodeCount}) {
|
PodcastLocal copyWith({int? updateCount, int? episodeCount}) {
|
||||||
return PodcastLocal(title, imageUrl, rssUrl, primaryColor, author, id,
|
return PodcastLocal(
|
||||||
imagePath, provider, link, funding,
|
title,
|
||||||
|
imageUrl,
|
||||||
|
rssUrl,
|
||||||
|
primaryColor,
|
||||||
|
author,
|
||||||
|
id,
|
||||||
|
imagePath,
|
||||||
|
provider,
|
||||||
|
link,
|
||||||
|
funding,
|
||||||
description: description,
|
description: description,
|
||||||
updateCount: updateCount ?? 0,
|
updateCount: updateCount ?? 0,
|
||||||
episodeCount: episodeCount ?? 0,
|
episodeCount: episodeCount ?? 0,
|
||||||
|
|
|
@ -2,8 +2,8 @@ import 'dart:convert';
|
||||||
import 'dart:developer' as developer;
|
import 'dart:developer' as developer;
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
import 'package:material_color_utilities/material_color_utilities.dart';
|
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:url_launcher/url_launcher_string.dart';
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
import '../generated/l10n.dart';
|
import '../generated/l10n.dart';
|
||||||
|
@ -16,6 +16,7 @@ extension ContextExtension on BuildContext {
|
||||||
Color get onPrimary => Theme.of(this).colorScheme.onPrimary;
|
Color get onPrimary => Theme.of(this).colorScheme.onPrimary;
|
||||||
Color get background => Theme.of(this).colorScheme.background;
|
Color get background => Theme.of(this).colorScheme.background;
|
||||||
Color get tertiary => colorScheme.tertiary;
|
Color get tertiary => colorScheme.tertiary;
|
||||||
|
Color get tertiaryContainer => colorScheme.tertiaryContainer;
|
||||||
Color get onTertiary => colorScheme.onTertiary;
|
Color get onTertiary => colorScheme.onTertiary;
|
||||||
Color get secondary => colorScheme.secondary;
|
Color get secondary => colorScheme.secondary;
|
||||||
Color get onsecondary => colorScheme.onSecondary;
|
Color get onsecondary => colorScheme.onSecondary;
|
||||||
|
@ -30,6 +31,12 @@ extension ContextExtension on BuildContext {
|
||||||
double get height => MediaQuery.of(this).size.height;
|
double get height => MediaQuery.of(this).size.height;
|
||||||
double get paddingTop => MediaQuery.of(this).padding.top;
|
double get paddingTop => MediaQuery.of(this).padding.top;
|
||||||
TextTheme get textTheme => Theme.of(this).textTheme;
|
TextTheme get textTheme => Theme.of(this).textTheme;
|
||||||
|
SystemUiOverlayStyle get overlay => SystemUiOverlayStyle(
|
||||||
|
statusBarColor: onPrimary,
|
||||||
|
statusBarIconBrightness: iconBrightness,
|
||||||
|
systemNavigationBarColor: onPrimary,
|
||||||
|
systemNavigationBarIconBrightness: iconBrightness,
|
||||||
|
);
|
||||||
S get s => S.of(this)!;
|
S get s => S.of(this)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,17 +36,15 @@ Widget featureDiscoveryOverlay(BuildContext context,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(description),
|
Text(description),
|
||||||
FlatButton(
|
TextButton(
|
||||||
color: buttonColor,
|
style: TextButton.styleFrom(primary: buttonColor),
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
child: Text(s.understood,
|
child: Text(s.understood,
|
||||||
style: context.textTheme.button!.copyWith(color: Colors.white)),
|
style: context.textTheme.button!.copyWith(color: Colors.white)),
|
||||||
onPressed: () async =>
|
onPressed: () async =>
|
||||||
FeatureDiscovery.completeCurrentStep(context),
|
FeatureDiscovery.completeCurrentStep(context),
|
||||||
),
|
),
|
||||||
FlatButton(
|
TextButton(
|
||||||
color: buttonColor,
|
style: TextButton.styleFrom(primary: buttonColor),
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
child: Text(s.dismiss,
|
child: Text(s.dismiss,
|
||||||
style: context.textTheme.button!.copyWith(color: Colors.white)),
|
style: context.textTheme.button!.copyWith(color: Colors.white)),
|
||||||
onPressed: () => FeatureDiscovery.dismissAll(context),
|
onPressed: () => FeatureDiscovery.dismissAll(context),
|
||||||
|
|
10
pubspec.yaml
10
pubspec.yaml
|
@ -4,7 +4,7 @@ description: An open source podcast player.
|
||||||
version: 0.6.0+48
|
version: 0.6.0+48
|
||||||
publish_to: "none"
|
publish_to: "none"
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.12.0 <3.0.0'
|
sdk: ">=2.12.0 <3.0.0"
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
|
@ -55,13 +55,13 @@ dependencies:
|
||||||
just_audio: ^0.9.23
|
just_audio: ^0.9.23
|
||||||
flutter_downloader:
|
flutter_downloader:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/stonega/flutter_downloader.git
|
url: https://github.com/tsacdop/flutter_downloader.git
|
||||||
focused_menu:
|
focused_menu:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/stonega/focused_menu.git
|
url: https://github.com/tsacdop/focused_menu.git
|
||||||
webfeed:
|
webfeed:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/stonega/webfeed.git
|
url: https://github.com/tsacdop/webfeed.git
|
||||||
equatable: ^2.0.0
|
equatable: ^2.0.0
|
||||||
path_provider: ^2.0.1
|
path_provider: ^2.0.1
|
||||||
http_parser: ^4.0.0
|
http_parser: ^4.0.0
|
||||||
|
@ -74,7 +74,7 @@ dependencies:
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
linkify:
|
linkify:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/stonega/linkify.git
|
url: https://github.com/tsacdop/linkify.git
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
Loading…
Reference in New Issue