diff --git a/README.md b/README.md index 8f952ad..46b1156 100644 --- a/README.md +++ b/README.md @@ -4,40 +4,36 @@

-![CircleCI](https://img.shields.io/circleci/build/github/stonega/tsacdop?token=efe1331861e017144f2abb363acd95197e436dad) - - - -![GitHub release (latest by date)](https://img.shields.io/github/v/release/stonega/tsacdop) [![GooglePlay](https://img.shields.io/badge/Google-PlayStore-%2323CCC6)](https://play.google.com/store/apps/details?id=com.stonegate.tsacdop) +![CircleCI](https://img.shields.io/circleci/build/github/stonega/tsacdop?token=efe1331861e017144f2abb363acd95197e436dad) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/stonega/tsacdop) [![GooglePlay](https://img.shields.io/badge/Google-PlayStore-%2323CCC6)](https://play.google.com/store/apps/details?id=com.stonegate.tsacdop) ## About Enjoy podcasts with Tsacdop. -Tsacdop is a podcast player developed with flutter, a clean, simply beautiful and friendly app, only support Android right now. +Tsacdop is a podcast player developed with flutter, a clean, simply beautiful and friendly app, only support Android right now. -Credit to flutter team and all involved plugins, especially [webfeed](https://github.com/witochandra/webfeed) and [Just_Audio](https://pub.dev/packages/just_audio). +Credit to flutter team and all involved plugins, especially [webfeed](https://github.com/witochandra/webfeed) and [Just_Audio](https://pub.dev/packages/just_audio). The podcasts search engine is powered by [ListenNotes](https://listennotes.com). ## Features -* Podcasts group management -* Playlist support -* Sleep timer / Speed setting -* OMPL file export and import -* Auto syncing in background -* Listen and subscribe history record -* Dark mode / Accent color -* Download for offline playing -* Auto download new episodes / Auto delete outdated downloads +- Podcasts group management +- Playlist support +- Sleep timer / Speed setting +- OMPL file export and import +- Auto syncing in background +- Listen and subscribe history record +- Dark mode / Accent color +- Download for offline playing +- Auto download new episodes / Auto delete outdated downloads More to come... ## Preview | HomePage | Group | Podcast | Episode | DarkMode | -|------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------| +| ---------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | | | | | | | ## License @@ -49,8 +45,8 @@ Tsacdop is licensed under the [GPL V3.0](https://github.com/stonega/tsacdop/blob Tsacdop is using ListenNotes api 1.0 pro to search podcast, which is not free. So I can not expose the api key in the repo. If you want to build the app, you need to create a new file named .env.dart in lib folder. Add below code in .env.dart. -``` -final environment = {"apiKey":"APIKEY", "shareKey":"SHAREKEY"}; +```dart +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. @@ -58,7 +54,7 @@ If no api key added, the search function in the app won't work. But you can stil ## Known Issue -* Playlist unstable +- Playlist unstable ## Getting Started @@ -66,10 +62,8 @@ This project is a starting point for a Flutter application. A few resources to get you started if this is your first Flutter project: -* [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) -* [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) For help getting started with Flutter, view our -[online documentation](https://flutter.dev/docs), which offers tutorials, -samples, guidance on mobile development, and a full API reference. - +[online documentation](https://flutter.dev/docs), which offers tutorials, samples, guidance on mobile development, and a full API reference. diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart index 5c3f786..67255d2 100644 --- a/lib/generated/intl/messages_en.dart +++ b/lib/generated/intl/messages_en.dart @@ -19,27 +19,85 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'en'; + static m0(groupName, count) => "${Intl.plural(count, zero: '', one: '${count} episode in ${groupName} added to playlist', other: '${count} episodes in ${groupName} added to playlist')}"; + + static m1(count) => "${Intl.plural(count, zero: '', one: '${count} episode added to playlist', other: '${count} episodes added to playlist')}"; + + static m2(host) => "Hosted on ${host}"; + + static m3(count) => "${Intl.plural(count, zero: '', one: '${count} hour', other: '${count} hours')}"; + + static m4(count) => "${Intl.plural(count, zero: '', one: '${count} min', other: '${count} mins')}"; + + static m5(title) => "Fetch data ${title}"; + + static m6(title) => "Subscribe failed, network error ${title}"; + + static m7(title) => "Subscribe ${title}"; + + static m8(title) => "Subscribe failed, podcast existed ${title}"; + + static m9(title) => "Subscribe success ${title}"; + + static m10(title) => "Update ${title}"; + + static m11(title) => "Update error ${title}"; + + static m12(time) => "Last time ${time}"; + + static m13(time) => "${time} Left"; + + static m14(count) => "${Intl.plural(count, zero: 'No Update', one: 'Updated ${count} Episode', other: 'Updated ${count} Episodes')}"; + + static m15(version) => "Version : ${version}"; + final messages = _notInlinedMessages(_notInlinedMessages); static _notInlinedMessages(_) => { + "add" : MessageLookupByLibrary.simpleMessage("Add"), + "addEpisodeGroup" : m0, + "addNewEpisodeAll" : m1, + "addNewEpisodeTooltip" : MessageLookupByLibrary.simpleMessage("Add new episodes to playlist"), + "addSomeGroups" : MessageLookupByLibrary.simpleMessage("Add some groups"), "all" : MessageLookupByLibrary.simpleMessage("All"), - "cancel" : MessageLookupByLibrary.simpleMessage("Cancel"), + "back" : MessageLookupByLibrary.simpleMessage("Back"), + "buffering" : MessageLookupByLibrary.simpleMessage("Buffering"), + "cancel" : MessageLookupByLibrary.simpleMessage("CANCEL"), + "changeLayout" : MessageLookupByLibrary.simpleMessage("Change layout"), + "changelog" : MessageLookupByLibrary.simpleMessage("Changelog"), "chooseA" : MessageLookupByLibrary.simpleMessage("Choose a"), + "clear" : MessageLookupByLibrary.simpleMessage("Clear"), "color" : MessageLookupByLibrary.simpleMessage("color"), - "confirm" : MessageLookupByLibrary.simpleMessage("Confirm"), + "confirm" : MessageLookupByLibrary.simpleMessage("CONFIRM"), "darkMode" : MessageLookupByLibrary.simpleMessage("Dark mode"), "delete" : MessageLookupByLibrary.simpleMessage("Delete"), + "developer" : MessageLookupByLibrary.simpleMessage("Developer"), + "dismiss" : MessageLookupByLibrary.simpleMessage("Dismiss"), "download" : MessageLookupByLibrary.simpleMessage("Download"), + "downloaded" : MessageLookupByLibrary.simpleMessage("Downloaded"), "editName" : MessageLookupByLibrary.simpleMessage("Edit name"), "endOfEpisode" : MessageLookupByLibrary.simpleMessage("End of Episode"), + "featureDiscoveryEpisode" : MessageLookupByLibrary.simpleMessage("Episode view"), + "featureDiscoveryEpisodeDes" : MessageLookupByLibrary.simpleMessage("You can long tap to play episode or add episode to playlist."), + "featureDiscoveryEpisodeTitle" : MessageLookupByLibrary.simpleMessage("Long tap to play episode instantly"), + "featureDiscoveryOMPL" : MessageLookupByLibrary.simpleMessage("Tap to import OMPL"), + "featureDiscoveryOMPLDes" : MessageLookupByLibrary.simpleMessage("You can import OMPL file, open setting or refresh all podcast at once here."), + "featureDiscoveryPlaylist" : MessageLookupByLibrary.simpleMessage("Tap to open playlist"), + "featureDiscoveryPlaylistDes" : MessageLookupByLibrary.simpleMessage("You can add episode to playlist by yourself. Episode will be auto removed from playlist when played."), + "featureDiscoveryPodcast" : MessageLookupByLibrary.simpleMessage("Podcast view"), + "featureDiscoveryPodcastDes" : MessageLookupByLibrary.simpleMessage("You can tap See All to add groups or manage podcasts."), + "featureDiscoveryPodcastTitle" : MessageLookupByLibrary.simpleMessage("Scroll vertically to switch groups"), + "featureDiscoverySearch" : MessageLookupByLibrary.simpleMessage("Tap to search podcast"), + "featureDiscoverySearchDes" : MessageLookupByLibrary.simpleMessage("You can search podcast title , key word or RSS link to subscribe new podcast."), "feedbackEmail" : MessageLookupByLibrary.simpleMessage("Write to me"), "feedbackGithub" : MessageLookupByLibrary.simpleMessage("Submit issue"), "feedbackPlay" : MessageLookupByLibrary.simpleMessage("Rate on Play"), "feedbackTelegram" : MessageLookupByLibrary.simpleMessage("Join group"), "from" : MessageLookupByLibrary.simpleMessage("From"), + "goodNight" : MessageLookupByLibrary.simpleMessage("Good Night"), + "groupFilter" : MessageLookupByLibrary.simpleMessage("Group filter"), "groups" : MessageLookupByLibrary.simpleMessage("Groups"), "homeGroupsSeeAll" : MessageLookupByLibrary.simpleMessage("See All"), "homeMenuPlaylist" : MessageLookupByLibrary.simpleMessage("Playlist"), - "homeSubMenuDownloaded" : MessageLookupByLibrary.simpleMessage("Downloaded"), "homeSubMenuLikeData" : MessageLookupByLibrary.simpleMessage("Like Date"), "homeSubMenuSortBy" : MessageLookupByLibrary.simpleMessage("Sort by"), "homeSubMenuUpdateDate" : MessageLookupByLibrary.simpleMessage("Update Date"), @@ -49,29 +107,52 @@ class MessageLookup extends MessageLookupByLibrary { "homeToprightMenuImportOMPL" : MessageLookupByLibrary.simpleMessage("Import OMPL"), "homeToprightMenuRefreshAll" : MessageLookupByLibrary.simpleMessage("Refresh all"), "homeToprightMenuSettings" : MessageLookupByLibrary.simpleMessage("Settings"), + "hostedOn" : m2, + "hoursCount" : m3, "later" : MessageLookupByLibrary.simpleMessage("Later"), "lightMode" : MessageLookupByLibrary.simpleMessage("Light mode"), "like" : MessageLookupByLibrary.simpleMessage("Like"), + "likeDate" : MessageLookupByLibrary.simpleMessage("Like date"), "liked" : MessageLookupByLibrary.simpleMessage("Liked"), "listen" : MessageLookupByLibrary.simpleMessage("Listen"), "listened" : MessageLookupByLibrary.simpleMessage("Listened"), + "loadMore" : MessageLookupByLibrary.simpleMessage("Load more"), + "markConfirm" : MessageLookupByLibrary.simpleMessage("Mark confirm"), + "markConfirmContent" : MessageLookupByLibrary.simpleMessage("Confirm mark all episodes listened?"), "markListened" : MessageLookupByLibrary.simpleMessage("Mark listened"), "menu" : MessageLookupByLibrary.simpleMessage("Menu"), "menuAllPodcasts" : MessageLookupByLibrary.simpleMessage("All podcasts"), "menuMarkAllListened" : MessageLookupByLibrary.simpleMessage("Mark All Listened"), - "menuMarkListened" : MessageLookupByLibrary.simpleMessage("Mark Listened"), "menuViewRSS" : MessageLookupByLibrary.simpleMessage("Visit RSS Feed"), "menuVisitSite" : MessageLookupByLibrary.simpleMessage("Visit Site"), + "minsCount" : m4, "network" : MessageLookupByLibrary.simpleMessage("Network"), "newGroup" : MessageLookupByLibrary.simpleMessage("Create new group"), + "newestFirst" : MessageLookupByLibrary.simpleMessage("Newest first"), + "noEpisodeDownload" : MessageLookupByLibrary.simpleMessage("No episode downloaded yet"), + "noEpisodeFavorite" : MessageLookupByLibrary.simpleMessage("No episode collected yet"), + "noEpisodeRecent" : MessageLookupByLibrary.simpleMessage("No episode received yet"), + "noPodcastGroup" : MessageLookupByLibrary.simpleMessage("No podcast in this group"), + "notificaitonFatch" : m5, + "notificationNetworkError" : m6, + "notificationSubscribe" : m7, + "notificationSubscribeExisted" : m8, + "notificationSuccess" : m9, + "notificationUpdate" : m10, + "notificationUpdateError" : m11, + "oldestFirst" : MessageLookupByLibrary.simpleMessage("Oldest first"), "play" : MessageLookupByLibrary.simpleMessage("Play"), + "playing" : MessageLookupByLibrary.simpleMessage("Playing"), + "podcastSubscribed" : MessageLookupByLibrary.simpleMessage("Podcast subscribed"), "popupMenuDownloadDes" : MessageLookupByLibrary.simpleMessage("Download episode"), "popupMenuLaterDes" : MessageLookupByLibrary.simpleMessage("Add episode to playlist"), "popupMenuLikeDes" : MessageLookupByLibrary.simpleMessage("Add episode to favorite"), "popupMenuMarkDes" : MessageLookupByLibrary.simpleMessage("Mark episode as listened"), "popupMenuPlayDes" : MessageLookupByLibrary.simpleMessage("Play the episode"), + "privacyPolicy" : MessageLookupByLibrary.simpleMessage("Privacy Policy"), "remove" : MessageLookupByLibrary.simpleMessage("Remove"), "schedule" : MessageLookupByLibrary.simpleMessage("Schedule"), + "searchInvalidRss" : MessageLookupByLibrary.simpleMessage("Invalid RSS link"), "searchPodcast" : MessageLookupByLibrary.simpleMessage("Search podcast"), "settingStorage" : MessageLookupByLibrary.simpleMessage("Storage"), "settingsAccentColor" : MessageLookupByLibrary.simpleMessage("Accent color"), @@ -128,9 +209,12 @@ class MessageLookup extends MessageLookupByLibrary { "settingsTheme" : MessageLookupByLibrary.simpleMessage("Theme"), "settingsUpdateInterval" : MessageLookupByLibrary.simpleMessage("Update interval"), "settingsUpdateIntervalDes" : MessageLookupByLibrary.simpleMessage("Default 24 hours"), + "size" : MessageLookupByLibrary.simpleMessage("Size"), "sleepTimer" : MessageLookupByLibrary.simpleMessage("Sleep timer"), "subscribe" : MessageLookupByLibrary.simpleMessage("Subscribe"), "systemDefault" : MessageLookupByLibrary.simpleMessage("System default"), + "timeLastPlayed" : m12, + "timeLeft" : m13, "to" : MessageLookupByLibrary.simpleMessage("To"), "toastAddPlaylist" : MessageLookupByLibrary.simpleMessage("Added to playlist"), "toastDescovery" : MessageLookupByLibrary.simpleMessage("Discovery feature reopened, pleast restart the app"), @@ -138,7 +222,12 @@ class MessageLookup extends MessageLookupByLibrary { "toastFileNotVilid" : MessageLookupByLibrary.simpleMessage("File not vilid"), "toastReadFile" : MessageLookupByLibrary.simpleMessage("Read file successfully"), "toastRemovePlaylist" : MessageLookupByLibrary.simpleMessage("Removed from playlist"), + "understood" : MessageLookupByLibrary.simpleMessage("Understood"), "unlike" : MessageLookupByLibrary.simpleMessage("Unlike"), - "unliked" : MessageLookupByLibrary.simpleMessage("Unliked") + "unliked" : MessageLookupByLibrary.simpleMessage("Removed from favorite"), + "updateDate" : MessageLookupByLibrary.simpleMessage("Update date"), + "updateEpisodesCount" : m14, + "updateFailed" : MessageLookupByLibrary.simpleMessage("Update failed, network error"), + "version" : m15 }; } diff --git a/lib/generated/intl/messages_zh-Hans.dart b/lib/generated/intl/messages_zh-Hans.dart index 435ef80..5f95c0b 100644 --- a/lib/generated/intl/messages_zh-Hans.dart +++ b/lib/generated/intl/messages_zh-Hans.dart @@ -19,27 +19,85 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'zh_Hans'; + static m0(groupName, count) => "{count, plural, zero{} other{{group Name}分组${count}集节目添加到播放列表}}"; + + static m1(count) => "${Intl.plural(count, zero: '', other: '${count}集节目添加到播放列表')}"; + + static m2(host) => "平台 ${host}"; + + static m3(count) => "${Intl.plural(count, zero: '', other: '${count} 小时')}"; + + static m4(count) => "${Intl.plural(count, zero: '', other: '${count}分钟')}"; + + static m5(title) => "获取数据 ${title}"; + + static m6(title) => "订阅失败,网络错误 ${title}"; + + static m7(title) => "订阅${title}"; + + static m8(title) => "订阅失败,播客已存在 ${title}"; + + static m9(title) => "订阅成功 ${title}"; + + static m10(title) => "更新 ${title}"; + + static m11(title) => "更新失败 ${title}"; + + static m12(time) => "上次播放${time}"; + + static m13(time) => "剩余 ${time}"; + + static m14(count) => "${Intl.plural(count, zero: '未有更新', other: '更新 ${count} 集节目')}"; + + static m15(version) => "版本:${version}"; + final messages = _notInlinedMessages(_notInlinedMessages); static _notInlinedMessages(_) => { + "add" : MessageLookupByLibrary.simpleMessage("订阅"), + "addEpisodeGroup" : m0, + "addNewEpisodeAll" : m1, + "addNewEpisodeTooltip" : MessageLookupByLibrary.simpleMessage("添加更新节目到播放列表"), + "addSomeGroups" : MessageLookupByLibrary.simpleMessage("请添加分组"), "all" : MessageLookupByLibrary.simpleMessage("全部"), + "back" : MessageLookupByLibrary.simpleMessage("返回"), + "buffering" : MessageLookupByLibrary.simpleMessage("缓冲"), "cancel" : MessageLookupByLibrary.simpleMessage("取消"), + "changeLayout" : MessageLookupByLibrary.simpleMessage("修改布局"), + "changelog" : MessageLookupByLibrary.simpleMessage("更新日志"), "chooseA" : MessageLookupByLibrary.simpleMessage("选择"), + "clear" : MessageLookupByLibrary.simpleMessage("清除"), "color" : MessageLookupByLibrary.simpleMessage("颜色"), "confirm" : MessageLookupByLibrary.simpleMessage("确认"), "darkMode" : MessageLookupByLibrary.simpleMessage("夜晚模式"), "delete" : MessageLookupByLibrary.simpleMessage("删除"), + "developer" : MessageLookupByLibrary.simpleMessage("关于我"), + "dismiss" : MessageLookupByLibrary.simpleMessage("忽略"), "download" : MessageLookupByLibrary.simpleMessage("下载"), + "downloaded" : MessageLookupByLibrary.simpleMessage("已下载"), "editName" : MessageLookupByLibrary.simpleMessage("修改组名"), "endOfEpisode" : MessageLookupByLibrary.simpleMessage("节目结束"), + "featureDiscoveryEpisode" : MessageLookupByLibrary.simpleMessage("节目界面"), + "featureDiscoveryEpisodeDes" : MessageLookupByLibrary.simpleMessage("您可以长按播放节目或者添加节目到播放列表。"), + "featureDiscoveryEpisodeTitle" : MessageLookupByLibrary.simpleMessage("您可以长按快速播放节目"), + "featureDiscoveryOMPL" : MessageLookupByLibrary.simpleMessage("点击导入 OMPL"), + "featureDiscoveryOMPLDes" : MessageLookupByLibrary.simpleMessage("在这里您可以导入OMPL文件,打开设置页面,或者刷新所有播客。"), + "featureDiscoveryPlaylist" : MessageLookupByLibrary.simpleMessage("点击打开播放列表"), + "featureDiscoveryPlaylistDes" : MessageLookupByLibrary.simpleMessage("您可以添加节目到播放列表,节目在播放后将会从播放列表自动移除。"), + "featureDiscoveryPodcast" : MessageLookupByLibrary.simpleMessage("播客界面"), + "featureDiscoveryPodcastDes" : MessageLookupByLibrary.simpleMessage("您可以点击“查看所有”新增或管理分组。"), + "featureDiscoveryPodcastTitle" : MessageLookupByLibrary.simpleMessage("您可以通过上下滑动切换分组"), + "featureDiscoverySearch" : MessageLookupByLibrary.simpleMessage("点击搜索播客"), + "featureDiscoverySearchDes" : MessageLookupByLibrary.simpleMessage("您可以通过搜索播客名称、关键字或者RSS链接订阅播客。"), "feedbackEmail" : MessageLookupByLibrary.simpleMessage("发送邮件"), "feedbackGithub" : MessageLookupByLibrary.simpleMessage("提交Issue"), "feedbackPlay" : MessageLookupByLibrary.simpleMessage("Play评价"), "feedbackTelegram" : MessageLookupByLibrary.simpleMessage("加入小组"), "from" : MessageLookupByLibrary.simpleMessage("自"), + "goodNight" : MessageLookupByLibrary.simpleMessage("晚安"), + "groupFilter" : MessageLookupByLibrary.simpleMessage("分组"), "groups" : MessageLookupByLibrary.simpleMessage("分组"), "homeGroupsSeeAll" : MessageLookupByLibrary.simpleMessage("查看全部"), "homeMenuPlaylist" : MessageLookupByLibrary.simpleMessage("播放列表"), - "homeSubMenuDownloaded" : MessageLookupByLibrary.simpleMessage("已下载"), "homeSubMenuLikeData" : MessageLookupByLibrary.simpleMessage("添加日期"), "homeSubMenuSortBy" : MessageLookupByLibrary.simpleMessage("排序"), "homeSubMenuUpdateDate" : MessageLookupByLibrary.simpleMessage("更新日期"), @@ -49,29 +107,52 @@ class MessageLookup extends MessageLookupByLibrary { "homeToprightMenuImportOMPL" : MessageLookupByLibrary.simpleMessage("导入OMPL"), "homeToprightMenuRefreshAll" : MessageLookupByLibrary.simpleMessage("全部刷新"), "homeToprightMenuSettings" : MessageLookupByLibrary.simpleMessage("设置"), + "hostedOn" : m2, + "hoursCount" : m3, "later" : MessageLookupByLibrary.simpleMessage("稍后"), "lightMode" : MessageLookupByLibrary.simpleMessage("明亮模式"), "like" : MessageLookupByLibrary.simpleMessage("喜欢"), + "likeDate" : MessageLookupByLibrary.simpleMessage("收藏日期"), "liked" : MessageLookupByLibrary.simpleMessage("已收藏"), "listen" : MessageLookupByLibrary.simpleMessage("收听"), "listened" : MessageLookupByLibrary.simpleMessage("已收听"), + "loadMore" : MessageLookupByLibrary.simpleMessage("加载更多"), + "markConfirm" : MessageLookupByLibrary.simpleMessage("确认标记"), + "markConfirmContent" : MessageLookupByLibrary.simpleMessage("是否确认标记全部节目为已收听?"), "markListened" : MessageLookupByLibrary.simpleMessage("标记已收听"), "menu" : MessageLookupByLibrary.simpleMessage("菜单"), "menuAllPodcasts" : MessageLookupByLibrary.simpleMessage("所有订阅"), "menuMarkAllListened" : MessageLookupByLibrary.simpleMessage("标记所有已收听"), - "menuMarkListened" : MessageLookupByLibrary.simpleMessage("标记已收听"), "menuViewRSS" : MessageLookupByLibrary.simpleMessage("查看 RSS"), "menuVisitSite" : MessageLookupByLibrary.simpleMessage("访问网站"), + "minsCount" : m4, "network" : MessageLookupByLibrary.simpleMessage("网络"), "newGroup" : MessageLookupByLibrary.simpleMessage("创建分组"), + "newestFirst" : MessageLookupByLibrary.simpleMessage("由新到旧"), + "noEpisodeDownload" : MessageLookupByLibrary.simpleMessage("暂无下载节目"), + "noEpisodeFavorite" : MessageLookupByLibrary.simpleMessage("暂无收藏节目"), + "noEpisodeRecent" : MessageLookupByLibrary.simpleMessage("暂无节目"), + "noPodcastGroup" : MessageLookupByLibrary.simpleMessage("分组无播客"), + "notificaitonFatch" : m5, + "notificationNetworkError" : m6, + "notificationSubscribe" : m7, + "notificationSubscribeExisted" : m8, + "notificationSuccess" : m9, + "notificationUpdate" : m10, + "notificationUpdateError" : m11, + "oldestFirst" : MessageLookupByLibrary.simpleMessage("由旧到新"), "play" : MessageLookupByLibrary.simpleMessage("播放"), + "playing" : MessageLookupByLibrary.simpleMessage("正在播放"), + "podcastSubscribed" : MessageLookupByLibrary.simpleMessage("播客已订阅"), "popupMenuDownloadDes" : MessageLookupByLibrary.simpleMessage("下载节目"), "popupMenuLaterDes" : MessageLookupByLibrary.simpleMessage("添加到播放列表"), "popupMenuLikeDes" : MessageLookupByLibrary.simpleMessage("添加到收藏"), "popupMenuMarkDes" : MessageLookupByLibrary.simpleMessage("设置为已收听"), "popupMenuPlayDes" : MessageLookupByLibrary.simpleMessage("播放节目"), + "privacyPolicy" : MessageLookupByLibrary.simpleMessage("隐私条款"), "remove" : MessageLookupByLibrary.simpleMessage("移除"), "schedule" : MessageLookupByLibrary.simpleMessage("定时"), + "searchInvalidRss" : MessageLookupByLibrary.simpleMessage("RSS 链接错误"), "searchPodcast" : MessageLookupByLibrary.simpleMessage("搜索播客"), "settingStorage" : MessageLookupByLibrary.simpleMessage("储存空间"), "settingsAccentColor" : MessageLookupByLibrary.simpleMessage("次要颜色"), @@ -128,9 +209,12 @@ class MessageLookup extends MessageLookupByLibrary { "settingsTheme" : MessageLookupByLibrary.simpleMessage("主题"), "settingsUpdateInterval" : MessageLookupByLibrary.simpleMessage("更新频率"), "settingsUpdateIntervalDes" : MessageLookupByLibrary.simpleMessage("默认 24 小时"), + "size" : MessageLookupByLibrary.simpleMessage("大小"), "sleepTimer" : MessageLookupByLibrary.simpleMessage("睡眠模式"), "subscribe" : MessageLookupByLibrary.simpleMessage("订阅"), "systemDefault" : MessageLookupByLibrary.simpleMessage("系统默认"), + "timeLastPlayed" : m12, + "timeLeft" : m13, "to" : MessageLookupByLibrary.simpleMessage("到"), "toastAddPlaylist" : MessageLookupByLibrary.simpleMessage("添加到播放列表"), "toastDescovery" : MessageLookupByLibrary.simpleMessage("重启应用后可查看"), @@ -138,7 +222,12 @@ class MessageLookup extends MessageLookupByLibrary { "toastFileNotVilid" : MessageLookupByLibrary.simpleMessage("文件错误"), "toastReadFile" : MessageLookupByLibrary.simpleMessage("读取文件成功"), "toastRemovePlaylist" : MessageLookupByLibrary.simpleMessage("从播放列表移除"), + "understood" : MessageLookupByLibrary.simpleMessage("了解"), "unlike" : MessageLookupByLibrary.simpleMessage("取消喜欢"), - "unliked" : MessageLookupByLibrary.simpleMessage("从收藏移除") + "unliked" : MessageLookupByLibrary.simpleMessage("从收藏移除"), + "updateDate" : MessageLookupByLibrary.simpleMessage("更新日期"), + "updateEpisodesCount" : m14, + "updateFailed" : MessageLookupByLibrary.simpleMessage("更新失败"), + "version" : m15 }; } diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart index 8928f4c..643066f 100644 --- a/lib/generated/l10n.dart +++ b/lib/generated/l10n.dart @@ -33,6 +33,62 @@ class S { return Localizations.of(context, S); } + /// `Add` + String get add { + return Intl.message( + 'Add', + name: 'add', + desc: 'Subscribe new podcast', + args: [], + ); + } + + /// `{count, plural, zero{} one{{count} episode in {groupName} added to playlist} other{{count} episodes in {groupName} added to playlist}}` + String addEpisodeGroup(Object groupName, num count) { + return Intl.plural( + count, + zero: '', + one: '$count episode in $groupName added to playlist', + other: '$count episodes in $groupName added to playlist', + name: 'addEpisodeGroup', + desc: '', + args: [groupName, count], + ); + } + + /// `{count, plural, zero{} one{{count} episode added to playlist} other{{count} episodes added to playlist}}` + String addNewEpisodeAll(num count) { + return Intl.plural( + count, + zero: '', + one: '$count episode added to playlist', + other: '$count episodes added to playlist', + name: 'addNewEpisodeAll', + desc: '', + args: [count], + ); + } + + /// `Add new episodes to playlist` + String get addNewEpisodeTooltip { + return Intl.message( + 'Add new episodes to playlist', + name: 'addNewEpisodeTooltip', + desc: '', + args: [], + ); + } + + /// `Add some groups` + String get addSomeGroups { + return Intl.message( + 'Add some groups', + name: 'addSomeGroups', + desc: 'Please add new groups', + args: [], + ); + } + /// `All` String get all { return Intl.message( @@ -43,16 +99,56 @@ class S { ); } - /// `Cancel` + /// `Back` + String get back { + return Intl.message( + 'Back', + name: 'back', + desc: '', + args: [], + ); + } + + /// `Buffering` + String get buffering { + return Intl.message( + 'Buffering', + name: 'buffering', + desc: '', + args: [], + ); + } + + /// `CANCEL` String get cancel { return Intl.message( - 'Cancel', + 'CANCEL', name: 'cancel', desc: '', args: [], ); } + /// `Change layout` + String get changeLayout { + return Intl.message( + 'Change layout', + name: 'changeLayout', + desc: '', + args: [], + ); + } + + /// `Changelog` + String get changelog { + return Intl.message( + 'Changelog', + name: 'changelog', + desc: '', + args: [], + ); + } + /// `Choose a` String get chooseA { return Intl.message( @@ -63,6 +159,16 @@ class S { ); } + /// `Clear` + String get clear { + return Intl.message( + 'Clear', + name: 'clear', + desc: '', + args: [], + ); + } + /// `color` String get color { return Intl.message( @@ -73,10 +179,10 @@ class S { ); } - /// `Confirm` + /// `CONFIRM` String get confirm { return Intl.message( - 'Confirm', + 'CONFIRM', name: 'confirm', desc: '', args: [], @@ -103,6 +209,26 @@ class S { ); } + /// `Developer` + String get developer { + return Intl.message( + 'Developer', + name: 'developer', + desc: '', + args: [], + ); + } + + /// `Dismiss` + String get dismiss { + return Intl.message( + 'Dismiss', + name: 'dismiss', + desc: '', + args: [], + ); + } + /// `Download` String get download { return Intl.message( @@ -113,6 +239,16 @@ class S { ); } + /// `Downloaded` + String get downloaded { + return Intl.message( + 'Downloaded', + name: 'downloaded', + desc: '', + args: [], + ); + } + /// `Edit name` String get editName { return Intl.message( @@ -133,6 +269,126 @@ class S { ); } + /// `Episode view` + String get featureDiscoveryEpisode { + return Intl.message( + 'Episode view', + name: 'featureDiscoveryEpisode', + desc: '', + args: [], + ); + } + + /// `You can long tap to play episode or add episode to playlist.` + String get featureDiscoveryEpisodeDes { + return Intl.message( + 'You can long tap to play episode or add episode to playlist.', + name: 'featureDiscoveryEpisodeDes', + desc: '', + args: [], + ); + } + + /// `Long tap to play episode instantly` + String get featureDiscoveryEpisodeTitle { + return Intl.message( + 'Long tap to play episode instantly', + name: 'featureDiscoveryEpisodeTitle', + desc: '', + args: [], + ); + } + + /// `Tap to import OMPL` + String get featureDiscoveryOMPL { + return Intl.message( + 'Tap to import OMPL', + name: 'featureDiscoveryOMPL', + desc: '', + args: [], + ); + } + + /// `You can import OMPL file, open setting or refresh all podcast at once here.` + String get featureDiscoveryOMPLDes { + return Intl.message( + 'You can import OMPL file, open setting or refresh all podcast at once here.', + name: 'featureDiscoveryOMPLDes', + desc: '', + args: [], + ); + } + + /// `Tap to open playlist` + String get featureDiscoveryPlaylist { + return Intl.message( + 'Tap to open playlist', + name: 'featureDiscoveryPlaylist', + desc: '', + args: [], + ); + } + + /// `You can add episode to playlist by yourself. Episode will be auto removed from playlist when played.` + String get featureDiscoveryPlaylistDes { + return Intl.message( + 'You can add episode to playlist by yourself. Episode will be auto removed from playlist when played.', + name: 'featureDiscoveryPlaylistDes', + desc: '', + args: [], + ); + } + + /// `Podcast view` + String get featureDiscoveryPodcast { + return Intl.message( + 'Podcast view', + name: 'featureDiscoveryPodcast', + desc: '', + args: [], + ); + } + + /// `You can tap See All to add groups or manage podcasts.` + String get featureDiscoveryPodcastDes { + return Intl.message( + 'You can tap See All to add groups or manage podcasts.', + name: 'featureDiscoveryPodcastDes', + desc: '', + args: [], + ); + } + + /// `Scroll vertically to switch groups` + String get featureDiscoveryPodcastTitle { + return Intl.message( + 'Scroll vertically to switch groups', + name: 'featureDiscoveryPodcastTitle', + desc: '', + args: [], + ); + } + + /// `Tap to search podcast` + String get featureDiscoverySearch { + return Intl.message( + 'Tap to search podcast', + name: 'featureDiscoverySearch', + desc: '', + args: [], + ); + } + + /// `You can search podcast title , key word or RSS link to subscribe new podcast.` + String get featureDiscoverySearchDes { + return Intl.message( + 'You can search podcast title , key word or RSS link to subscribe new podcast.', + name: 'featureDiscoverySearchDes', + desc: '', + args: [], + ); + } + /// `Write to me` String get feedbackEmail { return Intl.message( @@ -183,6 +439,26 @@ class S { ); } + /// `Good Night` + String get goodNight { + return Intl.message( + 'Good Night', + name: 'goodNight', + desc: '', + args: [], + ); + } + + /// `Group filter` + String get groupFilter { + return Intl.message( + 'Group filter', + name: 'groupFilter', + desc: '', + args: [], + ); + } + /// `Groups` String get groups { return Intl.message( @@ -213,16 +489,6 @@ class S { ); } - /// `Downloaded` - String get homeSubMenuDownloaded { - return Intl.message( - 'Downloaded', - name: 'homeSubMenuDownloaded', - desc: '', - args: [], - ); - } - /// `Like Date` String get homeSubMenuLikeData { return Intl.message( @@ -313,6 +579,29 @@ class S { ); } + /// `Hosted on {host}` + String hostedOn(Object host) { + return Intl.message( + 'Hosted on $host', + name: 'hostedOn', + desc: '', + args: [host], + ); + } + + /// `{count, plural, zero{} one{{count} hour} other{{count} hours}}` + String hoursCount(num count) { + return Intl.plural( + count, + zero: '', + one: '$count hour', + other: '$count hours', + name: 'hoursCount', + desc: '', + args: [count], + ); + } + /// `Later` String get later { return Intl.message( @@ -353,6 +642,16 @@ class S { ); } + /// `Like date` + String get likeDate { + return Intl.message( + 'Like date', + name: 'likeDate', + desc: '', + args: [], + ); + } + /// `Listen` String get listen { return Intl.message( @@ -373,6 +672,36 @@ class S { ); } + /// `Load more` + String get loadMore { + return Intl.message( + 'Load more', + name: 'loadMore', + desc: '', + args: [], + ); + } + + /// `Mark confirm` + String get markConfirm { + return Intl.message( + 'Mark confirm', + name: 'markConfirm', + desc: '', + args: [], + ); + } + + /// `Confirm mark all episodes listened?` + String get markConfirmContent { + return Intl.message( + 'Confirm mark all episodes listened?', + name: 'markConfirmContent', + desc: '', + args: [], + ); + } + /// `Mark listened` String get markListened { return Intl.message( @@ -413,16 +742,6 @@ class S { ); } - /// `Mark Listened` - String get menuMarkListened { - return Intl.message( - 'Mark Listened', - name: 'menuMarkListened', - desc: '', - args: [], - ); - } - /// `Visit RSS Feed` String get menuViewRSS { return Intl.message( @@ -443,6 +762,19 @@ class S { ); } + /// `{count, plural, zero{} one{{count} min} other{{count} mins}}` + String minsCount(num count) { + return Intl.plural( + count, + zero: '', + one: '$count min', + other: '$count mins', + name: 'minsCount', + desc: '', + args: [count], + ); + } + /// `Network` String get network { return Intl.message( @@ -453,6 +785,16 @@ class S { ); } + /// `Newest first` + String get newestFirst { + return Intl.message( + 'Newest first', + name: 'newestFirst', + desc: '', + args: [], + ); + } + /// `Create new group` String get newGroup { return Intl.message( @@ -463,6 +805,126 @@ class S { ); } + /// `No episode downloaded yet` + String get noEpisodeDownload { + return Intl.message( + 'No episode downloaded yet', + name: 'noEpisodeDownload', + desc: '', + args: [], + ); + } + + /// `No episode collected yet` + String get noEpisodeFavorite { + return Intl.message( + 'No episode collected yet', + name: 'noEpisodeFavorite', + desc: '', + args: [], + ); + } + + /// `No episode received yet` + String get noEpisodeRecent { + return Intl.message( + 'No episode received yet', + name: 'noEpisodeRecent', + desc: '', + args: [], + ); + } + + /// `No podcast in this group` + String get noPodcastGroup { + return Intl.message( + 'No podcast in this group', + name: 'noPodcastGroup', + desc: '', + args: [], + ); + } + + /// `Fetch data {title}` + String notificaitonFatch(Object title) { + return Intl.message( + 'Fetch data $title', + name: 'notificaitonFatch', + desc: '', + args: [title], + ); + } + + /// `Subscribe failed, network error {title}` + String notificationNetworkError(Object title) { + return Intl.message( + 'Subscribe failed, network error $title', + name: 'notificationNetworkError', + desc: '', + args: [title], + ); + } + + /// `Subscribe {title}` + String notificationSubscribe(Object title) { + return Intl.message( + 'Subscribe $title', + name: 'notificationSubscribe', + desc: '', + args: [title], + ); + } + + /// `Subscribe failed, podcast existed {title}` + String notificationSubscribeExisted(Object title) { + return Intl.message( + 'Subscribe failed, podcast existed $title', + name: 'notificationSubscribeExisted', + desc: '', + args: [title], + ); + } + + /// `Subscribe success {title}` + String notificationSuccess(Object title) { + return Intl.message( + 'Subscribe success $title', + name: 'notificationSuccess', + desc: '', + args: [title], + ); + } + + /// `Update {title}` + String notificationUpdate(Object title) { + return Intl.message( + 'Update $title', + name: 'notificationUpdate', + desc: '', + args: [title], + ); + } + + /// `Update error {title}` + String notificationUpdateError(Object title) { + return Intl.message( + 'Update error $title', + name: 'notificationUpdateError', + desc: '', + args: [title], + ); + } + + /// `Oldest first` + String get oldestFirst { + return Intl.message( + 'Oldest first', + name: 'oldestFirst', + desc: '', + args: [], + ); + } + /// `Play` String get play { return Intl.message( @@ -473,6 +935,26 @@ class S { ); } + /// `Playing` + String get playing { + return Intl.message( + 'Playing', + name: 'playing', + desc: '', + args: [], + ); + } + + /// `Podcast subscribed` + String get podcastSubscribed { + return Intl.message( + 'Podcast subscribed', + name: 'podcastSubscribed', + desc: '', + args: [], + ); + } + /// `Download episode` String get popupMenuDownloadDes { return Intl.message( @@ -523,6 +1005,16 @@ class S { ); } + /// `Privacy Policy` + String get privacyPolicy { + return Intl.message( + 'Privacy Policy', + name: 'privacyPolicy', + desc: '', + args: [], + ); + } + /// `Remove` String get remove { return Intl.message( @@ -543,6 +1035,16 @@ class S { ); } + /// `Invalid RSS link` + String get searchInvalidRss { + return Intl.message( + 'Invalid RSS link', + name: 'searchInvalidRss', + desc: '', + args: [], + ); + } + /// `Search podcast` String get searchPodcast { return Intl.message( @@ -1103,6 +1605,16 @@ class S { ); } + /// `Size` + String get size { + return Intl.message( + 'Size', + name: 'size', + desc: '', + args: [], + ); + } + /// `Sleep timer` String get sleepTimer { return Intl.message( @@ -1133,6 +1645,26 @@ class S { ); } + /// `Last time {time}` + String timeLastPlayed(Object time) { + return Intl.message( + 'Last time $time', + name: 'timeLastPlayed', + desc: '', + args: [time], + ); + } + + /// `{time} Left` + String timeLeft(Object time) { + return Intl.message( + '$time Left', + name: 'timeLeft', + desc: '', + args: [time], + ); + } + /// `To` String get to { return Intl.message( @@ -1203,6 +1735,16 @@ class S { ); } + /// `Understood` + String get understood { + return Intl.message( + 'Understood', + name: 'understood', + desc: '', + args: [], + ); + } + /// `Unlike` String get unlike { return Intl.message( @@ -1213,15 +1755,58 @@ class S { ); } - /// `Unliked` + /// `Removed from favorite` String get unliked { return Intl.message( - 'Unliked', + 'Removed from favorite', name: 'unliked', desc: '', args: [], ); } + + /// `Update date` + String get updateDate { + return Intl.message( + 'Update date', + name: 'updateDate', + desc: '', + args: [], + ); + } + + /// `{count, plural, zero{No Update} one{Updated {count} Episode} other{Updated {count} Episodes}}` + String updateEpisodesCount(num count) { + return Intl.plural( + count, + zero: 'No Update', + one: 'Updated $count Episode', + other: 'Updated $count Episodes', + name: 'updateEpisodesCount', + desc: '', + args: [count], + ); + } + + /// `Update failed, network error` + String get updateFailed { + return Intl.message( + 'Update failed, network error', + name: 'updateFailed', + desc: '', + args: [], + ); + } + + /// `Version : {version}` + String version(Object version) { + return Intl.message( + 'Version : $version', + name: 'version', + desc: '', + args: [version], + ); + } } class AppLocalizationDelegate extends LocalizationsDelegate { diff --git a/lib/home/about.dart b/lib/home/about.dart index 0fbc23f..a0751ab 100644 --- a/lib/home/about.dart +++ b/lib/home/about.dart @@ -63,6 +63,7 @@ class AboutApp extends StatelessWidget { ); } + final s = context.s; return AnnotatedRegion( value: SystemUiOverlayStyle( statusBarIconBrightness: Theme.of(context).accentColorBrightness, @@ -73,7 +74,7 @@ class AboutApp extends StatelessWidget { child: Scaffold( backgroundColor: Theme.of(context).primaryColor, appBar: AppBar( - title: Text('About'), + title: Text(s.homeToprightMenuAbout), ), body: SafeArea( child: SingleChildScrollView( @@ -95,7 +96,7 @@ class AboutApp extends StatelessWidget { image: AssetImage('assets/logo.png'), height: 80, ), - Text('Version: $version'), + Text(s.version(version)), ], ), ), @@ -113,7 +114,7 @@ class AboutApp extends StatelessWidget { FlatButton( onPressed: () => _launchUrl( 'https://tsacdop.stonegate.me/#/privacy'), - child: Text('Privacy Policy', + child: Text(s.privacyPolicy, style: TextStyle(color: context.accentColor)), ), Container( @@ -127,7 +128,7 @@ class AboutApp extends StatelessWidget { FlatButton( onPressed: () => _launchUrl( 'https://tsacdop.stonegate.me/#/changelog'), - child: Text('Changelog', + child: Text(s.changelog, style: TextStyle(color: context.accentColor)), ), ], @@ -152,7 +153,7 @@ class AboutApp extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - 'Developer', + s.developer, style: TextStyle( color: Theme.of(context).accentColor, fontWeight: FontWeight.bold), diff --git a/lib/home/addpodcast.dart b/lib/home/addpodcast.dart index 51fd1f2..e9b31e5 100644 --- a/lib/home/addpodcast.dart +++ b/lib/home/addpodcast.dart @@ -25,21 +25,6 @@ class MyHomePageDelegate extends SearchDelegate { searchFieldLabel: searchFieldLabel, ); - //static Future getList(String searchText) async { - // String apiKey = environment['apiKey']; - // String url = - // "https://listennotes.p.rapidapi.com/api/v1/search?only_in=title%2Cdescription&q=" + - // "$searchText&type=podcast"; - // Response response = await Dio().get(url, - // options: Options(headers: { - // 'X-RapidAPI-Key': "$apiKey", - // 'Accept': "application/json" - // })); - // Map searchResultMap = jsonDecode(response.toString()); - // var searchResult = SearchPodcast.fromJson(searchResultMap); - // return searchResult.results; - //} - static Future getRss(String url) async { try { BaseOptions options = new BaseOptions( @@ -60,10 +45,10 @@ class MyHomePageDelegate extends SearchDelegate { } RegExp rssExp = RegExp(r'^(https?):\/\/(.*)'); - Widget invalidRss() => Container( + Widget invalidRss(BuildContext context) => Container( height: 50, alignment: Alignment.center, - child: Text('Invalid rss link'), + child: Text(context.s.searchInvalidRss), ); @override @@ -72,7 +57,7 @@ class MyHomePageDelegate extends SearchDelegate { @override Widget buildLeading(BuildContext context) { return IconButton( - tooltip: 'Back', + tooltip: context.s.back, icon: AnimatedIcon( icon: AnimatedIcons.menu_arrow, progress: transitionAnimation, @@ -145,7 +130,7 @@ class MyHomePageDelegate extends SearchDelegate { Center() else IconButton( - tooltip: 'Clear', + tooltip: context.s.clear, icon: const Icon(Icons.clear), onPressed: () { query = ''; @@ -174,7 +159,7 @@ class MyHomePageDelegate extends SearchDelegate { future: getRss(rssExp.stringMatch(query)), builder: (context, snapshot) { if (snapshot.hasError) - return invalidRss(); + return invalidRss(context); else if (snapshot.hasData) return SearchResult( onlinePodcast: snapshot.data, @@ -297,7 +282,7 @@ class _SearchListState extends State { child: CircularProgressIndicator( strokeWidth: 2, )) - : Text('Load more'), + : Text(context.s.loadMore), onPressed: () => _loading ? null : setState(() { @@ -362,7 +347,7 @@ class _SearchResultState extends State @override Widget build(BuildContext context) { var subscribeWorker = Provider.of(context, listen: false); - + final s = context.s; savePodcast(OnlinePodcast podcast) { SubscribeItem item = SubscribeItem(podcast.rss, podcast.title, imgUrl: podcast.image); @@ -437,14 +422,14 @@ class _SearchResultState extends State ? OutlineButton( highlightedBorderColor: context.accentColor, splashColor: context.accentColor.withOpacity(0.8), - child: Text('Subscribe', + child: Text(s.subscribe, style: TextStyle( color: Theme.of(context).accentColor)), onPressed: () { savePodcast(widget.onlinePodcast); setState(() => _issubscribe = true); Fluttertoast.showToast( - msg: 'Podcast subscribed', + msg: s.podcastSubscribed, gravity: ToastGravity.BOTTOM, ); }) @@ -452,7 +437,7 @@ class _SearchResultState extends State color: context.accentColor.withOpacity(0.8), highlightedBorderColor: Colors.grey[500], disabledTextColor: Colors.grey[500], - child: Text('Subscribe'), + child: Text(s.subscribe), disabledBorderColor: Colors.grey[500], onPressed: () {}), ), diff --git a/lib/home/audioplayer.dart b/lib/home/audioplayer.dart index c4c43b9..332e7ec 100644 --- a/lib/home/audioplayer.dart +++ b/lib/home/audioplayer.dart @@ -77,7 +77,7 @@ class _PlayerWidgetState extends State { // color: context.primaryColorDark, alignment: Alignment.centerLeft, child: Text( - 'Playlist', + context.s.homeMenuPlaylist, style: TextStyle( color: Theme.of(context).accentColor, fontWeight: FontWeight.bold, @@ -389,6 +389,7 @@ class _PlayerWidgetState extends State { Widget _miniPanel(double width, BuildContext context) { var audio = Provider.of(context, listen: false); + final s = context.s; return Container( decoration: BoxDecoration( color: Theme.of(context).primaryColor, @@ -459,13 +460,13 @@ class _PlayerWidgetState extends State { BasicPlaybackState.skippingToNext || data.item1 == BasicPlaybackState.stopped ? Text( - 'Buffering...', + s.buffering, style: TextStyle( color: Theme.of(context).accentColor), ) : Text( - (_stringForSeconds(data.item2) ?? '') + - ' Left', + s.timeLeft( + _stringForSeconds(data.item2) ?? ''), maxLines: 2, ), ); @@ -582,6 +583,7 @@ class _LastPositionState extends State { @override Widget build(BuildContext context) { + final s = context.s; var audio = Provider.of(context, listen: false); return Selector( selector: (_, audio) => audio.episode, @@ -605,7 +607,7 @@ class _LastPositionState extends State { .color), borderRadius: BorderRadius.all(Radius.circular(10.0))), - child: Text('Played before')) + child: Text(s.listened)) : snapshot.data.seconds < 10 ? Center() : Material( @@ -628,8 +630,9 @@ class _LastPositionState extends State { .color), borderRadius: BorderRadius.all( Radius.circular(10.0))), - child: Text('Last time ' + - _stringForSeconds(snapshot.data.seconds)), + child: Text(s.timeLastPlayed( + _stringForSeconds( + snapshot.data.seconds))), ), ), ) @@ -851,6 +854,7 @@ class SleepModeState extends State @override Widget build(BuildContext context) { + final s = context.s; final ColorTween _colorTween = ColorTween(begin: context.primaryColor, end: Colors.black); var audio = Provider.of(context, listen: false); @@ -976,7 +980,7 @@ class SleepModeState extends State width: 120, child: Center( child: Text( - 'End of episode', + s.endOfEpisode, style: TextStyle( // fontWeight: FontWeight.bold, // fontSize: 20, @@ -1059,7 +1063,7 @@ class SleepModeState extends State width: 200, child: Container( alignment: Alignment.center, - child: Text('Good Night', + child: Text(s.goodNight, style: TextStyle( fontWeight: FontWeight.bold, fontSize: 20, @@ -1072,7 +1076,7 @@ class SleepModeState extends State width: 200, child: Container( alignment: Alignment.center, - child: Text('Sleep Timer', + child: Text(s.sleepTimer, style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20)), ), @@ -1223,7 +1227,7 @@ class _ControlPanelState extends State data.audioState == BasicPlaybackState .skippingToNext - ? 'Buffring...' + ? context.s.buffering : '', style: TextStyle( color: Theme.of(context) diff --git a/lib/home/home.dart b/lib/home/home.dart index b50797b..7e210e9 100644 --- a/lib/home/home.dart +++ b/lib/home/home.dart @@ -42,10 +42,6 @@ class Home extends StatefulWidget { } class _HomeState extends State with SingleTickerProviderStateMixin { - final MyHomePageDelegate _delegate = MyHomePageDelegate( - searchFieldLabel: 'Search podcast', - ); - final GlobalKey _scaffoldKey = GlobalKey(); TabController _controller; Decoration _getIndicator(BuildContext context) { @@ -140,8 +136,8 @@ class _HomeState extends State with SingleTickerProviderStateMixin { featureId: addFeature, tapTarget: Icon(Icons.add_circle_outline), - title: const Text( - 'Tap to search podcast'), + title: + Text(s.featureDiscoverySearch), backgroundColor: Colors.cyan[600], overflowMode: feature1OverflowMode, onDismiss: () { @@ -151,13 +147,13 @@ class _HomeState extends State with SingleTickerProviderStateMixin { crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( - 'You can search podcast title , key word or RSS link to subscribe new podcast.'), + Text(s + .featureDiscoverySearchDes), FlatButton( color: Colors.cyan[500], padding: const EdgeInsets.all(0), - child: Text('Understood', + child: Text(s.understood, style: Theme.of(context) .textTheme .button @@ -173,7 +169,7 @@ class _HomeState extends State with SingleTickerProviderStateMixin { color: Colors.cyan[500], padding: const EdgeInsets.all(0), - child: Text('Dismiss', + child: Text(s.dismiss, style: Theme.of(context) .textTheme .button @@ -187,13 +183,15 @@ class _HomeState extends State with SingleTickerProviderStateMixin { ], ), child: IconButton( - tooltip: 'Add', + tooltip: s.add, icon: const Icon( Icons.add_circle_outline), onPressed: () async { await showSearch( context: context, - delegate: _delegate, + delegate: MyHomePageDelegate( + searchFieldLabel: + s.searchPodcast), ); }, ), @@ -213,19 +211,19 @@ class _HomeState extends State with SingleTickerProviderStateMixin { backgroundColor: Colors.cyan[500], onDismiss: () => Future.value(true), - title: const Text( - 'Tap to import OMPL'), + title: + Text(s.featureDiscoveryOMPL), description: Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ - const Text( - 'You can import OMPL file, open setting or refresh all podcast at once here.'), + Text(s + .featureDiscoveryOMPLDes), FlatButton( color: Colors.cyan[600], padding: const EdgeInsets.all(0), - child: Text('Understood', + child: Text(s.understood, style: Theme.of(context) .textTheme .button @@ -241,7 +239,7 @@ class _HomeState extends State with SingleTickerProviderStateMixin { color: Colors.cyan[600], padding: const EdgeInsets.all(0), - child: Text('Dismiss', + child: Text(s.dismiss, style: Theme.of(context) .textTheme .button @@ -270,27 +268,26 @@ class _HomeState extends State with SingleTickerProviderStateMixin { featureId: groupsFeature, tapTarget: Center( child: Text( - 'Podcast View', + s.featureDiscoveryPodcast, textAlign: TextAlign.center, )), backgroundColor: Colors.cyan[500], enablePulsingAnimation: false, onDismiss: () => Future.value(true), - title: const Text( - 'Scroll vertically to switch groups'), + title: + Text(s.featureDiscoveryPodcastTitle), description: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( - 'You can tap See All to add groups or manage podcasts.'), + Text(s.featureDiscoveryPodcastDes), Row( children: [ FlatButton( color: Colors.cyan[600], padding: const EdgeInsets.all(0), - child: Text('Understood', + child: Text(s.understood, style: Theme.of(context) .textTheme .button @@ -309,7 +306,7 @@ class _HomeState extends State with SingleTickerProviderStateMixin { color: Colors.cyan[600], padding: const EdgeInsets.all(0), - child: Text('Dismiss', + child: Text(s.dismiss, style: Theme.of(context) .textTheme .button @@ -365,26 +362,25 @@ class _HomeState extends State with SingleTickerProviderStateMixin { Key('tab0'), DescribedFeatureOverlay( featureId: podcastFeature, - tapTarget: Text('Episode View', + tapTarget: Text(s.featureDiscoveryEpisode, textAlign: TextAlign.center), backgroundColor: Colors.cyan[500], enablePulsingAnimation: false, onDismiss: () => Future.value(true), - title: const Text( - 'Long tap to play episode instantly'), + title: + Text(s.featureDiscoveryEpisodeTitle), description: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( - 'You can long tap to play episode or add episode to playlist.'), + Text(s.featureDiscoveryEpisodeDes), Row( children: [ FlatButton( color: Colors.cyan[600], padding: const EdgeInsets.all(0), - child: Text('Understood', + child: Text(s.understood, style: Theme.of(context) .textTheme .button @@ -403,7 +399,7 @@ class _HomeState extends State with SingleTickerProviderStateMixin { color: Colors.cyan[600], padding: const EdgeInsets.all(0), - child: Text('Dismiss', + child: Text(s.dismiss, style: Theme.of(context) .textTheme .button @@ -457,6 +453,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { @override Widget build( BuildContext context, double shrinkOffset, bool overlapsContent) { + final s = context.s; return Container( color: Theme.of(context).scaffoldBackgroundColor, child: Column( @@ -471,17 +468,16 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { featureId: playlistFeature, tapTarget: Icon(Icons.playlist_play), backgroundColor: Colors.cyan[500], - title: const Text('Tap to open playlist'), + title: Text(s.featureDiscoveryPlaylist), onDismiss: () => Future.value(true), description: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( - 'You can add episode to playlist by yourself. Episode will be auto removed from playlist when played.'), + Text(s.featureDiscoveryPlaylistDes), FlatButton( color: Colors.cyan[600], padding: const EdgeInsets.all(0), - child: Text('Understood', + child: Text(s.understood, style: Theme.of(context) .textTheme .button @@ -492,7 +488,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { FlatButton( color: Colors.cyan[600], padding: const EdgeInsets.all(0), - child: Text('Dismiss', + child: Text(s.dismiss, style: Theme.of(context) .textTheme .button @@ -554,7 +550,7 @@ class PlaylistButtonState extends State { borderRadius: BorderRadius.all(Radius.circular(10))), elevation: 1, icon: Icon(Icons.playlist_play), - tooltip: "Menu", + tooltip: s.menu, itemBuilder: (context) => [ MyPopupMenuItem( height: 50, @@ -749,7 +745,7 @@ class _RecentUpdateState extends State<_RecentUpdate> Padding( padding: EdgeInsets.symmetric(vertical: 10)), Text( - 'No episode received yet', + s.noEpisodeRecent, style: TextStyle(color: Colors.grey[500]), ) ], @@ -792,7 +788,7 @@ class _RecentUpdateState extends State<_RecentUpdate> Radius.circular( 10))), elevation: 1, - tooltip: 'Groups fliter', + tooltip: s.groupFilter, child: Container( padding: EdgeInsets.symmetric( @@ -863,8 +859,8 @@ class _RecentUpdateState extends State<_RecentUpdate> color: Colors .transparent, child: IconButton( - tooltip: - 'Add new episodes to playlist', + tooltip: s + .addNewEpisodeTooltip, icon: // Icon(Icons.playlist_add), SizedBox( @@ -886,8 +882,13 @@ class _RecentUpdateState extends State<_RecentUpdate> .showToast( msg: _groupName == 'All' - ? '${snapshot.data} episode added to playlist' - : '${snapshot.data} episode in $_groupName added to playlist', + ? s.addNewEpisodeAll( + snapshot + .data) + : s.addEpisodeGroup( + _groupName, + snapshot + .data), gravity: ToastGravity .BOTTOM, @@ -898,8 +899,8 @@ class _RecentUpdateState extends State<_RecentUpdate> color: Colors .transparent, child: IconButton( - tooltip: - 'Add new episodes to playlist', + tooltip: s + .addNewEpisodeTooltip, icon: // Icon(Icons.playlist_add), SizedBox( @@ -923,7 +924,7 @@ class _RecentUpdateState extends State<_RecentUpdate> Material( color: Colors.transparent, child: IconButton( - tooltip: 'Change layout', + tooltip: s.changeLayout, padding: EdgeInsets.zero, onPressed: () { if (_layout == Layout.three) @@ -1073,7 +1074,7 @@ class _MyFavoriteState extends State<_MyFavorite> Padding( padding: EdgeInsets.symmetric(vertical: 10)), Text( - 'No episode collected yet', + s.noEpisodeFavorite, style: TextStyle(color: Colors.grey[500]), ) ], @@ -1103,7 +1104,7 @@ class _MyFavoriteState extends State<_MyFavorite> borderRadius: BorderRadius.all( Radius.circular(10))), elevation: 1, - tooltip: 'Sort By', + tooltip: s.homeSubMenuSortBy, child: Container( height: 50, padding: EdgeInsets.symmetric( @@ -1131,11 +1132,11 @@ class _MyFavoriteState extends State<_MyFavorite> itemBuilder: (context) => [ PopupMenuItem( value: 0, - child: Text('Update Date'), + child: Text(s.updateDate), ), PopupMenuItem( value: 1, - child: Text('Like Date'), + child: Text(s.likeDate), ) ], onSelected: (value) { @@ -1278,7 +1279,7 @@ class _MyDownloadState extends State<_MyDownload> children: [ Container( padding: EdgeInsets.symmetric(horizontal: 20), - child: Text(s.homeSubMenuDownloaded)), + child: Text(s.downloaded)), Spacer(), Material( color: Colors.transparent, @@ -1349,7 +1350,7 @@ class _MyDownloadState extends State<_MyDownload> size: 80, color: Colors.grey[500]), Padding(padding: EdgeInsets.symmetric(vertical: 10)), Text( - 'No episode downloaded yet', + s.noEpisodeDownload, style: TextStyle(color: Colors.grey[500]), ) ], diff --git a/lib/home/home_groups.dart b/lib/home/home_groups.dart index da75f80..13f1eb7 100644 --- a/lib/home/home_groups.dart +++ b/lib/home/home_groups.dart @@ -56,6 +56,7 @@ class _ScrollPodcastsState extends State { @override Widget build(BuildContext context) { double _width = MediaQuery.of(context).size.width; + final s = context.s; return Consumer(builder: (_, groupList, __) { var groups = groupList.groups; bool isLoading = groupList.isLoading; @@ -75,7 +76,7 @@ class _ScrollPodcastsState extends State { if (event.primaryVelocity > 200) { if (groups.length == 1) { Fluttertoast.showToast( - msg: 'Add some groups', + msg: s.addSomeGroups, gravity: ToastGravity.BOTTOM, ); } else { @@ -89,7 +90,7 @@ class _ScrollPodcastsState extends State { } else if (event.primaryVelocity < -200) { if (groups.length == 1) { Fluttertoast.showToast( - msg: 'Add some groups', + msg: s.addSomeGroups, gravity: ToastGravity.BOTTOM, ); } else { @@ -136,7 +137,7 @@ class _ScrollPodcastsState extends State { height: 30, padding: EdgeInsets.all(5.0), child: Text( - 'See All', + s.homeGroupsSeeAll, style: Theme.of(context) .textTheme .bodyText1 @@ -189,7 +190,7 @@ class _ScrollPodcastsState extends State { TextSpan(text: ' to subscribe podcasts') ], )) - : Text('No podcast in this group', + : Text(s.noPodcastGroup, style: TextStyle( color: context.textTheme.bodyText2.color .withOpacity(0.5)))), @@ -208,7 +209,7 @@ class _ScrollPodcastsState extends State { if (event.primaryVelocity > 200) { if (groups.length == 1) { Fluttertoast.showToast( - msg: 'Add some groups', + msg: s.addSomeGroups, gravity: ToastGravity.BOTTOM, ); } else { @@ -222,7 +223,7 @@ class _ScrollPodcastsState extends State { } else if (event.primaryVelocity < -200) { if (groups.length == 1) { Fluttertoast.showToast( - msg: 'Add some groups', + msg: s.addSomeGroups, gravity: ToastGravity.BOTTOM, ); } else { @@ -268,7 +269,7 @@ class _ScrollPodcastsState extends State { height: 30, padding: EdgeInsets.all(5.0), child: Text( - 'See All', + s.homeGroupsSeeAll, style: Theme.of(context) .textTheme .bodyText1 @@ -441,7 +442,7 @@ class PodcastPreview extends StatelessWidget { selector: (_, audio) => audio.playerRunning, builder: (_, playerRunning, __) => IconButton( icon: Icon(Icons.arrow_forward), - tooltip: 'See All', + tooltip: context.s.homeGroupsSeeAll, onPressed: () { Navigator.push( context, @@ -471,19 +472,19 @@ class PodcastPreview extends StatelessWidget { class ShowEpisode extends StatelessWidget { final List episodes; final PodcastLocal podcastLocal; - List _menuList = []; ShowEpisode({Key key, this.episodes, this.podcastLocal}) : super(key: key); String _stringForSeconds(double seconds) { if (seconds == null) return null; return '${(seconds ~/ 60)}:${(seconds.truncate() % 60).toString().padLeft(2, '0')}'; } - Future> _initData(EpisodeBrief episode) async { + Future>> _initData( + EpisodeBrief episode) async { int listened = await _isListened(episode); bool liked = await _isLiked(episode); bool downloaded = await _isDownloaded(episode); - _menuList = await _getEpisodeMenu(); - return Tuple3(listened, liked, downloaded); + List menuList = await _getEpisodeMenu(); + return Tuple4(listened, liked, downloaded, menuList); } Future _isListened(EpisodeBrief episode) async { @@ -697,9 +698,9 @@ class ShowEpisode extends StatelessWidget { @override Widget build(BuildContext context) { double _width = context.width; + final s = context.s; var downloader = Provider.of(context, listen: false); var audio = Provider.of(context, listen: false); - Offset offset; return CustomScrollView( physics: NeverScrollableScrollPhysics(), primary: false, @@ -727,14 +728,15 @@ class ShowEpisode extends StatelessWidget { .toList(), ), builder: (_, data, __) => FutureBuilder< - Tuple3>( + Tuple4>>( future: _initData(episodes[index]), - initialData: Tuple3(0, false, false), + initialData: Tuple4(0, false, false, []), builder: (BuildContext context, AsyncSnapshot snapshot) { int isListened = snapshot.data.item1; bool isLiked = snapshot.data.item2; bool isDownloaded = snapshot.data.item3; + List menuList = snapshot.data.item4; return Container( decoration: BoxDecoration( borderRadius: @@ -742,24 +744,7 @@ class ShowEpisode extends StatelessWidget { color: Theme.of(context).scaffoldBackgroundColor, ), alignment: Alignment.center, - child: - // InkWell( - // borderRadius: - // BorderRadius.all(Radius.circular(5.0)), - // onTapDown: (details) => offset = Offset( - // details.globalPosition.dx, - // details.globalPosition.dy), - // onLongPress: () => _showPopupMenu( - // offset, - // episodes[index], - // context, - // data.item1 == episodes[index], - // data.item2.contains( - // episodes[index].enclosureUrl)), - // onTap: () { - // - // }, - FocusedMenuHolder( + child: FocusedMenuHolder( blurSize: 0.0, menuItemExtent: 45, menuBoxDecoration: BoxDecoration( @@ -782,8 +767,8 @@ class ShowEpisode extends StatelessWidget { ? context.primaryColor : context.scaffoldBackgroundColor, title: Text(data.item1 != episodes[index] - ? "Play" - : "Playing"), + ? s.play + : s.playing), trailingIcon: Icon( LineIcons.play_circle_solid, color: Theme.of(context).accentColor, @@ -792,7 +777,7 @@ class ShowEpisode extends StatelessWidget { if (data.item1 != episodes[index]) audio.episodeLoad(episodes[index]); }), - _menuList.contains(1) + menuList.contains(1) ? FocusedMenuItem( backgroundColor: context.brightness == Brightness.light @@ -800,8 +785,8 @@ class ShowEpisode extends StatelessWidget { : context.scaffoldBackgroundColor, title: data.item2.contains( episodes[index].enclosureUrl) - ? Text("Remove") - : Text("Later"), + ? Text(s.remove) + : Text(s.later), trailingIcon: Icon( LineIcons.clock_solid, color: Colors.cyan, @@ -812,28 +797,28 @@ class ShowEpisode extends StatelessWidget { audio .addToPlaylist(episodes[index]); Fluttertoast.showToast( - msg: 'Added to playlist', + msg: s.toastAddPlaylist, gravity: ToastGravity.BOTTOM, ); } else { audio.delFromPlaylist( episodes[index]); Fluttertoast.showToast( - msg: 'Removed from playlist', + msg: s.toastRemovePlaylist, gravity: ToastGravity.BOTTOM, ); } }) : null, - _menuList.contains(2) + menuList.contains(2) ? FocusedMenuItem( backgroundColor: context.brightness == Brightness.light ? context.primaryColor : context.scaffoldBackgroundColor, title: isLiked - ? Text("Unlike") - : Text("Like"), + ? Text(s.unlike) + : Text(s.like), trailingIcon: Icon(LineIcons.heart, color: Colors.red, size: 21), onPressed: () async { @@ -842,7 +827,7 @@ class ShowEpisode extends StatelessWidget { episodes[index].enclosureUrl); audio.setEpisodeState = true; Fluttertoast.showToast( - msg: 'Unliked', + msg: s.unliked, gravity: ToastGravity.BOTTOM, ); } else { @@ -850,25 +835,25 @@ class ShowEpisode extends StatelessWidget { episodes[index].enclosureUrl); audio.setEpisodeState = true; Fluttertoast.showToast( - msg: 'Liked', + msg: s.liked, gravity: ToastGravity.BOTTOM, ); } }) : null, - _menuList.contains(3) + menuList.contains(3) ? FocusedMenuItem( backgroundColor: context.brightness == Brightness.light ? context.primaryColor : context.scaffoldBackgroundColor, title: isListened > 0 - ? Text('Listened', + ? Text(s.listened, style: TextStyle( color: context.textColor .withOpacity(0.5))) : Text( - 'Mark Listened', + s.markListened, maxLines: 1, overflow: TextOverflow.ellipsis, ), @@ -886,24 +871,24 @@ class ShowEpisode extends StatelessWidget { episodes[index]); audio.setEpisodeState = true; Fluttertoast.showToast( - msg: 'Mark listened', + msg: s.markListened, gravity: ToastGravity.BOTTOM, ); } }) : null, - _menuList.contains(4) + menuList.contains(4) ? FocusedMenuItem( backgroundColor: context.brightness == Brightness.light ? context.primaryColor : context.scaffoldBackgroundColor, title: isDownloaded - ? Text('Downloaded', + ? Text(s.downloaded, style: TextStyle( color: context.textColor .withOpacity(0.5))) - : Text('Download'), + : Text(s.download), trailingIcon: Icon( LineIcons.download_solid, color: Colors.green), diff --git a/lib/home/importompl.dart b/lib/home/importompl.dart index 1b0950b..4b802e5 100644 --- a/lib/home/importompl.dart +++ b/lib/home/importompl.dart @@ -56,6 +56,7 @@ class Import extends StatelessWidget { @override Widget build(BuildContext context) { + final s = context.s; GroupList groupList = Provider.of(context, listen: false); return Column( children: [ @@ -64,20 +65,21 @@ class Import extends StatelessWidget { SubscribeItem item = subscribeWorker.currentSubscribeItem; switch (item.subscribeState) { case SubscribeState.start: - return importColumn("Subscribe ${item.title}", context); + return importColumn( + s.notificationSubscribe(item.title), context); case SubscribeState.subscribe: - return importColumn("Fetch data ${item.title}", context); + return importColumn(s.notificaitonFatch(item.title), context); case SubscribeState.fetch: groupList.subscribeNewPodcast(item.id); // groupList.updatePodcast(item.id); - return importColumn("Subscribe success ${item.title}", context); + return importColumn(s.notificationSuccess(item.title), context); case SubscribeState.exist: //groupList.subscribeNewPodcast(item.id); return importColumn( - "Subscribe failed, podcast existed ${item.title}", context); + s.notificationSubscribeExisted(item.title), context); case SubscribeState.error: return importColumn( - "Subscribe failed, network error ${item.title}", context); + s.notificationNetworkError(item.title), context); default: return Center(); } @@ -92,9 +94,10 @@ class Import extends StatelessWidget { } switch (item.refreshState) { case RefreshState.fetch: - return importColumn("Update ${item.title}", context); + return importColumn(s.notificationUpdate(item.title), context); case RefreshState.error: - return importColumn("Update error ${item.title}", context); + return importColumn( + s.notificationUpdateError(item.title), context); default: return Center(); } diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 554e53d..1d6e73c 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -1,25 +1,83 @@ { "@@locale": "en", + "add": "Add", + "@add": { + "description": "Subscribe new podcast" + }, + "addEpisodeGroup": "{count, plural, zero{} one{{count} episode in {groupName} added to playlist} other{{count} episodes in {groupName} added to playlist}}", + "@addEpisodeGroup": { + "placeholders": { + "groupName": {} + } + }, + "addNewEpisodeAll": "{count, plural, zero{} one{{count} episode added to playlist} other{{count} episodes added to playlist}}", + "@addNewEpisodeAll": {}, + "addNewEpisodeTooltip": "Add new episodes to playlist", + "@addNewEpisodeTooltip": {}, + "addSomeGroups": "Add some groups", + "@addSomeGroups": { + "description": "Please add new groups" + }, "all": "All", "@all": {}, - "cancel": "Cancel", + "back": "Back", + "@back": {}, + "buffering": "Buffering", + "@buffering": {}, + "cancel": "CANCEL", "@cancel": {}, + "changeLayout": "Change layout", + "@changeLayout": {}, + "changelog": "Changelog", + "@changelog": {}, "chooseA": "Choose a", "@chooseA": {}, + "clear": "Clear", + "@clear": {}, "color": "color", "@color": {}, - "confirm": "Confirm", + "confirm": "CONFIRM", "@confirm": {}, "darkMode": "Dark mode", "@darkMode": {}, "delete": "Delete", "@delete": {}, + "developer": "Developer", + "@developer": {}, + "dismiss": "Dismiss", + "@dismiss": {}, "download": "Download", "@download": {}, + "downloaded": "Downloaded", + "@downloaded": {}, "editName": "Edit name", "@editName": {}, "endOfEpisode": "End of Episode", "@endOfEpisode": {}, + "featureDiscoveryEpisode": "Episode view", + "@featureDiscoveryEpisode": {}, + "featureDiscoveryEpisodeDes": "You can long tap to play episode or add episode to playlist.", + "@featureDiscoveryEpisodeDes": {}, + "featureDiscoveryEpisodeTitle": "Long tap to play episode instantly", + "@featureDiscoveryEpisodeTitle": {}, + "featureDiscoveryOMPL": "Tap to import OMPL", + "@featureDiscoveryOMPL": {}, + "featureDiscoveryOMPLDes": "You can import OMPL file, open setting or refresh all podcast at once here.", + "@featureDiscoveryOMPLDes": {}, + "featureDiscoveryPlaylist": "Tap to open playlist", + "@featureDiscoveryPlaylist": {}, + "featureDiscoveryPlaylistDes": "You can add episode to playlist by yourself. Episode will be auto removed from playlist when played.", + "@featureDiscoveryPlaylistDes": {}, + "featureDiscoveryPodcast": "Podcast view", + "@featureDiscoveryPodcast": {}, + "featureDiscoveryPodcastDes": "You can tap See All to add groups or manage podcasts.", + "@featureDiscoveryPodcastDes": {}, + "featureDiscoveryPodcastTitle": "Scroll vertically to switch groups", + "@featureDiscoveryPodcastTitle": {}, + "featureDiscoverySearch": "Tap to search podcast", + "@featureDiscoverySearch": {}, + "featureDiscoverySearchDes": "You can search podcast title , key word or RSS link to subscribe new podcast.", + "@featureDiscoverySearchDes": {}, "feedbackEmail": "Write to me", "@feedbackEmail": {}, "feedbackGithub": "Submit issue", @@ -30,14 +88,16 @@ "@feedbackTelegram": {}, "from": "From", "@from": {}, + "goodNight": "Good Night", + "@goodNight": {}, + "groupFilter": "Group filter", + "@groupFilter": {}, "groups": "Groups", "@groups": {}, "homeGroupsSeeAll": "See All", "@homeGroupsSeeAll": {}, "homeMenuPlaylist": "Playlist", "@homeMenuPlaylist": {}, - "homeSubMenuDownloaded": "Downloaded", - "@homeSubMenuDownloaded": {}, "homeSubMenuLikeData": "Like Date", "@homeSubMenuLikeData": {}, "homeSubMenuSortBy": "Sort by", @@ -56,6 +116,14 @@ "@homeToprightMenuRefreshAll": {}, "homeToprightMenuSettings": "Settings", "@homeToprightMenuSettings": {}, + "hostedOn": "Hosted on {host}", + "@hostedOn": { + "placeholders": { + "host": {} + } + }, + "hoursCount": "{count, plural, zero{} one{{count} hour} other{{count} hours}}", + "@hoursCount": {}, "later": "Later", "@later": {}, "lightMode": "Light mode", @@ -64,10 +132,18 @@ "@like": {}, "liked": "Liked", "@liked": {}, + "likeDate": "Like date", + "@likeDate": {}, "listen": "Listen", "@listen": {}, "listened": "Listened", "@listened": {}, + "loadMore": "Load more", + "@loadMore": {}, + "markConfirm": "Mark confirm", + "@markConfirm": {}, + "markConfirmContent": "Confirm mark all episodes listened?", + "@markConfirmContent": {}, "markListened": "Mark listened", "@markListened": {}, "menu": "Menu", @@ -76,18 +152,72 @@ "@menuAllPodcasts": {}, "menuMarkAllListened": "Mark All Listened", "@menuMarkAllListened": {}, - "menuMarkListened": "Mark Listened", - "@menuMarkListened": {}, "menuViewRSS": "Visit RSS Feed", "@menuViewRSS": {}, "menuVisitSite": "Visit Site", "@menuVisitSite": {}, + "minsCount": "{count, plural, zero{} one{{count} min} other{{count} mins}}", + "@minsCount": {}, "network": "Network", "@network": {}, + "newestFirst": "Newest first", + "@newestFirst": {}, "newGroup": "Create new group", "@newGroup": {}, + "noEpisodeDownload": "No episode downloaded yet", + "@noEpisodeDownload": {}, + "noEpisodeFavorite": "No episode collected yet", + "@noEpisodeFavorite": {}, + "noEpisodeRecent": "No episode received yet", + "@noEpisodeRecent": {}, + "noPodcastGroup": "No podcast in this group", + "@noPodcastGroup": {}, + "notificaitonFatch": "Fetch data {title}", + "@notificaitonFatch": {}, + "notificationNetworkError": "Subscribe failed, network error {title}", + "@notificationNetworkError": { + "placeholders": { + "title": {} + } + }, + "notificationSubscribe": "Subscribe {title}", + "@notificationSubscribe": { + "placeholders": { + "title": {} + } + }, + "notificationSubscribeExisted": "Subscribe failed, podcast existed {title}", + "@notificationSubscribeExisted": { + "placeholders": { + "title": {} + } + }, + "notificationSuccess": "Subscribe success {title}", + "@notificationSuccess": { + "placeholders": { + "title": {} + } + }, + "notificationUpdate": "Update {title}", + "@notificationUpdate": { + "placeholders": { + "title": {} + } + }, + "notificationUpdateError": "Update error {title}", + "@notificationUpdateError": { + "placeholders": { + "title": {} + } + }, + "oldestFirst": "Oldest first", + "@oldestFirst": {}, "play": "Play", "@play": {}, + "playing": "Playing", + "@playing": {}, + "podcastSubscribed": "Podcast subscribed", + "@podcastSubscribed": {}, "popupMenuDownloadDes": "Download episode", "@popupMenuDownloadDes": {}, "popupMenuLaterDes": "Add episode to playlist", @@ -98,10 +228,14 @@ "@popupMenuMarkDes": {}, "popupMenuPlayDes": "Play the episode", "@popupMenuPlayDes": {}, + "privacyPolicy": "Privacy Policy", + "@privacyPolicy": {}, "remove": "Remove", "@remove": {}, "schedule": "Schedule", "@schedule": {}, + "searchInvalidRss": "Invalid RSS link", + "@searchInvalidRss": {}, "searchPodcast": "Search podcast", "@searchPodcast": {}, "settingsAccentColor": "Accent color", @@ -214,12 +348,26 @@ "@settingsUpdateInterval": {}, "settingsUpdateIntervalDes": "Default 24 hours", "@settingsUpdateIntervalDes": {}, + "size": "Size", + "@size": {}, "sleepTimer": "Sleep timer", "@sleepTimer": {}, "subscribe": "Subscribe", "@subscribe": {}, "systemDefault": "System default", "@systemDefault": {}, + "timeLastPlayed": "Last time {time}", + "@timeLastPlayed": { + "placeholders": { + "time": {} + } + }, + "timeLeft": "{time} Left", + "@timeLeft": { + "placeholders": { + "time": {} + } + }, "to": "To", "@to": {}, "toastAddPlaylist": "Added to playlist", @@ -234,8 +382,22 @@ "@toastReadFile": {}, "toastRemovePlaylist": "Removed from playlist", "@toastRemovePlaylist": {}, + "understood": "Understood", + "@understood": {}, "unlike": "Unlike", "@unlike": {}, - "unliked": "Unliked", - "@unliked": {} + "unliked": "Removed from favorite", + "@unliked": {}, + "updateDate": "Update date", + "@updateDate": {}, + "updateEpisodesCount": "{count, plural, zero{No Update} one{Updated {count} Episode} other{Updated {count} Episodes}}", + "@updateEpisodesCount": {}, + "updateFailed": "Update failed, network error", + "@updateFailed": {}, + "version": "Version : {version}", + "@version": { + "placeholders": { + "version": {} + } + } } \ No newline at end of file diff --git a/lib/l10n/intl_zh_Hans.arb b/lib/l10n/intl_zh_Hans.arb index f76a377..0f0cdb1 100644 --- a/lib/l10n/intl_zh_Hans.arb +++ b/lib/l10n/intl_zh_Hans.arb @@ -1,11 +1,39 @@ { "@@locale": "zh-Hans", + "add": "订阅", + "@add": { + "description": "Subscribe new podcast" + }, + "addEpisodeGroup": "{count, plural, zero{} other{{group Name}分组{count}集节目添加到播放列表}}", + "@addEpisodeGroup": { + "placeholders": { + "groupName": {} + } + }, + "addNewEpisodeAll": "{count, plural, zero{} other{{count}集节目添加到播放列表}}", + "@addNewEpisodeAll": {}, + "addNewEpisodeTooltip": "添加更新节目到播放列表", + "@addNewEpisodeTooltip": {}, + "addSomeGroups": "请添加分组", + "@addSomeGroups": { + "description": "Please add new groups" + }, "all": "全部", "@all": {}, + "back": "返回", + "@back": {}, + "buffering": "缓冲", + "@buffering": {}, "cancel": "取消", "@cancel": {}, + "changeLayout": "修改布局", + "@changeLayout": {}, + "changelog": "更新日志", + "@changelog": {}, "chooseA": "选择", "@chooseA": {}, + "clear": "清除", + "@clear": {}, "color": "颜色", "@color": {}, "confirm": "确认", @@ -14,12 +42,42 @@ "@darkMode": {}, "delete": "删除", "@delete": {}, + "developer": "关于我", + "@developer": {}, + "dismiss": "忽略", + "@dismiss": {}, "download": "下载", "@download": {}, + "downloaded": "已下载", + "@downloaded": {}, "editName": "修改组名", "@editName": {}, "endOfEpisode": "节目结束", "@endOfEpisode": {}, + "featureDiscoveryEpisode": "节目界面", + "@featureDiscoveryEpisode": {}, + "featureDiscoveryEpisodeDes": "您可以长按播放节目或者添加节目到播放列表。", + "@featureDiscoveryEpisodeDes": {}, + "featureDiscoveryEpisodeTitle": "您可以长按快速播放节目", + "@featureDiscoveryEpisodeTitle": {}, + "featureDiscoveryOMPL": "点击导入 OMPL", + "@featureDiscoveryOMPL": {}, + "featureDiscoveryOMPLDes": "在这里您可以导入OMPL文件,打开设置页面,或者刷新所有播客。", + "@featureDiscoveryOMPLDes": {}, + "featureDiscoveryPlaylist": "点击打开播放列表", + "@featureDiscoveryPlaylist": {}, + "featureDiscoveryPlaylistDes": "您可以添加节目到播放列表,节目在播放后将会从播放列表自动移除。", + "@featureDiscoveryPlaylistDes": {}, + "featureDiscoveryPodcast": "播客界面", + "@featureDiscoveryPodcast": {}, + "featureDiscoveryPodcastDes": "您可以点击“查看所有”新增或管理分组。", + "@featureDiscoveryPodcastDes": {}, + "featureDiscoveryPodcastTitle": "您可以通过上下滑动切换分组", + "@featureDiscoveryPodcastTitle": {}, + "featureDiscoverySearch": "点击搜索播客", + "@featureDiscoverySearch": {}, + "featureDiscoverySearchDes": "您可以通过搜索播客名称、关键字或者RSS链接订阅播客。", + "@featureDiscoverySearchDes": {}, "feedbackEmail": "发送邮件", "@feedbackEmail": {}, "feedbackGithub": "提交Issue", @@ -30,14 +88,16 @@ "@feedbackTelegram": {}, "from": "自", "@from": {}, + "goodNight": "晚安", + "@goodNight": {}, + "groupFilter": "分组", + "@groupFilter": {}, "groups": "分组", "@groups": {}, "homeGroupsSeeAll": "查看全部", "@homeGroupsSeeAll": {}, "homeMenuPlaylist": "播放列表", "@homeMenuPlaylist": {}, - "homeSubMenuDownloaded": "已下载", - "@homeSubMenuDownloaded": {}, "homeSubMenuLikeData": "添加日期", "@homeSubMenuLikeData": {}, "homeSubMenuSortBy": "排序", @@ -56,6 +116,14 @@ "@homeToprightMenuRefreshAll": {}, "homeToprightMenuSettings": "设置", "@homeToprightMenuSettings": {}, + "hostedOn": "平台 {host}", + "@hostedOn": { + "placeholders": { + "host": {} + } + }, + "hoursCount": "{count, plural, zero{} other{{count} 小时}}", + "@hoursCount": {}, "later": "稍后", "@later": {}, "lightMode": "明亮模式", @@ -64,10 +132,18 @@ "@like": {}, "liked": "已收藏", "@liked": {}, + "likeDate": "收藏日期", + "@likeDate": {}, "listen": "收听", "@listen": {}, "listened": "已收听", "@listened": {}, + "loadMore": "加载更多", + "@loadMore": {}, + "markConfirm": "确认标记", + "@markConfirm": {}, + "markConfirmContent": "是否确认标记全部节目为已收听?", + "@markConfirmContent": {}, "markListened": "标记已收听", "@markListened": {}, "menu": "菜单", @@ -76,18 +152,72 @@ "@menuAllPodcasts": {}, "menuMarkAllListened": "标记所有已收听", "@menuMarkAllListened": {}, - "menuMarkListened": "标记已收听", - "@menuMarkListened": {}, "menuViewRSS": "查看 RSS", "@menuViewRSS": {}, "menuVisitSite": "访问网站", "@menuVisitSite": {}, + "minsCount": "{count, plural, zero{} other{{count}分钟}}", + "@minsCount": {}, "network": "网络", "@network": {}, + "newestFirst": "由新到旧", + "@newestFirst": {}, "newGroup": "创建分组", "@newGroup": {}, + "noEpisodeDownload": "暂无下载节目", + "@noEpisodeDownload": {}, + "noEpisodeFavorite": "暂无收藏节目", + "@noEpisodeFavorite": {}, + "noEpisodeRecent": "暂无节目", + "@noEpisodeRecent": {}, + "noPodcastGroup": "分组无播客", + "@noPodcastGroup": {}, + "notificaitonFatch": "获取数据 {title}", + "@notificaitonFatch": {}, + "notificationNetworkError": "订阅失败,网络错误 {title}", + "@notificationNetworkError": { + "placeholders": { + "title": {} + } + }, + "notificationSubscribe": "订阅{title}", + "@notificationSubscribe": { + "placeholders": { + "title": {} + } + }, + "notificationSubscribeExisted": "订阅失败,播客已存在 {title}", + "@notificationSubscribeExisted": { + "placeholders": { + "title": {} + } + }, + "notificationSuccess": "订阅成功 {title}", + "@notificationSuccess": { + "placeholders": { + "title": {} + } + }, + "notificationUpdate": "更新 {title}", + "@notificationUpdate": { + "placeholders": { + "title": {} + } + }, + "notificationUpdateError": "更新失败 {title}", + "@notificationUpdateError": { + "placeholders": { + "title": {} + } + }, + "oldestFirst": "由旧到新", + "@oldestFirst": {}, "play": "播放", "@play": {}, + "playing": "正在播放", + "@playing": {}, + "podcastSubscribed": "播客已订阅", + "@podcastSubscribed": {}, "popupMenuDownloadDes": "下载节目", "@popupMenuDownloadDes": {}, "popupMenuLaterDes": "添加到播放列表", @@ -98,10 +228,14 @@ "@popupMenuMarkDes": {}, "popupMenuPlayDes": "播放节目", "@popupMenuPlayDes": {}, + "privacyPolicy": "隐私条款", + "@privacyPolicy": {}, "remove": "移除", "@remove": {}, "schedule": "定时", "@schedule": {}, + "searchInvalidRss": "RSS 链接错误", + "@searchInvalidRss": {}, "searchPodcast": "搜索播客", "@searchPodcast": {}, "settingsAccentColor": "次要颜色", @@ -214,12 +348,26 @@ "@settingsUpdateInterval": {}, "settingsUpdateIntervalDes": "默认 24 小时", "@settingsUpdateIntervalDes": {}, + "size": "大小", + "@size": {}, "sleepTimer": "睡眠模式", "@sleepTimer": {}, "subscribe": "订阅", "@subscribe": {}, "systemDefault": "系统默认", "@systemDefault": {}, + "timeLastPlayed": "上次播放{time}", + "@timeLastPlayed": { + "placeholders": { + "time": {} + } + }, + "timeLeft": "剩余 {time}", + "@timeLeft": { + "placeholders": { + "time": {} + } + }, "to": "到", "@to": {}, "toastAddPlaylist": "添加到播放列表", @@ -234,8 +382,22 @@ "@toastReadFile": {}, "toastRemovePlaylist": "从播放列表移除", "@toastRemovePlaylist": {}, + "understood": "了解", + "@understood": {}, "unlike": "取消喜欢", "@unlike": {}, "unliked": "从收藏移除", - "@unliked": {} + "@unliked": {}, + "updateDate": "更新日期", + "@updateDate": {}, + "updateEpisodesCount": "{count, plural, zero{未有更新} other{更新 {count} 集节目}}", + "@updateEpisodesCount": {}, + "updateFailed": "更新失败", + "@updateFailed": {}, + "version": "版本:{version}", + "@version": { + "placeholders": { + "version": {} + } + } } \ No newline at end of file diff --git a/lib/podcasts/podcastdetail.dart b/lib/podcasts/podcastdetail.dart index a26e76e..f2e8703 100644 --- a/lib/podcasts/podcastdetail.dart +++ b/lib/podcasts/podcastdetail.dart @@ -44,7 +44,7 @@ class _PodcastDetailState extends State { int _episodeCount; Layout _layout; bool _scroll; - Future _updateRssItem(PodcastLocal podcastLocal) async { + Future _updateRssItem(BuildContext context, PodcastLocal podcastLocal) async { var dbHelper = DBHelper(); final result = await dbHelper.updatePodcastRss(podcastLocal); if (result == 0) { @@ -54,7 +54,7 @@ class _PodcastDetailState extends State { ); } else if (result > 0) { Fluttertoast.showToast( - msg: 'Updated $result Episodes', + msg: context.s.updateEpisodesCount(result), gravity: ToastGravity.TOP, ); @@ -85,7 +85,7 @@ class _PodcastDetailState extends State { } } else { Fluttertoast.showToast( - msg: 'Update failed, network error', + msg: context.s.updateFailed, gravity: ToastGravity.TOP, ); } @@ -226,15 +226,15 @@ class _PodcastDetailState extends State { _confirmMarkListened(BuildContext context) => generalDialog( context, - title: Text('Mark confirm'), - content: Text('Confirm mark all episodes listened?'), + title: Text(context.s.markConfirm), + content: Text(context.s.markConfirmContent), actions: [ FlatButton( onPressed: () { Navigator.of(context).pop(); }, child: Text( - 'CANCEL', + context.s.cancel, style: TextStyle(color: Colors.grey[600]), ), ), @@ -244,7 +244,7 @@ class _PodcastDetailState extends State { await _markListened(widget.podcastLocal.id); }, child: Text( - 'CONFIRM', + context.s.confirm, style: TextStyle(color: context.accentColor), ), ) @@ -293,7 +293,7 @@ class _PodcastDetailState extends State { key: _refreshIndicatorKey, color: Theme.of(context).accentColor, onRefresh: () async { - await _updateRssItem(widget.podcastLocal); + await _updateRssItem(context, widget.podcastLocal); // audio.addNewEpisode(widget.podcastLocal.id); }, child: Stack( @@ -346,7 +346,7 @@ class _PodcastDetailState extends State { borderRadius: BorderRadius.all( Radius.circular(10))), elevation: 2, - tooltip: 'Menu', + tooltip: s.menu, itemBuilder: (context) => [ widget.podcastLocal.link != null ? PopupMenuItem( @@ -494,10 +494,9 @@ class _PodcastDetailState extends State { widget.podcastLocal.provider .isNotEmpty ? Text( - 'Hosted on ' + - widget - .podcastLocal - .provider, + s.hostedOn(widget + .podcastLocal + .provider), maxLines: 1, style: TextStyle( color: Colors @@ -588,12 +587,12 @@ class _PodcastDetailState extends State { PopupMenuItem( value: 0, child: - Text('Newest first'), + Text(s.newestFirst), ), PopupMenuItem( value: 1, child: - Text('Oldest first'), + Text(s.oldestFirst), ) ], onSelected: (value) { diff --git a/lib/settings/theme.dart b/lib/settings/theme.dart index 1f7249c..0994bad 100644 --- a/lib/settings/theme.dart +++ b/lib/settings/theme.dart @@ -91,7 +91,7 @@ class ThemeSetting extends StatelessWidget { Navigator.of(context).pop(); }), RadioListTile( - title: Text('Dark mode'), + title: Text(s.darkMode), value: ThemeMode.dark, groupValue: settings.theme, onChanged: (value) { @@ -99,7 +99,7 @@ class ThemeSetting extends StatelessWidget { Navigator.of(context).pop(); }), RadioListTile( - title: Text('Light mode'), + title: Text(s.lightMode), value: ThemeMode.light, groupValue: settings.theme, onChanged: (value) { @@ -140,9 +140,9 @@ class ThemeSetting extends StatelessWidget { ListTile( onTap: () => generalDialog( context, - title: Text.rich(TextSpan(text: 'Choose a ', children: [ + title: Text.rich(TextSpan(text: s.chooseA, children: [ TextSpan( - text: 'color', + text: s.color, style: TextStyle( fontWeight: FontWeight.bold, color: context.accentColor)) diff --git a/lib/state/subscribe_podcast.dart b/lib/state/subscribe_podcast.dart index 359a9d3..98b116c 100644 --- a/lib/state/subscribe_podcast.dart +++ b/lib/state/subscribe_podcast.dart @@ -205,7 +205,7 @@ Future subIsolateEntryPoint(SendPort sendPort) async { print(e); } } - int count = await dbHelper.savePodcastRss(p, uuid); + await dbHelper.savePodcastRss(p, uuid); sendPort.send([item.title, item.url, 3, uuid]); diff --git a/lib/util/episodegrid.dart b/lib/util/episodegrid.dart index 7e3fbe3..69be382 100644 --- a/lib/util/episodegrid.dart +++ b/lib/util/episodegrid.dart @@ -46,20 +46,18 @@ class EpisodeGrid extends StatelessWidget { this.reverse, }) : super(key: key); - List _menuList = []; - Future _isListened(EpisodeBrief episode) async { DBHelper dbHelper = DBHelper(); - _menuList = await _getEpisodeMenu(); return await dbHelper.isListened(episode.enclosureUrl); } - Future> _initData(EpisodeBrief episode) async { + Future>> _initData( + EpisodeBrief episode) async { int listened = await _isListened(episode); bool liked = await _isLiked(episode); bool downloaded = await _isDownloaded(episode); - _menuList = await _getEpisodeMenu(); - return Tuple3(listened, liked, downloaded); + List menuList = await _getEpisodeMenu(); + return Tuple4(listened, liked, downloaded, menuList); } Future _isLiked(EpisodeBrief episode) async { @@ -431,13 +429,14 @@ class EpisodeGrid extends StatelessWidget { builder: (_, data, __) => OpenContainerWrapper( episode: episodes[index], closedBuilder: (context, action, boo) => FutureBuilder< - Tuple3>( + Tuple4>>( future: _initData(episodes[index]), - initialData: Tuple3(0, false, false), + initialData: Tuple4(0, false, false, []), builder: (BuildContext context, AsyncSnapshot snapshot) { int isListened = snapshot.data.item1; bool isLiked = snapshot.data.item2; bool isDownloaded = snapshot.data.item3; + List menuList = snapshot.data.item4; return Container( decoration: BoxDecoration( borderRadius: @@ -457,21 +456,6 @@ class EpisodeGrid extends StatelessWidget { ), ]), alignment: Alignment.center, - // InkWell( - // borderRadius: - // BorderRadius.all(Radius.circular(5.0)), - // onTapDown: (details) => _offset = Offset( - // details.globalPosition.dx, - // details.globalPosition.dy), - // onLongPress: () => _showPopupMenu( - // _offset, - // episodes[index], - // context, - // isPlaying: data.item1 == episodes[index], - // isInPlaylist: data.item2 - // .contains(episodes[index].enclosureUrl), - // ), - // onTap: action, child: Container( decoration: BoxDecoration( borderRadius: @@ -507,7 +491,7 @@ class EpisodeGrid extends StatelessWidget { : context.scaffoldBackgroundColor, title: Text(data.item1 != episodes[index] ? s.play - : "Playing"), + : s.playing), trailingIcon: Icon( LineIcons.play_circle_solid, color: Theme.of(context).accentColor, @@ -516,7 +500,7 @@ class EpisodeGrid extends StatelessWidget { if (data.item1 != episodes[index]) audio.episodeLoad(episodes[index]); }), - _menuList.contains(1) + menuList.contains(1) ? FocusedMenuItem( backgroundColor: context.brightness == Brightness.light @@ -524,7 +508,7 @@ class EpisodeGrid extends StatelessWidget { : context.scaffoldBackgroundColor, title: data.item2.contains( episodes[index].enclosureUrl) - ? Text("Remove") + ? Text(s.remove) : Text(s.later), trailingIcon: Icon( LineIcons.clock_solid, @@ -535,20 +519,20 @@ class EpisodeGrid extends StatelessWidget { episodes[index].enclosureUrl)) { audio.addToPlaylist(episodes[index]); Fluttertoast.showToast( - msg: 'Added to playlist', + msg: s.toastAddPlaylist, gravity: ToastGravity.BOTTOM, ); } else { audio .delFromPlaylist(episodes[index]); Fluttertoast.showToast( - msg: 'Removed from playlist', + msg: s.toastRemovePlaylist, gravity: ToastGravity.BOTTOM, ); } }) : null, - _menuList.contains(2) + menuList.contains(2) ? FocusedMenuItem( backgroundColor: context.brightness == Brightness.light @@ -565,7 +549,7 @@ class EpisodeGrid extends StatelessWidget { episodes[index].enclosureUrl); audio.setEpisodeState = true; Fluttertoast.showToast( - msg: 'Unliked', + msg: s.unliked, gravity: ToastGravity.BOTTOM, ); } else { @@ -573,20 +557,20 @@ class EpisodeGrid extends StatelessWidget { episodes[index].enclosureUrl); audio.setEpisodeState = true; Fluttertoast.showToast( - msg: 'Liked', + msg: s.liked, gravity: ToastGravity.BOTTOM, ); } }) : null, - _menuList.contains(3) + menuList.contains(3) ? FocusedMenuItem( backgroundColor: context.brightness == Brightness.light ? context.primaryColor : context.scaffoldBackgroundColor, title: isListened > 0 - ? Text('Listened', + ? Text(s.listened, style: TextStyle( color: context.textColor .withOpacity(0.5))) @@ -614,14 +598,14 @@ class EpisodeGrid extends StatelessWidget { } }) : null, - _menuList.contains(4) + menuList.contains(4) ? FocusedMenuItem( backgroundColor: context.brightness == Brightness.light ? context.primaryColor : context.scaffoldBackgroundColor, title: isDownloaded - ? Text(s.homeSubMenuDownloaded, + ? Text(s.downloaded, style: TextStyle( color: context.textColor .withOpacity(0.5)))