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>();
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarColor: context.priamryContainer,
|
||||
systemNavigationBarColor: context.priamryContainer,
|
||||
statusBarColor: widget.episodeItem!.cardColor(context),
|
||||
systemNavigationBarColor: widget.episodeItem!.cardColor(context),
|
||||
systemNavigationBarContrastEnforced: false,
|
||||
systemNavigationBarIconBrightness: context.iconBrightness,
|
||||
statusBarBrightness: context.brightness,
|
||||
|
@ -104,7 +104,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
|||
}
|
||||
},
|
||||
child: Scaffold(
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
backgroundColor: context.onPrimary,
|
||||
body: SafeArea(
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
|
@ -116,7 +116,8 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
|||
headerSliverBuilder: (context, innerBoxScrolled) {
|
||||
return <Widget>[
|
||||
SliverAppBar(
|
||||
backgroundColor: context.priamryContainer,
|
||||
backgroundColor:
|
||||
widget.episodeItem!.cardColor(context),
|
||||
floating: true,
|
||||
pinned: true,
|
||||
title: _showTitle
|
||||
|
@ -296,8 +297,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
|||
final height = kMinPlayerHeight[data.item2!.index];
|
||||
return Container(
|
||||
alignment: Alignment.bottomCenter,
|
||||
padding:
|
||||
EdgeInsets.only(bottom: data.item1 ? height : 0),
|
||||
padding: EdgeInsets.only(bottom: data.item1 ? height : 0),
|
||||
child: AnimatedContainer(
|
||||
duration: Duration(milliseconds: 400),
|
||||
height: _showMenu ? 50 : 0,
|
||||
|
@ -310,13 +310,16 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
|||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
},
|
||||
),
|
||||
Selector<AudioPlayerNotifier, EpisodeBrief?>(
|
||||
selector: (_, audio) => audio.episode,
|
||||
builder: (_, data, __) => Container(
|
||||
child: PlayerWidget(
|
||||
playerKey: _playerKey,
|
||||
isPlayingPage: data == widget.episodeItem))),
|
||||
isPlayingPage: data == widget.episodeItem),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -28,7 +28,7 @@ class MenuBarState extends State<MenuBar> {
|
|||
return Container(
|
||||
height: 50.0,
|
||||
decoration: BoxDecoration(
|
||||
color: context.priamryContainer,
|
||||
color: widget.episodeItem!.cardColor(context),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
|
@ -48,7 +48,6 @@ class MenuBarState extends State<MenuBar> {
|
|||
child: Container(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
color: context.priamryContainer,
|
||||
child: widget.hide!
|
||||
? Center()
|
||||
: CircleAvatar(
|
||||
|
|
|
@ -7,100 +7,12 @@ import '../widgets/custom_widget.dart';
|
|||
|
||||
const String version = '0.6.0';
|
||||
|
||||
class AboutApp extends StatefulWidget {
|
||||
@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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
class AboutApp extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
OverlayEntry _createOverlayEntry(TapDownDetails detail) {
|
||||
// RenderBox renderBox = context.findRenderObject();
|
||||
var offset = detail.globalPosition;
|
||||
final offset = detail.globalPosition;
|
||||
return OverlayEntry(
|
||||
builder: (constext) => Positioned(
|
||||
left: offset.dx - 5,
|
||||
|
@ -118,23 +30,21 @@ class _AboutAppState extends State<AboutApp> {
|
|||
final s = context.s;
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
||||
systemNavigationBarIconBrightness:
|
||||
Theme.of(context).accentColorBrightness,
|
||||
statusBarColor: context.onPrimary,
|
||||
statusBarIconBrightness: context.iconBrightness,
|
||||
systemNavigationBarColor: context.onPrimary,
|
||||
systemNavigationBarIconBrightness: context.iconBrightness,
|
||||
),
|
||||
child: SafeArea(
|
||||
child: Scaffold(
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
backgroundColor: context.onPrimary,
|
||||
appBar: AppBar(
|
||||
backgroundColor: context.onPrimary,
|
||||
title: Text(s.homeToprightMenuAbout),
|
||||
scrolledUnderElevation: 1,
|
||||
leading: CustomBackButton(),
|
||||
elevation: _scroll ? 1 : 0,
|
||||
),
|
||||
body: SafeArea(
|
||||
child: ScrollConfiguration(
|
||||
behavior: NoGrowBehavior(),
|
||||
child: SingleChildScrollView(
|
||||
controller: _scrollController,
|
||||
body: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
|
@ -170,12 +80,10 @@ class _AboutAppState extends State<AboutApp> {
|
|||
children: [
|
||||
TextButton(
|
||||
onPressed: () =>
|
||||
'https://tsacdop.stonegate.me/#/privacy'
|
||||
.launchUrl,
|
||||
'https://tsacdop.stonegate.me/#/privacy'.launchUrl,
|
||||
style: TextButton.styleFrom(
|
||||
primary: context.accentColor,
|
||||
textStyle:
|
||||
TextStyle(fontWeight: FontWeight.bold)),
|
||||
textStyle: TextStyle(fontWeight: FontWeight.bold)),
|
||||
child: Text(
|
||||
s.privacyPolicy,
|
||||
),
|
||||
|
@ -185,8 +93,7 @@ class _AboutAppState extends State<AboutApp> {
|
|||
height: 4,
|
||||
width: 4,
|
||||
decoration: BoxDecoration(
|
||||
color: context.accentColor,
|
||||
shape: BoxShape.circle),
|
||||
color: context.accentColor, shape: BoxShape.circle),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () =>
|
||||
|
@ -194,8 +101,7 @@ class _AboutAppState extends State<AboutApp> {
|
|||
.launchUrl,
|
||||
style: TextButton.styleFrom(
|
||||
primary: context.accentColor,
|
||||
textStyle:
|
||||
TextStyle(fontWeight: FontWeight.bold)),
|
||||
textStyle: TextStyle(fontWeight: FontWeight.bold)),
|
||||
child: Text(s.changelog,
|
||||
style: TextStyle(color: context.accentColor)),
|
||||
),
|
||||
|
@ -209,10 +115,7 @@ class _AboutAppState extends State<AboutApp> {
|
|||
children: <Widget>[
|
||||
_listItem(context, 'Twitter @tsacdop',
|
||||
LineIcons.twitter, 'https://twitter.com/tsacdop'),
|
||||
_listItem(
|
||||
context,
|
||||
'GitHub',
|
||||
LineIcons.alternateGithub,
|
||||
_listItem(context, 'GitHub', LineIcons.alternateGithub,
|
||||
'https://github.com/stonega/tsacdop'),
|
||||
_listItem(context, 'Telegram', LineIcons.telegram,
|
||||
'https://t.me/joinchat/Bk3LkRpTHy40QYC78PK7Qg'),
|
||||
|
@ -226,23 +129,29 @@ class _AboutAppState extends State<AboutApp> {
|
|||
'https://www.buymeacoffee.com/stonegate'
|
||||
.launchUrl,
|
||||
style: ElevatedButton.styleFrom(
|
||||
primary: context.accentColor),
|
||||
primary: Color(0xffffdd00),
|
||||
elevation: 0,
|
||||
enableFeedback: false,
|
||||
),
|
||||
child: Container(
|
||||
height: 30.0,
|
||||
padding:
|
||||
EdgeInsets.symmetric(horizontal: 4.0),
|
||||
padding: EdgeInsets.symmetric(horizontal: 4.0),
|
||||
alignment: Alignment.center,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Text('Buy Me A Coffee',
|
||||
Text(
|
||||
'Buy Me A Coffee',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold)),
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Image(
|
||||
image: AssetImage(
|
||||
'assets/buymeacoffee.png'),
|
||||
image:
|
||||
AssetImage('assets/buymeacoffee.png'),
|
||||
height: 20,
|
||||
fit: BoxFit.fitHeight,
|
||||
),
|
||||
|
@ -270,7 +179,7 @@ class _AboutAppState extends State<AboutApp> {
|
|||
Text(
|
||||
s.translators,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
color: context.accentColor,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
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>[
|
||||
SafeArea(
|
||||
bottom: false,
|
||||
child: StretchingOverscrollIndicator(
|
||||
axisDirection: AxisDirection.down,
|
||||
child: NestedScrollView(
|
||||
innerScrollPositionKeyBuilder: () {
|
||||
return Key('tab${_controller!.index}');
|
||||
|
@ -175,7 +173,8 @@ class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
|
|||
textStyle: TextStyle(fontSize: 25)),
|
||||
),
|
||||
),
|
||||
featureDiscoveryOverlay(context,
|
||||
featureDiscoveryOverlay(
|
||||
context,
|
||||
featureId: menuFeature,
|
||||
tapTarget: Icon(Icons.more_vert),
|
||||
backgroundColor: Colors.cyan[500],
|
||||
|
@ -186,7 +185,8 @@ class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
|
|||
padding:
|
||||
const EdgeInsets.only(right: 5.0),
|
||||
child: PopupMenu(),
|
||||
)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -232,11 +232,17 @@ class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
|
|||
controller: _controller,
|
||||
children: <Widget>[
|
||||
NestedScrollViewInnerScrollPositionKeyWidget(
|
||||
Key('tab0'), _RecentUpdate()),
|
||||
Key('tab0'),
|
||||
_RecentUpdate(),
|
||||
),
|
||||
NestedScrollViewInnerScrollPositionKeyWidget(
|
||||
Key('tab1'), _MyFavorite()),
|
||||
Key('tab1'),
|
||||
_MyFavorite(),
|
||||
),
|
||||
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))),
|
||||
elevation: 1,
|
||||
icon: Icon(Icons.playlist_play),
|
||||
color: context.priamryContainer,
|
||||
tooltip: s.menu,
|
||||
itemBuilder: (context) => [
|
||||
MyPopupMenuItem(
|
||||
|
@ -1249,8 +1257,7 @@ class _MyDownloadState extends State<_MyDownload>
|
|||
),
|
||||
),
|
||||
onPressed: () {
|
||||
setState(
|
||||
() => _hideListened = !_hideListened!);
|
||||
setState(() => _hideListened = !_hideListened!);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
@ -1276,8 +1283,7 @@ class _MyDownloadState extends State<_MyDownload>
|
|||
Icon(LineIcons.download,
|
||||
size: 80, color: Colors.grey[500]),
|
||||
Padding(
|
||||
padding:
|
||||
EdgeInsets.symmetric(vertical: 10)),
|
||||
padding: EdgeInsets.symmetric(vertical: 10)),
|
||||
Text(
|
||||
s.noEpisodeDownload,
|
||||
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 {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
setState(
|
||||
() {
|
||||
(_groupIndex < groups.length - 1)
|
||||
? _groupIndex++
|
||||
: _groupIndex = 0;
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -134,13 +136,13 @@ class _ScrollPodcastsState extends State<ScrollPodcasts>
|
|||
child: Row(
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding:
|
||||
EdgeInsets.symmetric(horizontal: 15.0),
|
||||
padding: EdgeInsets.symmetric(horizontal: 15.0),
|
||||
child: Text(
|
||||
groups[_groupIndex]!.name!,
|
||||
style: context.textTheme.bodyText1!
|
||||
.copyWith(color: context.accentColor),
|
||||
)),
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 15),
|
||||
|
@ -154,7 +156,8 @@ class _ScrollPodcastsState extends State<ScrollPodcasts>
|
|||
.read<SettingState>()
|
||||
.openAllPodcastDefalt!
|
||||
? PodcastList()
|
||||
: PodcastManage()),
|
||||
: PodcastManage(),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
|
@ -443,12 +446,14 @@ class _ScrollPodcastsState extends State<ScrollPodcasts>
|
|||
width: 10,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.red,
|
||||
border: Border.all(color: context.primaryColor, width: 2),
|
||||
border:
|
||||
Border.all(color: context.primaryColor, width: 2),
|
||||
shape: BoxShape.circle),
|
||||
),
|
||||
)
|
||||
: Center();
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
class PodcastPreview extends StatefulWidget {
|
||||
|
@ -463,12 +468,6 @@ class PodcastPreview extends StatefulWidget {
|
|||
class _PodcastPreviewState extends State<PodcastPreview> {
|
||||
Future? _getRssItem;
|
||||
|
||||
Future<List<EpisodeBrief>> _getRssItemTop(PodcastLocal podcastLocal) async {
|
||||
final dbHelper = DBHelper();
|
||||
final episodes = await dbHelper.getRssItemTop(podcastLocal.id);
|
||||
return episodes;
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
@ -510,10 +509,12 @@ class _PodcastPreviewState extends State<PodcastPreview> {
|
|||
children: <Widget>[
|
||||
Expanded(
|
||||
flex: 4,
|
||||
child: Text(widget.podcastLocal!.title!,
|
||||
child: Text(
|
||||
widget.podcastLocal!.title!,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(fontWeight: FontWeight.bold, color: c)),
|
||||
style: TextStyle(fontWeight: FontWeight.bold, color: c),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
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 {
|
||||
|
@ -539,121 +546,6 @@ class ShowEpisode extends StatelessWidget {
|
|||
final DBHelper _dbHelper = DBHelper();
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
final width = context.width;
|
||||
|
@ -669,7 +561,7 @@ class ShowEpisode extends StatelessWidget {
|
|||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
childAspectRatio: 1.5,
|
||||
crossAxisCount: 2,
|
||||
mainAxisSpacing: 6.0,
|
||||
mainAxisSpacing: 8.0,
|
||||
crossAxisSpacing: 6.0,
|
||||
),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
|
@ -691,19 +583,17 @@ class ShowEpisode extends StatelessWidget {
|
|||
final isDownloaded = snapshot.data!.item3;
|
||||
final tapToOpen = snapshot.data!.item4;
|
||||
final menuList = snapshot.data!.item5;
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(5.0),
|
||||
color: context.background,
|
||||
),
|
||||
return Align(
|
||||
alignment: Alignment.center,
|
||||
child: FocusedMenuHolder(
|
||||
blurSize: 0.0,
|
||||
menuItemExtent: 45,
|
||||
menuBoxDecoration: BoxDecoration(
|
||||
color: Colors.transparent,
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(15.0))),
|
||||
color: context.priamryContainer,
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(15.0),
|
||||
),
|
||||
),
|
||||
duration: Duration(milliseconds: 100),
|
||||
tapMode:
|
||||
tapToOpen ? TapMode.onTap : TapMode.onLongPress,
|
||||
|
@ -716,10 +606,7 @@ class ShowEpisode extends StatelessWidget {
|
|||
menuOffset: 6,
|
||||
menuItems: <FocusedMenuItem>[
|
||||
FocusedMenuItem(
|
||||
backgroundColor:
|
||||
context.brightness == Brightness.light
|
||||
? context.primaryColor
|
||||
: context.dialogBackgroundColor,
|
||||
backgroundColor: context.priamryContainer,
|
||||
title: Text(data.item1 != episodes![index] ||
|
||||
!data.item3
|
||||
? s.play
|
||||
|
@ -736,10 +623,7 @@ class ShowEpisode extends StatelessWidget {
|
|||
}),
|
||||
if (menuList.contains(1))
|
||||
FocusedMenuItem(
|
||||
backgroundColor:
|
||||
context.brightness == Brightness.light
|
||||
? context.primaryColor
|
||||
: context.dialogBackgroundColor,
|
||||
backgroundColor: context.priamryContainer,
|
||||
title: data.item2.contains(
|
||||
episodes![index].enclosureUrl)
|
||||
? Text(s.remove)
|
||||
|
@ -766,10 +650,7 @@ class ShowEpisode extends StatelessWidget {
|
|||
}),
|
||||
if (menuList.contains(2))
|
||||
FocusedMenuItem(
|
||||
backgroundColor:
|
||||
context.brightness == Brightness.light
|
||||
? context.primaryColor
|
||||
: context.dialogBackgroundColor,
|
||||
backgroundColor: context.priamryContainer,
|
||||
title:
|
||||
isLiked ? Text(s.unlike) : Text(s.like),
|
||||
trailingIcon: Icon(LineIcons.heart,
|
||||
|
@ -795,10 +676,7 @@ class ShowEpisode extends StatelessWidget {
|
|||
}),
|
||||
if (menuList.contains(3))
|
||||
FocusedMenuItem(
|
||||
backgroundColor:
|
||||
context.brightness == Brightness.light
|
||||
? context.primaryColor
|
||||
: context.dialogBackgroundColor,
|
||||
backgroundColor: context.priamryContainer,
|
||||
title: isListened > 0
|
||||
? Text(s.listened,
|
||||
style: TextStyle(
|
||||
|
@ -828,10 +706,7 @@ class ShowEpisode extends StatelessWidget {
|
|||
}),
|
||||
if (menuList.contains(4))
|
||||
FocusedMenuItem(
|
||||
backgroundColor:
|
||||
context.brightness == Brightness.light
|
||||
? context.primaryColor
|
||||
: context.dialogBackgroundColor,
|
||||
backgroundColor: context.priamryContainer,
|
||||
title: isDownloaded
|
||||
? Text(s.downloaded,
|
||||
style: TextStyle(
|
||||
|
@ -850,10 +725,7 @@ class ShowEpisode extends StatelessWidget {
|
|||
}),
|
||||
if (menuList.contains(5))
|
||||
FocusedMenuItem(
|
||||
backgroundColor:
|
||||
context.brightness == Brightness.light
|
||||
? context.primaryColor
|
||||
: context.dialogBackgroundColor,
|
||||
backgroundColor: context.priamryContainer,
|
||||
title: Text(s.playNext),
|
||||
trailingIcon: Icon(
|
||||
LineIcons.lightningBolt,
|
||||
|
@ -865,7 +737,8 @@ class ShowEpisode extends StatelessWidget {
|
|||
msg: s.playNextDes,
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}),
|
||||
},
|
||||
),
|
||||
],
|
||||
onPressed: () => Navigator.push(
|
||||
context,
|
||||
|
@ -878,6 +751,10 @@ class ShowEpisode extends StatelessWidget {
|
|||
),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
decoration: BoxDecoration(
|
||||
color: podcastLocal!.cardColor(context),
|
||||
borderRadius: BorderRadius.circular(15.0),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
|
@ -999,18 +876,18 @@ class ShowEpisode extends StatelessWidget {
|
|||
),
|
||||
if (episodes![index].enclosureLength !=
|
||||
null &&
|
||||
episodes![index].enclosureLength !=
|
||||
0)
|
||||
episodes![index].enclosureLength != 0)
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
'${episodes![index].enclosureLength! ~/ 1000000}MB',
|
||||
style: TextStyle(
|
||||
fontSize: width / 35),
|
||||
style:
|
||||
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
|
||||
|
|
|
@ -673,10 +673,10 @@ class _PodcastDetailState extends State<PodcastDetail> {
|
|||
final s = context.s;
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarColor: color,
|
||||
statusBarIconBrightness: Brightness.dark,
|
||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
||||
systemNavigationBarIconBrightness:
|
||||
Theme.of(context).accentColorBrightness,
|
||||
systemNavigationBarColor: context.primaryColor,
|
||||
systemNavigationBarIconBrightness: context.iconBrightness,
|
||||
),
|
||||
child: WillPopScope(
|
||||
onWillPop: () {
|
||||
|
|
|
@ -33,18 +33,233 @@ class DataBackup extends StatefulWidget {
|
|||
|
||||
class _DataBackupState extends State<DataBackup> {
|
||||
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 {
|
||||
var groups = context.read<GroupList>().groups;
|
||||
var opml = PodcastsBackup(groups).omplBuilder();
|
||||
var tempdir = await getTemporaryDirectory();
|
||||
var now = DateTime.now();
|
||||
var datePlus = now.year.toString() +
|
||||
final groups = context.read<GroupList>().groups;
|
||||
final opml = PodcastsBackup(groups).omplBuilder();
|
||||
final tempdir = await getTemporaryDirectory();
|
||||
final now = DateTime.now();
|
||||
final datePlus = now.year.toString() +
|
||||
now.month.toString() +
|
||||
now.day.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());
|
||||
return file;
|
||||
}
|
||||
|
@ -147,27 +362,6 @@ class _DataBackupState extends State<DataBackup> {
|
|||
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 {
|
||||
var dateTimeStorage = KeyValueStorage(gpodderSyncDateTimeKey);
|
||||
var statusStorage = KeyValueStorage(gpodderSyncStatusKey);
|
||||
|
@ -175,353 +369,6 @@ class _DataBackupState extends State<DataBackup> {
|
|||
final statusIndex = await statusStorage.getInt();
|
||||
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 {
|
||||
|
@ -710,7 +557,6 @@ class __LoginGpodderState extends State<_LoginGpodder> {
|
|||
context.s.settingsSyncing,
|
||||
style: TextStyle(color: Colors.white),
|
||||
);
|
||||
break;
|
||||
case LoginStatus.start:
|
||||
return SizedBox(
|
||||
height: 20,
|
||||
|
@ -725,7 +571,6 @@ class __LoginGpodderState extends State<_LoginGpodder> {
|
|||
context.s.login,
|
||||
style: TextStyle(color: Colors.white),
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,86 +25,6 @@ class PlayedHistory extends StatefulWidget {
|
|||
|
||||
class _PlayedHistoryState extends State<PlayedHistory>
|
||||
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
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
@ -122,13 +42,9 @@ class _PlayedHistoryState extends State<PlayedHistory>
|
|||
Widget build(BuildContext context) {
|
||||
final s = context.s;
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarIconBrightness: context.brightness,
|
||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
||||
systemNavigationBarIconBrightness: context.iconBrightness,
|
||||
),
|
||||
value: context.overlay,
|
||||
child: Scaffold(
|
||||
backgroundColor: context.primaryColor,
|
||||
backgroundColor: context.onPrimary,
|
||||
body: SafeArea(
|
||||
child: NestedScrollView(
|
||||
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 {
|
||||
|
|
|
@ -21,6 +21,246 @@ class LayoutSetting extends StatefulWidget {
|
|||
}
|
||||
|
||||
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);
|
||||
Future<Layout> _getLayout(String key) async {
|
||||
final keyValueStorage = KeyValueStorage(key);
|
||||
|
@ -38,8 +278,8 @@ class _LayoutSettingState extends State<LayoutSetting> {
|
|||
}
|
||||
|
||||
Future<bool> _hideListened() async {
|
||||
var hideListenedStorage = KeyValueStorage(hideListenedKey);
|
||||
var hideListened = await hideListenedStorage.getBool(defaultValue: false);
|
||||
final hideListenedStorage = KeyValueStorage(hideListenedKey);
|
||||
final hideListened = await hideListenedStorage.getBool(defaultValue: false);
|
||||
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/services.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import '../util/extension_helper.dart';
|
||||
import '../widgets/custom_widget.dart';
|
||||
import 'licenses.dart';
|
||||
|
||||
class Libries extends StatelessWidget {
|
||||
_launchUrl(String url) async {
|
||||
if (await canLaunch(url)) {
|
||||
await launch(url);
|
||||
} else {
|
||||
throw 'Could not launch $url';
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
||||
systemNavigationBarIconBrightness:
|
||||
Theme.of(context).accentColorBrightness,
|
||||
),
|
||||
value: context.overlay,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(context.s.settingsLibraries),
|
||||
|
@ -50,14 +36,14 @@ class Libries extends StatelessWidget {
|
|||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyText1!
|
||||
.copyWith(color: Theme.of(context).accentColor)),
|
||||
.copyWith(color: context.accentColor)),
|
||||
),
|
||||
Column(
|
||||
children: google.map<Widget>(
|
||||
(e) {
|
||||
return ListTile(
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 80),
|
||||
onTap: () => _launchUrl(e.link),
|
||||
onTap: () => e.link.launchUrl,
|
||||
title: Text(e.name),
|
||||
subtitle: Text(e.license),
|
||||
);
|
||||
|
@ -72,14 +58,14 @@ class Libries extends StatelessWidget {
|
|||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyText1!
|
||||
.copyWith(color: Theme.of(context).accentColor)),
|
||||
.copyWith(color: context.accentColor)),
|
||||
),
|
||||
Column(
|
||||
children: fonts.map<Widget>(
|
||||
(e) {
|
||||
return ListTile(
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 80),
|
||||
onTap: () => _launchUrl(e.link),
|
||||
onTap: () => e.link.launchUrl,
|
||||
title: Text(e.name),
|
||||
subtitle: Text(e.license),
|
||||
);
|
||||
|
@ -94,14 +80,14 @@ class Libries extends StatelessWidget {
|
|||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyText1!
|
||||
.copyWith(color: Theme.of(context).accentColor)),
|
||||
.copyWith(color: context.accentColor)),
|
||||
),
|
||||
Container(
|
||||
child: Column(
|
||||
children: plugins.map<Widget>(
|
||||
(e) {
|
||||
return ListTile(
|
||||
onTap: () => _launchUrl(e.link),
|
||||
onTap: () => e.link.launchUrl,
|
||||
contentPadding:
|
||||
EdgeInsets.symmetric(horizontal: 80),
|
||||
title: Text(e.name),
|
||||
|
|
|
@ -38,198 +38,15 @@ class PlaySetting extends StatefulWidget {
|
|||
}
|
||||
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
var settings = context.watch<SettingState>();
|
||||
var audio = context.watch<AudioPlayerNotifier>();
|
||||
final settings = context.watch<SettingState>();
|
||||
final audio = context.watch<AudioPlayerNotifier>();
|
||||
final s = context.s;
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarIconBrightness: context.brightness,
|
||||
systemNavigationBarColor: context.primaryColor,
|
||||
systemNavigationBarIconBrightness: context.iconBrightness,
|
||||
),
|
||||
value: context.overlay,
|
||||
child: Scaffold(
|
||||
backgroundColor: context.onPrimary,
|
||||
appBar: AppBar(
|
||||
title: Text(s.play),
|
||||
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 {
|
||||
|
|
|
@ -71,20 +71,19 @@ class _SettingsState extends State<Settings> {
|
|||
final s = context.s;
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
||||
systemNavigationBarIconBrightness:
|
||||
Theme.of(context).accentColorBrightness,
|
||||
statusBarIconBrightness: context.brightness,
|
||||
systemNavigationBarColor: context.onPrimary,
|
||||
systemNavigationBarIconBrightness: context.iconBrightness,
|
||||
),
|
||||
child: Scaffold(
|
||||
backgroundColor: context.onPrimary,
|
||||
appBar: AppBar(
|
||||
title: Text(s.settings),
|
||||
leading: CustomBackButton(),
|
||||
elevation: _showTitle ? 1 : 0,
|
||||
backgroundColor: context.primaryColor,
|
||||
backgroundColor: context.onPrimary,
|
||||
),
|
||||
body: SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
body: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
controller: _controller,
|
||||
child: Column(
|
||||
|
@ -142,10 +141,8 @@ class _SettingsState extends State<Settings> {
|
|||
subtitle: Text(s.settingsSyncingDes)),
|
||||
Divider(height: 1),
|
||||
ListTile(
|
||||
onTap: () => Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => StorageSetting())),
|
||||
onTap: () => Navigator.push(context,
|
||||
MaterialPageRoute(builder: (context) => StorageSetting())),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 25.0),
|
||||
leading: Icon(LineIcons.save, color: Colors.green[700]),
|
||||
title: Text(s.settingStorage),
|
||||
|
@ -218,9 +215,7 @@ class _SettingsState extends State<Settings> {
|
|||
'https://github.com/stonega/tsacdop/issues'),
|
||||
_feedbackItem(LineIcons.telegram, s.feedbackTelegram,
|
||||
'https://t.me/joinchat/Bk3LkRpTHy40QYC78PK7Qg'),
|
||||
_feedbackItem(
|
||||
LineIcons.envelopeOpenText,
|
||||
s.feedbackEmail,
|
||||
_feedbackItem(LineIcons.envelopeOpenText, s.feedbackEmail,
|
||||
'mailto:<tsacdop.app@gmail.com>?subject=Tsacdop Feedback'),
|
||||
_feedbackItem(LineIcons.googlePlay, s.feedbackPlay,
|
||||
'https://play.google.com/store/apps/details?id=com.stonegate.tsacdop'),
|
||||
|
@ -261,8 +256,7 @@ class _SettingsState extends State<Settings> {
|
|||
onTap: () => Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
SlideIntro(goto: Goto.settings))),
|
||||
builder: (context) => SlideIntro(goto: Goto.settings))),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 25.0),
|
||||
leading: Icon(LineIcons.columns, color: Colors.blueGrey),
|
||||
title: Text(s.settingsAppIntro),
|
||||
|
@ -275,7 +269,6 @@ class _SettingsState extends State<Settings> {
|
|||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,75 +23,6 @@ class _StorageSettingState extends State<StorageSetting>
|
|||
AnimationController? _controller;
|
||||
late Animation<double> _animation;
|
||||
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;
|
||||
|
||||
|
@ -113,13 +44,9 @@ class _StorageSettingState extends State<StorageSetting>
|
|||
final s = context.s;
|
||||
var settings = Provider.of<SettingState>(context, listen: false);
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
||||
systemNavigationBarIconBrightness:
|
||||
Theme.of(context).accentColorBrightness,
|
||||
),
|
||||
value: context.overlay,
|
||||
child: Scaffold(
|
||||
backgroundColor: context.onPrimary,
|
||||
appBar: AppBar(
|
||||
title: Text(s.settingStorage),
|
||||
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;
|
||||
var settings = Provider.of<SettingState>(context, listen: false);
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
||||
systemNavigationBarIconBrightness:
|
||||
Theme.of(context).accentColorBrightness,
|
||||
),
|
||||
value: context.overlay,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(s.settingsSyncing),
|
||||
|
|
|
@ -13,18 +13,14 @@ class ThemeSetting extends StatelessWidget {
|
|||
final s = context.s;
|
||||
var settings = Provider.of<SettingState>(context, listen: false);
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
||||
systemNavigationBarColor: Theme.of(context).primaryColor,
|
||||
systemNavigationBarIconBrightness:
|
||||
Theme.of(context).accentColorBrightness,
|
||||
),
|
||||
value: context.overlay,
|
||||
child: Scaffold(
|
||||
backgroundColor: context.onPrimary,
|
||||
appBar: AppBar(
|
||||
title: Text(s.settingsAppearance),
|
||||
leading: CustomBackButton(),
|
||||
elevation: 0,
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
backgroundColor: context.onPrimary,
|
||||
),
|
||||
body: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
|
@ -37,18 +33,20 @@ class ThemeSetting extends StatelessWidget {
|
|||
height: 30.0,
|
||||
padding: EdgeInsets.symmetric(horizontal: 70),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(s.settingsInterface,
|
||||
child: Text(
|
||||
s.settingsInterface,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyText1!
|
||||
.copyWith(color: Theme.of(context).accentColor)),
|
||||
.copyWith(color: context.accentColor),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () => showGeneralDialog(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
barrierLabel: MaterialLocalizations.of(context)
|
||||
.modalBarrierDismissLabel,
|
||||
barrierLabel:
|
||||
MaterialLocalizations.of(context).modalBarrierDismissLabel,
|
||||
barrierColor: Colors.black54,
|
||||
transitionDuration: const Duration(milliseconds: 200),
|
||||
pageBuilder: (context, animaiton, secondaryAnimation) =>
|
||||
|
@ -68,8 +66,7 @@ class ThemeSetting extends StatelessWidget {
|
|||
),
|
||||
elevation: 1,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(10.0))),
|
||||
borderRadius: BorderRadius.all(Radius.circular(10.0))),
|
||||
title: Text(s.settingsTheme),
|
||||
content: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
|
@ -78,8 +75,7 @@ class ThemeSetting extends StatelessWidget {
|
|||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
ClipRRect(
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(5)),
|
||||
borderRadius: BorderRadius.all(Radius.circular(5)),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: RadioListTile(
|
||||
|
@ -93,8 +89,7 @@ class ThemeSetting extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
ClipRRect(
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(5)),
|
||||
borderRadius: BorderRadius.all(Radius.circular(5)),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: RadioListTile(
|
||||
|
@ -108,8 +103,7 @@ class ThemeSetting extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
ClipRRect(
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(5)),
|
||||
borderRadius: BorderRadius.all(Radius.circular(5)),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: RadioListTile(
|
||||
|
@ -126,7 +120,8 @@ class ThemeSetting extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
)),
|
||||
),
|
||||
),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 70.0),
|
||||
// leading: Icon(Icons.colorize),
|
||||
title: Text(s.settingsTheme),
|
||||
|
@ -324,7 +319,8 @@ class __ColorPickerState extends State<_ColorPicker>
|
|||
key: UniqueKey(),
|
||||
controller: _controller,
|
||||
children: Colors.primaries
|
||||
.map<Widget>((color) => ScrollConfiguration(
|
||||
.map<Widget>(
|
||||
(color) => ScrollConfiguration(
|
||||
behavior: NoGrowBehavior(),
|
||||
child: GridView.count(
|
||||
primary: false,
|
||||
|
@ -351,8 +347,7 @@ class __ColorPickerState extends State<_ColorPicker>
|
|||
: color == Colors.orange
|
||||
? _accentList(Colors.orangeAccent)
|
||||
: color == Colors.amber
|
||||
? _accentList(
|
||||
Colors.amberAccent)
|
||||
? _accentList(Colors.amberAccent)
|
||||
: color == Colors.yellow
|
||||
? _accentList(
|
||||
Colors.yellowAccent)
|
||||
|
@ -360,8 +355,7 @@ class __ColorPickerState extends State<_ColorPicker>
|
|||
? _accentList(
|
||||
Colors.limeAccent)
|
||||
: color ==
|
||||
Colors
|
||||
.lightGreen
|
||||
Colors.lightGreen
|
||||
? _accentList(Colors
|
||||
.lightGreenAccent)
|
||||
: color ==
|
||||
|
@ -377,7 +371,8 @@ class __ColorPickerState extends State<_ColorPicker>
|
|||
: color ==
|
||||
Colors
|
||||
.cyan
|
||||
? _accentList(Colors
|
||||
? _accentList(
|
||||
Colors
|
||||
.cyanAccent)
|
||||
: color ==
|
||||
Colors.lightBlue
|
||||
|
@ -393,7 +388,8 @@ class __ColorPickerState extends State<_ColorPicker>
|
|||
: []
|
||||
],
|
||||
),
|
||||
))
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -150,6 +150,7 @@ class SettingState extends ChangeNotifier {
|
|||
color: Colors.grey[100],
|
||||
elevation: 0,
|
||||
titleTextStyle: TextStyle(color: Colors.black),
|
||||
scrolledUnderElevation: 1,
|
||||
iconTheme: IconThemeData(color: Colors.black),
|
||||
systemOverlayStyle: SystemUiOverlayStyle.dark),
|
||||
textTheme: TextTheme(
|
||||
|
@ -259,6 +260,7 @@ class SettingState extends ChangeNotifier {
|
|||
appBarTheme: AppBarTheme(
|
||||
color: Colors.grey[900],
|
||||
elevation: 0,
|
||||
scrolledUnderElevation: 0,
|
||||
systemOverlayStyle: SystemUiOverlayStyle.light),
|
||||
buttonTheme: ButtonThemeData(height: 32),
|
||||
dialogBackgroundColor: _realDark! ? Colors.grey[900] : null,
|
||||
|
|
|
@ -80,6 +80,14 @@ class EpisodeBrief extends Equatable {
|
|||
: primaryColor!.colorizeLight();
|
||||
}
|
||||
|
||||
Color cardColor(BuildContext context) {
|
||||
final schema = ColorScheme.fromSeed(
|
||||
seedColor: primaryColor!.colorizedark(),
|
||||
brightness: context.brightness,
|
||||
);
|
||||
return schema.primaryContainer;
|
||||
}
|
||||
|
||||
EpisodeBrief copyWith({
|
||||
String? mediaId,
|
||||
}) =>
|
||||
|
|
|
@ -42,12 +42,13 @@ class PodcastLocal extends Equatable {
|
|||
this.description = '',
|
||||
this.updateCount = 0,
|
||||
this.episodeCount = 0,
|
||||
}) : assert(rssUrl != null);
|
||||
});
|
||||
|
||||
ImageProvider get avatarImage {
|
||||
return (File(imagePath!).existsSync()
|
||||
? 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) {
|
||||
|
@ -56,9 +57,26 @@ class PodcastLocal extends Equatable {
|
|||
: 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}) {
|
||||
return PodcastLocal(title, imageUrl, rssUrl, primaryColor, author, id,
|
||||
imagePath, provider, link, funding,
|
||||
return PodcastLocal(
|
||||
title,
|
||||
imageUrl,
|
||||
rssUrl,
|
||||
primaryColor,
|
||||
author,
|
||||
id,
|
||||
imagePath,
|
||||
provider,
|
||||
link,
|
||||
funding,
|
||||
description: description,
|
||||
updateCount: updateCount ?? 0,
|
||||
episodeCount: episodeCount ?? 0,
|
||||
|
|
|
@ -2,8 +2,8 @@ import 'dart:convert';
|
|||
import 'dart:developer' as developer;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:material_color_utilities/material_color_utilities.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
import '../generated/l10n.dart';
|
||||
|
@ -16,6 +16,7 @@ extension ContextExtension on BuildContext {
|
|||
Color get onPrimary => Theme.of(this).colorScheme.onPrimary;
|
||||
Color get background => Theme.of(this).colorScheme.background;
|
||||
Color get tertiary => colorScheme.tertiary;
|
||||
Color get tertiaryContainer => colorScheme.tertiaryContainer;
|
||||
Color get onTertiary => colorScheme.onTertiary;
|
||||
Color get secondary => colorScheme.secondary;
|
||||
Color get onsecondary => colorScheme.onSecondary;
|
||||
|
@ -30,6 +31,12 @@ extension ContextExtension on BuildContext {
|
|||
double get height => MediaQuery.of(this).size.height;
|
||||
double get paddingTop => MediaQuery.of(this).padding.top;
|
||||
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)!;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,17 +36,15 @@ Widget featureDiscoveryOverlay(BuildContext context,
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(description),
|
||||
FlatButton(
|
||||
color: buttonColor,
|
||||
padding: EdgeInsets.zero,
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(primary: buttonColor),
|
||||
child: Text(s.understood,
|
||||
style: context.textTheme.button!.copyWith(color: Colors.white)),
|
||||
onPressed: () async =>
|
||||
FeatureDiscovery.completeCurrentStep(context),
|
||||
),
|
||||
FlatButton(
|
||||
color: buttonColor,
|
||||
padding: EdgeInsets.zero,
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(primary: buttonColor),
|
||||
child: Text(s.dismiss,
|
||||
style: context.textTheme.button!.copyWith(color: Colors.white)),
|
||||
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
|
||||
publish_to: "none"
|
||||
environment:
|
||||
sdk: '>=2.12.0 <3.0.0'
|
||||
sdk: ">=2.12.0 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
|
@ -55,13 +55,13 @@ dependencies:
|
|||
just_audio: ^0.9.23
|
||||
flutter_downloader:
|
||||
git:
|
||||
url: https://github.com/stonega/flutter_downloader.git
|
||||
url: https://github.com/tsacdop/flutter_downloader.git
|
||||
focused_menu:
|
||||
git:
|
||||
url: https://github.com/stonega/focused_menu.git
|
||||
url: https://github.com/tsacdop/focused_menu.git
|
||||
webfeed:
|
||||
git:
|
||||
url: https://github.com/stonega/webfeed.git
|
||||
url: https://github.com/tsacdop/webfeed.git
|
||||
equatable: ^2.0.0
|
||||
path_provider: ^2.0.1
|
||||
http_parser: ^4.0.0
|
||||
|
@ -74,7 +74,7 @@ dependencies:
|
|||
dependency_overrides:
|
||||
linkify:
|
||||
git:
|
||||
url: https://github.com/stonega/linkify.git
|
||||
url: https://github.com/tsacdop/linkify.git
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
Loading…
Reference in New Issue