1
0
mirror of https://github.com/stonega/tsacdop synced 2025-02-17 20:10:37 +01:00

Change filenames.

Update README.
This commit is contained in:
stonegate 2020-07-07 23:29:21 +08:00
parent afd89ea80c
commit c5d6261c11
33 changed files with 476 additions and 186 deletions

View File

@ -36,6 +36,18 @@ More to come...
| ---------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| <img src="https://raw.githubusercontent.com/stonega/tsacdop/master/preview/1585893838840.png" art = "HomePage"/> | <img src="https://raw.githubusercontent.com/stonega/tsacdop/master/preview/1585894051734.png" art = "Groups"/> | <img src="https://raw.githubusercontent.com/stonega/tsacdop/master/preview/1585893877702.png" art = "Podcast"/> | <img src="https://raw.githubusercontent.com/stonega/tsacdop/master/preview/1585896237809.png" art = "Episode"/> | <img src="https://raw.githubusercontent.com/stonega/tsacdop/master/preview/1585893920721.png" art = "DarkMode"/> |
## Localization
Support languages
* English
* Chinese Simplified (beta)
Please [email](tsacdop.app@gmail.com) me you'd like to contribute to support more languages!
Credit to [Localizely](https://localizely.com/) for kind support to open source project.
## License
Tsacdop is licensed under the [GPL V3.0](https://github.com/stonega/tsacdop/blob/master/LICENSE) license.
@ -52,17 +64,48 @@ final environment = {"apiKey":"APIKEY"};
You can get own api key on [ListenNotes](https://www.listennotes.com/api/), basic plan is free to all, and replace "APIKEY" with it.
If no api key added, the search function in the app won't work. But you can still add podcasts by serach rss link or import ompl file.
## Localization
## Archetecture
Support languages
### Plugins
* English
* Chinese Simplified (beta)
* Local storage
- sqflite
- share_preference
* Audio
- just_audio
- audio_service
* State management
- provider
* Download
- flutter_downloader
Please [email](tsacdop.app@gmail.com) me you'd to contribute to support more languages!
### Directory Structure
Credit to [Localizely](https://localizely.com/) for kind support to open source project.
```
UI
src
├──home
├──home.dart [Homepage]
├──addpodcast.dart [Search Page]
├──playlist.dart [Playlist Page]
├──podcasts
├──podcast_manage.dart [Group Page]
├──podcast_detail.dart [Podcast Page]
├──episodes
├──episode_detail.dart [Episode Page]
├──settings
├──setting.dart [Setting Page]
STATES
src
├──state
├──audio_state.dart [Audio State]
├──download_state.dart [Episode Download]
├──podcast_group.dart [Podcast Groups]
├──refresh_podcast.dart [Episode Refresh]
├──setting_state.dart [Setting]
├──subscribe_podcast.dart [Podcast Subscribe]
```
## Known Issue

View File

@ -1 +1 @@
export '../state/settingstate.dart';
export '../state/setting_state.dart';

View File

@ -12,12 +12,12 @@ import 'package:tuple/tuple.dart';
import 'package:flutter_linkify/flutter_linkify.dart';
import 'package:google_fonts/google_fonts.dart';
import '../state/audiostate.dart';
import '../state/audio_state.dart';
import '../type/episodebrief.dart';
import '../local_storage/sqflite_localpodcast.dart';
import '../util/context_extension.dart';
import '../util/custompaint.dart';
import 'episodedownload.dart';
import 'episode_download.dart';
class EpisodeDetail extends StatefulWidget {
final EpisodeBrief episodeItem;
@ -101,6 +101,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
@override
Widget build(BuildContext context) {
final s = context.s;
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
@ -118,7 +119,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10))),
elevation: 1,
tooltip: 'Menu',
tooltip: s.menu,
itemBuilder: (context) => [
PopupMenuItem(
value: 0,
@ -139,7 +140,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
padding: EdgeInsets.symmetric(horizontal: 5.0),
),
Text(
'Mark Listened',
s.markListened,
),
],
),
@ -152,7 +153,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
await _markListened(widget.episodeItem);
if (mounted) setState(() {});
Fluttertoast.showToast(
msg: 'Mark as listened',
msg: s.markListened,
gravity: ToastGravity.BOTTOM,
);
break;
@ -189,10 +190,9 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
padding: EdgeInsets.symmetric(horizontal: 20.0),
height: 30.0,
child: Text(
'Published ' +
DateFormat.yMMMd().format(
DateTime.fromMillisecondsSinceEpoch(
widget.episodeItem.pubDate)),
s.published(DateFormat.yMMMd().format(
DateTime.fromMillisecondsSinceEpoch(
widget.episodeItem.pubDate))),
style: TextStyle(
color: Theme.of(context).accentColor)),
),
@ -226,9 +226,9 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
horizontal: 10.0),
alignment: Alignment.center,
child: Text(
(widget.episodeItem.duration ~/ 60)
.toString() +
'min',
s.minsCount(
widget.episodeItem.duration ~/
60),
style: textstyle),
)
: Center(),
@ -326,8 +326,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
),
Padding(
padding: EdgeInsets.all(5.0)),
Text(
'Still no shownote received\n for this episode.',
Text(s.noShownote,
textAlign: TextAlign.center,
style: TextStyle(
color: context.textColor
@ -444,7 +443,7 @@ class _MenuBarState extends State<MenuBar> {
@override
Widget build(BuildContext context) {
var audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
final s = context.s;
return Container(
height: 50.0,
decoration: BoxDecoration(
@ -518,7 +517,7 @@ class _MenuBarState extends State<MenuBar> {
color: context.accentColor), () {
audio.delFromPlaylist(widget.episodeItem);
Fluttertoast.showToast(
msg: 'Removed from playlist',
msg: s.toastRemovePlaylist,
gravity: ToastGravity.BOTTOM,
);
})
@ -526,7 +525,7 @@ class _MenuBarState extends State<MenuBar> {
Icon(Icons.playlist_add, color: Colors.grey[700]),
() {
Fluttertoast.showToast(
msg: 'Added to playlist',
msg: s.toastAddPlaylist,
gravity: ToastGravity.BOTTOM,
);
audio.addToPlaylist(widget.episodeItem);
@ -637,7 +636,7 @@ class _MenuBarState extends State<MenuBar> {
padding: EdgeInsets.symmetric(horizontal: 20.0),
child: Row(
children: <Widget>[
Text('Play',
Text(s.play,
style: TextStyle(
color: Theme.of(context).accentColor,
fontSize: 15,

View File

@ -9,8 +9,8 @@ import 'package:fluttertoast/fluttertoast.dart';
import 'package:connectivity/connectivity.dart';
import '../state/download_state.dart';
import '../state/audiostate.dart';
import '../state/settingstate.dart';
import '../state/audio_state.dart';
import '../state/setting_state.dart';
import '../type/episodebrief.dart';
import '../util/general_dialog.dart';

View File

@ -27,47 +27,53 @@ class MessageLookup extends MessageLookupByLibrary {
static m3(count) => "${Intl.plural(count, zero: 'Never', one: '${count} day', other: '${count} days')}";
static m4(time) => "From ${time}";
static m4(count) => "${Intl.plural(count, zero: '', one: 'Episode', other: 'Episodes')}";
static m5(count) => "${Intl.plural(count, zero: 'Group', one: 'Group', other: 'Groups')}";
static m5(time) => "From ${time}";
static m6(host) => "Hosted on ${host}";
static m6(count) => "${Intl.plural(count, zero: 'Group', one: 'Group', other: 'Groups')}";
static m7(count) => "${Intl.plural(count, zero: '', one: '${count} hour ago', other: '${count} hours ago')}";
static m7(host) => "Hosted on ${host}";
static m8(count) => "${Intl.plural(count, zero: '', one: '${count} hour', other: '${count} hours')}";
static m8(count) => "${Intl.plural(count, zero: 'In an hour', one: '${count} hour ago', other: '${count} hours ago')}";
static m9(count) => "${Intl.plural(count, zero: '', one: '${count} minute ago', other: '${count} minutes ago')}";
static m9(count) => "${Intl.plural(count, zero: '', one: '${count} hour', other: '${count} hours')}";
static m10(count) => "${Intl.plural(count, zero: '', one: '${count} min', other: '${count} mins')}";
static m10(count) => "${Intl.plural(count, zero: '', one: '${count} minute ago', other: '${count} minutes ago')}";
static m11(title) => "Fetch data ${title}";
static m11(count) => "${Intl.plural(count, zero: '', one: '${count} min', other: '${count} mins')}";
static m12(title) => "Subscribe failed, network error ${title}";
static m12(title) => "Fetch data ${title}";
static m13(title) => "Subscribe ${title}";
static m13(title) => "Subscribe failed, network error ${title}";
static m14(title) => "Subscribe failed, podcast existed ${title}";
static m14(title) => "Subscribe ${title}";
static m15(title) => "Subscribe success ${title}";
static m15(title) => "Subscribe failed, podcast existed ${title}";
static m16(title) => "Update ${title}";
static m16(title) => "Subscribe success ${title}";
static m17(title) => "Update error ${title}";
static m17(title) => "Update ${title}";
static m18(date) => "Removed at ${date}";
static m18(title) => "Update error ${title}";
static m19(count) => "${Intl.plural(count, zero: '', one: '${count} second ago', other: '${count} seconds ago')}";
static m19(count) => "${Intl.plural(count, zero: '', one: 'Podcast', other: 'Podcasts')}";
static m20(time) => "Last time ${time}";
static m20(date) => "Published at ${date}";
static m21(time) => "${time} Left";
static m21(date) => "Removed at ${date}";
static m22(time) => "To ${time}";
static m22(count) => "${Intl.plural(count, zero: '', one: '${count} second ago', other: '${count} seconds ago')}";
static m23(count) => "${Intl.plural(count, zero: 'No update', one: 'Updated ${count} episode', other: 'Updated ${count} episodes')}";
static m23(time) => "Last time ${time}";
static m24(version) => "Version : ${version}";
static m24(time) => "${time} Left";
static m25(time) => "To ${time}";
static m26(count) => "${Intl.plural(count, zero: 'No update', one: 'Updated ${count} episode', other: 'Updated ${count} episodes')}";
static m27(version) => "Version : ${version}";
final messages = _notInlinedMessages(_notInlinedMessages);
static _notInlinedMessages(_) => <String, Function> {
@ -98,7 +104,7 @@ class MessageLookup extends MessageLookupByLibrary {
"downloaded" : MessageLookupByLibrary.simpleMessage("Downloaded"),
"editGroupName" : MessageLookupByLibrary.simpleMessage("Edit group name"),
"endOfEpisode" : MessageLookupByLibrary.simpleMessage("End of Episode"),
"episode" : MessageLookupByLibrary.simpleMessage("Episode"),
"episode" : m4,
"featureDiscoveryEditGroup" : MessageLookupByLibrary.simpleMessage("Tap to edit group"),
"featureDiscoveryEditGroupDes" : MessageLookupByLibrary.simpleMessage("You can change group name or delete group here, but home group can not be edited or deleted"),
"featureDiscoveryEpisode" : MessageLookupByLibrary.simpleMessage("Episode view"),
@ -122,12 +128,12 @@ class MessageLookup extends MessageLookupByLibrary {
"feedbackPlay" : MessageLookupByLibrary.simpleMessage("Rate on Play"),
"feedbackTelegram" : MessageLookupByLibrary.simpleMessage("Join group"),
"fonts" : MessageLookupByLibrary.simpleMessage("Fonts"),
"from" : m4,
"from" : m5,
"goodNight" : MessageLookupByLibrary.simpleMessage("Good Night"),
"groupExisted" : MessageLookupByLibrary.simpleMessage("Group existed"),
"groupFilter" : MessageLookupByLibrary.simpleMessage("Group filter"),
"groupRemoveConfirm" : MessageLookupByLibrary.simpleMessage("Are you sure you want to delete this group? Podcasts will be moved to Home group."),
"groups" : m5,
"groups" : m6,
"homeGroupsSeeAll" : MessageLookupByLibrary.simpleMessage("See All"),
"homeMenuPlaylist" : MessageLookupByLibrary.simpleMessage("Playlist"),
"homeSubMenuSortBy" : MessageLookupByLibrary.simpleMessage("Sort by"),
@ -137,9 +143,9 @@ class MessageLookup extends MessageLookupByLibrary {
"homeToprightMenuImportOMPL" : MessageLookupByLibrary.simpleMessage("Import OMPL"),
"homeToprightMenuRefreshAll" : MessageLookupByLibrary.simpleMessage("Refresh all"),
"homeToprightMenuSettings" : MessageLookupByLibrary.simpleMessage("Settings"),
"hostedOn" : m6,
"hoursAgo" : m7,
"hoursCount" : m8,
"hostedOn" : m7,
"hoursAgo" : m8,
"hoursCount" : m9,
"introFourthPage" : MessageLookupByLibrary.simpleMessage("Long press on episode card for quick actions."),
"introSecondPage" : MessageLookupByLibrary.simpleMessage("Subscribe podcast via search or import OMPL file."),
"introThirdPage" : MessageLookupByLibrary.simpleMessage("You can create new group for podcasts, swipe on podcast list to change group."),
@ -160,8 +166,8 @@ class MessageLookup extends MessageLookupByLibrary {
"menuMarkAllListened" : MessageLookupByLibrary.simpleMessage("Mark All Listened"),
"menuViewRSS" : MessageLookupByLibrary.simpleMessage("Visit RSS Feed"),
"menuVisitSite" : MessageLookupByLibrary.simpleMessage("Visit Site"),
"minsAgo" : m9,
"minsCount" : m10,
"minsAgo" : m10,
"minsCount" : m11,
"network" : MessageLookupByLibrary.simpleMessage("Network"),
"newGroup" : MessageLookupByLibrary.simpleMessage("Create new group"),
"newestFirst" : MessageLookupByLibrary.simpleMessage("Newest first"),
@ -170,18 +176,19 @@ class MessageLookup extends MessageLookupByLibrary {
"noEpisodeFavorite" : MessageLookupByLibrary.simpleMessage("No episode collected yet"),
"noEpisodeRecent" : MessageLookupByLibrary.simpleMessage("No episode received yet"),
"noPodcastGroup" : MessageLookupByLibrary.simpleMessage("No podcast in this group"),
"notificaitonFatch" : m11,
"notificationNetworkError" : m12,
"notificationSubscribe" : m13,
"notificationSubscribeExisted" : m14,
"notificationSuccess" : m15,
"notificationUpdate" : m16,
"notificationUpdateError" : m17,
"noShownote" : MessageLookupByLibrary.simpleMessage("Still no show notes received \\nfor this episode."),
"notificaitonFatch" : m12,
"notificationNetworkError" : m13,
"notificationSubscribe" : m14,
"notificationSubscribeExisted" : m15,
"notificationSuccess" : m16,
"notificationUpdate" : m17,
"notificationUpdateError" : m18,
"oldestFirst" : MessageLookupByLibrary.simpleMessage("Oldest first"),
"play" : MessageLookupByLibrary.simpleMessage("Play"),
"playing" : MessageLookupByLibrary.simpleMessage("Playing"),
"plugins" : MessageLookupByLibrary.simpleMessage("Plugins"),
"podcast" : MessageLookupByLibrary.simpleMessage("Podcast"),
"podcast" : m19,
"podcastSubscribed" : MessageLookupByLibrary.simpleMessage("Podcast subscribed"),
"popupMenuDownloadDes" : MessageLookupByLibrary.simpleMessage("Download episode"),
"popupMenuLaterDes" : MessageLookupByLibrary.simpleMessage("Add episode to playlist"),
@ -189,15 +196,16 @@ class MessageLookup extends MessageLookupByLibrary {
"popupMenuMarkDes" : MessageLookupByLibrary.simpleMessage("Mark episode as listened"),
"popupMenuPlayDes" : MessageLookupByLibrary.simpleMessage("Play the episode"),
"privacyPolicy" : MessageLookupByLibrary.simpleMessage("Privacy Policy"),
"published" : m20,
"recoverSubscribe" : MessageLookupByLibrary.simpleMessage("Recover subscribe"),
"remove" : MessageLookupByLibrary.simpleMessage("Remove"),
"removeConfirm" : MessageLookupByLibrary.simpleMessage("Remove confirm"),
"removePodcastDes" : MessageLookupByLibrary.simpleMessage("Are you sure you want to unsubscribe?"),
"removedAt" : m18,
"removedAt" : m21,
"schedule" : MessageLookupByLibrary.simpleMessage("Schedule"),
"searchInvalidRss" : MessageLookupByLibrary.simpleMessage("Invalid RSS link"),
"searchPodcast" : MessageLookupByLibrary.simpleMessage("Search podcast"),
"secondsAgo" : m19,
"secondsAgo" : m22,
"settingStorage" : MessageLookupByLibrary.simpleMessage("Storage"),
"settingsAccentColor" : MessageLookupByLibrary.simpleMessage("Accent color"),
"settingsAccentColorDes" : MessageLookupByLibrary.simpleMessage("Include the ovelay color"),
@ -225,6 +233,8 @@ class MessageLookup extends MessageLookupByLibrary {
"settingsHistoryDes" : MessageLookupByLibrary.simpleMessage("Listen date"),
"settingsInfo" : MessageLookupByLibrary.simpleMessage("Info"),
"settingsInterface" : MessageLookupByLibrary.simpleMessage("Interface"),
"settingsLanguages" : MessageLookupByLibrary.simpleMessage("Languages"),
"settingsLanguagesDes" : MessageLookupByLibrary.simpleMessage("Change language"),
"settingsLayout" : MessageLookupByLibrary.simpleMessage("Layout"),
"settingsLayoutDes" : MessageLookupByLibrary.simpleMessage("App layout"),
"settingsLibraries" : MessageLookupByLibrary.simpleMessage("Libraries"),
@ -258,9 +268,9 @@ class MessageLookup extends MessageLookupByLibrary {
"sleepTimer" : MessageLookupByLibrary.simpleMessage("Sleep timer"),
"subscribe" : MessageLookupByLibrary.simpleMessage("Subscribe"),
"systemDefault" : MessageLookupByLibrary.simpleMessage("System default"),
"timeLastPlayed" : m20,
"timeLeft" : m21,
"to" : m22,
"timeLastPlayed" : m23,
"timeLeft" : m24,
"to" : m25,
"toastAddPlaylist" : MessageLookupByLibrary.simpleMessage("Added to playlist"),
"toastDiscovery" : MessageLookupByLibrary.simpleMessage("Discovery feature reopened, pleast restart the app"),
"toastFileError" : MessageLookupByLibrary.simpleMessage("File error, subscribe failed"),
@ -279,8 +289,8 @@ class MessageLookup extends MessageLookupByLibrary {
"unlike" : MessageLookupByLibrary.simpleMessage("Unlike"),
"unliked" : MessageLookupByLibrary.simpleMessage("Episode removed from favorite"),
"updateDate" : MessageLookupByLibrary.simpleMessage("Update date"),
"updateEpisodesCount" : m23,
"updateEpisodesCount" : m26,
"updateFailed" : MessageLookupByLibrary.simpleMessage("Update failed, network error"),
"version" : m24
"version" : m27
};
}

View File

@ -27,47 +27,53 @@ class MessageLookup extends MessageLookupByLibrary {
static m3(count) => "${Intl.plural(count, zero: '从不', other: '${count}天')}";
static m4(time) => "${time}";
static m4(count) => "${Intl.plural(count, zero: '', other: '节目')}";
static m5(count) => "${Intl.plural(count, zero: '分组', other: '分组')}";
static m5(time) => "${time}";
static m6(host) => "平台 ${host}";
static m6(count) => "${Intl.plural(count, zero: '分组', other: '分组')}";
static m7(count) => "${Intl.plural(count, zero: '', other: '${count}小时前')}";
static m7(host) => "平台 ${host}";
static m8(count) => "${Intl.plural(count, zero: '', other: '${count} 小时')}";
static m8(count) => "${Intl.plural(count, zero: '刚刚', other: '${count}小时')}";
static m9(count) => "${Intl.plural(count, zero: '', other: '${count}分钟前')}";
static m9(count) => "${Intl.plural(count, zero: '', other: '${count} 小时')}";
static m10(count) => "${Intl.plural(count, zero: '', other: '${count}分钟')}";
static m10(count) => "${Intl.plural(count, zero: '', other: '${count}分钟')}";
static m11(title) => "获取数据 ${title}";
static m11(count) => "${Intl.plural(count, zero: '', other: '${count}分钟')}";
static m12(title) => "订阅失败,网络错误 ${title}";
static m12(title) => "获取数据 ${title}";
static m13(title) => "订阅${title}";
static m13(title) => "订阅失败,网络错误 ${title}";
static m14(title) => "订阅失败,播客已存在 ${title}";
static m14(title) => "订阅${title}";
static m15(title) => "订阅成功 ${title}";
static m15(title) => "订阅失败,播客已存在 ${title}";
static m16(title) => "更新 ${title}";
static m16(title) => "订阅成功 ${title}";
static m17(title) => "更新失败 ${title}";
static m17(title) => "更新 ${title}";
static m18(date) => "${date}移除";
static m18(title) => "更新失败 ${title}";
static m19(count) => "${Intl.plural(count, zero: '', other: '${count}秒前')}";
static m19(count) => "${Intl.plural(count, zero: '', other: '播客')}";
static m20(time) => "上次播放${time}";
static m20(date) => "${date}上线";
static m21(time) => "剩余 ${time}";
static m21(date) => "${date}移除";
static m22(time) => "${time}";
static m22(count) => "${Intl.plural(count, zero: '', other: '${count}秒前')}";
static m23(count) => "${Intl.plural(count, zero: '未有更新', other: '更新 ${count} 集节目')}";
static m23(time) => "上次播放${time}";
static m24(version) => "版本:${version}";
static m24(time) => "剩余 ${time}";
static m25(time) => "${time}";
static m26(count) => "${Intl.plural(count, zero: '未有更新', other: '更新 ${count} 集节目')}";
static m27(version) => "版本:${version}";
final messages = _notInlinedMessages(_notInlinedMessages);
static _notInlinedMessages(_) => <String, Function> {
@ -98,7 +104,7 @@ class MessageLookup extends MessageLookupByLibrary {
"downloaded" : MessageLookupByLibrary.simpleMessage("已下载"),
"editGroupName" : MessageLookupByLibrary.simpleMessage("修改组名"),
"endOfEpisode" : MessageLookupByLibrary.simpleMessage("节目结束"),
"episode" : MessageLookupByLibrary.simpleMessage("节目"),
"episode" : m4,
"featureDiscoveryEditGroup" : MessageLookupByLibrary.simpleMessage("点击修改分组"),
"featureDiscoveryEditGroupDes" : MessageLookupByLibrary.simpleMessage("您可以修改分组名或者删除分组,注意 Home 分组无法修改,也不能被删除。"),
"featureDiscoveryEpisode" : MessageLookupByLibrary.simpleMessage("节目界面"),
@ -122,12 +128,12 @@ class MessageLookup extends MessageLookupByLibrary {
"feedbackPlay" : MessageLookupByLibrary.simpleMessage("Play评价"),
"feedbackTelegram" : MessageLookupByLibrary.simpleMessage("加入小组"),
"fonts" : MessageLookupByLibrary.simpleMessage("字体"),
"from" : m4,
"from" : m5,
"goodNight" : MessageLookupByLibrary.simpleMessage("晚安"),
"groupExisted" : MessageLookupByLibrary.simpleMessage("组名已使用"),
"groupFilter" : MessageLookupByLibrary.simpleMessage("分组"),
"groupRemoveConfirm" : MessageLookupByLibrary.simpleMessage("您确认要移除该分组吗?播客将被移动到 Home 分组。"),
"groups" : m5,
"groups" : m6,
"homeGroupsSeeAll" : MessageLookupByLibrary.simpleMessage("查看全部"),
"homeMenuPlaylist" : MessageLookupByLibrary.simpleMessage("播放列表"),
"homeSubMenuSortBy" : MessageLookupByLibrary.simpleMessage("排序"),
@ -137,9 +143,9 @@ class MessageLookup extends MessageLookupByLibrary {
"homeToprightMenuImportOMPL" : MessageLookupByLibrary.simpleMessage("导入OMPL"),
"homeToprightMenuRefreshAll" : MessageLookupByLibrary.simpleMessage("全部刷新"),
"homeToprightMenuSettings" : MessageLookupByLibrary.simpleMessage("设置"),
"hostedOn" : m6,
"hoursAgo" : m7,
"hoursCount" : m8,
"hostedOn" : m7,
"hoursAgo" : m8,
"hoursCount" : m9,
"introFourthPage" : MessageLookupByLibrary.simpleMessage("长按节目打开快捷菜单。"),
"introSecondPage" : MessageLookupByLibrary.simpleMessage("您可以通过搜索订阅播客也可以直接导入OMPL文件。"),
"introThirdPage" : MessageLookupByLibrary.simpleMessage("您可以创建分组,上下滑动切换分组。"),
@ -160,8 +166,8 @@ class MessageLookup extends MessageLookupByLibrary {
"menuMarkAllListened" : MessageLookupByLibrary.simpleMessage("标记所有已收听"),
"menuViewRSS" : MessageLookupByLibrary.simpleMessage("查看 RSS"),
"menuVisitSite" : MessageLookupByLibrary.simpleMessage("访问网站"),
"minsAgo" : m9,
"minsCount" : m10,
"minsAgo" : m10,
"minsCount" : m11,
"network" : MessageLookupByLibrary.simpleMessage("网络"),
"newGroup" : MessageLookupByLibrary.simpleMessage("创建分组"),
"newestFirst" : MessageLookupByLibrary.simpleMessage("由新到旧"),
@ -170,18 +176,19 @@ class MessageLookup extends MessageLookupByLibrary {
"noEpisodeFavorite" : MessageLookupByLibrary.simpleMessage("暂无收藏节目"),
"noEpisodeRecent" : MessageLookupByLibrary.simpleMessage("暂无节目"),
"noPodcastGroup" : MessageLookupByLibrary.simpleMessage("分组无播客"),
"notificaitonFatch" : m11,
"notificationNetworkError" : m12,
"notificationSubscribe" : m13,
"notificationSubscribeExisted" : m14,
"notificationSuccess" : m15,
"notificationUpdate" : m16,
"notificationUpdateError" : m17,
"noShownote" : MessageLookupByLibrary.simpleMessage("节目简介暂未收到。"),
"notificaitonFatch" : m12,
"notificationNetworkError" : m13,
"notificationSubscribe" : m14,
"notificationSubscribeExisted" : m15,
"notificationSuccess" : m16,
"notificationUpdate" : m17,
"notificationUpdateError" : m18,
"oldestFirst" : MessageLookupByLibrary.simpleMessage("由旧到新"),
"play" : MessageLookupByLibrary.simpleMessage("播放"),
"playing" : MessageLookupByLibrary.simpleMessage("正在播放"),
"plugins" : MessageLookupByLibrary.simpleMessage("插件"),
"podcast" : MessageLookupByLibrary.simpleMessage("播客"),
"podcast" : m19,
"podcastSubscribed" : MessageLookupByLibrary.simpleMessage("播客已订阅"),
"popupMenuDownloadDes" : MessageLookupByLibrary.simpleMessage("下载节目"),
"popupMenuLaterDes" : MessageLookupByLibrary.simpleMessage("添加到播放列表"),
@ -189,15 +196,16 @@ class MessageLookup extends MessageLookupByLibrary {
"popupMenuMarkDes" : MessageLookupByLibrary.simpleMessage("设置为已收听"),
"popupMenuPlayDes" : MessageLookupByLibrary.simpleMessage("播放节目"),
"privacyPolicy" : MessageLookupByLibrary.simpleMessage("隐私条款"),
"published" : m20,
"recoverSubscribe" : MessageLookupByLibrary.simpleMessage("恢复订阅"),
"remove" : MessageLookupByLibrary.simpleMessage("移除"),
"removeConfirm" : MessageLookupByLibrary.simpleMessage("取消订阅"),
"removePodcastDes" : MessageLookupByLibrary.simpleMessage("您确认要取消订阅吗?"),
"removedAt" : m18,
"removedAt" : m21,
"schedule" : MessageLookupByLibrary.simpleMessage("定时"),
"searchInvalidRss" : MessageLookupByLibrary.simpleMessage("RSS 链接错误"),
"searchPodcast" : MessageLookupByLibrary.simpleMessage("搜索播客"),
"secondsAgo" : m19,
"secondsAgo" : m22,
"settingStorage" : MessageLookupByLibrary.simpleMessage("储存空间"),
"settingsAccentColor" : MessageLookupByLibrary.simpleMessage("次要颜色"),
"settingsAccentColorDes" : MessageLookupByLibrary.simpleMessage("包括溢出颜色"),
@ -225,6 +233,8 @@ class MessageLookup extends MessageLookupByLibrary {
"settingsHistoryDes" : MessageLookupByLibrary.simpleMessage("播放日期"),
"settingsInfo" : MessageLookupByLibrary.simpleMessage("信息"),
"settingsInterface" : MessageLookupByLibrary.simpleMessage("界面"),
"settingsLanguages" : MessageLookupByLibrary.simpleMessage("语言"),
"settingsLanguagesDes" : MessageLookupByLibrary.simpleMessage("设置语言"),
"settingsLayout" : MessageLookupByLibrary.simpleMessage("布局"),
"settingsLayoutDes" : MessageLookupByLibrary.simpleMessage("应用布局"),
"settingsLibraries" : MessageLookupByLibrary.simpleMessage("开源"),
@ -258,9 +268,9 @@ class MessageLookup extends MessageLookupByLibrary {
"sleepTimer" : MessageLookupByLibrary.simpleMessage("睡眠模式"),
"subscribe" : MessageLookupByLibrary.simpleMessage("订阅"),
"systemDefault" : MessageLookupByLibrary.simpleMessage("系统默认"),
"timeLastPlayed" : m20,
"timeLeft" : m21,
"to" : m22,
"timeLastPlayed" : m23,
"timeLeft" : m24,
"to" : m25,
"toastAddPlaylist" : MessageLookupByLibrary.simpleMessage("添加到播放列表"),
"toastDiscovery" : MessageLookupByLibrary.simpleMessage("重启应用后可查看"),
"toastFileError" : MessageLookupByLibrary.simpleMessage("文件错误,导入失败"),
@ -279,8 +289,8 @@ class MessageLookup extends MessageLookupByLibrary {
"unlike" : MessageLookupByLibrary.simpleMessage("取消喜欢"),
"unliked" : MessageLookupByLibrary.simpleMessage("从收藏移除"),
"updateDate" : MessageLookupByLibrary.simpleMessage("更新日期"),
"updateEpisodesCount" : m23,
"updateEpisodesCount" : m26,
"updateFailed" : MessageLookupByLibrary.simpleMessage("更新失败"),
"version" : m24
"version" : m27
};
}

View File

@ -315,13 +315,16 @@ class S {
);
}
/// `Episode`
String get episode {
return Intl.message(
'Episode',
/// `{count, plural, zero{} one{Episode} other{Episodes}}`
String episode(num count) {
return Intl.plural(
count,
zero: '',
one: 'Episode',
other: 'Episodes',
name: 'episode',
desc: '',
args: [],
args: [count],
);
}
@ -718,11 +721,11 @@ class S {
);
}
/// `{count, plural, zero{} one{{count} hour ago} other{{count} hours ago}}`
/// `{count, plural, zero{In an hour} one{{count} hour ago} other{{count} hours ago}}`
String hoursAgo(num count) {
return Intl.plural(
count,
zero: '',
zero: 'In an hour',
one: '$count hour ago',
other: '$count hours ago',
name: 'hoursAgo',
@ -1050,6 +1053,16 @@ class S {
);
}
/// `Still no show notes received \nfor this episode.`
String get noShownote {
return Intl.message(
'Still no show notes received \nfor this episode.',
name: 'noShownote',
desc: 'Means this episode have no show notes.',
args: [],
);
}
/// `Fetch data {title}`
String notificaitonFatch(Object title) {
return Intl.message(
@ -1160,13 +1173,16 @@ class S {
);
}
/// `Podcast`
String get podcast {
return Intl.message(
'Podcast',
/// `{count, plural, zero{} one{Podcast} other{Podcasts}}`
String podcast(num count) {
return Intl.plural(
count,
zero: '',
one: 'Podcast',
other: 'Podcasts',
name: 'podcast',
desc: '',
args: [],
args: [count],
);
}
@ -1240,6 +1256,16 @@ class S {
);
}
/// `Published at {date}`
String published(Object date) {
return Intl.message(
'Published at $date',
name: 'published',
desc: '',
args: [date],
);
}
/// `Recover subscribe`
String get recoverSubscribe {
return Intl.message(
@ -1593,6 +1619,26 @@ class S {
);
}
/// `Languages`
String get settingsLanguages {
return Intl.message(
'Languages',
name: 'settingsLanguages',
desc: '',
args: [],
);
}
/// `Change language`
String get settingsLanguagesDes {
return Intl.message(
'Change language',
name: 'settingsLanguagesDes',
desc: '',
args: [],
);
}
/// `Layout`
String get settingsLayout {
return Intl.message(

View File

@ -9,7 +9,7 @@ import 'package:audio_service/audio_service.dart';
import 'package:line_icons/line_icons.dart';
import '../type/episodebrief.dart';
import '../state/audiostate.dart';
import '../state/audio_state.dart';
import '../local_storage/sqflite_localpodcast.dart';
import '../local_storage/key_value_storage.dart';
import '../util/pageroute.dart';
@ -17,7 +17,7 @@ import '../util/colorize.dart';
import '../util/context_extension.dart';
import '../util/custompaint.dart';
import '../util/customslider.dart';
import '../episodes/episodedetail.dart';
import '../episodes/episode_detail.dart';
import 'playlist.dart';
import 'audiopanel.dart';

View File

@ -4,7 +4,7 @@ import 'package:provider/provider.dart';
import 'package:flutter/material.dart';
import '../state/download_state.dart';
import '../episodes/episodedetail.dart';
import '../episodes/episode_detail.dart';
import '../util/pageroute.dart';
class DownloadList extends StatefulWidget {

View File

@ -10,7 +10,7 @@ import 'package:line_icons/line_icons.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:feature_discovery/feature_discovery.dart';
import '../state/audiostate.dart';
import '../state/audio_state.dart';
import '../type/episodebrief.dart';
import '../local_storage/sqflite_localpodcast.dart';
import '../local_storage/key_value_storage.dart';

View File

@ -5,6 +5,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:focused_menu/focused_menu.dart';
import 'package:focused_menu/modals.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:tuple/tuple.dart';
@ -15,16 +16,16 @@ import '../state/podcast_group.dart';
import '../state/subscribe_podcast.dart';
import '../state/download_state.dart';
import '../type/podcastlocal.dart';
import '../state/audiostate.dart';
import '../state/audio_state.dart';
import '../util/custompaint.dart';
import '../util/pageroute.dart';
import '../util/colorize.dart';
import '../util/context_extension.dart';
import '../local_storage/sqflite_localpodcast.dart';
import '../local_storage/key_value_storage.dart';
import '../episodes/episodedetail.dart';
import '../podcasts/podcastdetail.dart';
import '../podcasts/podcastmanage.dart';
import '../episodes/episode_detail.dart';
import '../podcasts/podcast_detail.dart';
import '../podcasts/podcast_manage.dart';
class ScrollPodcasts extends StatefulWidget {
@override
@ -478,6 +479,20 @@ class ShowEpisode extends StatelessWidget {
return '${(seconds ~/ 60)}:${(seconds.truncate() % 60).toString().padLeft(2, '0')}';
}
String _dateToString(BuildContext context, {int pubDate}) {
final s = context.s;
DateTime date = DateTime.fromMillisecondsSinceEpoch(pubDate, isUtc: true);
var difference = DateTime.now().toUtc().difference(date);
if (difference.inHours < 24) {
return s.hoursAgo(difference.inHours);
} else if (difference.inDays < 7) {
return s.daysAgo(difference.inDays);
} else {
return DateFormat.yMMMd().format(
DateTime.fromMillisecondsSinceEpoch(pubDate, isUtc: true).toLocal());
}
}
Future<Tuple4<int, bool, bool, List<int>>> _initData(
EpisodeBrief episode) async {
int listened = await _isListened(episode);
@ -993,8 +1008,9 @@ class ShowEpisode extends StatelessWidget {
Container(
alignment: Alignment.bottomLeft,
child: Text(
episodes[index].dateToString(),
//podcast[index].pubDate.substring(4, 16),
_dateToString(context,
pubDate: episodes[index]
.pubDate),
style: TextStyle(
fontSize: _width / 35,
color: _c,

View File

@ -8,7 +8,7 @@ import 'package:tuple/tuple.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:line_icons/line_icons.dart';
import '../state/audiostate.dart';
import '../state/audio_state.dart';
import '../type/episodebrief.dart';
import '../util/context_extension.dart';
import '../util/custompaint.dart';

View File

@ -9,7 +9,7 @@ import 'package:tsacdop/home/preview.dart';
import 'package:wc_flutter_share/wc_flutter_share.dart';
import 'package:tuple/tuple.dart';
import '../state/audiostate.dart';
import '../state/audio_state.dart';
import '../util/context_extension.dart';
import '../util/customslider.dart';
import '../util/pageroute.dart';

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import '../state/settingstate.dart';
import '../state/setting_state.dart';
import '../home/home.dart';
import '../util/pageroute.dart';
import '../util/context_extension.dart';

View File

@ -64,7 +64,7 @@
"@editGroupName": {},
"endOfEpisode": "End of Episode",
"@endOfEpisode": {},
"episode": "Episode",
"episode": "{count, plural, zero{} one{Episode} other{Episodes}}",
"@episode": {},
"featureDiscoveryEditGroup": "Tap to edit group",
"@featureDiscoveryEditGroup": {},
@ -152,7 +152,7 @@
"host": {}
}
},
"hoursAgo": "{count, plural, zero{} one{{count} hour ago} other{{count} hours ago}}",
"hoursAgo": "{count, plural, zero{In an hour} one{{count} hour ago} other{{count} hours ago}}",
"@hoursAgo": {},
"hoursCount": "{count, plural, zero{} one{{count} hour} other{{count} hours}}",
"@hoursCount": {},
@ -218,6 +218,10 @@
"@noEpisodeRecent": {},
"noPodcastGroup": "No podcast in this group",
"@noPodcastGroup": {},
"noShownote": "Still no show notes received \\nfor this episode.",
"@noShownote": {
"description": "Means this episode have no show notes."
},
"notificaitonFatch": "Fetch data {title}",
"@notificaitonFatch": {},
"notificationNetworkError": "Subscribe failed, network error {title}",
@ -264,7 +268,7 @@
"@playing": {},
"plugins": "Plugins",
"@plugins": {},
"podcast": "Podcast",
"podcast": "{count, plural, zero{} one{Podcast} other{Podcasts}}",
"@podcast": {},
"podcastSubscribed": "Podcast subscribed",
"@podcastSubscribed": {},
@ -280,6 +284,12 @@
"@popupMenuPlayDes": {},
"privacyPolicy": "Privacy Policy",
"@privacyPolicy": {},
"published": "Published at {date}",
"@published": {
"placeholders": {
"date": {}
}
},
"recoverSubscribe": "Recover subscribe",
"@recoverSubscribe": {},
"remove": "Remove",
@ -357,6 +367,10 @@
"@settingsInfo": {},
"settingsInterface": "Interface",
"@settingsInterface": {},
"settingsLanguages": "Languages",
"@settingsLanguages": {},
"settingsLanguagesDes": "Change language",
"@settingsLanguagesDes": {},
"settingsLayout": "Layout",
"@settingsLayout": {},
"settingsLayoutDes": "App layout",

View File

@ -64,7 +64,7 @@
"@editGroupName": {},
"endOfEpisode": "节目结束",
"@endOfEpisode": {},
"episode": "节目",
"episode": "{count, plural, zero{} other{节目}}",
"@episode": {},
"featureDiscoveryEditGroup": "点击修改分组",
"@featureDiscoveryEditGroup": {},
@ -152,7 +152,7 @@
"host": {}
}
},
"hoursAgo": "{count, plural, zero{} other{{count}小时前}}",
"hoursAgo": "{count, plural, zero{刚刚} other{{count}小时前}}",
"@hoursAgo": {},
"hoursCount": "{count, plural, zero{} other{{count} 小时}}",
"@hoursCount": {},
@ -218,6 +218,10 @@
"@noEpisodeRecent": {},
"noPodcastGroup": "分组无播客",
"@noPodcastGroup": {},
"noShownote": "节目简介暂未收到。",
"@noShownote": {
"description": "Means this episode have no show notes."
},
"notificaitonFatch": "获取数据 {title}",
"@notificaitonFatch": {},
"notificationNetworkError": "订阅失败,网络错误 {title}",
@ -264,7 +268,7 @@
"@playing": {},
"plugins": "插件",
"@plugins": {},
"podcast": "播客",
"podcast": "{count, plural, zero{} other{播客}}",
"@podcast": {},
"podcastSubscribed": "播客已订阅",
"@podcastSubscribed": {},
@ -280,6 +284,12 @@
"@popupMenuPlayDes": {},
"privacyPolicy": "隐私条款",
"@privacyPolicy": {},
"published": "{date}上线",
"@published": {
"placeholders": {
"date": {}
}
},
"recoverSubscribe": "恢复订阅",
"@recoverSubscribe": {},
"remove": "移除",
@ -357,6 +367,10 @@
"@settingsInfo": {},
"settingsInterface": "界面",
"@settingsInterface": {},
"settingsLanguages": "语言",
"@settingsLanguages": {},
"settingsLanguagesDes": "设置语言",
"@settingsLanguagesDes": {},
"settingsLayout": "布局",
"@settingsLayout": {},
"settingsLayoutDes": "应用布局",

View File

@ -5,7 +5,7 @@ import 'package:intl/intl.dart';
import 'package:flutter_downloader/flutter_downloader.dart';
import 'package:dio/dio.dart';
import '../type/podcastlocal.dart';
import '../state/audiostate.dart';
import '../state/audio_state.dart';
import '../type/episodebrief.dart';
import '../webfeed/webfeed.dart';
import '../type/sub_history.dart';

View File

@ -8,8 +8,8 @@ import 'package:feature_discovery/feature_discovery.dart';
import 'generated/l10n.dart';
import 'state/podcast_group.dart';
import 'state/audiostate.dart';
import 'state/settingstate.dart';
import 'state/audio_state.dart';
import 'state/setting_state.dart';
import 'state/download_state.dart';
import 'state/refresh_podcast.dart';
import 'state/subscribe_podcast.dart';

View File

@ -25,7 +25,7 @@ import '../util/colorize.dart';
import '../util/context_extension.dart';
import '../util/custompaint.dart';
import '../util/general_dialog.dart';
import '../state/audiostate.dart';
import '../state/audio_state.dart';
class PodcastDetail extends StatefulWidget {
PodcastDetail({Key key, @required this.podcastLocal, this.hide = false})

View File

@ -9,8 +9,8 @@ import 'package:fluttertoast/fluttertoast.dart';
import 'package:feature_discovery/feature_discovery.dart';
import '../state/podcast_group.dart';
import '../podcasts/podcastgroup.dart';
import '../podcasts/podcastlist.dart';
import 'podcastgroup.dart';
import 'podcastlist.dart';
import '../util/pageroute.dart';
import '../util/context_extension.dart';
import '../util/general_dialog.dart';
@ -292,7 +292,7 @@ class _PodcastManageState extends State<PodcastManage>
pageBuilder: (context, index) =>
DescribedFeatureOverlay(
featureId: configurePodcast,
tapTarget: Text(s.podcast),
tapTarget: Text(s.podcast(1)),
title: Text(s.featureDiscoveryGroupPodcast),
overflowMode: OverflowMode.clipContent,
onDismiss: () => Future.value(true),

View File

@ -11,7 +11,7 @@ import 'package:provider/provider.dart';
import '../state/podcast_group.dart';
import '../type/podcastlocal.dart';
import '../local_storage/sqflite_localpodcast.dart';
import '../podcasts/podcastdetail.dart';
import 'podcast_detail.dart';
import '../util/pageroute.dart';
import '../util/context_extension.dart';
@ -46,6 +46,7 @@ class _AboutPodcastState extends State<AboutPodcast> {
@override
Widget build(BuildContext context) {
var _groupList = Provider.of<GroupList>(context, listen: false);
final s = context.s;
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10.0))),
@ -60,7 +61,7 @@ class _AboutPodcastState extends State<AboutPodcast> {
},
textColor: Colors.red,
child: Text(
'UNSUBSCRIBE',
s.remove,
),
),
],
@ -109,7 +110,7 @@ class _PodcastListState extends State<PodcastList> {
),
child: Scaffold(
appBar: AppBar(
title: Text('Podcasts'),
title: Text(context.s.podcast(2)),
centerTitle: true,
),
body: SafeArea(

View File

@ -2,6 +2,7 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
import 'package:path_provider/path_provider.dart';
import 'package:line_icons/line_icons.dart';
import 'package:provider/provider.dart';
@ -73,6 +74,21 @@ class _DownloadsManageState extends State<DownloadsManage> {
_getStorageSize();
}
String _downloadDateToString(BuildContext context,
{int downloadDate, int pubDate}) {
final s = context.s;
DateTime date = DateTime.fromMillisecondsSinceEpoch(downloadDate);
var diffrence = DateTime.now().toUtc().difference(date);
if (diffrence.inHours < 24) {
return s.hoursAgo(diffrence.inHours);
} else if (diffrence.inDays < 7) {
return s.daysAgo(diffrence.inDays);
} else {
return DateFormat.yMMMd().format(
DateTime.fromMillisecondsSinceEpoch(pubDate, isUtc: true).toLocal());
}
}
int sumSelected() {
int sum = 0;
if (_selectedList.length == 0) {
@ -313,8 +329,14 @@ class _DownloadsManageState extends State<DownloadsManage> {
),
subtitle: Row(
children: [
Text(_episodes[index]
.downloadDateToString()),
Text(_downloadDateToString(
context,
downloadDate:
_episodes[index]
.downloadDate,
pubDate:
_episodes[index]
.pubDate)),
SizedBox(width: 20),
_episodes[index]
.enclosureLength !=

View File

@ -11,7 +11,7 @@ import '../local_storage/sqflite_localpodcast.dart';
import '../webfeed/webfeed.dart';
import '../type/searchpodcast.dart';
import '../util/context_extension.dart';
import '../state/audiostate.dart';
import '../state/audio_state.dart';
import '../state/subscribe_podcast.dart';
import '../type/sub_history.dart';

105
lib/settings/languages.dart Normal file
View File

@ -0,0 +1,105 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
import 'package:line_icons/line_icons.dart';
import 'package:url_launcher/url_launcher.dart';
import '../util/context_extension.dart';
import '../generated/l10n.dart';
class LanguagesSetting extends StatefulWidget {
const LanguagesSetting({Key key}) : super(key: key);
@override
_LanguagesSettingState createState() => _LanguagesSettingState();
}
class _LanguagesSettingState extends State<LanguagesSetting> {
_launchUrl(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
@override
Widget build(BuildContext context) {
final s = context.s;
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
systemNavigationBarColor: Theme.of(context).primaryColor,
systemNavigationBarIconBrightness:
Theme.of(context).accentColorBrightness,
),
child: Scaffold(
appBar: AppBar(
title: Text(s.settingsLanguages),
elevation: 0,
backgroundColor: Theme.of(context).primaryColor,
),
body: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
ListTile(
title: Text(s.systemDefault),
onTap: () async {
await S.load(Locale(Intl.systemLocale));
setState(() {});
},
trailing: Radio<Locale>(
value: Locale(Intl.systemLocale),
groupValue: Locale(Intl.getCurrentLocale()),
onChanged: (Locale locale) async {
await S.load(locale);
setState(() {});
}),
),
Divider(height: 2),
ListTile(
title: Text('English'),
onTap: () async {
await S.load(Locale('en'));
setState(() {});
},
trailing: Radio<Locale>(
value: Locale('en'),
groupValue: Locale(Intl.getCurrentLocale()),
onChanged: (Locale locale) async {
await S.load(locale);
setState(() {});
}),
),
Divider(height: 2),
ListTile(
title: Text('简体中文'),
onTap: () async {
await S.load(Locale('zh_Hans'));
setState(() {});
},
trailing: Radio<Locale>(
value: Locale('zh_Hans'),
groupValue: Locale(Intl.getCurrentLocale()),
onChanged: (Locale locale) async {
await S.load(locale);
setState(() {});
}),
),
Divider(height: 2),
ListTile(
onTap: () => _launchUrl(
'mailto:<tsacdop.app@gmail.com>?subject=Tsacdop localization project'),
subtitle: Text(
"If you'd like to contribute to support more languages, please contact me."),
trailing: IconButton(
icon: Icon(LineIcons.envelope_open_solid),
onPressed: () => _launchUrl(
'mailto:<tsacdop.app@gmail.com>?subject=Tsacdop localization project')),
),
],
))),
);
}
}

View File

@ -8,7 +8,7 @@ import 'package:google_fonts/google_fonts.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:flutter_time_picker_spinner/flutter_time_picker_spinner.dart';
import '../state/settingstate.dart';
import '../state/setting_state.dart';
import '../home/audioplayer.dart';
import '../util/general_dialog.dart';
import '../util/context_extension.dart';

View File

@ -17,13 +17,14 @@ import '../intro_slider/app_intro.dart';
import '../type/podcastlocal.dart';
import '../local_storage/sqflite_localpodcast.dart';
import '../home/home.dart';
import '../podcasts/podcastmanage.dart';
import '../podcasts/podcast_manage.dart';
import 'theme.dart';
import 'layouts.dart';
import 'storage.dart';
import 'history.dart';
import 'syncing.dart';
import 'libries.dart';
import 'languages.dart';
import 'play_setting.dart';
class Settings extends StatefulWidget {
@ -217,6 +218,18 @@ class _SettingsState extends State<Settings>
subtitle: Text(s.settingsHistoryDes),
),
Divider(height: 2),
ListTile(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LanguagesSetting())),
contentPadding:
EdgeInsets.symmetric(horizontal: 25.0),
leading: Icon(LineIcons.language_solid),
title: Text(s.settingsLanguages),
subtitle: Text(s.settingsLanguagesDes),
),
Divider(height: 2),
ListTile(
onTap: () {
_exportOmpl();

View File

@ -4,7 +4,7 @@ import 'package:provider/provider.dart';
import 'package:google_fonts/google_fonts.dart';
import '../settings/downloads_manage.dart';
import '../state/settingstate.dart';
import '../state/setting_state.dart';
import '../local_storage/key_value_storage.dart';
import '../util/context_extension.dart';

View File

@ -3,7 +3,7 @@ import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:tuple/tuple.dart';
import '../state/settingstate.dart';
import '../state/setting_state.dart';
import '../util/context_extension.dart';
class SyncingSetting extends StatelessWidget {

View File

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import '../state/settingstate.dart';
import '../state/setting_state.dart';
import '../util/context_extension.dart';
import '../util/general_dialog.dart';

View File

@ -39,7 +39,7 @@ class EpisodeBrief {
this.downloadDate = 0})
: assert(enclosureUrl != null);
String dateToString() {
String ateToString() {
DateTime date = DateTime.fromMillisecondsSinceEpoch(pubDate, isUtc: true);
var diffrence = DateTime.now().toUtc().difference(date);
if (diffrence.inHours < 1) {
@ -56,23 +56,6 @@ class EpisodeBrief {
}
}
String downloadDateToString() {
DateTime date = DateTime.fromMillisecondsSinceEpoch(downloadDate);
var diffrence = DateTime.now().toUtc().difference(date);
if (diffrence.inHours < 1) {
return '1 hour ago';
} else if (diffrence.inHours < 24) {
return '${diffrence.inHours} hours ago';
} else if (diffrence.inHours == 24) {
return '1 day ago';
} else if (diffrence.inDays < 7) {
return '${diffrence.inDays} days ago';
} else {
return DateFormat.yMMMd().format(
DateTime.fromMillisecondsSinceEpoch(pubDate, isUtc: true).toLocal());
}
}
MediaItem toMediaItem() {
return MediaItem(
id: mediaId,

View File

@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:focused_menu/focused_menu.dart';
import 'package:focused_menu/modals.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:tuple/tuple.dart';
import 'package:line_icons/line_icons.dart';
@ -12,10 +13,10 @@ import 'package:fluttertoast/fluttertoast.dart';
import 'package:auto_animated/auto_animated.dart';
import 'open_container.dart';
import '../state/audiostate.dart';
import '../state/audio_state.dart';
import '../state/download_state.dart';
import '../type/episodebrief.dart';
import '../episodes/episodedetail.dart';
import '../episodes/episode_detail.dart';
import '../local_storage/sqflite_localpodcast.dart';
import '../local_storage/key_value_storage.dart';
import 'colorize.dart';
@ -45,6 +46,19 @@ class EpisodeGrid extends StatelessWidget {
this.layout = Layout.three,
this.reverse,
}) : super(key: key);
String _dateToString(BuildContext context, {int pubDate}) {
final s = context.s;
DateTime date = DateTime.fromMillisecondsSinceEpoch(pubDate, isUtc: true);
var difference = DateTime.now().toUtc().difference(date);
if (difference.inHours < 24) {
return s.hoursAgo(difference.inHours);
} else if (difference.inDays < 7) {
return s.daysAgo(difference.inDays);
} else {
return DateFormat.yMMMd().format(
DateTime.fromMillisecondsSinceEpoch(pubDate, isUtc: true).toLocal());
}
}
Future<int> _isListened(EpisodeBrief episode) async {
DBHelper dbHelper = DBHelper();
@ -210,7 +224,7 @@ class EpisodeGrid extends StatelessWidget {
Widget _pubDate(BuildContext context, {EpisodeBrief episode, Color color}) =>
Text(
episode.dateToString(),
_dateToString(context, pubDate: episode.pubDate),
style: TextStyle(
fontSize: context.width / 35,
color: color,