Minor change.

This commit is contained in:
stonegate 2020-08-15 16:24:53 +08:00
parent b1a39fd1b3
commit 39c56eef6a
4 changed files with 285 additions and 163 deletions

View File

@ -133,7 +133,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
_loaddes = false;
_showMenu = true;
_showTitle = false;
_getSDescription(widget.episodeItem.enclosureUrl);
//_getSDescription(widget.episodeItem.enclosureUrl);
_controller = ScrollController();
_controller.addListener(_scrollListener);
}
@ -229,7 +229,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
body: Stack(
children: <Widget>[
Container(
color: Theme.of(context).primaryColor,
color: context.primaryColor,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
controller: _controller,
@ -346,71 +346,72 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
],
),
),
_loaddes
? _description.length > 0
? Selector<AudioPlayerNotifier, EpisodeBrief>(
selector: (_, audio) => audio.episode,
builder: (_, data, __) {
var description = _description;
if (data == widget.episodeItem) {
final linkList = linkify(_description,
options:
LinkifyOptions(humanize: false),
linkifiers: [TimeStampLinkifier()]);
for (var element in linkList) {
if (element is TimeStampElement) {
final time = element.timeStamp;
description = description.replaceFirst(
time,
'<a rel="nofollow" href = "skipto:$time">$time</a>');
}
}
}
return Html(
padding: EdgeInsets.only(
left: 20.0, right: 20, bottom: 50),
defaultTextStyle: GoogleFonts.martel(
textStyle: TextStyle(
height: 1.8,
),
),
data: description,
linkStyle: TextStyle(
color: context.accentColor,
textBaseline:
TextBaseline.ideographic),
onLinkTap: (url) {
if (url.substring(0, 6) == 'skipto') {
final seconds = _getTimeStamp(url);
audio.seekTo(seconds * 1000);
} else {
url.launchUrl;
}
},
useRichText: true,
);
})
: Container(
height: context.width,
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image(
image:
AssetImage('assets/shownote.png'),
height: 100.0,
),
Padding(padding: EdgeInsets.all(5.0)),
Text(s.noShownote,
textAlign: TextAlign.center,
style: TextStyle(
color: context.textColor
.withOpacity(0.5))),
],
),
)
: Center(),
_ShowNote(episode: widget.episodeItem),
// _loaddes
// ? _description.length > 0
// ? Selector<AudioPlayerNotifier, EpisodeBrief>(
// selector: (_, audio) => audio.episode,
// builder: (_, data, __) {
// var description = _description;
// if (data == widget.episodeItem) {
// final linkList = linkify(_description,
// options:
// LinkifyOptions(humanize: false),
// linkifiers: [TimeStampLinkifier()]);
// for (var element in linkList) {
// if (element is TimeStampElement) {
// final time = element.timeStamp;
// description = description.replaceFirst(
// time,
// '<a rel="nofollow" href = "skipto:$time">$time</a>');
// }
// }
// }
// return Html(
// padding: EdgeInsets.only(
// left: 20.0, right: 20, bottom: 50),
// defaultTextStyle: GoogleFonts.martel(
// textStyle: TextStyle(
// height: 1.8,
// ),
// ),
// data: description,
// linkStyle: TextStyle(
// color: context.accentColor,
// textBaseline:
// TextBaseline.ideographic),
// onLinkTap: (url) {
// if (url.substring(0, 6) == 'skipto') {
// final seconds = _getTimeStamp(url);
// audio.seekTo(seconds * 1000);
// } else {
// url.launchUrl;
// }
// },
// useRichText: true,
// );
// })
// : Container(
// height: context.width,
// alignment: Alignment.center,
// child: Column(
// mainAxisAlignment: MainAxisAlignment.center,
// children: <Widget>[
// Image(
// image:
// AssetImage('assets/shownote.png'),
// height: 100.0,
// ),
// Padding(padding: EdgeInsets.all(5.0)),
// Text(s.noShownote,
// textAlign: TextAlign.center,
// style: TextStyle(
// color: context.textColor
// .withOpacity(0.5))),
// ],
// ),
// )
// : Center(),
Selector<AudioPlayerNotifier, Tuple2<bool, PlayerHeight>>(
selector: (_, audio) =>
Tuple2(audio.playerRunning, audio.playerHeight),
@ -437,7 +438,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
height: _showMenu ? 50 : 0,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: MenuBar(
child: _MenuBar(
episodeItem: widget.episodeItem,
heroTag: widget.heroTag,
hide: widget.hide),
@ -459,17 +460,17 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
}
}
class MenuBar extends StatefulWidget {
class _MenuBar extends StatefulWidget {
final EpisodeBrief episodeItem;
final String heroTag;
final bool hide;
MenuBar({this.episodeItem, this.heroTag, this.hide, Key key})
_MenuBar({this.episodeItem, this.heroTag, this.hide, Key key})
: super(key: key);
@override
_MenuBarState createState() => _MenuBarState();
__MenuBarState createState() => __MenuBarState();
}
class _MenuBarState extends State<MenuBar> {
class __MenuBarState extends State<_MenuBar> {
Future<int> _isListened(EpisodeBrief episode) async {
var dbHelper = DBHelper();
return await dbHelper.isListened(episode.enclosureUrl);
@ -607,7 +608,8 @@ class _MenuBarState extends State<MenuBar> {
selector: (_, audio) =>
Tuple2(audio.queue.playlist, audio.queueUpdate),
builder: (_, data, __) {
return data.item1.contains(widget.episodeItem)
return (data.item1.contains(widget.episodeItem) &&
!widget.hide)
? _buttonOnMenu(
child: Icon(Icons.playlist_add_check,
color: context.accentColor),
@ -719,3 +721,121 @@ class _MenuBarState extends State<MenuBar> {
);
}
}
class _ShowNote extends StatelessWidget {
final EpisodeBrief episode;
const _ShowNote({this.episode, Key key}) : super(key: key);
int _getTimeStamp(String url) {
final time = url.substring(7);
final data = time.split(':');
var seconds;
if (data.length == 3) {
seconds = int.tryParse(data[0]) * 3600 +
int.tryParse(data[1]) * 60 +
int.tryParse(data[2]);
} else if (data.length == 2) {
seconds = int.tryParse(data[0]) * 60 + int.tryParse(data[1]);
}
return seconds;
}
Future<String> _getSDescription(String url) async {
var description;
var dbHelper = DBHelper();
description = (await dbHelper.getDescription(url))
.replaceAll(RegExp(r'\s?<p>(<br>)?</p>\s?'), '')
.replaceAll('\r', '')
.trim();
if (!description.contains('<')) {
final linkList = linkify(description,
options: LinkifyOptions(humanize: false),
linkifiers: [UrlLinkifier(), EmailLinkifier()]);
for (var element in linkList) {
if (element is UrlElement) {
description = description.replaceAll(element.url,
'<a rel="nofollow" href = ${element.url}>${element.text}</a>');
}
if (element is EmailElement) {
final address = element.emailAddress;
description = description.replaceAll(address,
'<a rel="nofollow" href = "mailto:$address">$address</a>');
}
}
}
return description;
}
@override
Widget build(BuildContext context) {
var audio = context.watch<AudioPlayerNotifier>();
final s = context.s;
return FutureBuilder(
future: _getSDescription(episode.enclosureUrl),
builder: (context, snapshot) {
if (snapshot.hasData) {
var description = snapshot.data;
return description.length > 0
? Selector<AudioPlayerNotifier, EpisodeBrief>(
selector: (_, audio) => audio.episode,
builder: (_, data, __) {
if (data == episode) {
final linkList = linkify(description,
options: LinkifyOptions(humanize: false),
linkifiers: [TimeStampLinkifier()]);
for (var element in linkList) {
if (element is TimeStampElement) {
final time = element.timeStamp;
description = description.replaceFirst(time,
'<a rel="nofollow" href = "skipto:$time">$time</a>');
}
}
}
return Html(
padding:
EdgeInsets.only(left: 20.0, right: 20, bottom: 50),
defaultTextStyle: GoogleFonts.martel(
textStyle: TextStyle(
height: 1.8,
),
),
data: description,
linkStyle: TextStyle(
color: context.accentColor,
textBaseline: TextBaseline.ideographic),
onLinkTap: (url) {
if (url.substring(0, 6) == 'skipto') {
final seconds = _getTimeStamp(url);
audio.seekTo(seconds * 1000);
} else {
url.launchUrl;
}
},
useRichText: true,
);
})
: Container(
height: context.width,
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image(
image: AssetImage('assets/shownote.png'),
height: 100.0,
),
Padding(padding: EdgeInsets.all(5.0)),
Text(s.noShownote,
textAlign: TextAlign.center,
style: TextStyle(
color: context.textColor.withOpacity(0.5))),
],
),
);
} else {
return Center();
}
},
);
}
}

View File

@ -115,7 +115,7 @@ class KeyValueStorage {
Future<List<int>> getMenu() async {
var prefs = await SharedPreferences.getInstance();
if (prefs.getStringList(key) == null) {
if (prefs.getStringList(key) == null || prefs.getStringList(key).isEmpty) {
await prefs.setStringList(key, ['0', '1', '2', '13', '14']);
}
var list = prefs.getStringList(key);

View File

@ -114,37 +114,6 @@ class _PopupMenuSettingState extends State<PopupMenuSetting> {
animation: 'longtap',
fit: BoxFit.cover,
)),
Divider(height: 2),
Padding(
padding: EdgeInsets.symmetric(vertical: 10),
),
Container(
height: 30.0,
padding: EdgeInsets.symmetric(horizontal: 80),
alignment: Alignment.centerLeft,
child: Text(s.settingsPopupMenu,
style: Theme.of(context)
.textTheme
.bodyText1
.copyWith(color: Theme.of(context).accentColor)),
),
FutureBuilder<bool>(
future: _getTapToOpenPopupMenu(),
initialData: false,
builder: (context, snapshot) => ListTile(
contentPadding:
EdgeInsets.only(left: 80, top: 10, bottom: 10, right: 30),
onTap: () => _saveTapToOpenPopupMenu(!snapshot.data),
title: Text(s.settingsTapToOpenPopupMenu),
subtitle: Text(s.settingsTapToOpenPopupMenuDes),
trailing: Transform.scale(
scale: 0.9,
child: Switch(
value: snapshot.data,
onChanged: _saveTapToOpenPopupMenu),
),
),
),
FutureBuilder<List<int>>(
future: _getEpisodeMenu(),
initialData: [0, 1, 12, 13, 14],
@ -152,62 +121,96 @@ class _PopupMenuSettingState extends State<PopupMenuSetting> {
var menu = snapshot.data;
return Expanded(
child: ListView(
physics: const BouncingScrollPhysics(),
shrinkWrap: true,
children: menu.map<Widget>((e) {
var i = e % 10;
switch (i) {
case 0:
return _popupMenuItem(menu, e,
icon: Icon(
LineIcons.play_circle_solid,
color: context.accentColor,
),
text: s.play,
description: s.popupMenuPlayDes);
break;
case 1:
return _popupMenuItem(menu, e,
icon: Icon(
LineIcons.clock_solid,
color: Colors.cyan,
),
text: s.later,
description: s.popupMenuLaterDes);
break;
case 2:
return _popupMenuItem(menu, e,
icon: Icon(LineIcons.heart,
color: Colors.red, size: 21),
text: s.like,
description: s.popupMenuLikeDes);
break;
case 3:
return _popupMenuItem(menu, e,
icon: SizedBox(
width: 23,
height: 23,
child: CustomPaint(
painter: ListenedAllPainter(Colors.blue,
stroke: 1.5)),
),
text: s.markListened,
description: s.popupMenuMarkDes);
break;
case 4:
return _popupMenuItem(menu, e,
icon: Icon(
LineIcons.download_solid,
color: Colors.green,
),
text: s.download,
description: s.popupMenuDownloadDes);
break;
default:
return Text('Text');
break;
}
}).toList(),
children: [
Padding(
padding: EdgeInsets.symmetric(vertical: 10),
),
Container(
height: 30.0,
padding: EdgeInsets.symmetric(horizontal: 80),
alignment: Alignment.centerLeft,
child: Text(s.settingsPopupMenu,
style: Theme.of(context)
.textTheme
.bodyText1
.copyWith(
color: Theme.of(context).accentColor)),
),
FutureBuilder<bool>(
future: _getTapToOpenPopupMenu(),
initialData: false,
builder: (context, snapshot) => ListTile(
contentPadding: EdgeInsets.only(
left: 80, top: 10, bottom: 10, right: 30),
onTap: () =>
_saveTapToOpenPopupMenu(!snapshot.data),
title: Text(s.settingsTapToOpenPopupMenu),
subtitle: Text(s.settingsTapToOpenPopupMenuDes),
trailing: Transform.scale(
scale: 0.9,
child: Switch(
value: snapshot.data,
onChanged: _saveTapToOpenPopupMenu),
),
),
),
...menu.map<Widget>((e) {
var i = e % 10;
switch (i) {
case 0:
return _popupMenuItem(menu, e,
icon: Icon(
LineIcons.play_circle_solid,
color: context.accentColor,
),
text: s.play,
description: s.popupMenuPlayDes);
break;
case 1:
return _popupMenuItem(menu, e,
icon: Icon(
LineIcons.clock_solid,
color: Colors.cyan,
),
text: s.later,
description: s.popupMenuLaterDes);
break;
case 2:
return _popupMenuItem(menu, e,
icon: Icon(LineIcons.heart,
color: Colors.red, size: 21),
text: s.like,
description: s.popupMenuLikeDes);
break;
case 3:
return _popupMenuItem(menu, e,
icon: SizedBox(
width: 23,
height: 23,
child: CustomPaint(
painter: ListenedAllPainter(
Colors.blue,
stroke: 1.5)),
),
text: s.markListened,
description: s.popupMenuMarkDes);
break;
case 4:
return _popupMenuItem(menu, e,
icon: Icon(
LineIcons.download_solid,
color: Colors.green,
),
text: s.download,
description: s.popupMenuDownloadDes);
break;
default:
return Text('Text');
break;
}
}).toList(),
],
),
);
}),

View File

@ -436,8 +436,7 @@ class SettingState extends ChangeNotifier {
var downloadLayout = await downloadLayoutStorage.getInt();
var autoDownloadNetwork =
await autoDownloadStorage.getBool(defaultValue: false);
var episodePopupMenu =
await KeyValueStorage(episodePopupMenuKey).getStringList();
var episodePopupMenu = await KeyValueStorage(episodePopupMenuKey).getMenu();
var autoDelete = await autoDeleteStorage.getInt();
var autoSleepTimer =
await autoSleepTimerStorage.getBool(defaultValue: false);
@ -470,7 +469,7 @@ class SettingState extends ChangeNotifier {
favLayout: favLayout,
downloadLayout: downloadLayout,
autoDownloadNetwork: autoDownloadNetwork,
episodePopupMenu: episodePopupMenu,
episodePopupMenu: episodePopupMenu.map((e) => e.toString()).toList(),
autoDelete: autoDelete,
autoSleepTimer: autoSleepTimer,
autoSleepTimerStart: autoSleepTimerStart,