mirror of
https://github.com/stonega/tsacdop
synced 2025-03-10 00:00:07 +01:00
Minor change.
This commit is contained in:
parent
b1a39fd1b3
commit
39c56eef6a
@ -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();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -114,7 +114,15 @@ class _PopupMenuSettingState extends State<PopupMenuSetting> {
|
||||
animation: 'longtap',
|
||||
fit: BoxFit.cover,
|
||||
)),
|
||||
Divider(height: 2),
|
||||
FutureBuilder<List<int>>(
|
||||
future: _getEpisodeMenu(),
|
||||
initialData: [0, 1, 12, 13, 14],
|
||||
builder: (context, snapshot) {
|
||||
var menu = snapshot.data;
|
||||
return Expanded(
|
||||
child: ListView(
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 10),
|
||||
),
|
||||
@ -126,15 +134,17 @@ class _PopupMenuSettingState extends State<PopupMenuSetting> {
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.copyWith(color: Theme.of(context).accentColor)),
|
||||
.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),
|
||||
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(
|
||||
@ -145,16 +155,7 @@ class _PopupMenuSettingState extends State<PopupMenuSetting> {
|
||||
),
|
||||
),
|
||||
),
|
||||
FutureBuilder<List<int>>(
|
||||
future: _getEpisodeMenu(),
|
||||
initialData: [0, 1, 12, 13, 14],
|
||||
builder: (context, snapshot) {
|
||||
var menu = snapshot.data;
|
||||
return Expanded(
|
||||
child: ListView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
children: menu.map<Widget>((e) {
|
||||
...menu.map<Widget>((e) {
|
||||
var i = e % 10;
|
||||
switch (i) {
|
||||
case 0:
|
||||
@ -188,7 +189,8 @@ class _PopupMenuSettingState extends State<PopupMenuSetting> {
|
||||
width: 23,
|
||||
height: 23,
|
||||
child: CustomPaint(
|
||||
painter: ListenedAllPainter(Colors.blue,
|
||||
painter: ListenedAllPainter(
|
||||
Colors.blue,
|
||||
stroke: 1.5)),
|
||||
),
|
||||
text: s.markListened,
|
||||
@ -208,6 +210,7 @@ class _PopupMenuSettingState extends State<PopupMenuSetting> {
|
||||
break;
|
||||
}
|
||||
}).toList(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user