mirror of
https://github.com/nini22P/iris.git
synced 2026-06-08 17:42:13 +08:00
v1.0.2 (#2)
* feat: built-in audio track switch * update readme * update subtitle icon and l10n * fix: delay setting default audio track * move android subtitle font * improved subtitle and audio track title display * v1.0.2
This commit is contained in:
25
.github/workflows/ci.yml
vendored
25
.github/workflows/ci.yml
vendored
@@ -1,6 +1,8 @@
|
||||
name: CI
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- README.md
|
||||
- README_CN.md
|
||||
@@ -87,6 +89,18 @@ jobs:
|
||||
cmd: yq '.version' 'pubspec.yaml'
|
||||
- name: Print version
|
||||
run: echo ${{ steps.yq.outputs.result }}
|
||||
- name: Create Tag
|
||||
id: create_tag
|
||||
run: |
|
||||
VERSION="${{ steps.yq.outputs.result }}"
|
||||
TAG_NAME="v${VERSION%%+*}"
|
||||
echo "TAG_NAME=$TAG_NAME" >> "$GITHUB_OUTPUT"
|
||||
echo "Creating new tag $TAG_NAME..."
|
||||
git tag "$TAG_NAME"
|
||||
git push origin "$TAG_NAME"
|
||||
- name: Eextract log
|
||||
id: extract_log
|
||||
run: python extract_log.py ${{ steps.create_tag.outputs.TAG_NAME }}
|
||||
- name: Download Windows artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
@@ -97,22 +111,13 @@ jobs:
|
||||
with:
|
||||
name: Iris_android
|
||||
path: artifacts
|
||||
- name: Create Tag
|
||||
id: create_tag
|
||||
run: |
|
||||
VERSION="${{ steps.yq.outputs.result }}"
|
||||
TAG_NAME="v${VERSION%%+*}"
|
||||
echo "TAG_NAME=$TAG_NAME" >> "$GITHUB_OUTPUT"
|
||||
echo "Creating new tag $TAG_NAME..."
|
||||
git tag "$TAG_NAME"
|
||||
git push origin "$TAG_NAME"
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ steps.create_tag.outputs.TAG_NAME }}
|
||||
body_path: CHANGELOG.md
|
||||
body: ${{ steps.extract_log.outputs.result }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
files: |
|
||||
|
||||
21
CHANGELOG.md
21
CHANGELOG.md
@@ -1,5 +1,24 @@
|
||||
## v1.0.2
|
||||
### Changelog
|
||||
* Support for switching built-in audio tracks
|
||||
* Reduce package size for Windows version
|
||||
|
||||
### 更新日志
|
||||
* 支持切换内置音轨
|
||||
* 减小 Windows 版本包体大小
|
||||
|
||||
|
||||
## v1.0.1
|
||||
### Changelog
|
||||
* Windows version support auto update
|
||||
|
||||
### 更新日志
|
||||
* Windows 版本支持自动更新
|
||||
* Windows 版本支持自动更新
|
||||
|
||||
|
||||
## v1.0.0
|
||||
### Changelog
|
||||
* Supports WebDAV and local storage video playback
|
||||
|
||||
### 更新日志
|
||||
* 支持 WebDAV 和本地存储视频播放
|
||||
@@ -15,7 +15,7 @@ English | [中文](./README_CN.md)
|
||||
|
||||
## Download
|
||||
|
||||
Go to [Releases](https://github.com/nini22P/Iris/releases) to download.
|
||||
[Windows](https://github.com/nini22P/Iris/releases/latest/download/Iris_windows.zip) | [Android](https://github.com/nini22P/Iris/releases/latest/download/Iris_android.apk)
|
||||
|
||||
## Contribution
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
## 下载
|
||||
|
||||
前往 [Releases](https://github.com/nini22P/Iris/releases) 下载。
|
||||
[Windows](https://github.com/nini22P/Iris/releases/latest/download/Iris_windows.zip) | [Android](https://github.com/nini22P/Iris/releases/latest/download/Iris_android.apk)
|
||||
|
||||
## 贡献
|
||||
|
||||
|
||||
Binary file not shown.
35
extract_log.py
Normal file
35
extract_log.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import sys
|
||||
|
||||
def extract_log(version):
|
||||
try:
|
||||
with open("CHANGELOG.md", "r", encoding="utf-8") as file:
|
||||
lines = file.readlines()
|
||||
except FileNotFoundError:
|
||||
print("Error: not found CHANGELOG.md")
|
||||
return
|
||||
|
||||
found = False
|
||||
changelog_lines = []
|
||||
|
||||
for line in lines:
|
||||
if line.startswith(f"## {version}"):
|
||||
found = True
|
||||
continue
|
||||
elif line.startswith("## ") and found:
|
||||
break
|
||||
if found:
|
||||
changelog_lines.append(line)
|
||||
|
||||
while changelog_lines and not changelog_lines[-1].strip():
|
||||
changelog_lines.pop()
|
||||
|
||||
output = "".join(changelog_lines).strip()
|
||||
print(output)
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) != 2:
|
||||
print("Usage: python extract_log.py <version>")
|
||||
sys.exit(1)
|
||||
|
||||
version = sys.argv[1]
|
||||
extract_log(version)
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:flutter_zustand/flutter_zustand.dart';
|
||||
import 'package:iris/hooks/use_player_core.dart';
|
||||
import 'package:iris/store/use_app_store.dart';
|
||||
import 'package:iris/store/use_play_queue_store.dart';
|
||||
@@ -28,8 +29,10 @@ class PlayerController {
|
||||
|
||||
PlayerController usePlayerController(
|
||||
BuildContext context, PlayerCore playerCore) {
|
||||
final playQueue = playerCore.playQueue;
|
||||
final currentIndex = playerCore.currentIndex;
|
||||
final playQueue =
|
||||
usePlayQueueStore().select(context, (state) => state.playQueue);
|
||||
final currentIndex =
|
||||
usePlayQueueStore().select(context, (state) => state.currentIndex);
|
||||
|
||||
Future<void> play() async {
|
||||
await useAppStore().updateAutoPlay(true);
|
||||
|
||||
@@ -14,12 +14,12 @@ import 'package:media_kit/media_kit.dart';
|
||||
class PlayerCore {
|
||||
final Player player;
|
||||
final String title;
|
||||
final List<FileItem> playQueue;
|
||||
final int currentIndex;
|
||||
final FileItem? currentFile;
|
||||
final SubtitleTrack subtitle;
|
||||
final List<SubtitleTrack> subtitles;
|
||||
final List<Subtitle> externalSubtitles;
|
||||
final AudioTrack audio;
|
||||
final List<AudioTrack> audios;
|
||||
final bool playing;
|
||||
final Duration position;
|
||||
final Duration duration;
|
||||
@@ -35,12 +35,12 @@ class PlayerCore {
|
||||
PlayerCore(
|
||||
this.player,
|
||||
this.title,
|
||||
this.playQueue,
|
||||
this.currentIndex,
|
||||
this.currentFile,
|
||||
this.subtitle,
|
||||
this.subtitles,
|
||||
this.externalSubtitles,
|
||||
this.audio,
|
||||
this.audios,
|
||||
this.playing,
|
||||
this.position,
|
||||
this.duration,
|
||||
@@ -79,18 +79,32 @@ PlayerCore usePlayerCore(BuildContext context, Player player) {
|
||||
Duration buffer = useStream(player.stream.buffer).data ?? Duration.zero;
|
||||
bool completed = useStream(player.stream.completed).data ?? false;
|
||||
double rate = useStream(player.stream.rate).data ?? 1.0;
|
||||
|
||||
Track? track = useStream(player.stream.track).data;
|
||||
AudioTrack audio =
|
||||
useMemoized(() => track?.audio ?? AudioTrack.no(), [track?.audio]);
|
||||
SubtitleTrack subtitle = useMemoized(
|
||||
() => track?.subtitle ?? SubtitleTrack.no(), [track?.subtitle]);
|
||||
|
||||
Tracks? tracks = useStream(player.stream.tracks).data;
|
||||
List<AudioTrack> audios =
|
||||
useMemoized(() => (tracks?.audio ?? []), [tracks?.audio]);
|
||||
List<SubtitleTrack> subtitles = useMemoized(
|
||||
() => [...(tracks?.subtitle ?? [])]
|
||||
..removeWhere((subtitle) => subtitle == SubtitleTrack.auto()),
|
||||
[tracks?.subtitle]);
|
||||
|
||||
final List<Subtitle>? externalSubtitles = useMemoized(
|
||||
() => [...currentFile?.subtitles ?? []]..removeWhere(
|
||||
(subtitle) => subtitles.any((item) => item.title == subtitle.name)),
|
||||
[currentFile?.subtitles, subtitles]);
|
||||
|
||||
VideoParams? videoParams = useStream(player.stream.videoParams).data;
|
||||
double aspectRatio =
|
||||
videoParams != null && videoParams.w != null && videoParams.h != null
|
||||
? (videoParams.w! / videoParams.h!)
|
||||
: 0;
|
||||
|
||||
final subtitle = useState(SubtitleTrack.no());
|
||||
final subtitles = useState<List<SubtitleTrack>>([]);
|
||||
|
||||
final List<Subtitle>? externalSubtitles =
|
||||
useMemoized(() => currentFile?.subtitles ?? [], [currentFile]);
|
||||
|
||||
final positionStream = useStream(player.stream.position);
|
||||
|
||||
if (positionStream.hasData) {
|
||||
@@ -142,21 +156,6 @@ PlayerCore usePlayerCore(BuildContext context, Player player) {
|
||||
|
||||
final cover = useFuture(getCover).data;
|
||||
|
||||
useEffect(() {
|
||||
final subscription = player.stream.track.listen((event) {
|
||||
subtitle.value = event.subtitle;
|
||||
});
|
||||
return subscription.cancel;
|
||||
}, []);
|
||||
|
||||
useEffect(() {
|
||||
final subscription = player.stream.tracks.listen((event) {
|
||||
subtitles.value = [...event.subtitle]..removeWhere((subtitle) =>
|
||||
[SubtitleTrack.auto(), SubtitleTrack.no()].contains(subtitle));
|
||||
});
|
||||
return subscription.cancel;
|
||||
}, []);
|
||||
|
||||
useEffect(() {
|
||||
if (currentFile == null || playQueue.isEmpty) return;
|
||||
log('Now playing: ${currentFile.name}, auto play: $autoPlay');
|
||||
@@ -171,20 +170,27 @@ PlayerCore usePlayerCore(BuildContext context, Player player) {
|
||||
}, [currentFile]);
|
||||
|
||||
useEffect(() {
|
||||
if (duration == Duration.zero) return;
|
||||
if (externalSubtitles!.isNotEmpty) {
|
||||
log('Set external subtitle: ${externalSubtitles[0].name}');
|
||||
player.setSubtitleTrack(
|
||||
SubtitleTrack.uri(
|
||||
externalSubtitles[0].uri,
|
||||
title: externalSubtitles[0].name,
|
||||
),
|
||||
);
|
||||
} else if (subtitles.value.isNotEmpty) {
|
||||
log('Set subtitle: ${subtitles.value[0].title}');
|
||||
player.setSubtitleTrack(subtitles.value[0]);
|
||||
}
|
||||
return null;
|
||||
() async {
|
||||
if (duration == Duration.zero) {
|
||||
await player.setSubtitleTrack(SubtitleTrack.no());
|
||||
return;
|
||||
}
|
||||
if (externalSubtitles!.isNotEmpty) {
|
||||
log('Set external subtitle: ${externalSubtitles[0].name}');
|
||||
await player.setSubtitleTrack(
|
||||
SubtitleTrack.uri(
|
||||
externalSubtitles[0].uri,
|
||||
title: externalSubtitles[0].name,
|
||||
),
|
||||
);
|
||||
} else if (subtitles.length > 1) {
|
||||
log('Set subtitle: ${subtitles[1].title ?? subtitles[1].language ?? subtitles[1].id}');
|
||||
await player.setSubtitleTrack(subtitles[1]);
|
||||
} else {
|
||||
await player.setSubtitleTrack(SubtitleTrack.no());
|
||||
}
|
||||
}();
|
||||
return;
|
||||
}, [duration]);
|
||||
|
||||
void updatePosition(Duration newPosition) => position.value = newPosition;
|
||||
@@ -194,12 +200,12 @@ PlayerCore usePlayerCore(BuildContext context, Player player) {
|
||||
return PlayerCore(
|
||||
player,
|
||||
title,
|
||||
playQueue,
|
||||
currentIndex,
|
||||
currentFile,
|
||||
subtitle.value,
|
||||
subtitles.value,
|
||||
subtitle,
|
||||
subtitles,
|
||||
externalSubtitles ?? [],
|
||||
audio,
|
||||
audios,
|
||||
playing,
|
||||
duration == Duration.zero ? Duration.zero : position.value,
|
||||
duration,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
class INFO {
|
||||
static const String title = 'Iris';
|
||||
static const String description = 'A lightweight video player';
|
||||
static const String author = '22';
|
||||
static const String authorUrl = 'https://github.com/nini22P';
|
||||
static const String githubUrl = 'https://github.com/nini22P/Iris';
|
||||
|
||||
@@ -1,63 +1,66 @@
|
||||
{
|
||||
"@@locale": "en",
|
||||
"ok": "OK",
|
||||
"cancel": "Cancel",
|
||||
"close": "Close",
|
||||
"add": "Add",
|
||||
"edit": "Edit",
|
||||
"save": "Save",
|
||||
"remove": "Remove",
|
||||
"name": "Name",
|
||||
"url": "URL",
|
||||
"path": "Path",
|
||||
"port": "Port",
|
||||
"username": "Username",
|
||||
"password": "Password",
|
||||
"storages": "Storages",
|
||||
"add_storage": "Add Storage",
|
||||
"favorites": "Favorites",
|
||||
"add_favorite": "Add Favorite",
|
||||
"remove_favorite": "Remove Favorite",
|
||||
"local_storage": "Local Storage",
|
||||
"connection_test": "Connection Test",
|
||||
"subtitles": "Subtitles",
|
||||
"open_file": "Open File",
|
||||
"open_link": "Open Link",
|
||||
"play": "Play",
|
||||
"pause": "Pause",
|
||||
"previous": "Previous",
|
||||
"next": "Next",
|
||||
"play_queue": "Play Queue",
|
||||
"enter_fullscreen": "Enter Fullscreen",
|
||||
"exit_fullscreen": "Exit Fullscreen",
|
||||
"version": "Version",
|
||||
"source_code": "Source Code",
|
||||
"author": "Author",
|
||||
"theme_mode": "Theme Mode",
|
||||
"auto": "Auto",
|
||||
"light": "Light",
|
||||
"dark": "Datk",
|
||||
"settings": "Settings",
|
||||
"general": "General",
|
||||
"about": "About",
|
||||
"libraries": "Libraries",
|
||||
"back": "Back",
|
||||
"home": "Home",
|
||||
"menu": "Menu",
|
||||
"off": "Off",
|
||||
"unable_to_fetch_files": "Unable to fetch files.",
|
||||
"language": "Language",
|
||||
"select_language": "Select Language",
|
||||
"add": "Add",
|
||||
"add_favorite": "Add Favorite",
|
||||
"add_local_storage": "Add Local Storage",
|
||||
"edit_local_storage": "Edit Local Storage",
|
||||
"add_storage": "Add Storage",
|
||||
"add_webdav_storage": "Add WebDAV Storage",
|
||||
"edit_webdav_storage": "Edit WebDAV Storage",
|
||||
"auto_resize": "Auto Resize Window Proportion",
|
||||
"always_on_top_on": "Always On Top: On",
|
||||
"always_on_top_off": "Always On Top: Off",
|
||||
"always_on_top_on": "Always On Top: On",
|
||||
"app_description": "A lightweight video player",
|
||||
"audio_track": "Audio Track",
|
||||
"author": "Author",
|
||||
"auto": "Auto",
|
||||
"auto_resize": "Auto Resize Window Proportion",
|
||||
"back": "Back",
|
||||
"cancel": "Cancel",
|
||||
"check_update": "Check Update",
|
||||
"checked_new_version": "Checked New Version",
|
||||
"close": "Close",
|
||||
"connection_test": "Connection Test",
|
||||
"dark": "Datk",
|
||||
"download": "Download",
|
||||
"download_and_update": "Download and Update",
|
||||
"checked_new_version": "Checked New Version",
|
||||
"no_new_version": "No New Version"
|
||||
"edit": "Edit",
|
||||
"edit_local_storage": "Edit Local Storage",
|
||||
"edit_webdav_storage": "Edit WebDAV Storage",
|
||||
"enter_fullscreen": "Enter Fullscreen",
|
||||
"exit_fullscreen": "Exit Fullscreen",
|
||||
"favorites": "Favorites",
|
||||
"general": "General",
|
||||
"home": "Home",
|
||||
"language": "Language",
|
||||
"libraries": "Libraries",
|
||||
"light": "Light",
|
||||
"local_storage": "Local Storage",
|
||||
"menu": "Menu",
|
||||
"name": "Name",
|
||||
"next": "Next",
|
||||
"no_new_version": "No New Version",
|
||||
"off": "Off",
|
||||
"ok": "OK",
|
||||
"open_file": "Open File",
|
||||
"open_link": "Open Link",
|
||||
"password": "Password",
|
||||
"path": "Path",
|
||||
"pause": "Pause",
|
||||
"play": "Play",
|
||||
"play_queue": "Play Queue",
|
||||
"port": "Port",
|
||||
"previous": "Previous",
|
||||
"remove": "Remove",
|
||||
"remove_favorite": "Remove Favorite",
|
||||
"save": "Save",
|
||||
"select_language": "Select Language",
|
||||
"settings": "Settings",
|
||||
"source_code": "Source Code",
|
||||
"storages": "Storages",
|
||||
"subtitle": "Subtitle",
|
||||
"subtitle_and_audio_track": "Subtitle and Audio Track",
|
||||
"theme_mode": "Theme Mode",
|
||||
"unable_to_fetch_files": "Unable to fetch files.",
|
||||
"url": "URL",
|
||||
"username": "Username",
|
||||
"version": "Version"
|
||||
}
|
||||
@@ -1,63 +1,66 @@
|
||||
{
|
||||
"@@locale": "zh",
|
||||
"ok": "确定",
|
||||
"cancel": "取消",
|
||||
"close": "关闭",
|
||||
"add": "添加",
|
||||
"edit": "编辑",
|
||||
"save": "保存",
|
||||
"remove": "移除",
|
||||
"name": "名称",
|
||||
"url": "URL",
|
||||
"path": "路径",
|
||||
"port": "端口",
|
||||
"username": "用户名",
|
||||
"password": "密码",
|
||||
"storages": "存储",
|
||||
"add_storage": "添加存储",
|
||||
"favorites": "收藏",
|
||||
"add_favorite": "添加收藏",
|
||||
"remove_favorite": "移除收藏",
|
||||
"local_storage": "本地存储",
|
||||
"connection_test": "连接测试",
|
||||
"subtitles": "字幕",
|
||||
"open_file": "打开文件",
|
||||
"open_link": "打开链接",
|
||||
"play": "播放",
|
||||
"pause": "暂停",
|
||||
"previous": "上一个",
|
||||
"next": "下一个",
|
||||
"play_queue": "播放队列",
|
||||
"enter_fullscreen": "进入全屏",
|
||||
"exit_fullscreen": "退出全屏",
|
||||
"version": "版本",
|
||||
"source_code": "源码",
|
||||
"author": "作者",
|
||||
"theme_mode": "主题模式",
|
||||
"auto": "自动",
|
||||
"light": "亮色",
|
||||
"dark": "暗色",
|
||||
"settings": "设置",
|
||||
"general": "通用",
|
||||
"about": "关于",
|
||||
"libraries": "开源库",
|
||||
"back": "返回",
|
||||
"home": "主页",
|
||||
"menu": "菜单",
|
||||
"off": "关闭",
|
||||
"unable_to_fetch_files": "无法获取文件",
|
||||
"language": "语言",
|
||||
"select_language": "选择语言",
|
||||
"add": "添加",
|
||||
"add_favorite": "添加收藏",
|
||||
"add_local_storage": "添加本地存储",
|
||||
"edit_local_storage": "编辑本地存储",
|
||||
"add_storage": "添加存储",
|
||||
"add_webdav_storage": "添加 WebDAV 存储",
|
||||
"edit_webdav_storage": "编辑 WebDAV 存储",
|
||||
"auto_resize": "自动调整窗口比例",
|
||||
"always_on_top_on": "窗口置顶: 开",
|
||||
"always_on_top_off": "窗口置顶: 关",
|
||||
"always_on_top_on": "窗口置顶: 开",
|
||||
"app_description": "轻量级视频播放器",
|
||||
"audio_track": "音轨",
|
||||
"author": "作者",
|
||||
"auto": "自动",
|
||||
"auto_resize": "自动调整窗口比例",
|
||||
"back": "返回",
|
||||
"cancel": "取消",
|
||||
"check_update": "检查更新",
|
||||
"checked_new_version": "检查到新版本",
|
||||
"close": "关闭",
|
||||
"connection_test": "连接测试",
|
||||
"dark": "暗色",
|
||||
"download": "下载",
|
||||
"download_and_update": "下载并更新",
|
||||
"checked_new_version": "检查到新版本",
|
||||
"no_new_version": "没有新版本"
|
||||
"edit": "编辑",
|
||||
"edit_local_storage": "编辑本地存储",
|
||||
"edit_webdav_storage": "编辑 WebDAV 存储",
|
||||
"enter_fullscreen": "进入全屏",
|
||||
"exit_fullscreen": "退出全屏",
|
||||
"favorites": "收藏",
|
||||
"general": "通用",
|
||||
"home": "主页",
|
||||
"language": "语言",
|
||||
"libraries": "开源库",
|
||||
"light": "亮色",
|
||||
"local_storage": "本地存储",
|
||||
"menu": "菜单",
|
||||
"name": "名称",
|
||||
"next": "下一个",
|
||||
"no_new_version": "没有新版本",
|
||||
"off": "关闭",
|
||||
"ok": "确定",
|
||||
"open_file": "打开文件",
|
||||
"open_link": "打开链接",
|
||||
"password": "密码",
|
||||
"path": "路径",
|
||||
"pause": "暂停",
|
||||
"play": "播放",
|
||||
"play_queue": "播放队列",
|
||||
"port": "端口",
|
||||
"previous": "上一个",
|
||||
"remove": "移除",
|
||||
"remove_favorite": "移除收藏",
|
||||
"save": "保存",
|
||||
"select_language": "选择语言",
|
||||
"settings": "设置",
|
||||
"source_code": "源码",
|
||||
"storages": "存储",
|
||||
"subtitle": "字幕",
|
||||
"subtitle_and_audio_track": "字幕和音轨",
|
||||
"theme_mode": "主题模式",
|
||||
"unable_to_fetch_files": "无法获取文件",
|
||||
"url": "URL",
|
||||
"username": "用户名",
|
||||
"version": "版本"
|
||||
}
|
||||
720
lib/l10n/iso_639.dart
Normal file
720
lib/l10n/iso_639.dart
Normal file
@@ -0,0 +1,720 @@
|
||||
class Info {
|
||||
final List<String> en;
|
||||
|
||||
Info({required this.en});
|
||||
}
|
||||
|
||||
Map<String, Info> customLanguageCodes = {
|
||||
'chs': Info(en: ['Chinese (Simplified)']),
|
||||
'cht': Info(en: ['Chinese (Traditional)']),
|
||||
};
|
||||
|
||||
Map<String, Info> iso_639_1 = {
|
||||
'aa': Info(en: ['Afar']),
|
||||
'ab': Info(en: ['Abkhazian']),
|
||||
'ae': Info(en: ['Avestan']),
|
||||
'af': Info(en: ['Afrikaans']),
|
||||
'ak': Info(en: ['Akan']),
|
||||
'am': Info(en: ['Amharic']),
|
||||
'an': Info(en: ['Aragonese']),
|
||||
'ar': Info(en: ['Arabic']),
|
||||
'as': Info(en: ['Assamese']),
|
||||
'av': Info(en: ['Avaric']),
|
||||
'ay': Info(en: ['Aymara']),
|
||||
'az': Info(en: ['Azerbaijani']),
|
||||
'ba': Info(en: ['Bashkir']),
|
||||
'be': Info(en: ['Belarusian']),
|
||||
'bg': Info(en: ['Bulgarian']),
|
||||
'bh': Info(en: ['Bihari languages']),
|
||||
'bi': Info(en: ['Bislama']),
|
||||
'bm': Info(en: ['Bambara']),
|
||||
'bn': Info(en: ['Bengali']),
|
||||
'bo': Info(en: ['Tibetan']),
|
||||
'br': Info(en: ['Breton']),
|
||||
'bs': Info(en: ['Bosnian']),
|
||||
'ca': Info(en: ['Catalan', 'Valencian']),
|
||||
'ce': Info(en: ['Chechen']),
|
||||
'ch': Info(en: ['Chamorro']),
|
||||
'co': Info(en: ['Corsican']),
|
||||
'cr': Info(en: ['Cree']),
|
||||
'cs': Info(en: ['Czech']),
|
||||
'cu': Info(en: [
|
||||
'Church Slavic',
|
||||
'Old Slavonic',
|
||||
'Church Slavonic',
|
||||
'Old Bulgarian',
|
||||
'Old Church Slavonic'
|
||||
]),
|
||||
'cv': Info(en: ['Chuvash']),
|
||||
'cy': Info(en: ['Welsh']),
|
||||
'da': Info(en: ['Danish']),
|
||||
'de': Info(en: ['German']),
|
||||
'dv': Info(en: ['Divehi', 'Dhivehi', 'Maldivian']),
|
||||
'dz': Info(en: ['Dzongkha']),
|
||||
'ee': Info(en: ['Ewe']),
|
||||
'el': Info(en: ['Greek, Modern (1453-)']),
|
||||
'en': Info(en: ['English']),
|
||||
'eo': Info(en: ['Esperanto']),
|
||||
'es': Info(en: ['Spanish', 'Castilian']),
|
||||
'et': Info(en: ['Estonian']),
|
||||
'eu': Info(en: ['Basque']),
|
||||
'fa': Info(en: ['Persian']),
|
||||
'ff': Info(en: ['Fulah']),
|
||||
'fi': Info(en: ['Finnish']),
|
||||
'fj': Info(en: ['Fijian']),
|
||||
'fo': Info(en: ['Faroese']),
|
||||
'fr': Info(en: ['French']),
|
||||
'fy': Info(en: ['Western Frisian']),
|
||||
'ga': Info(en: ['Irish']),
|
||||
'gd': Info(en: ['Gaelic', 'Scottish Gaelic']),
|
||||
'gl': Info(en: ['Galician']),
|
||||
'gn': Info(en: ['Guarani']),
|
||||
'gu': Info(en: ['Gujarati']),
|
||||
'gv': Info(en: ['Manx']),
|
||||
'ha': Info(en: ['Hausa']),
|
||||
'he': Info(en: ['Hebrew']),
|
||||
'hi': Info(en: ['Hindi']),
|
||||
'ho': Info(en: ['Hiri Motu']),
|
||||
'hr': Info(en: ['Croatian']),
|
||||
'ht': Info(en: ['Haitian', 'Haitian Creole']),
|
||||
'hu': Info(en: ['Hungarian']),
|
||||
'hy': Info(en: ['Armenian']),
|
||||
'hz': Info(en: ['Herero']),
|
||||
'ia':
|
||||
Info(en: ['Interlingua (International Auxiliary Language Association)']),
|
||||
'id': Info(en: ['Indonesian']),
|
||||
'ie': Info(en: ['Interlingue', 'Occidental']),
|
||||
'ig': Info(en: ['Igbo']),
|
||||
'ii': Info(en: ['Sichuan Yi', 'Nuosu']),
|
||||
'ik': Info(en: ['Inupiaq']),
|
||||
'io': Info(en: ['Ido']),
|
||||
'is': Info(en: ['Icelandic']),
|
||||
'it': Info(en: ['Italian']),
|
||||
'iu': Info(en: ['Inuktitut']),
|
||||
'ja': Info(en: ['Japanese']),
|
||||
'jv': Info(en: ['Javanese']),
|
||||
'ka': Info(en: ['Georgian']),
|
||||
'kg': Info(en: ['Kongo']),
|
||||
'ki': Info(en: ['Kikuyu', 'Gikuyu']),
|
||||
'kj': Info(en: ['Kuanyama', 'Kwanyama']),
|
||||
'kk': Info(en: ['Kazakh']),
|
||||
'kl': Info(en: ['Kalaallisut', 'Greenlandic']),
|
||||
'km': Info(en: ['Central Khmer']),
|
||||
'kn': Info(en: ['Kannada']),
|
||||
'ko': Info(en: ['Korean']),
|
||||
'kr': Info(en: ['Kanuri']),
|
||||
'ks': Info(en: ['Kashmiri']),
|
||||
'ku': Info(en: ['Kurdish']),
|
||||
'kv': Info(en: ['Komi']),
|
||||
'kw': Info(en: ['Cornish']),
|
||||
'ky': Info(en: ['Kirghiz', 'Kyrgyz']),
|
||||
'la': Info(en: ['Latin']),
|
||||
'lb': Info(en: ['Luxembourgish', 'Letzeburgesch']),
|
||||
'lg': Info(en: ['Ganda']),
|
||||
'li': Info(en: ['Limburgan', 'Limburger', 'Limburgish']),
|
||||
'ln': Info(en: ['Lingala']),
|
||||
'lo': Info(en: ['Lao']),
|
||||
'lt': Info(en: ['Lithuanian']),
|
||||
'lu': Info(en: ['Luba-Katanga']),
|
||||
'lv': Info(en: ['Latvian']),
|
||||
'mg': Info(en: ['Malagasy']),
|
||||
'mh': Info(en: ['Marshallese']),
|
||||
'mi': Info(en: ['Maori']),
|
||||
'mk': Info(en: ['Macedonian']),
|
||||
'ml': Info(en: ['Malayalam']),
|
||||
'mn': Info(en: ['Mongolian']),
|
||||
'mr': Info(en: ['Marathi']),
|
||||
'ms': Info(en: ['Malay']),
|
||||
'mt': Info(en: ['Maltese']),
|
||||
'my': Info(en: ['Burmese']),
|
||||
'na': Info(en: ['Nauru']),
|
||||
'nb': Info(en: ['Bokmål, Norwegian', 'Norwegian Bokmål']),
|
||||
'nd': Info(en: ['Ndebele, North', 'North Ndebele']),
|
||||
'ne': Info(en: ['Nepali']),
|
||||
'ng': Info(en: ['Ndonga']),
|
||||
'nl': Info(en: ['Dutch', 'Flemish']),
|
||||
'nn': Info(en: ['Norwegian Nynorsk', 'Nynorsk, Norwegian']),
|
||||
'no': Info(en: ['Norwegian']),
|
||||
'nr': Info(en: ['Ndebele, South', 'South Ndebele']),
|
||||
'nv': Info(en: ['Navajo', 'Navaho']),
|
||||
'ny': Info(en: ['Chichewa', 'Chewa', 'Nyanja']),
|
||||
'oc': Info(en: ['Occitan (post 1500)']),
|
||||
'oj': Info(en: ['Ojibwa']),
|
||||
'om': Info(en: ['Oromo']),
|
||||
'or': Info(en: ['Oriya']),
|
||||
'os': Info(en: ['Ossetian', 'Ossetic']),
|
||||
'pa': Info(en: ['Panjabi', 'Punjabi']),
|
||||
'pi': Info(en: ['Pali']),
|
||||
'pl': Info(en: ['Polish']),
|
||||
'ps': Info(en: ['Pushto', 'Pashto']),
|
||||
'pt': Info(en: ['Portuguese']),
|
||||
'qu': Info(en: ['Quechua']),
|
||||
'rm': Info(en: ['Romansh']),
|
||||
'rn': Info(en: ['Rundi']),
|
||||
'ro': Info(en: ['Romanian', 'Moldavian', 'Moldovan']),
|
||||
'ru': Info(en: ['Russian']),
|
||||
'rw': Info(en: ['Kinyarwanda']),
|
||||
'sa': Info(en: ['Sanskrit']),
|
||||
'sc': Info(en: ['Sardinian']),
|
||||
'sd': Info(en: ['Sindhi']),
|
||||
'se': Info(en: ['Northern Sami']),
|
||||
'sg': Info(en: ['Sango']),
|
||||
'si': Info(en: ['Sinhala', 'Sinhalese']),
|
||||
'sk': Info(en: ['Slovak']),
|
||||
'sl': Info(en: ['Slovenian']),
|
||||
'sm': Info(en: ['Samoan']),
|
||||
'sn': Info(en: ['Shona']),
|
||||
'so': Info(en: ['Somali']),
|
||||
'sq': Info(en: ['Albanian']),
|
||||
'sr': Info(en: ['Serbian']),
|
||||
'ss': Info(en: ['Swati']),
|
||||
'st': Info(en: ['Sotho, Southern']),
|
||||
'su': Info(en: ['Sundanese']),
|
||||
'sv': Info(en: ['Swedish']),
|
||||
'sw': Info(en: ['Swahili']),
|
||||
'ta': Info(en: ['Tamil']),
|
||||
'te': Info(en: ['Telugu']),
|
||||
'tg': Info(en: ['Tajik']),
|
||||
'th': Info(en: ['Thai']),
|
||||
'ti': Info(en: ['Tigrinya']),
|
||||
'tk': Info(en: ['Turkmen']),
|
||||
'tl': Info(en: ['Tagalog']),
|
||||
'tn': Info(en: ['Tswana']),
|
||||
'to': Info(en: ['Tonga (Tonga Islands)']),
|
||||
'tr': Info(en: ['Turkish']),
|
||||
'ts': Info(en: ['Tsonga']),
|
||||
'tt': Info(en: ['Tatar']),
|
||||
'tw': Info(en: ['Twi']),
|
||||
'ty': Info(en: ['Tahitian']),
|
||||
'ug': Info(en: ['Uighur', 'Uyghur']),
|
||||
'uk': Info(en: ['Ukrainian']),
|
||||
'ur': Info(en: ['Urdu']),
|
||||
'uz': Info(en: ['Uzbek']),
|
||||
've': Info(en: ['Venda']),
|
||||
'vi': Info(en: ['Vietnamese']),
|
||||
'vo': Info(en: ['Volapük']),
|
||||
'wa': Info(en: ['Walloon']),
|
||||
'wo': Info(en: ['Wolof']),
|
||||
'xh': Info(en: ['Xhosa']),
|
||||
'yi': Info(en: ['Yiddish']),
|
||||
'yo': Info(en: ['Yoruba']),
|
||||
'za': Info(en: ['Zhuang', 'Chuang']),
|
||||
'zh': Info(en: ['Chinese']),
|
||||
'zu': Info(en: ['Zulu']),
|
||||
};
|
||||
|
||||
Map<String, Info> iso_639_2 = {
|
||||
'aar': Info(en: ['Afar']),
|
||||
'abk': Info(en: ['Abkhazian']),
|
||||
'ace': Info(en: ['Achinese']),
|
||||
'ach': Info(en: ['Acoli']),
|
||||
'ada': Info(en: ['Adangme']),
|
||||
'ady': Info(en: ['Adyghe', 'Adygei']),
|
||||
'afa': Info(en: ['Afro-Asiatic languages']),
|
||||
'afh': Info(en: ['Afrihili']),
|
||||
'afr': Info(en: ['Afrikaans']),
|
||||
'ain': Info(en: ['Ainu']),
|
||||
'aka': Info(en: ['Akan']),
|
||||
'akk': Info(en: ['Akkadian']),
|
||||
'alb': Info(en: ['Albanian']),
|
||||
'ale': Info(en: ['Aleut']),
|
||||
'alg': Info(en: ['Algonquian languages']),
|
||||
'alt': Info(en: ['Southern Altai']),
|
||||
'amh': Info(en: ['Amharic']),
|
||||
'ang': Info(en: ['English, Old (ca.450-1100)']),
|
||||
'anp': Info(en: ['Angika']),
|
||||
'apa': Info(en: ['Apache languages']),
|
||||
'ara': Info(en: ['Arabic']),
|
||||
'arc': Info(
|
||||
en: ['Official Aramaic (700-300 BCE)', 'Imperial Aramaic (700-300 BCE)']),
|
||||
'arg': Info(en: ['Aragonese']),
|
||||
'arm': Info(en: ['Armenian']),
|
||||
'arn': Info(en: ['Mapudungun', 'Mapuche']),
|
||||
'arp': Info(en: ['Arapaho']),
|
||||
'art': Info(en: ['Artificial languages']),
|
||||
'arw': Info(en: ['Arawak']),
|
||||
'asm': Info(en: ['Assamese']),
|
||||
'ast': Info(en: ['Asturian', 'Bable', 'Leonese', 'Asturleonese']),
|
||||
'ath': Info(en: ['Athapascan languages']),
|
||||
'aus': Info(en: ['Australian languages']),
|
||||
'ava': Info(en: ['Avaric']),
|
||||
'ave': Info(en: ['Avestan']),
|
||||
'awa': Info(en: ['Awadhi']),
|
||||
'aym': Info(en: ['Aymara']),
|
||||
'aze': Info(en: ['Azerbaijani']),
|
||||
'bad': Info(en: ['Banda languages']),
|
||||
'bai': Info(en: ['Bamileke languages']),
|
||||
'bak': Info(en: ['Bashkir']),
|
||||
'bal': Info(en: ['Baluchi']),
|
||||
'bam': Info(en: ['Bambara']),
|
||||
'ban': Info(en: ['Balinese']),
|
||||
'baq': Info(en: ['Basque']),
|
||||
'bas': Info(en: ['Basa']),
|
||||
'bat': Info(en: ['Baltic languages']),
|
||||
'bej': Info(en: ['Beja', 'Bedawiyet']),
|
||||
'bel': Info(en: ['Belarusian']),
|
||||
'bem': Info(en: ['Bemba']),
|
||||
'ben': Info(en: ['Bengali']),
|
||||
'ber': Info(en: ['Berber languages']),
|
||||
'bho': Info(en: ['Bhojpuri']),
|
||||
'bih': Info(en: ['Bihari languages']),
|
||||
'bik': Info(en: ['Bikol']),
|
||||
'bin': Info(en: ['Bini', 'Edo']),
|
||||
'bis': Info(en: ['Bislama']),
|
||||
'bla': Info(en: ['Siksika']),
|
||||
'bnt': Info(en: ['Bantu languages']),
|
||||
'bod': Info(en: ['Tibetan']),
|
||||
'bos': Info(en: ['Bosnian']),
|
||||
'bra': Info(en: ['Braj']),
|
||||
'bre': Info(en: ['Breton']),
|
||||
'btk': Info(en: ['Batak languages']),
|
||||
'bua': Info(en: ['Buriat']),
|
||||
'bug': Info(en: ['Buginese']),
|
||||
'bul': Info(en: ['Bulgarian']),
|
||||
'bur': Info(en: ['Burmese']),
|
||||
'byn': Info(en: ['Blin', 'Bilin']),
|
||||
'cad': Info(en: ['Caddo']),
|
||||
'cai': Info(en: ['Central American Indian languages']),
|
||||
'car': Info(en: ['Galibi Carib']),
|
||||
'cat': Info(en: ['Catalan', 'Valencian']),
|
||||
'cau': Info(en: ['Caucasian languages']),
|
||||
'ceb': Info(en: ['Cebuano']),
|
||||
'cel': Info(en: ['Celtic languages']),
|
||||
'ces': Info(en: ['Czech']),
|
||||
'cha': Info(en: ['Chamorro']),
|
||||
'chb': Info(en: ['Chibcha']),
|
||||
'che': Info(en: ['Chechen']),
|
||||
'chg': Info(en: ['Chagatai']),
|
||||
'chi': Info(en: ['Chinese']),
|
||||
'chk': Info(en: ['Chuukese']),
|
||||
'chm': Info(en: ['Mari']),
|
||||
'chn': Info(en: ['Chinook jargon']),
|
||||
'cho': Info(en: ['Choctaw']),
|
||||
'chp': Info(en: ['Chipewyan', 'Dene Suline']),
|
||||
'chr': Info(en: ['Cherokee']),
|
||||
'chu': Info(en: [
|
||||
'Church Slavic',
|
||||
'Old Slavonic',
|
||||
'Church Slavonic',
|
||||
'Old Bulgarian',
|
||||
'Old Church Slavonic'
|
||||
]),
|
||||
'chv': Info(en: ['Chuvash']),
|
||||
'chy': Info(en: ['Cheyenne']),
|
||||
'cmc': Info(en: ['Chamic languages']),
|
||||
'cop': Info(en: ['Coptic']),
|
||||
'cor': Info(en: ['Cornish']),
|
||||
'cos': Info(en: ['Corsican']),
|
||||
'cpe': Info(en: ['Creoles and pidgins, English based']),
|
||||
'cpf': Info(en: ['Creoles and pidgins, French-based']),
|
||||
'cpp': Info(en: ['Creoles and pidgins, Portuguese-based']),
|
||||
'cre': Info(en: ['Cree']),
|
||||
'crh': Info(en: ['Crimean Tatar', 'Crimean Turkish']),
|
||||
'crp': Info(en: ['Creoles and pidgins']),
|
||||
'csb': Info(en: ['Kashubian']),
|
||||
'cus': Info(en: ['Cushitic languages']),
|
||||
'cym': Info(en: ['Welsh']),
|
||||
'cze': Info(en: ['Czech']),
|
||||
'dak': Info(en: ['Dakota']),
|
||||
'dan': Info(en: ['Danish']),
|
||||
'dar': Info(en: ['Dargwa']),
|
||||
'day': Info(en: ['Land Dayak languages']),
|
||||
'del': Info(en: ['Delaware']),
|
||||
'den': Info(en: ['Slave (Athapascan)']),
|
||||
'deu': Info(en: ['German']),
|
||||
'dgr': Info(en: ['Dogrib']),
|
||||
'din': Info(en: ['Dinka']),
|
||||
'div': Info(en: ['Divehi', 'Dhivehi', 'Maldivian']),
|
||||
'doi': Info(en: ['Dogri']),
|
||||
'dra': Info(en: ['Dravidian languages']),
|
||||
'dsb': Info(en: ['Lower Sorbian']),
|
||||
'dua': Info(en: ['Duala']),
|
||||
'dum': Info(en: ['Dutch, Middle (ca.1050-1350)']),
|
||||
'dut': Info(en: ['Dutch', 'Flemish']),
|
||||
'dyu': Info(en: ['Dyula']),
|
||||
'dzo': Info(en: ['Dzongkha']),
|
||||
'efi': Info(en: ['Efik']),
|
||||
'egy': Info(en: ['Egyptian (Ancient)']),
|
||||
'eka': Info(en: ['Ekajuk']),
|
||||
'ell': Info(en: ['Greek, Modern (1453-)']),
|
||||
'elx': Info(en: ['Elamite']),
|
||||
'eng': Info(en: ['English']),
|
||||
'enm': Info(en: ['English, Middle (1100-1500)']),
|
||||
'epo': Info(en: ['Esperanto']),
|
||||
'est': Info(en: ['Estonian']),
|
||||
'eus': Info(en: ['Basque']),
|
||||
'ewe': Info(en: ['Ewe']),
|
||||
'ewo': Info(en: ['Ewondo']),
|
||||
'fan': Info(en: ['Fang']),
|
||||
'fao': Info(en: ['Faroese']),
|
||||
'fas': Info(en: ['Persian']),
|
||||
'fat': Info(en: ['Fanti']),
|
||||
'fij': Info(en: ['Fijian']),
|
||||
'fil': Info(en: ['Filipino', 'Pilipino']),
|
||||
'fin': Info(en: ['Finnish']),
|
||||
'fiu': Info(en: ['Finno-Ugrian languages']),
|
||||
'fon': Info(en: ['Fon']),
|
||||
'fra': Info(en: ['French']),
|
||||
'fre': Info(en: ['French']),
|
||||
'frm': Info(en: ['French, Middle (ca.1400-1600)']),
|
||||
'fro': Info(en: ['French, Old (842-ca.1400)']),
|
||||
'frr': Info(en: ['Northern Frisian']),
|
||||
'frs': Info(en: ['Eastern Frisian']),
|
||||
'fry': Info(en: ['Western Frisian']),
|
||||
'ful': Info(en: ['Fulah']),
|
||||
'fur': Info(en: ['Friulian']),
|
||||
'gaa': Info(en: ['Ga']),
|
||||
'gay': Info(en: ['Gayo']),
|
||||
'gba': Info(en: ['Gbaya']),
|
||||
'gem': Info(en: ['Germanic languages']),
|
||||
'geo': Info(en: ['Georgian']),
|
||||
'ger': Info(en: ['German']),
|
||||
'gez': Info(en: ['Geez']),
|
||||
'gil': Info(en: ['Gilbertese']),
|
||||
'gla': Info(en: ['Gaelic', 'Scottish Gaelic']),
|
||||
'gle': Info(en: ['Irish']),
|
||||
'glg': Info(en: ['Galician']),
|
||||
'glv': Info(en: ['Manx']),
|
||||
'gmh': Info(en: ['German, Middle High (ca.1050-1500)']),
|
||||
'goh': Info(en: ['German, Old High (ca.750-1050)']),
|
||||
'gon': Info(en: ['Gondi']),
|
||||
'gor': Info(en: ['Gorontalo']),
|
||||
'got': Info(en: ['Gothic']),
|
||||
'grb': Info(en: ['Grebo']),
|
||||
'grc': Info(en: ['Greek, Ancient (to 1453)']),
|
||||
'gre': Info(en: ['Greek, Modern (1453-)']),
|
||||
'grn': Info(en: ['Guarani']),
|
||||
'gsw': Info(en: ['Swiss German', 'Alemannic', 'Alsatian']),
|
||||
'guj': Info(en: ['Gujarati']),
|
||||
'gwi': Info(en: ['Gwich\'in']),
|
||||
'hai': Info(en: ['Haida']),
|
||||
'hat': Info(en: ['Haitian', 'Haitian Creole']),
|
||||
'hau': Info(en: ['Hausa']),
|
||||
'haw': Info(en: ['Hawaiian']),
|
||||
'heb': Info(en: ['Hebrew']),
|
||||
'her': Info(en: ['Herero']),
|
||||
'hil': Info(en: ['Hiligaynon']),
|
||||
'him': Info(en: ['Himachali languages', 'Western Pahari languages']),
|
||||
'hin': Info(en: ['Hindi']),
|
||||
'hit': Info(en: ['Hittite']),
|
||||
'hmn': Info(en: ['Hmong', 'Mong']),
|
||||
'hmo': Info(en: ['Hiri Motu']),
|
||||
'hrv': Info(en: ['Croatian']),
|
||||
'hsb': Info(en: ['Upper Sorbian']),
|
||||
'hun': Info(en: ['Hungarian']),
|
||||
'hup': Info(en: ['Hupa']),
|
||||
'hye': Info(en: ['Armenian']),
|
||||
'iba': Info(en: ['Iban']),
|
||||
'ibo': Info(en: ['Igbo']),
|
||||
'ice': Info(en: ['Icelandic']),
|
||||
'ido': Info(en: ['Ido']),
|
||||
'iii': Info(en: ['Sichuan Yi', 'Nuosu']),
|
||||
'ijo': Info(en: ['Ijo languages']),
|
||||
'iku': Info(en: ['Inuktitut']),
|
||||
'ile': Info(en: ['Interlingue', 'Occidental']),
|
||||
'ilo': Info(en: ['Iloko']),
|
||||
'ina':
|
||||
Info(en: ['Interlingua (International Auxiliary Language Association)']),
|
||||
'inc': Info(en: ['Indic languages']),
|
||||
'ind': Info(en: ['Indonesian']),
|
||||
'ine': Info(en: ['Indo-European languages']),
|
||||
'inh': Info(en: ['Ingush']),
|
||||
'ipk': Info(en: ['Inupiaq']),
|
||||
'ira': Info(en: ['Iranian languages']),
|
||||
'iro': Info(en: ['Iroquoian languages']),
|
||||
'isl': Info(en: ['Icelandic']),
|
||||
'ita': Info(en: ['Italian']),
|
||||
'jav': Info(en: ['Javanese']),
|
||||
'jbo': Info(en: ['Lojban']),
|
||||
'jpn': Info(en: ['Japanese']),
|
||||
'jpr': Info(en: ['Judeo-Persian']),
|
||||
'jrb': Info(en: ['Judeo-Arabic']),
|
||||
'kaa': Info(en: ['Kara-Kalpak']),
|
||||
'kab': Info(en: ['Kabyle']),
|
||||
'kac': Info(en: ['Kachin', 'Jingpho']),
|
||||
'kal': Info(en: ['Kalaallisut', 'Greenlandic']),
|
||||
'kam': Info(en: ['Kamba']),
|
||||
'kan': Info(en: ['Kannada']),
|
||||
'kar': Info(en: ['Karen languages']),
|
||||
'kas': Info(en: ['Kashmiri']),
|
||||
'kat': Info(en: ['Georgian']),
|
||||
'kau': Info(en: ['Kanuri']),
|
||||
'kaw': Info(en: ['Kawi']),
|
||||
'kaz': Info(en: ['Kazakh']),
|
||||
'kbd': Info(en: ['Kabardian']),
|
||||
'kha': Info(en: ['Khasi']),
|
||||
'khi': Info(en: ['Khoisan languages']),
|
||||
'khm': Info(en: ['Central Khmer']),
|
||||
'kho': Info(en: ['Khotanese', 'Sakan']),
|
||||
'kik': Info(en: ['Kikuyu', 'Gikuyu']),
|
||||
'kin': Info(en: ['Kinyarwanda']),
|
||||
'kir': Info(en: ['Kirghiz', 'Kyrgyz']),
|
||||
'kmb': Info(en: ['Kimbundu']),
|
||||
'kok': Info(en: ['Konkani']),
|
||||
'kom': Info(en: ['Komi']),
|
||||
'kon': Info(en: ['Kongo']),
|
||||
'kor': Info(en: ['Korean']),
|
||||
'kos': Info(en: ['Kosraean']),
|
||||
'kpe': Info(en: ['Kpelle']),
|
||||
'krc': Info(en: ['Karachay-Balkar']),
|
||||
'krl': Info(en: ['Karelian']),
|
||||
'kro': Info(en: ['Kru languages']),
|
||||
'kru': Info(en: ['Kurukh']),
|
||||
'kua': Info(en: ['Kuanyama', 'Kwanyama']),
|
||||
'kum': Info(en: ['Kumyk']),
|
||||
'kur': Info(en: ['Kurdish']),
|
||||
'kut': Info(en: ['Kutenai']),
|
||||
'lad': Info(en: ['Ladino']),
|
||||
'lah': Info(en: ['Lahnda']),
|
||||
'lam': Info(en: ['Lamba']),
|
||||
'lao': Info(en: ['Lao']),
|
||||
'lat': Info(en: ['Latin']),
|
||||
'lav': Info(en: ['Latvian']),
|
||||
'lez': Info(en: ['Lezghian']),
|
||||
'lim': Info(en: ['Limburgan', 'Limburger', 'Limburgish']),
|
||||
'lin': Info(en: ['Lingala']),
|
||||
'lit': Info(en: ['Lithuanian']),
|
||||
'lol': Info(en: ['Mongo']),
|
||||
'loz': Info(en: ['Lozi']),
|
||||
'ltz': Info(en: ['Luxembourgish', 'Letzeburgesch']),
|
||||
'lua': Info(en: ['Luba-Lulua']),
|
||||
'lub': Info(en: ['Luba-Katanga']),
|
||||
'lug': Info(en: ['Ganda']),
|
||||
'lui': Info(en: ['Luiseno']),
|
||||
'lun': Info(en: ['Lunda']),
|
||||
'luo': Info(en: ['Luo (Kenya and Tanzania)']),
|
||||
'lus': Info(en: ['Lushai']),
|
||||
'mac': Info(en: ['Macedonian']),
|
||||
'mad': Info(en: ['Madurese']),
|
||||
'mag': Info(en: ['Magahi']),
|
||||
'mah': Info(en: ['Marshallese']),
|
||||
'mai': Info(en: ['Maithili']),
|
||||
'mak': Info(en: ['Makasar']),
|
||||
'mal': Info(en: ['Malayalam']),
|
||||
'man': Info(en: ['Mandingo']),
|
||||
'mao': Info(en: ['Maori']),
|
||||
'map': Info(en: ['Austronesian languages']),
|
||||
'mar': Info(en: ['Marathi']),
|
||||
'mas': Info(en: ['Masai']),
|
||||
'may': Info(en: ['Malay']),
|
||||
'mdf': Info(en: ['Moksha']),
|
||||
'mdr': Info(en: ['Mandar']),
|
||||
'men': Info(en: ['Mende']),
|
||||
'mga': Info(en: ['Irish, Middle (900-1200)']),
|
||||
'mic': Info(en: ['Mi\'kmaq', 'Micmac']),
|
||||
'min': Info(en: ['Minangkabau']),
|
||||
'mis': Info(en: ['Uncoded languages']),
|
||||
'mkd': Info(en: ['Macedonian']),
|
||||
'mkh': Info(en: ['Mon-Khmer languages']),
|
||||
'mlg': Info(en: ['Malagasy']),
|
||||
'mlt': Info(en: ['Maltese']),
|
||||
'mnc': Info(en: ['Manchu']),
|
||||
'mni': Info(en: ['Manipuri']),
|
||||
'mno': Info(en: ['Manobo languages']),
|
||||
'moh': Info(en: ['Mohawk']),
|
||||
'mon': Info(en: ['Mongolian']),
|
||||
'mos': Info(en: ['Mossi']),
|
||||
'mri': Info(en: ['Maori']),
|
||||
'msa': Info(en: ['Malay']),
|
||||
'mul': Info(en: ['Multiple languages']),
|
||||
'mun': Info(en: ['Munda languages']),
|
||||
'mus': Info(en: ['Creek']),
|
||||
'mwl': Info(en: ['Mirandese']),
|
||||
'mwr': Info(en: ['Marwari']),
|
||||
'mya': Info(en: ['Burmese']),
|
||||
'myn': Info(en: ['Mayan languages']),
|
||||
'myv': Info(en: ['Erzya']),
|
||||
'nah': Info(en: ['Nahuatl languages']),
|
||||
'nai': Info(en: ['North American Indian languages']),
|
||||
'nap': Info(en: ['Neapolitan']),
|
||||
'nau': Info(en: ['Nauru']),
|
||||
'nav': Info(en: ['Navajo', 'Navaho']),
|
||||
'nbl': Info(en: ['Ndebele, South', 'South Ndebele']),
|
||||
'nde': Info(en: ['Ndebele, North', 'North Ndebele']),
|
||||
'ndo': Info(en: ['Ndonga']),
|
||||
'nds': Info(en: ['Low German', 'Low Saxon', 'German, Low', 'Saxon, Low']),
|
||||
'nep': Info(en: ['Nepali']),
|
||||
'new': Info(en: ['Nepal Bhasa', 'Newari']),
|
||||
'nia': Info(en: ['Nias']),
|
||||
'nic': Info(en: ['Niger-Kordofanian languages']),
|
||||
'niu': Info(en: ['Niuean']),
|
||||
'nld': Info(en: ['Dutch', 'Flemish']),
|
||||
'nno': Info(en: ['Norwegian Nynorsk', 'Nynorsk, Norwegian']),
|
||||
'nob': Info(en: ['Bokmål, Norwegian', 'Norwegian Bokmål']),
|
||||
'nog': Info(en: ['Nogai']),
|
||||
'non': Info(en: ['Norse, Old']),
|
||||
'nor': Info(en: ['Norwegian']),
|
||||
'nqo': Info(en: ['N\'Ko']),
|
||||
'nso': Info(en: ['Pedi', 'Sepedi', 'Northern Sotho']),
|
||||
'nub': Info(en: ['Nubian languages']),
|
||||
'nwc': Info(en: ['Classical Newari', 'Old Newari', 'Classical Nepal Bhasa']),
|
||||
'nya': Info(en: ['Chichewa', 'Chewa', 'Nyanja']),
|
||||
'nym': Info(en: ['Nyamwezi']),
|
||||
'nyn': Info(en: ['Nyankole']),
|
||||
'nyo': Info(en: ['Nyoro']),
|
||||
'nzi': Info(en: ['Nzima']),
|
||||
'oci': Info(en: ['Occitan (post 1500)']),
|
||||
'oji': Info(en: ['Ojibwa']),
|
||||
'ori': Info(en: ['Oriya']),
|
||||
'orm': Info(en: ['Oromo']),
|
||||
'osa': Info(en: ['Osage']),
|
||||
'oss': Info(en: ['Ossetian', 'Ossetic']),
|
||||
'ota': Info(en: ['Turkish, Ottoman (1500-1928)']),
|
||||
'oto': Info(en: ['Otomian languages']),
|
||||
'paa': Info(en: ['Papuan languages']),
|
||||
'pag': Info(en: ['Pangasinan']),
|
||||
'pal': Info(en: ['Pahlavi']),
|
||||
'pam': Info(en: ['Pampanga', 'Kapampangan']),
|
||||
'pan': Info(en: ['Panjabi', 'Punjabi']),
|
||||
'pap': Info(en: ['Papiamento']),
|
||||
'pau': Info(en: ['Palauan']),
|
||||
'peo': Info(en: ['Persian, Old (ca.600-400 B.C.)']),
|
||||
'per': Info(en: ['Persian']),
|
||||
'phi': Info(en: ['Philippine languages']),
|
||||
'phn': Info(en: ['Phoenician']),
|
||||
'pli': Info(en: ['Pali']),
|
||||
'pol': Info(en: ['Polish']),
|
||||
'pon': Info(en: ['Pohnpeian']),
|
||||
'por': Info(en: ['Portuguese']),
|
||||
'pra': Info(en: ['Prakrit languages']),
|
||||
'pro': Info(en: ['Provençal, Old (to 1500)', 'Occitan, Old (to 1500)']),
|
||||
'pus': Info(en: ['Pushto', 'Pashto']),
|
||||
'que': Info(en: ['Quechua']),
|
||||
'raj': Info(en: ['Rajasthani']),
|
||||
'rap': Info(en: ['Rapanui']),
|
||||
'rar': Info(en: ['Rarotongan', 'Cook Islands Maori']),
|
||||
'roa': Info(en: ['Romance languages']),
|
||||
'roh': Info(en: ['Romansh']),
|
||||
'rom': Info(en: ['Romany']),
|
||||
'ron': Info(en: ['Romanian', 'Moldavian', 'Moldovan']),
|
||||
'rum': Info(en: ['Romanian', 'Moldavian', 'Moldovan']),
|
||||
'run': Info(en: ['Rundi']),
|
||||
'rup': Info(en: ['Aromanian', 'Arumanian', 'Macedo-Romanian']),
|
||||
'rus': Info(en: ['Russian']),
|
||||
'sad': Info(en: ['Sandawe']),
|
||||
'sag': Info(en: ['Sango']),
|
||||
'sah': Info(en: ['Yakut']),
|
||||
'sai': Info(en: ['South American Indian languages']),
|
||||
'sal': Info(en: ['Salishan languages']),
|
||||
'sam': Info(en: ['Samaritan Aramaic']),
|
||||
'san': Info(en: ['Sanskrit']),
|
||||
'sas': Info(en: ['Sasak']),
|
||||
'sat': Info(en: ['Santali']),
|
||||
'scn': Info(en: ['Sicilian']),
|
||||
'sco': Info(en: ['Scots']),
|
||||
'sel': Info(en: ['Selkup']),
|
||||
'sem': Info(en: ['Semitic languages']),
|
||||
'sga': Info(en: ['Irish, Old (to 900)']),
|
||||
'sgn': Info(en: ['Sign Languages']),
|
||||
'shn': Info(en: ['Shan']),
|
||||
'sid': Info(en: ['Sidamo']),
|
||||
'sin': Info(en: ['Sinhala', 'Sinhalese']),
|
||||
'sio': Info(en: ['Siouan languages']),
|
||||
'sit': Info(en: ['Sino-Tibetan languages']),
|
||||
'sla': Info(en: ['Slavic languages']),
|
||||
'slk': Info(en: ['Slovak']),
|
||||
'slo': Info(en: ['Slovak']),
|
||||
'slv': Info(en: ['Slovenian']),
|
||||
'sma': Info(en: ['Southern Sami']),
|
||||
'sme': Info(en: ['Northern Sami']),
|
||||
'smi': Info(en: ['Sami languages']),
|
||||
'smj': Info(en: ['Lule Sami']),
|
||||
'smn': Info(en: ['Inari Sami']),
|
||||
'smo': Info(en: ['Samoan']),
|
||||
'sms': Info(en: ['Skolt Sami']),
|
||||
'sna': Info(en: ['Shona']),
|
||||
'snd': Info(en: ['Sindhi']),
|
||||
'snk': Info(en: ['Soninke']),
|
||||
'sog': Info(en: ['Sogdian']),
|
||||
'som': Info(en: ['Somali']),
|
||||
'son': Info(en: ['Songhai languages']),
|
||||
'sot': Info(en: ['Sotho, Southern']),
|
||||
'spa': Info(en: ['Spanish', 'Castilian']),
|
||||
'sqi': Info(en: ['Albanian']),
|
||||
'srd': Info(en: ['Sardinian']),
|
||||
'srn': Info(en: ['Sranan Tongo']),
|
||||
'srp': Info(en: ['Serbian']),
|
||||
'srr': Info(en: ['Serer']),
|
||||
'ssa': Info(en: ['Nilo-Saharan languages']),
|
||||
'ssw': Info(en: ['Swati']),
|
||||
'suk': Info(en: ['Sukuma']),
|
||||
'sun': Info(en: ['Sundanese']),
|
||||
'sus': Info(en: ['Susu']),
|
||||
'sux': Info(en: ['Sumerian']),
|
||||
'swa': Info(en: ['Swahili']),
|
||||
'swe': Info(en: ['Swedish']),
|
||||
'syc': Info(en: ['Classical Syriac']),
|
||||
'syr': Info(en: ['Syriac']),
|
||||
'tah': Info(en: ['Tahitian']),
|
||||
'tai': Info(en: ['Tai languages']),
|
||||
'tam': Info(en: ['Tamil']),
|
||||
'tat': Info(en: ['Tatar']),
|
||||
'tel': Info(en: ['Telugu']),
|
||||
'tem': Info(en: ['Timne']),
|
||||
'ter': Info(en: ['Tereno']),
|
||||
'tet': Info(en: ['Tetum']),
|
||||
'tgk': Info(en: ['Tajik']),
|
||||
'tgl': Info(en: ['Tagalog']),
|
||||
'tha': Info(en: ['Thai']),
|
||||
'tib': Info(en: ['Tibetan']),
|
||||
'tig': Info(en: ['Tigre']),
|
||||
'tir': Info(en: ['Tigrinya']),
|
||||
'tiv': Info(en: ['Tiv']),
|
||||
'tkl': Info(en: ['Tokelau']),
|
||||
'tlh': Info(en: ['Klingon', 'tlhIngan-Hol']),
|
||||
'tli': Info(en: ['Tlingit']),
|
||||
'tmh': Info(en: ['Tamashek']),
|
||||
'tog': Info(en: ['Tonga (Nyasa)']),
|
||||
'ton': Info(en: ['Tonga (Tonga Islands)']),
|
||||
'tpi': Info(en: ['Tok Pisin']),
|
||||
'tsi': Info(en: ['Tsimshian']),
|
||||
'tsn': Info(en: ['Tswana']),
|
||||
'tso': Info(en: ['Tsonga']),
|
||||
'tuk': Info(en: ['Turkmen']),
|
||||
'tum': Info(en: ['Tumbuka']),
|
||||
'tup': Info(en: ['Tupi languages']),
|
||||
'tur': Info(en: ['Turkish']),
|
||||
'tut': Info(en: ['Altaic languages']),
|
||||
'tvl': Info(en: ['Tuvalu']),
|
||||
'twi': Info(en: ['Twi']),
|
||||
'tyv': Info(en: ['Tuvinian']),
|
||||
'udm': Info(en: ['Udmurt']),
|
||||
'uga': Info(en: ['Ugaritic']),
|
||||
'uig': Info(en: ['Uighur', 'Uyghur']),
|
||||
'ukr': Info(en: ['Ukrainian']),
|
||||
'umb': Info(en: ['Umbundu']),
|
||||
'und': Info(en: ['Undetermined']),
|
||||
'urd': Info(en: ['Urdu']),
|
||||
'uzb': Info(en: ['Uzbek']),
|
||||
'vai': Info(en: ['Vai']),
|
||||
'ven': Info(en: ['Venda']),
|
||||
'vie': Info(en: ['Vietnamese']),
|
||||
'vol': Info(en: ['Volapük']),
|
||||
'vot': Info(en: ['Votic']),
|
||||
'wak': Info(en: ['Wakashan languages']),
|
||||
'wal': Info(en: ['Wolaitta', 'Wolaytta']),
|
||||
'war': Info(en: ['Waray']),
|
||||
'was': Info(en: ['Washo']),
|
||||
'wel': Info(en: ['Welsh']),
|
||||
'wen': Info(en: ['Sorbian languages']),
|
||||
'wln': Info(en: ['Walloon']),
|
||||
'wol': Info(en: ['Wolof']),
|
||||
'xal': Info(en: ['Kalmyk', 'Oirat']),
|
||||
'xho': Info(en: ['Xhosa']),
|
||||
'yao': Info(en: ['Yao']),
|
||||
'yap': Info(en: ['Yapese']),
|
||||
'yid': Info(en: ['Yiddish']),
|
||||
'yor': Info(en: ['Yoruba']),
|
||||
'ypk': Info(en: ['Yupik languages']),
|
||||
'zap': Info(en: ['Zapotec']),
|
||||
'zbl': Info(en: ['Blissymbols', 'Blissymbolics', 'Bliss']),
|
||||
'zen': Info(en: ['Zenaga']),
|
||||
'zgh': Info(en: ['Standard Moroccan Tamazight']),
|
||||
'zha': Info(en: ['Zhuang', 'Chuang']),
|
||||
'zho': Info(en: ['Chinese']),
|
||||
'znd': Info(en: ['Zande languages']),
|
||||
'zul': Info(en: ['Zulu']),
|
||||
'zun': Info(en: ['Zuni']),
|
||||
'zxx': Info(en: ['No linguistic content', 'Not applicable']),
|
||||
'zza': Info(en: ['Zaza', 'Dimili', 'Dimli', 'Kirdki', 'Kirmanjki', 'Zazaki']),
|
||||
};
|
||||
56
lib/pages/player/audio_tracks.dart
Normal file
56
lib/pages/player/audio_tracks.dart
Normal file
@@ -0,0 +1,56 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:iris/hooks/use_player_core.dart';
|
||||
import 'package:iris/utils/get_localizations.dart';
|
||||
import 'package:iris/utils/get_subtitle_title.dart';
|
||||
import 'package:iris/utils/logger.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
|
||||
class AudioTracks extends HookWidget {
|
||||
const AudioTracks({super.key, required this.playerCore});
|
||||
|
||||
final PlayerCore playerCore;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = getLocalizations(context);
|
||||
|
||||
final focusNode = useFocusNode();
|
||||
|
||||
useEffect(() {
|
||||
focusNode.requestFocus();
|
||||
return () => focusNode.unfocus();
|
||||
}, []);
|
||||
|
||||
return ListView(
|
||||
children: [
|
||||
...playerCore.audios.map(
|
||||
(audio) => ListTile(
|
||||
focusNode: playerCore.audio == audio ? focusNode : null,
|
||||
title: Text(
|
||||
audio == AudioTrack.auto()
|
||||
? t.auto
|
||||
: audio == AudioTrack.no()
|
||||
? t.off
|
||||
: getTrackTitle(audio),
|
||||
style: playerCore.audio == audio
|
||||
? TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
)
|
||||
: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
logger(
|
||||
'Set audio track: ${audio.title ?? audio.language ?? audio.id}');
|
||||
playerCore.player.setAudioTrack(audio);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import 'package:iris/hooks/use_player_controller.dart';
|
||||
import 'package:iris/hooks/use_player_core.dart';
|
||||
import 'package:iris/models/storages/local_storage.dart';
|
||||
import 'package:iris/pages/player/control_bar_slider.dart';
|
||||
import 'package:iris/pages/player/subtitles.dart';
|
||||
import 'package:iris/pages/player/subtitle_and_audio_track.dart';
|
||||
import 'package:iris/pages/settings/settings.dart';
|
||||
import 'package:iris/store/use_play_queue_store.dart';
|
||||
import 'package:iris/utils/get_localizations.dart';
|
||||
@@ -14,7 +14,6 @@ import 'package:iris/pages/player/play_queue.dart';
|
||||
import 'package:iris/utils/resize_window.dart';
|
||||
import 'package:iris/pages/show_popup.dart';
|
||||
import 'package:iris/pages/storages/storages.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
class ControlBar extends HookWidget {
|
||||
@@ -200,18 +199,16 @@ class ControlBar extends HookWidget {
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
tooltip: '${t.subtitles} ( S )',
|
||||
icon: Icon(
|
||||
playerCore.subtitle == SubtitleTrack.no()
|
||||
? Icons.subtitles_off_rounded
|
||||
: Icons.subtitles_rounded,
|
||||
tooltip: '${t.subtitle_and_audio_track} ( S )',
|
||||
icon: const Icon(
|
||||
Icons.subtitles_rounded,
|
||||
size: 19,
|
||||
),
|
||||
onPressed: () async {
|
||||
showControlForHover(
|
||||
showPopup(
|
||||
context: context,
|
||||
child: Subtitles(playerCore: playerCore),
|
||||
child: SubtitleAndAudioTrack(playerCore: playerCore),
|
||||
direction: PopupDirection.right,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -10,7 +10,7 @@ import 'package:iris/info.dart';
|
||||
import 'package:iris/models/storages/local_storage.dart';
|
||||
import 'package:iris/pages/player/control_bar_slider.dart';
|
||||
import 'package:iris/pages/player/play_queue.dart';
|
||||
import 'package:iris/pages/player/subtitles.dart';
|
||||
import 'package:iris/pages/player/subtitle_and_audio_track.dart';
|
||||
import 'package:iris/pages/settings/settings.dart';
|
||||
import 'package:iris/pages/show_popup.dart';
|
||||
import 'package:iris/pages/storages/storages.dart';
|
||||
@@ -43,6 +43,7 @@ class IrisPlayer extends HookWidget {
|
||||
|
||||
useEffect(() {
|
||||
() async {
|
||||
player.setSubtitleTrack(SubtitleTrack.no());
|
||||
if (Platform.isAndroid) {
|
||||
NativePlayer nativePlayer = player.platform as NativePlayer;
|
||||
|
||||
@@ -269,7 +270,7 @@ class IrisPlayer extends HookWidget {
|
||||
showControlForHover(
|
||||
showPopup(
|
||||
context: context,
|
||||
child: Subtitles(playerCore: playerCore),
|
||||
child: SubtitleAndAudioTrack(playerCore: playerCore),
|
||||
direction: PopupDirection.right,
|
||||
),
|
||||
);
|
||||
|
||||
72
lib/pages/player/subtitle_and_audio_track.dart
Normal file
72
lib/pages/player/subtitle_and_audio_track.dart
Normal file
@@ -0,0 +1,72 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:iris/hooks/use_player_core.dart';
|
||||
import 'package:iris/pages/player/audio_tracks.dart';
|
||||
import 'package:iris/pages/player/subtitles.dart';
|
||||
import 'package:iris/utils/get_localizations.dart';
|
||||
|
||||
class ITab {
|
||||
final String title;
|
||||
final Widget child;
|
||||
|
||||
const ITab({
|
||||
required this.title,
|
||||
required this.child,
|
||||
});
|
||||
}
|
||||
|
||||
class SubtitleAndAudioTrack extends HookWidget {
|
||||
const SubtitleAndAudioTrack({super.key, required this.playerCore});
|
||||
|
||||
final PlayerCore playerCore;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = getLocalizations(context);
|
||||
|
||||
List<ITab> tabs = [
|
||||
ITab(title: t.subtitle, child: Subtitles(playerCore: playerCore)),
|
||||
ITab(title: t.audio_track, child: AudioTracks(playerCore: playerCore)),
|
||||
];
|
||||
|
||||
final tabController = useTabController(initialLength: tabs.length);
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
controller: tabController,
|
||||
children: tabs.map((e) => Card(child: e.child)).toList(),
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
color: Theme.of(context).colorScheme.primary.withValues(alpha: 0.25),
|
||||
height: 0,
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.zero,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.fromLTRB(0, 0, 4, 0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
TabBar(
|
||||
controller: tabController,
|
||||
isScrollable: true,
|
||||
tabAlignment: TabAlignment.start,
|
||||
dividerColor: Colors.transparent,
|
||||
tabs: tabs.map((tab) => Tab(text: tab.title)).toList()),
|
||||
const Spacer(),
|
||||
IconButton(
|
||||
tooltip: '${t.close} ( Escape )',
|
||||
icon: const Icon(Icons.close_rounded),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:iris/hooks/use_player_core.dart';
|
||||
import 'package:iris/utils/get_localizations.dart';
|
||||
import 'package:iris/utils/get_subtitle_title.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
|
||||
class Subtitles extends HookWidget {
|
||||
@@ -14,101 +15,55 @@ class Subtitles extends HookWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = getLocalizations(context);
|
||||
final externalSubtitles = useMemoized(
|
||||
() => [...playerCore.externalSubtitles]..removeWhere((subtitle) =>
|
||||
playerCore.subtitles.any((item) => item.title == subtitle.name)),
|
||||
[playerCore.externalSubtitles, playerCore.subtitles]);
|
||||
|
||||
return Column(
|
||||
final focusNode = useFocusNode();
|
||||
|
||||
useEffect(() {
|
||||
focusNode.requestFocus();
|
||||
return () => focusNode.unfocus();
|
||||
}, []);
|
||||
|
||||
return ListView(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Card(
|
||||
child: ListView(
|
||||
children: [
|
||||
ListTile(
|
||||
autofocus: playerCore.subtitle == SubtitleTrack.no(),
|
||||
title: Text(
|
||||
t.off,
|
||||
style: playerCore.subtitle == SubtitleTrack.no()
|
||||
? TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
)
|
||||
: TextStyle(
|
||||
color:
|
||||
Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
playerCore.player.setSubtitleTrack(SubtitleTrack.no());
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
...playerCore.subtitles.map(
|
||||
(subtitle) => ListTile(
|
||||
autofocus: playerCore.subtitle == subtitle,
|
||||
title: Text(
|
||||
'${subtitle.title ?? subtitle.language}',
|
||||
style: playerCore.subtitle == subtitle
|
||||
? TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
)
|
||||
: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurfaceVariant,
|
||||
),
|
||||
...playerCore.subtitles.map(
|
||||
(subtitle) => ListTile(
|
||||
focusNode: playerCore.subtitle == subtitle ? focusNode : null,
|
||||
title: Text(
|
||||
subtitle == SubtitleTrack.no() ? t.off : getTrackTitle(subtitle),
|
||||
style: playerCore.subtitle == subtitle
|
||||
? TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
)
|
||||
: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
onTap: () {
|
||||
playerCore.player.setSubtitleTrack(subtitle);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
...externalSubtitles.map(
|
||||
(subtitle) => ListTile(
|
||||
title: Text(
|
||||
subtitle.name,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
log('Set external subtitle: ${subtitle.name}');
|
||||
playerCore.player.setSubtitleTrack(
|
||||
SubtitleTrack.uri(
|
||||
subtitle.uri,
|
||||
title: subtitle.name,
|
||||
),
|
||||
);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
log('Set subtitle: ${subtitle.title ?? subtitle.language ?? subtitle.id}');
|
||||
playerCore.player.setSubtitleTrack(subtitle);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
color: Theme.of(context).colorScheme.primary.withValues(alpha: 0.25),
|
||||
height: 0,
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.fromLTRB(16, 4, 4, 4),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
t.subtitles,
|
||||
style: const TextStyle(fontWeight: FontWeight.w500),
|
||||
...playerCore.externalSubtitles.map(
|
||||
(subtitle) => ListTile(
|
||||
title: Text(
|
||||
getTrackLanguage(subtitle.name) ?? subtitle.name,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
const Spacer(),
|
||||
IconButton(
|
||||
tooltip: '${t.close} ( Escape )',
|
||||
icon: const Icon(Icons.close_rounded),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
log('Set external subtitle: ${subtitle.name}');
|
||||
playerCore.player.setSubtitleTrack(
|
||||
SubtitleTrack.uri(
|
||||
subtitle.uri,
|
||||
title: subtitle.name,
|
||||
),
|
||||
);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -33,13 +33,15 @@ class About extends HookWidget {
|
||||
leading:
|
||||
Image.asset('assets/images/icon.png', width: 24, height: 24),
|
||||
title: const Text(INFO.title),
|
||||
subtitle: const Text(INFO.description),
|
||||
subtitle: Text(t.app_description),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.info_rounded),
|
||||
title: Text(t.version),
|
||||
subtitle: Text(
|
||||
packageInfo.value != null ? packageInfo.value!.version : ''),
|
||||
onTap: () => launchURL(
|
||||
'${INFO.githubUrl}/releases/tag/v${packageInfo.value?.version}'),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.update_rounded),
|
||||
|
||||
@@ -6,11 +6,11 @@ import 'package:iris/pages/settings/libraries.dart';
|
||||
import 'package:iris/pages/settings/play.dart';
|
||||
import 'package:iris/utils/get_localizations.dart';
|
||||
|
||||
class SettingsTab {
|
||||
class ITab {
|
||||
final String title;
|
||||
final Widget child;
|
||||
|
||||
const SettingsTab({
|
||||
const ITab({
|
||||
required this.title,
|
||||
required this.child,
|
||||
});
|
||||
@@ -25,21 +25,21 @@ class Settings extends HookWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final t = getLocalizations(context);
|
||||
|
||||
List<SettingsTab> settingsTabs = [
|
||||
SettingsTab(title: t.general, child: const General()),
|
||||
SettingsTab(title: t.play, child: const Play()),
|
||||
SettingsTab(title: t.about, child: const About()),
|
||||
SettingsTab(title: t.libraries, child: const Libraries()),
|
||||
List<ITab> tabs = [
|
||||
ITab(title: t.general, child: const General()),
|
||||
ITab(title: t.play, child: const Play()),
|
||||
ITab(title: t.about, child: const About()),
|
||||
ITab(title: t.libraries, child: const Libraries()),
|
||||
];
|
||||
|
||||
final tabController = useTabController(initialLength: settingsTabs.length);
|
||||
final tabController = useTabController(initialLength: tabs.length);
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
controller: tabController,
|
||||
children: settingsTabs.map((e) => Card(child: e.child)).toList(),
|
||||
children: tabs.map((e) => Card(child: e.child)).toList(),
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
@@ -58,7 +58,7 @@ class Settings extends HookWidget {
|
||||
isScrollable: true,
|
||||
tabAlignment: TabAlignment.start,
|
||||
dividerColor: Colors.transparent,
|
||||
tabs: settingsTabs.map((e) => Tab(text: e.title)).toList()),
|
||||
tabs: tabs.map((e) => Tab(text: e.title)).toList()),
|
||||
const Spacer(),
|
||||
IconButton(
|
||||
tooltip: '${t.close} ( Escape )',
|
||||
|
||||
@@ -12,6 +12,16 @@ import 'package:iris/pages/dialog/show_local_dialog.dart';
|
||||
import 'package:iris/pages/dialog/show_webdav_dialog.dart';
|
||||
import 'package:iris/pages/storages/storages_list.dart';
|
||||
|
||||
class ITab {
|
||||
final String title;
|
||||
final Widget child;
|
||||
|
||||
const ITab({
|
||||
required this.title,
|
||||
required this.child,
|
||||
});
|
||||
}
|
||||
|
||||
class Storages extends HookWidget {
|
||||
const Storages({super.key});
|
||||
|
||||
@@ -21,7 +31,12 @@ class Storages extends HookWidget {
|
||||
final currentStorage =
|
||||
useStorageStore().select(context, (state) => state.currentStorage);
|
||||
|
||||
final tabController = useTabController(initialLength: 2);
|
||||
List<ITab> tabs = [
|
||||
ITab(title: t.storages, child: const StoragesList()),
|
||||
ITab(title: t.favorites, child: const FavoriteStoragesList()),
|
||||
];
|
||||
|
||||
final tabController = useTabController(initialLength: tabs.length);
|
||||
|
||||
return currentStorage != null
|
||||
? Files(storage: currentStorage)
|
||||
@@ -30,14 +45,7 @@ class Storages extends HookWidget {
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
controller: tabController,
|
||||
children: const [
|
||||
Card(
|
||||
child: StoragesList(),
|
||||
),
|
||||
Card(
|
||||
child: FavoriteStoragesList(),
|
||||
),
|
||||
],
|
||||
children: tabs.map((tab) => Card(child: tab.child)).toList(),
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
@@ -58,10 +66,7 @@ class Storages extends HookWidget {
|
||||
isScrollable: true,
|
||||
tabAlignment: TabAlignment.start,
|
||||
dividerColor: Colors.transparent,
|
||||
tabs: [
|
||||
Tab(text: t.storages),
|
||||
Tab(text: t.favorites),
|
||||
],
|
||||
tabs: tabs.map((tab) => Tab(text: tab.title)).toList(),
|
||||
),
|
||||
),
|
||||
PopupMenuButton<String>(
|
||||
|
||||
42
lib/utils/get_subtitle_title.dart
Normal file
42
lib/utils/get_subtitle_title.dart
Normal file
@@ -0,0 +1,42 @@
|
||||
import 'package:iris/l10n/iso_639.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
|
||||
String getTrackTitle(dynamic track) {
|
||||
if (track is SubtitleTrack || track is AudioTrack) {
|
||||
if (track.title != null) {
|
||||
final lowerCaseTitle = track.title!.toLowerCase();
|
||||
final languageFromTitle = getTrackLanguage(lowerCaseTitle);
|
||||
if (languageFromTitle != null) {
|
||||
return languageFromTitle;
|
||||
}
|
||||
return track.title!;
|
||||
}
|
||||
|
||||
if (track.language != null) {
|
||||
final lowerCaseLanguage = track.language!.toLowerCase();
|
||||
final languageFromLanguage = getTrackLanguage(lowerCaseLanguage);
|
||||
if (languageFromLanguage != null) {
|
||||
return languageFromLanguage;
|
||||
}
|
||||
return track.language!;
|
||||
}
|
||||
return track.id;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
String? getTrackLanguage(String languageCode) {
|
||||
if (customLanguageCodes[languageCode] != null) {
|
||||
return '${(customLanguageCodes[languageCode]!.en).join(', ')}, $languageCode';
|
||||
}
|
||||
|
||||
if (iso_639_1[languageCode] != null) {
|
||||
return '${(iso_639_1[languageCode]!.en).join(', ')}, $languageCode';
|
||||
}
|
||||
|
||||
if (iso_639_2[languageCode] != null) {
|
||||
return '${(iso_639_2[languageCode]!.en).join(', ')}, $languageCode';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
# In Windows, build-name is used as the major, minor, and patch parts
|
||||
# of the product and file versions while build-number is used as the build suffix.
|
||||
version: 1.0.1+1
|
||||
version: 1.0.2+1
|
||||
|
||||
environment:
|
||||
sdk: ^3.5.4
|
||||
@@ -88,7 +88,6 @@ flutter:
|
||||
|
||||
# To add assets to your application, add an assets section, like this:
|
||||
assets:
|
||||
- assets/fonts/
|
||||
- assets/images/
|
||||
|
||||
# An image asset can refer to one or more resolution-specific "variants", see
|
||||
|
||||
Reference in New Issue
Block a user