mirror of
https://github.com/oxyroid/M3UAndroid.git
synced 2025-05-17 19:35:58 +08:00
build: i18n module.
This commit is contained in:
1
.idea/gradle.xml
generated
1
.idea/gradle.xml
generated
@ -23,6 +23,7 @@
|
||||
<option value="$PROJECT_DIR$/features/live" />
|
||||
<option value="$PROJECT_DIR$/features/main" />
|
||||
<option value="$PROJECT_DIR$/features/setting" />
|
||||
<option value="$PROJECT_DIR$/i18n" />
|
||||
<option value="$PROJECT_DIR$/lint" />
|
||||
<option value="$PROJECT_DIR$/ui" />
|
||||
</set>
|
||||
|
@ -1,5 +1,12 @@
|
||||
# M3UAndroid
|
||||

|
||||
|
||||
### 📢 Translations Wanted 📢
|
||||
|
||||
Please submit a pull request if you want to help with translation.
|
||||
|
||||
App strings ([ENGLISH](i18n/src/main/res/values), [Simplified Chinese](i18n/src/main/res/values-zh-rCN))
|
||||
|
||||
### Features
|
||||
|
||||
- [x] M3U and M3U8 files.
|
||||
|
@ -28,7 +28,7 @@
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:label="@string/ui_app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.M3U.Starting"
|
||||
android:usesCleartextTraffic="true"
|
||||
@ -54,7 +54,7 @@
|
||||
|
||||
<activity
|
||||
android:name="com.m3u.features.crash.CrashActivity"
|
||||
android:label="@string/label_crash"
|
||||
android:label="@string/app_label_crash"
|
||||
android:launchMode="singleInstance" />
|
||||
|
||||
<provider
|
||||
|
@ -14,10 +14,10 @@ import com.m3u.features.console.navigation.consoleScreen
|
||||
import com.m3u.features.feed.navigation.feedScreen
|
||||
import com.m3u.features.live.navigation.livePlaylistScreen
|
||||
import com.m3u.features.live.navigation.liveScreen
|
||||
import com.m3u.features.main.R
|
||||
import com.m3u.ui.Destination
|
||||
import com.m3u.ui.Navigate
|
||||
import com.m3u.ui.model.LocalHelper
|
||||
import com.m3u.i18n.R as I18R
|
||||
|
||||
@Composable
|
||||
fun M3UNavHost(
|
||||
@ -42,7 +42,7 @@ fun M3UNavHost(
|
||||
onCurrentPage = onCurrentPage,
|
||||
navigateToFeed = { feed ->
|
||||
helper.title = feed.title.ifEmpty {
|
||||
if (feed.local) context.getString(R.string.imported_feed_title)
|
||||
if (feed.local) context.getString(I18R.string.feat_main_imported_feed_title)
|
||||
else ""
|
||||
}
|
||||
navigate(Destination.Feed(feed.url))
|
||||
|
@ -1,4 +0,0 @@
|
||||
<resources>
|
||||
<string name="label_crash">应用发生崩溃</string>
|
||||
<string name="features_scheme_import">导入频道</string>
|
||||
</resources>
|
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="label_crash">app crashes</string>
|
||||
<string name="features_scheme_import">Import as live</string>
|
||||
</resources>
|
@ -35,6 +35,7 @@ android {
|
||||
dependencies {
|
||||
lintPublish(project(":lint"))
|
||||
lintChecks(project(":lint"))
|
||||
api(project(":i18n"))
|
||||
|
||||
implementation(libs.androidx.core.core.ktx)
|
||||
implementation(libs.androidx.appcompat.appcompat)
|
||||
|
@ -15,7 +15,6 @@ import com.m3u.core.wrapper.emitException
|
||||
import com.m3u.core.wrapper.emitMessage
|
||||
import com.m3u.core.wrapper.emitProgress
|
||||
import com.m3u.core.wrapper.emitResource
|
||||
import com.m3u.data.R
|
||||
import com.m3u.data.database.dao.FeedDao
|
||||
import com.m3u.data.database.dao.LiveDao
|
||||
import com.m3u.data.database.entity.Feed
|
||||
@ -35,6 +34,7 @@ import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.InputStream
|
||||
import javax.inject.Inject
|
||||
import com.m3u.i18n.R as I18R
|
||||
|
||||
class FeedRepositoryImpl @Inject constructor(
|
||||
private val feedDao: FeedDao,
|
||||
@ -124,7 +124,7 @@ class FeedRepositoryImpl @Inject constructor(
|
||||
liveDao.insert(live)
|
||||
emitResource(Unit)
|
||||
} catch (e: FileNotFoundException) {
|
||||
error(context.getString(R.string.error_file_not_found))
|
||||
error(context.getString(I18R.string.data_error_file_not_found))
|
||||
} catch (e: Exception) {
|
||||
logger.log(e)
|
||||
emitException(e)
|
||||
|
@ -17,6 +17,7 @@ import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.supervisorScope
|
||||
import com.m3u.i18n.R as I18R
|
||||
|
||||
@HiltWorker
|
||||
class SubscriptionInBackgroundWorker @AssistedInject constructor(
|
||||
@ -33,7 +34,7 @@ class SubscriptionInBackgroundWorker @AssistedInject constructor(
|
||||
url ?: return@coroutineScope Result.failure()
|
||||
createChannel()
|
||||
if (title.isEmpty()) {
|
||||
val message = context.getString(R.string.error_empty_title)
|
||||
val message = context.getString(I18R.string.data_error_empty_title)
|
||||
val data = workDataOf("message" to message)
|
||||
failure(message)
|
||||
Result.failure(data)
|
||||
|
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="error_file_not_found">文件不存在</string>
|
||||
<string name="error_empty_title">订阅名称为空</string>
|
||||
</resources>
|
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="error_file_not_found">file not found</string>
|
||||
<string name="error_empty_title">playlist name is empty</string>
|
||||
</resources>
|
@ -19,6 +19,7 @@ import com.m3u.ui.components.MonoText
|
||||
import com.m3u.ui.model.LocalHelper
|
||||
import com.m3u.ui.model.LocalSpacing
|
||||
import com.m3u.ui.model.repeatOnLifecycle
|
||||
import com.m3u.i18n.R as I18R
|
||||
|
||||
@Composable
|
||||
internal fun AboutRoute(
|
||||
@ -26,7 +27,7 @@ internal fun AboutRoute(
|
||||
viewModel: AboutViewModel = hiltViewModel()
|
||||
) {
|
||||
val helper = LocalHelper.current
|
||||
val title = stringResource(R.string.about_title)
|
||||
val title = stringResource(I18R.string.feat_about_title)
|
||||
helper.repeatOnLifecycle {
|
||||
this.title = title
|
||||
}
|
||||
|
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="about_title">关于项目</string>
|
||||
</resources>
|
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="about_title">about project</string>
|
||||
</resources>
|
@ -30,6 +30,7 @@ import com.m3u.ui.components.TextField
|
||||
import com.m3u.ui.model.LocalHelper
|
||||
import com.m3u.ui.model.LocalSpacing
|
||||
import com.m3u.ui.model.repeatOnLifecycle
|
||||
import com.m3u.i18n.R as I18R
|
||||
|
||||
@Composable
|
||||
internal fun ConsoleRoute(
|
||||
@ -37,7 +38,7 @@ internal fun ConsoleRoute(
|
||||
viewModel: ConsoleViewModel = hiltViewModel()
|
||||
) {
|
||||
val helper = LocalHelper.current
|
||||
val title = stringResource(R.string.console_title)
|
||||
val title = stringResource(I18R.string.feat_console_title)
|
||||
helper.repeatOnLifecycle {
|
||||
this.title = title
|
||||
}
|
||||
|
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="console_title">Console Editor</string>
|
||||
</resources>
|
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="console_title">Console Editor</string>
|
||||
</resources>
|
@ -25,7 +25,6 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import com.m3u.data.database.entity.Live
|
||||
import com.m3u.features.favorite.R
|
||||
import com.m3u.ui.components.Image
|
||||
import com.m3u.ui.components.TextBadge
|
||||
import com.m3u.ui.model.LocalScalable
|
||||
@ -33,6 +32,7 @@ import com.m3u.ui.model.LocalSpacing
|
||||
import com.m3u.ui.model.LocalTheme
|
||||
import com.m3u.ui.ktx.animated
|
||||
import java.net.URI
|
||||
import com.m3u.i18n.R as I18R
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
@ -52,7 +52,7 @@ internal fun FavoriteItem(
|
||||
val actualBackgroundColor by theme.surface.animated("FavoriteItemBackground")
|
||||
val actualContentColor by theme.onSurface.animated("FavoriteItemContent")
|
||||
val scheme = remember(live) {
|
||||
URI(live.url).scheme ?: context.getString(R.string.scheme_unknown).uppercase()
|
||||
URI(live.url).scheme ?: context.getString(I18R.string.feat_feed_scheme_unknown).uppercase()
|
||||
}
|
||||
Surface(
|
||||
shape = RoundedCornerShape(spacing.medium),
|
||||
|
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="scheme_unknown">未知</string>
|
||||
</resources>
|
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="scheme_unknown">unknown</string>
|
||||
</resources>
|
@ -94,6 +94,7 @@ import com.m3u.ui.model.Scalable
|
||||
import com.m3u.ui.model.repeatOnLifecycle
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import com.m3u.i18n.R as I18R
|
||||
|
||||
internal typealias NavigateToLive = (liveId: Int) -> Unit
|
||||
internal typealias NavigateToPlaylist = (playlist: List<Int>, initial: Int) -> Unit
|
||||
@ -259,7 +260,7 @@ private fun FeedScreen(
|
||||
onValueChange = onQuery,
|
||||
fontWeight = FontWeight.Bold,
|
||||
height = 32.dp,
|
||||
placeholder = stringResource(R.string.query_placeholder).capitalize(Locale.current),
|
||||
placeholder = stringResource(I18R.string.feat_feed_query_placeholder).capitalize(Locale.current),
|
||||
modifier = Modifier
|
||||
.padding(spacing.medium)
|
||||
.fillMaxWidth()
|
||||
|
@ -23,6 +23,7 @@ import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import com.m3u.i18n.R as I18R
|
||||
|
||||
@HiltViewModel
|
||||
class FeedViewModel @Inject constructor(
|
||||
@ -54,7 +55,7 @@ class FeedViewModel @Inject constructor(
|
||||
private fun observe(feedUrl: String) {
|
||||
observeJob?.cancel()
|
||||
if (feedUrl.isEmpty()) {
|
||||
val message = string(R.string.error_observe_feed, "")
|
||||
val message = string(I18R.string.feat_feed_error_observe_feed, "")
|
||||
onMessage(message)
|
||||
return
|
||||
}
|
||||
@ -74,7 +75,7 @@ class FeedViewModel @Inject constructor(
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val message = string(R.string.error_observe_feed, feedUrl)
|
||||
val message = string(I18R.string.feat_feed_error_observe_feed, feedUrl)
|
||||
onMessage(message)
|
||||
}
|
||||
}
|
||||
|
@ -14,11 +14,11 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import com.m3u.data.database.entity.Live
|
||||
import com.m3u.features.feed.R
|
||||
import com.m3u.ui.components.DialogTextField
|
||||
import com.m3u.ui.components.DialogItem
|
||||
import com.m3u.ui.components.AppDialog
|
||||
import com.m3u.ui.model.LocalSpacing
|
||||
import com.m3u.i18n.R as I18R
|
||||
|
||||
internal typealias OnUpdateDialogStatus = (DialogStatus) -> Unit
|
||||
internal typealias OnFavoriteLive = (liveId: Int, target: Boolean) -> Unit
|
||||
@ -48,18 +48,18 @@ internal fun FeedDialog(
|
||||
)
|
||||
val favourite = status.live.favourite
|
||||
DialogItem(
|
||||
if (favourite) R.string.dialog_favourite_cancel_title
|
||||
else R.string.dialog_favourite_title
|
||||
if (favourite) I18R.string.feat_feed_dialog_favourite_cancel_title
|
||||
else I18R.string.feat_feed_dialog_favourite_title
|
||||
) {
|
||||
onUpdate(DialogStatus.Idle)
|
||||
onFavorite(status.live.id, !favourite)
|
||||
}
|
||||
DialogItem(R.string.dialog_mute_title) {
|
||||
DialogItem(I18R.string.feat_feed_dialog_mute_title) {
|
||||
onUpdate(DialogStatus.Idle)
|
||||
onBanned(status.live.id, true)
|
||||
}
|
||||
if (!status.live.cover.isNullOrEmpty()) {
|
||||
DialogItem(R.string.dialog_save_picture_title) {
|
||||
DialogItem(I18R.string.feat_feed_dialog_save_picture_title) {
|
||||
onUpdate(DialogStatus.Idle)
|
||||
onSavePicture(status.live.id)
|
||||
}
|
||||
|
@ -28,13 +28,13 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import com.m3u.data.database.entity.Live
|
||||
import com.m3u.features.feed.R
|
||||
import com.m3u.ui.components.Image
|
||||
import com.m3u.ui.components.TextBadge
|
||||
import com.m3u.ui.model.LocalScalable
|
||||
import com.m3u.ui.model.LocalSpacing
|
||||
import com.m3u.ui.model.LocalTheme
|
||||
import java.net.URI
|
||||
import com.m3u.i18n.R as I18R
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
@ -57,7 +57,7 @@ internal fun LiveItem(
|
||||
URI(live.url).scheme
|
||||
} catch (ignored: Exception) {
|
||||
null
|
||||
} ?: context.getString(R.string.scheme_unknown).uppercase()
|
||||
} ?: context.getString(I18R.string.feat_feed_scheme_unknown).uppercase()
|
||||
}
|
||||
Surface(
|
||||
shape = RoundedCornerShape(spacing.medium),
|
||||
|
@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="scheme_unknown">未知</string>
|
||||
<string name="dialog_menu_title">屏蔽这个频道?</string>
|
||||
|
||||
<string name="dialog_favourite_title">喜欢</string>
|
||||
<string name="dialog_favourite_cancel_title">取消喜欢</string>
|
||||
<string name="dialog_mute_title">屏蔽</string>
|
||||
|
||||
<string name="error_observe_feed">订阅不存在(%s)</string>
|
||||
<string name="dialog_save_picture_title">保存封面</string>
|
||||
<string name="query_placeholder">输入关键字</string>
|
||||
</resources>
|
@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="scheme_unknown">unknown</string>
|
||||
<string name="dialog_menu_title">do you want to ban this live?</string>
|
||||
<string name="dialog_favourite_title">like</string>
|
||||
<string name="dialog_favourite_cancel_title">cancel like</string>
|
||||
<string name="dialog_mute_title">ban</string>
|
||||
<string name="error_observe_feed">playlist is not existed (%s)</string>
|
||||
<string name="dialog_save_picture_title">save to gallery</string>
|
||||
<string name="query_placeholder">enter key word</string>
|
||||
</resources>
|
@ -24,12 +24,12 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.m3u.features.live.R
|
||||
import com.m3u.ui.components.CircularProgressIndicator
|
||||
import com.m3u.ui.components.MaskState
|
||||
import com.m3u.ui.components.OnDismiss
|
||||
import com.m3u.ui.model.LocalSpacing
|
||||
import net.mm2d.upnp.Device
|
||||
import com.m3u.i18n.R as I18R
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
@ -67,7 +67,7 @@ fun DlnaDevicesBottomSheet(
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.dlna_devices),
|
||||
text = stringResource(I18R.string.feat_live_dlna_devices),
|
||||
fontWeight = FontWeight.Bold,
|
||||
style = MaterialTheme.typography.h6,
|
||||
modifier = Modifier.weight(1f)
|
||||
|
@ -39,7 +39,6 @@ import androidx.media3.common.PlaybackException
|
||||
import androidx.media3.common.Player
|
||||
import com.m3u.core.annotation.ClipMode
|
||||
import com.m3u.core.util.basic.isNotEmpty
|
||||
import com.m3u.features.live.R
|
||||
import com.m3u.features.live.components.CoverPlaceholder
|
||||
import com.m3u.features.live.components.LiveMask
|
||||
import com.m3u.ui.components.Background
|
||||
@ -52,6 +51,7 @@ import com.m3u.ui.components.rememberPlayerState
|
||||
import com.m3u.ui.model.LocalHelper
|
||||
import com.m3u.ui.model.LocalSpacing
|
||||
import com.m3u.ui.model.LocalTheme
|
||||
import com.m3u.i18n.R as I18R
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
@ -114,7 +114,7 @@ internal fun LiveFragment(
|
||||
state = maskState,
|
||||
icon = Icons.AutoMirrored.Rounded.ArrowBack,
|
||||
onClick = onBackPressed,
|
||||
contentDescription = stringResource(R.string.tooltip_on_back_pressed)
|
||||
contentDescription = stringResource(I18R.string.feat_live_tooltip_on_back_pressed)
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
MaskButton(
|
||||
@ -122,16 +122,16 @@ internal fun LiveFragment(
|
||||
icon = if (muted) Icons.AutoMirrored.Rounded.VolumeMute
|
||||
else Icons.AutoMirrored.Rounded.VolumeUp,
|
||||
onClick = onMuted,
|
||||
contentDescription = if (muted) stringResource(R.string.tooltip_unmute)
|
||||
else stringResource(R.string.tooltip_mute)
|
||||
contentDescription = if (muted) stringResource(I18R.string.feat_live_tooltip_unmute)
|
||||
else stringResource(I18R.string.feat_live_tooltip_mute)
|
||||
)
|
||||
MaskButton(
|
||||
state = maskState,
|
||||
icon = Icons.Rounded.Star,
|
||||
tint = if (stared) Color.Yellow else Color.Unspecified,
|
||||
onClick = onFavourite,
|
||||
contentDescription = if (stared) stringResource(R.string.tooltip_unfavourite)
|
||||
else stringResource(R.string.tooltip_favourite)
|
||||
contentDescription = if (stared) stringResource(I18R.string.feat_live_tooltip_unfavourite)
|
||||
else stringResource(I18R.string.feat_live_tooltip_favourite)
|
||||
)
|
||||
if (experimentalMode) {
|
||||
MaskButton(
|
||||
@ -142,8 +142,8 @@ internal fun LiveFragment(
|
||||
tint = if (recording) LocalTheme.current.error
|
||||
else Color.Unspecified,
|
||||
onClick = onRecord,
|
||||
contentDescription = if (recording) stringResource(R.string.tooltip_unrecord)
|
||||
else stringResource(R.string.tooltip_record)
|
||||
contentDescription = if (recording) stringResource(I18R.string.feat_live_tooltip_unrecord)
|
||||
else stringResource(I18R.string.feat_live_tooltip_record)
|
||||
)
|
||||
if (playback != Player.STATE_IDLE) {
|
||||
MaskButton(
|
||||
@ -151,7 +151,7 @@ internal fun LiveFragment(
|
||||
enabled = false,
|
||||
icon = Icons.Rounded.Cast,
|
||||
onClick = searchDlnaDevices,
|
||||
contentDescription = stringResource(R.string.tooltip_cast)
|
||||
contentDescription = stringResource(I18R.string.feat_live_tooltip_cast)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -163,7 +163,7 @@ internal fun LiveFragment(
|
||||
helper.enterPipMode(videoSize)
|
||||
maskState.sleep()
|
||||
},
|
||||
contentDescription = stringResource(R.string.tooltip_enter_pip_mode)
|
||||
contentDescription = stringResource(I18R.string.feat_live_tooltip_enter_pip_mode)
|
||||
)
|
||||
}
|
||||
},
|
||||
@ -255,10 +255,10 @@ private val PlaybackException?.displayText: String
|
||||
|
||||
private val @Player.State Int.displayText: String
|
||||
@Composable get() = when (this) {
|
||||
Player.STATE_IDLE -> R.string.playback_state_idle
|
||||
Player.STATE_BUFFERING -> R.string.playback_state_buffering
|
||||
Player.STATE_IDLE -> I18R.string.feat_live_playback_state_idle
|
||||
Player.STATE_BUFFERING -> I18R.string.feat_live_playback_state_buffering
|
||||
Player.STATE_READY -> null
|
||||
Player.STATE_ENDED -> R.string.playback_state_ended
|
||||
Player.STATE_ENDED -> I18R.string.feat_live_playback_state_ended
|
||||
else -> null
|
||||
}
|
||||
?.let { stringResource(it) }
|
||||
|
@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="playback_state_idle">空闲</string>
|
||||
<string name="playback_state_buffering">缓冲中</string>
|
||||
<string name="playback_state_ready">就绪</string>
|
||||
<string name="playback_state_ended">结束</string>
|
||||
|
||||
<string name="tooltip_on_back_pressed">返回</string>
|
||||
<string name="tooltip_mute">静音</string>
|
||||
<string name="tooltip_unmute">取消静音</string>
|
||||
<string name="tooltip_favourite">收藏</string>
|
||||
<string name="tooltip_unfavourite">取消收藏</string>
|
||||
<string name="tooltip_record">录制</string>
|
||||
<string name="tooltip_unrecord">停止录制</string>
|
||||
<string name="tooltip_cast">投屏</string>
|
||||
<string name="tooltip_enter_pip_mode">画中画模式</string>
|
||||
<string name="dlna_devices">DLNA 设备</string>
|
||||
</resources>
|
@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="playback_state_idle">idle</string>
|
||||
<string name="playback_state_buffering">buffering</string>
|
||||
<string name="playback_state_ready">ready</string>
|
||||
<string name="playback_state_ended">completed</string>
|
||||
|
||||
<string name="tooltip_on_back_pressed">back</string>
|
||||
<string name="tooltip_mute">mute</string>
|
||||
<string name="tooltip_unmute">unmute</string>
|
||||
<string name="tooltip_favourite">favourite</string>
|
||||
<string name="tooltip_unfavourite">unfavourite</string>
|
||||
<string name="tooltip_record">record</string>
|
||||
<string name="tooltip_unrecord">unrecord</string>
|
||||
<string name="tooltip_cast">cast screen</string>
|
||||
<string name="tooltip_enter_pip_mode">PIP mode</string>
|
||||
<string name="dlna_devices">DLNA Devices</string>
|
||||
</resources>
|
@ -36,6 +36,7 @@ import com.m3u.ui.model.LocalHelper
|
||||
import com.m3u.ui.model.LocalScalable
|
||||
import com.m3u.ui.model.LocalSpacing
|
||||
import com.m3u.ui.model.Scalable
|
||||
import com.m3u.i18n.R as I18R
|
||||
|
||||
private typealias showDialog = (Feed) -> Unit
|
||||
typealias NavigateToFeed = (feed: Feed) -> Unit
|
||||
@ -213,7 +214,7 @@ private fun LandscapeOrientationContent(
|
||||
@Composable
|
||||
private fun Feed.calculateUiTitle(): AnnotatedString {
|
||||
val actual = title.ifEmpty {
|
||||
if (local) stringResource(R.string.imported_feed_title)
|
||||
if (local) stringResource(I18R.string.feat_main_imported_feed_title)
|
||||
else ""
|
||||
}
|
||||
return AnnotatedString(
|
||||
|
@ -18,6 +18,7 @@ import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import com.m3u.i18n.R as I18R
|
||||
|
||||
@HiltViewModel
|
||||
class MainViewModel @Inject constructor(
|
||||
@ -70,7 +71,7 @@ class MainViewModel @Inject constructor(
|
||||
viewModelScope.launch {
|
||||
val feed = feedRepository.unsubscribe(url)
|
||||
if (feed == null) {
|
||||
val message = string(R.string.error_unsubscribe_feed)
|
||||
val message = string(I18R.string.feat_main_error_unsubscribe_feed)
|
||||
logger.log(message)
|
||||
}
|
||||
}
|
||||
|
@ -15,13 +15,13 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.m3u.data.database.entity.Feed
|
||||
import com.m3u.features.main.R
|
||||
import com.m3u.ui.components.AppDialog
|
||||
import com.m3u.ui.components.DialogItem
|
||||
import com.m3u.ui.components.DialogTextField
|
||||
import com.m3u.ui.ktx.animateDp
|
||||
import com.m3u.ui.model.LocalSpacing
|
||||
import com.m3u.ui.model.LocalTheme
|
||||
import com.m3u.i18n.R as I18R
|
||||
|
||||
internal typealias OnUpdateStatus = (MainDialog) -> Unit
|
||||
internal typealias OnUnsubscribe = (feedUrl: String) -> Unit
|
||||
@ -68,7 +68,7 @@ internal fun MainDialog(
|
||||
var renamedText by remember(currentStatus) {
|
||||
mutableStateOf(
|
||||
with(currentStatus.feed) {
|
||||
if (editable) title else context.getString(R.string.imported_feed_title)
|
||||
if (editable) title else context.getString(I18R.string.feat_main_imported_feed_title)
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -87,13 +87,13 @@ internal fun MainDialog(
|
||||
}
|
||||
)
|
||||
if (!editMode) {
|
||||
DialogItem(R.string.unsubscribe_feed) {
|
||||
DialogItem(I18R.string.feat_main_unsubscribe_feed) {
|
||||
unsubscribe(currentStatus.feed.url)
|
||||
update(MainDialog.Idle)
|
||||
}
|
||||
if (!currentStatus.feed.local) {
|
||||
val clipboardManager = LocalClipboardManager.current
|
||||
DialogItem(R.string.copy_feed_url) {
|
||||
DialogItem(I18R.string.feat_main_copy_feed_url) {
|
||||
val annotatedString = AnnotatedString(currentStatus.feed.url)
|
||||
clipboardManager.setText(annotatedString)
|
||||
update(MainDialog.Idle)
|
||||
|
@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="muted_lives_feed">屏蔽的频道</string>
|
||||
<string name="unsubscribe_feed">取消订阅</string>
|
||||
<string name="error_unsubscribe_feed">取消订阅失败</string>
|
||||
<string name="copy_feed_url">复制链接</string>
|
||||
<string name="rename_feed">重命名</string>
|
||||
<string name="imported_feed_title">导入频道</string>
|
||||
</resources>
|
@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="muted_lives_feed">banned lives</string>
|
||||
<string name="unsubscribe_feed">unsubscribe</string>
|
||||
<string name="error_unsubscribe_feed">cannot unsubscribe</string>
|
||||
<string name="copy_feed_url">copy url</string>
|
||||
<string name="rename_feed">rename</string>
|
||||
<string name="imported_feed_title">imported</string>
|
||||
</resources>
|
@ -23,6 +23,7 @@ import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import com.m3u.i18n.R as I18R
|
||||
|
||||
@HiltViewModel
|
||||
class SettingViewModel @Inject constructor(
|
||||
@ -159,7 +160,7 @@ class SettingViewModel @Inject constructor(
|
||||
private fun subscribe() {
|
||||
val title = writable.value.title
|
||||
if (title.isEmpty()) {
|
||||
val message = string(R.string.error_empty_title)
|
||||
val message = string(I18R.string.feat_setting_error_empty_title)
|
||||
logger.log(message)
|
||||
return
|
||||
}
|
||||
@ -167,8 +168,8 @@ class SettingViewModel @Inject constructor(
|
||||
val url = readable.actualUrl
|
||||
if (url == null) {
|
||||
val message = when {
|
||||
readable.localStorage -> string(R.string.error_unselected_file)
|
||||
else -> string(R.string.error_blank_url)
|
||||
readable.localStorage -> string(I18R.string.feat_setting_error_unselected_file)
|
||||
else -> string(I18R.string.feat_setting_error_blank_url)
|
||||
}
|
||||
logger.log(message)
|
||||
return
|
||||
@ -186,7 +187,7 @@ class SettingViewModel @Inject constructor(
|
||||
.addTag(url)
|
||||
.build()
|
||||
workManager.enqueue(request)
|
||||
val message = string(R.string.enqueue_subscribe)
|
||||
val message = string(I18R.string.feat_setting_enqueue_subscribe)
|
||||
logger.log(message)
|
||||
writable.update {
|
||||
it.copy(
|
||||
|
@ -27,13 +27,13 @@ import com.m3u.core.annotation.OnClipMode
|
||||
import com.m3u.core.annotation.OnFeedStrategy
|
||||
import com.m3u.features.setting.NavigateToAbout
|
||||
import com.m3u.features.setting.NavigateToConsole
|
||||
import com.m3u.features.setting.R
|
||||
import com.m3u.features.setting.components.CheckBoxPreference
|
||||
import com.m3u.features.setting.components.IconPreference
|
||||
import com.m3u.features.setting.components.Preference
|
||||
import com.m3u.features.setting.components.TextPreference
|
||||
import com.m3u.ui.Destination
|
||||
import com.m3u.ui.model.LocalSpacing
|
||||
import com.m3u.i18n.R as I18R
|
||||
|
||||
@Composable
|
||||
internal fun PreferencesFragment(
|
||||
@ -84,43 +84,43 @@ internal fun PreferencesFragment(
|
||||
verticalArrangement = Arrangement.spacedBy(1.dp)
|
||||
) {
|
||||
Preference(
|
||||
title = stringResource(R.string.feed_management),
|
||||
title = stringResource(I18R.string.feat_setting_feed_management),
|
||||
enabled = true,
|
||||
onClick = onFeedManagement
|
||||
)
|
||||
|
||||
TextPreference(
|
||||
title = stringResource(R.string.sync_mode),
|
||||
title = stringResource(I18R.string.feat_setting_sync_mode),
|
||||
content = when (feedStrategy) {
|
||||
FeedStrategy.ALL -> stringResource(R.string.sync_mode_all)
|
||||
FeedStrategy.SKIP_FAVORITE -> stringResource(R.string.sync_mode_skip_favourite)
|
||||
FeedStrategy.ALL -> stringResource(I18R.string.feat_setting_sync_mode_all)
|
||||
FeedStrategy.SKIP_FAVORITE -> stringResource(I18R.string.feat_setting_sync_mode_skip_favourite)
|
||||
else -> ""
|
||||
},
|
||||
onClick = onFeedStrategy
|
||||
)
|
||||
TextPreference(
|
||||
title = stringResource(R.string.clip_mode),
|
||||
title = stringResource(I18R.string.feat_setting_clip_mode),
|
||||
content = when (clipMode) {
|
||||
ClipMode.ADAPTIVE -> stringResource(R.string.clip_mode_adaptive)
|
||||
ClipMode.CLIP -> stringResource(R.string.clip_mode_clip)
|
||||
ClipMode.STRETCHED -> stringResource(R.string.clip_mode_stretched)
|
||||
ClipMode.ADAPTIVE -> stringResource(I18R.string.feat_setting_clip_mode_adaptive)
|
||||
ClipMode.CLIP -> stringResource(I18R.string.feat_setting_clip_mode_clip)
|
||||
ClipMode.STRETCHED -> stringResource(I18R.string.feat_setting_clip_mode_stretched)
|
||||
else -> ""
|
||||
},
|
||||
onClick = onClipMode
|
||||
)
|
||||
TextPreference(
|
||||
title = stringResource(R.string.connect_timeout),
|
||||
title = stringResource(I18R.string.feat_setting_connect_timeout),
|
||||
content = "${connectTimeout / 1000}s",
|
||||
onClick = onConnectTimeout
|
||||
)
|
||||
TextPreference(
|
||||
title = stringResource(R.string.initial_tab),
|
||||
title = stringResource(I18R.string.feat_setting_initial_tab),
|
||||
content = stringResource(Destination.Root.entries[initialRootDestination].iconTextId),
|
||||
onClick = onInitialTabIndex
|
||||
)
|
||||
CheckBoxPreference(
|
||||
title = stringResource(R.string.auto_refresh),
|
||||
subtitle = stringResource(R.string.auto_refresh_description),
|
||||
title = stringResource(I18R.string.feat_setting_auto_refresh),
|
||||
subtitle = stringResource(I18R.string.feat_setting_auto_refresh_description),
|
||||
checked = autoRefresh,
|
||||
onCheckedChange = { newValue ->
|
||||
if (newValue != autoRefresh) {
|
||||
@ -129,8 +129,8 @@ internal fun PreferencesFragment(
|
||||
}
|
||||
)
|
||||
CheckBoxPreference(
|
||||
title = stringResource(R.string.no_picture_mode),
|
||||
subtitle = stringResource(R.string.no_picture_mode_description),
|
||||
title = stringResource(I18R.string.feat_setting_no_picture_mode),
|
||||
subtitle = stringResource(I18R.string.feat_setting_no_picture_mode_description),
|
||||
checked = noPictureMode,
|
||||
onCheckedChange = { newValue ->
|
||||
if (newValue != noPictureMode) {
|
||||
@ -139,8 +139,8 @@ internal fun PreferencesFragment(
|
||||
}
|
||||
)
|
||||
CheckBoxPreference(
|
||||
title = stringResource(R.string.full_info_player),
|
||||
subtitle = stringResource(R.string.full_info_player_description),
|
||||
title = stringResource(I18R.string.feat_setting_full_info_player),
|
||||
subtitle = stringResource(I18R.string.feat_setting_full_info_player_description),
|
||||
checked = fullInfoPlayer,
|
||||
onCheckedChange = { newValue ->
|
||||
if (newValue != fullInfoPlayer) {
|
||||
@ -149,8 +149,8 @@ internal fun PreferencesFragment(
|
||||
}
|
||||
)
|
||||
CheckBoxPreference(
|
||||
title = stringResource(R.string.god_mode),
|
||||
subtitle = stringResource(R.string.god_mode_description),
|
||||
title = stringResource(I18R.string.feat_setting_god_mode),
|
||||
subtitle = stringResource(I18R.string.feat_setting_god_mode_description),
|
||||
checked = godMode,
|
||||
onCheckedChange = { newValue ->
|
||||
if (newValue != godMode) {
|
||||
@ -159,9 +159,9 @@ internal fun PreferencesFragment(
|
||||
}
|
||||
)
|
||||
CheckBoxPreference(
|
||||
title = stringResource(R.string.common_ui_mode),
|
||||
subtitle = if (useCommonUIModeEnable) stringResource(R.string.common_ui_mode_description)
|
||||
else stringResource(R.string.common_ui_mode_disabled_description),
|
||||
title = stringResource(I18R.string.feat_setting_common_ui_mode),
|
||||
subtitle = if (useCommonUIModeEnable) stringResource(I18R.string.feat_setting_common_ui_mode_description)
|
||||
else stringResource(I18R.string.feat_setting_common_ui_mode_disabled_description),
|
||||
enabled = useCommonUIModeEnable,
|
||||
checked = useCommonUIMode,
|
||||
onCheckedChange = { newValue ->
|
||||
@ -181,8 +181,8 @@ internal fun PreferencesFragment(
|
||||
verticalArrangement = Arrangement.spacedBy(1.dp)
|
||||
) {
|
||||
CheckBoxPreference(
|
||||
title = stringResource(R.string.experimental_mode),
|
||||
subtitle = stringResource(R.string.experimental_mode_description),
|
||||
title = stringResource(I18R.string.feat_setting_experimental_mode),
|
||||
subtitle = stringResource(I18R.string.feat_setting_experimental_mode_description),
|
||||
checked = experimentalMode,
|
||||
onCheckedChange = { newValue ->
|
||||
if (newValue != experimentalMode) {
|
||||
@ -203,8 +203,8 @@ internal fun PreferencesFragment(
|
||||
verticalArrangement = Arrangement.spacedBy(1.dp)
|
||||
) {
|
||||
CheckBoxPreference(
|
||||
title = stringResource(R.string.cinema_mode),
|
||||
subtitle = stringResource(R.string.cinema_mode_description),
|
||||
title = stringResource(I18R.string.feat_setting_cinema_mode),
|
||||
subtitle = stringResource(I18R.string.feat_setting_cinema_mode_description),
|
||||
checked = cinemaMode,
|
||||
onCheckedChange = { newValue ->
|
||||
if (newValue != cinemaMode) {
|
||||
@ -213,16 +213,16 @@ internal fun PreferencesFragment(
|
||||
}
|
||||
)
|
||||
Preference(
|
||||
title = stringResource(R.string.script_management),
|
||||
title = stringResource(I18R.string.feat_setting_script_management),
|
||||
enabled = true,
|
||||
onClick = onScriptManagement
|
||||
)
|
||||
Preference(
|
||||
title = stringResource(R.string.console_editor),
|
||||
title = stringResource(I18R.string.feat_setting_console_editor),
|
||||
onClick = navigateToConsole
|
||||
)
|
||||
CheckBoxPreference(
|
||||
title = stringResource(R.string.scroll_mode),
|
||||
title = stringResource(I18R.string.feat_setting_scroll_mode),
|
||||
checked = scrollMode,
|
||||
onCheckedChange = { newValue ->
|
||||
if (newValue != scrollMode) {
|
||||
@ -231,8 +231,8 @@ internal fun PreferencesFragment(
|
||||
}
|
||||
)
|
||||
CheckBoxPreference(
|
||||
title = stringResource(R.string.ssl_verification_enabled),
|
||||
subtitle = stringResource(R.string.ssl_verification_enabled_description),
|
||||
title = stringResource(I18R.string.feat_setting_ssl_verification_enabled),
|
||||
subtitle = stringResource(I18R.string.feat_setting_ssl_verification_enabled_description),
|
||||
checked = isSSLVerificationEnabled,
|
||||
onCheckedChange = { newValue ->
|
||||
if (newValue != isSSLVerificationEnabled) {
|
||||
@ -253,7 +253,7 @@ internal fun PreferencesFragment(
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
IconPreference(
|
||||
title = stringResource(R.string.system_setting),
|
||||
title = stringResource(I18R.string.feat_setting_system_setting),
|
||||
imageVector = Icons.AutoMirrored.Rounded.OpenInNew,
|
||||
onClick = {
|
||||
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
|
||||
@ -264,17 +264,17 @@ internal fun PreferencesFragment(
|
||||
)
|
||||
// TODO: https://www.dropbox.com/developers/documentation/http/documentation#file_requests-list
|
||||
Preference(
|
||||
title = stringResource(R.string.dropbox).uppercase(),
|
||||
title = stringResource(I18R.string.feat_setting_dropbox).uppercase(),
|
||||
onClick = navigateToAbout,
|
||||
enabled = false
|
||||
)
|
||||
Preference(
|
||||
title = stringResource(R.string.project_about),
|
||||
title = stringResource(I18R.string.feat_setting_project_about),
|
||||
onClick = navigateToAbout,
|
||||
// enabled = false
|
||||
)
|
||||
Preference(
|
||||
title = stringResource(R.string.app_version),
|
||||
title = stringResource(I18R.string.feat_setting_app_version),
|
||||
subtitle = version
|
||||
)
|
||||
}
|
||||
|
@ -7,9 +7,9 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.m3u.features.setting.R
|
||||
import com.m3u.ui.components.Button
|
||||
import com.m3u.ui.components.OuterColumn
|
||||
import com.m3u.i18n.R as I18R
|
||||
|
||||
@Composable
|
||||
internal fun ScriptsFragment(
|
||||
@ -33,7 +33,7 @@ internal fun ScriptsFragment(
|
||||
|
||||
}
|
||||
Button(
|
||||
textRes = R.string.script_management_import_js,
|
||||
textRes = I18R.string.feat_setting_script_management_import_js,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = {
|
||||
launcher.launch(arrayOf("text/javascript"))
|
||||
|
@ -39,13 +39,13 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.m3u.core.util.readContentFilename
|
||||
import com.m3u.data.database.entity.Live
|
||||
import com.m3u.features.setting.R
|
||||
import com.m3u.features.setting.components.MutedLiveItem
|
||||
import com.m3u.ui.components.Button
|
||||
import com.m3u.ui.components.LabelField
|
||||
import com.m3u.ui.components.TextButton
|
||||
import com.m3u.ui.model.LocalSpacing
|
||||
import com.m3u.ui.model.LocalTheme
|
||||
import com.m3u.i18n.R as I18R
|
||||
|
||||
@Composable
|
||||
internal fun SubscriptionsFragment(
|
||||
@ -80,7 +80,7 @@ internal fun SubscriptionsFragment(
|
||||
verticalArrangement = Arrangement.spacedBy(1.dp)
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.label_muted_lives),
|
||||
text = stringResource(I18R.string.feat_setting_label_muted_lives),
|
||||
style = MaterialTheme.typography.button,
|
||||
color = theme.onTint,
|
||||
modifier = Modifier
|
||||
@ -105,7 +105,7 @@ internal fun SubscriptionsFragment(
|
||||
item {
|
||||
LabelField(
|
||||
text = title,
|
||||
placeholder = stringResource(R.string.placeholder_title).uppercase(),
|
||||
placeholder = stringResource(I18R.string.feat_setting_placeholder_title).uppercase(),
|
||||
onValueChange = onTitle,
|
||||
keyboardActions = KeyboardActions(
|
||||
onNext = {
|
||||
@ -124,7 +124,7 @@ internal fun SubscriptionsFragment(
|
||||
if (!localStorage) {
|
||||
LabelField(
|
||||
text = url,
|
||||
placeholder = stringResource(R.string.placeholder_url).uppercase(),
|
||||
placeholder = stringResource(I18R.string.feat_setting_placeholder_url).uppercase(),
|
||||
onValueChange = onUrl,
|
||||
keyboardActions = KeyboardActions(
|
||||
onDone = {
|
||||
@ -154,7 +154,7 @@ internal fun SubscriptionsFragment(
|
||||
item {
|
||||
Column {
|
||||
Button(
|
||||
text = stringResource(R.string.label_subscribe),
|
||||
text = stringResource(I18R.string.feat_setting_label_subscribe),
|
||||
onClick = onSubscribe,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
@ -189,7 +189,7 @@ fun LocalStorageSwitch(
|
||||
horizontalArrangement = Arrangement.spacedBy(spacing.medium)
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.local_storage),
|
||||
text = stringResource(I18R.string.feat_setting_local_storage),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
@ -214,7 +214,7 @@ private fun LocalStorageButton(
|
||||
val icon = Icons.AutoMirrored.Rounded.OpenInNew
|
||||
val text = if (selected) remember(uri) {
|
||||
uri?.readContentFilename(context.contentResolver).orEmpty()
|
||||
} else stringResource(R.string.label_select_from_local_storage)
|
||||
} else stringResource(I18R.string.feat_setting_label_select_from_local_storage)
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
@ -262,7 +262,7 @@ private fun ClipboardButton(
|
||||
val clipboardManager = LocalClipboardManager.current
|
||||
TextButton(
|
||||
enabled = enabled,
|
||||
text = stringResource(R.string.label_parse_from_clipboard),
|
||||
text = stringResource(I18R.string.feat_setting_label_parse_from_clipboard),
|
||||
onClick = {
|
||||
val clipboardUrl = clipboardManager.getText()?.text.orEmpty()
|
||||
val clipboardTitle = run {
|
||||
|
@ -1,58 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="placeholder_url">订阅链接</string>
|
||||
<string name="app_version">应用版本</string>
|
||||
<string name="label_subscribe">订阅</string>
|
||||
|
||||
<string name="success_subscribe">订阅成功</string>
|
||||
<string name="failed_malformed_url">URL错误(%s)</string>
|
||||
<string name="error_empty_title">订阅名称为空</string>
|
||||
<string name="placeholder_title">订阅名称</string>
|
||||
<string name="label_subscribing">订阅中…</string>
|
||||
|
||||
<string name="sync_mode_all">所有</string>
|
||||
<string name="sync_mode_skip_favourite">绕过收藏夹</string>
|
||||
<string name="sync_mode">同步策略</string>
|
||||
|
||||
<string name="common_ui_mode">默认布局</string>
|
||||
<string name="common_ui_mode_description">使用手机设备布局模式</string>
|
||||
<string name="common_ui_mode_disabled_description">手机设备不可调整</string>
|
||||
|
||||
<string name="script_management">脚本管理</string>
|
||||
<string name="feed_management">订阅管理</string>
|
||||
<string name="connect_timeout">最大超时时间</string>
|
||||
<string name="god_mode">上帝模式</string>
|
||||
<string name="god_mode_description">通过物理按键调节界面</string>
|
||||
<string name="console_editor">console editor</string>
|
||||
<string name="experimental_mode">试验特性</string>
|
||||
<string name="experimental_mode_description">不稳定的功能可能引发致命错误</string>
|
||||
<string name="label_muted_lives">屏蔽的频道</string>
|
||||
<string name="label_add_feed">新增订阅</string>
|
||||
<string name="label_parse_from_clipboard">解析剪贴板</string>
|
||||
<string name="label_select_from_local_storage">选择文件</string>
|
||||
<string name="label_parse_from_disk">解析本地文件</string>
|
||||
<string name="clip_mode">视频裁剪模式</string>
|
||||
<string name="clip_mode_adaptive">自适应</string>
|
||||
<string name="clip_mode_clip">裁剪</string>
|
||||
<string name="clip_mode_stretched">拉伸</string>
|
||||
<string name="scroll_mode">滑动切换频道</string>
|
||||
<string name="auto_refresh">自动刷新</string>
|
||||
<string name="auto_refresh_description">进入播放列表自动刷新</string>
|
||||
<string name="ssl_verification_enabled">SSL证书校验</string>
|
||||
<string name="ssl_verification_enabled_description">校验网络连接安全性</string>
|
||||
<string name="full_info_player">详细信息的播放器</string>
|
||||
<string name="full_info_player_description">播放器中展示更多的信息</string>
|
||||
<string name="initial_tab">初始界面</string>
|
||||
<string name="no_picture_mode">无图模式</string>
|
||||
<string name="no_picture_mode_description">可能会对性能有所提升</string>
|
||||
<string name="system_setting">系统设置</string>
|
||||
<string name="cinema_mode">影院模式</string>
|
||||
<string name="cinema_mode_description">使用OLED纯黑主题</string>
|
||||
<string name="script_management_import_js">导入Javascript</string>
|
||||
<string name="enqueue_subscribe">订阅任务已添加至队列</string>
|
||||
<string name="dropbox">dropbox</string>
|
||||
<string name="project_about">关于项目</string>
|
||||
<string name="local_storage">本地导入</string>
|
||||
<string name="error_unselected_file">还未选择文件</string>
|
||||
<string name="error_blank_url">目标地址为空</string>
|
||||
</resources>
|
@ -1,54 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="placeholder_url">playlist link</string>
|
||||
<string name="app_version">app version</string>
|
||||
<string name="label_subscribe">subscribe</string>
|
||||
<string name="success_subscribe">subscribe successfully</string>
|
||||
<string name="failed_malformed_url">malformed url (%s)</string>
|
||||
<string name="error_empty_title">playlist name is empty</string>
|
||||
<string name="placeholder_title">playlist name</string>
|
||||
<string name="label_subscribing">subscribing</string>
|
||||
<string name="sync_mode_all">all</string>
|
||||
<string name="sync_mode_skip_favourite">skip favourite</string>
|
||||
<string name="sync_mode">synchronization strategy</string>
|
||||
<string name="common_ui_mode">UI mode</string>
|
||||
<string name="common_ui_mode_description">use mobile device UI mode</string>
|
||||
<string name="common_ui_mode_disabled_description">mobile device could not adjust this</string>
|
||||
<string name="script_management">script management</string>
|
||||
<string name="feed_management">playlist management</string>
|
||||
<string name="connect_timeout">connect timeout</string>
|
||||
<string name="god_mode">god mode</string>
|
||||
<string name="god_mode_description">adjust layouts by physical volume buttons</string>
|
||||
<string name="console_editor">Console Editor</string>
|
||||
<string name="experimental_mode">experimental mode</string>
|
||||
<string name="experimental_mode_description">unstable features can throw fatal errors</string>
|
||||
<string name="label_muted_lives">banned lives</string>
|
||||
<string name="label_add_feed">add playlist</string>
|
||||
<string name="label_parse_from_clipboard">parse clipboard</string>
|
||||
<string name="label_select_from_local_storage">select file</string>
|
||||
<string name="label_parse_from_disk">parse file</string>
|
||||
<string name="clip_mode">video clip mode</string>
|
||||
<string name="clip_mode_adaptive">adaptive</string>
|
||||
<string name="clip_mode_clip">clip</string>
|
||||
<string name="clip_mode_stretched">stretched</string>
|
||||
<string name="scroll_mode">scroll to change lives</string>
|
||||
<string name="auto_refresh">auto refresh</string>
|
||||
<string name="auto_refresh_description">automatically refreshed when enter the playlist</string>
|
||||
<string name="ssl_verification_enabled">SSL certificate verification</string>
|
||||
<string name="ssl_verification_enabled_description">ensure valid and trustworthy SSL/TLS certificates for secure communications</string>
|
||||
<string name="full_info_player">full information player</string>
|
||||
<string name="full_info_player_description">display more information in the player</string>
|
||||
<string name="initial_tab">initial Screen</string>
|
||||
<string name="no_picture_mode">no picture mode</string>
|
||||
<string name="no_picture_mode_description">may improve performance</string>
|
||||
<string name="system_setting">system setting</string>
|
||||
<string name="cinema_mode">cinema mode</string>
|
||||
<string name="cinema_mode_description">use OLED black theme</string>
|
||||
<string name="script_management_import_js">import Javascript</string>
|
||||
<string name="enqueue_subscribe">a subscription task has been added to the queue</string>
|
||||
<string name="dropbox">dropbox</string>
|
||||
<string name="project_about">about project</string>
|
||||
<string name="local_storage">local storage</string>
|
||||
<string name="error_unselected_file">no file selected yet</string>
|
||||
<string name="error_blank_url">blank url</string>
|
||||
</resources>
|
1
i18n/.gitignore
vendored
Normal file
1
i18n/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
38
i18n/build.gradle.kts
Normal file
38
i18n/build.gradle.kts
Normal file
@ -0,0 +1,38 @@
|
||||
plugins {
|
||||
alias(libs.plugins.com.android.library)
|
||||
alias(libs.plugins.org.jetbrains.kotlin.android)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.m3u.i18n"
|
||||
compileSdk = 33
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 26
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = true
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.androidx.core.core.ktx)
|
||||
implementation(libs.androidx.appcompat.appcompat)
|
||||
}
|
0
i18n/consumer-rules.pro
Normal file
0
i18n/consumer-rules.pro
Normal file
21
i18n/proguard-rules.pro
vendored
Normal file
21
i18n/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
4
i18n/src/main/AndroidManifest.xml
Normal file
4
i18n/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest>
|
||||
|
||||
</manifest>
|
4
i18n/src/main/res/values-zh-rCN/app.xml
Normal file
4
i18n/src/main/res/values-zh-rCN/app.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_label_crash">应用发生崩溃</string>
|
||||
</resources>
|
5
i18n/src/main/res/values-zh-rCN/data.xml
Normal file
5
i18n/src/main/res/values-zh-rCN/data.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="data_error_file_not_found">文件不存在</string>
|
||||
<string name="data_error_empty_title">订阅名称为空</string>
|
||||
</resources>
|
4
i18n/src/main/res/values-zh-rCN/feat_about.xml
Normal file
4
i18n/src/main/res/values-zh-rCN/feat_about.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="feat_about_title">关于项目</string>
|
||||
</resources>
|
4
i18n/src/main/res/values-zh-rCN/feat_console.xml
Normal file
4
i18n/src/main/res/values-zh-rCN/feat_console.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="feat_console_title">Console Editor</string>
|
||||
</resources>
|
4
i18n/src/main/res/values-zh-rCN/feat_favourite.xml
Normal file
4
i18n/src/main/res/values-zh-rCN/feat_favourite.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="feat_favorite_scheme_unknown">未知</string>
|
||||
</resources>
|
11
i18n/src/main/res/values-zh-rCN/feat_feed.xml
Normal file
11
i18n/src/main/res/values-zh-rCN/feat_feed.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="feat_feed_scheme_unknown">未知</string>
|
||||
<string name="feat_feed_dialog_menu_title">屏蔽这个频道?</string>
|
||||
<string name="feat_feed_dialog_favourite_title">喜欢</string>
|
||||
<string name="feat_feed_dialog_favourite_cancel_title">取消喜欢</string>
|
||||
<string name="feat_feed_dialog_mute_title">屏蔽</string>
|
||||
<string name="feat_feed_error_observe_feed">订阅不存在(%s)</string>
|
||||
<string name="feat_feed_dialog_save_picture_title">保存封面</string>
|
||||
<string name="feat_feed_query_placeholder">输入关键字</string>
|
||||
</resources>
|
17
i18n/src/main/res/values-zh-rCN/feat_live.xml
Normal file
17
i18n/src/main/res/values-zh-rCN/feat_live.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="feat_live_playback_state_idle">空闲</string>
|
||||
<string name="feat_live_playback_state_buffering">缓冲中</string>
|
||||
<string name="feat_live_playback_state_ready">就绪</string>
|
||||
<string name="feat_live_playback_state_ended">结束</string>
|
||||
<string name="feat_live_tooltip_on_back_pressed">返回</string>
|
||||
<string name="feat_live_tooltip_mute">静音</string>
|
||||
<string name="feat_live_tooltip_unmute">取消静音</string>
|
||||
<string name="feat_live_tooltip_favourite">收藏</string>
|
||||
<string name="feat_live_tooltip_unfavourite">取消收藏</string>
|
||||
<string name="feat_live_tooltip_record">录制</string>
|
||||
<string name="feat_live_tooltip_unrecord">停止录制</string>
|
||||
<string name="feat_live_tooltip_cast">投屏</string>
|
||||
<string name="feat_live_tooltip_enter_pip_mode">画中画模式</string>
|
||||
<string name="feat_live_dlna_devices">DLNA 设备</string>
|
||||
</resources>
|
9
i18n/src/main/res/values-zh-rCN/feat_main.xml
Normal file
9
i18n/src/main/res/values-zh-rCN/feat_main.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="feat_main_muted_lives_feed">屏蔽的频道</string>
|
||||
<string name="feat_main_unsubscribe_feed">取消订阅</string>
|
||||
<string name="feat_main_error_unsubscribe_feed">取消订阅失败</string>
|
||||
<string name="feat_main_copy_feed_url">复制链接</string>
|
||||
<string name="feat_main_rename_feed">重命名</string>
|
||||
<string name="feat_main_imported_feed_title">导入频道</string>
|
||||
</resources>
|
58
i18n/src/main/res/values-zh-rCN/feat_setting.xml
Normal file
58
i18n/src/main/res/values-zh-rCN/feat_setting.xml
Normal file
@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="feat_setting_placeholder_url">订阅链接</string>
|
||||
<string name="feat_setting_app_version">应用版本</string>
|
||||
<string name="feat_setting_label_subscribe">订阅</string>
|
||||
|
||||
<string name="feat_setting_success_subscribe">订阅成功</string>
|
||||
<string name="feat_setting_failed_malformed_url">URL错误(%s)</string>
|
||||
<string name="feat_setting_error_empty_title">订阅名称为空</string>
|
||||
<string name="feat_setting_placeholder_title">订阅名称</string>
|
||||
<string name="feat_setting_label_subscribing">订阅中…</string>
|
||||
|
||||
<string name="feat_setting_sync_mode_all">所有</string>
|
||||
<string name="feat_setting_sync_mode_skip_favourite">绕过收藏夹</string>
|
||||
<string name="feat_setting_sync_mode">同步策略</string>
|
||||
|
||||
<string name="feat_setting_common_ui_mode">默认布局</string>
|
||||
<string name="feat_setting_common_ui_mode_description">使用手机设备布局模式</string>
|
||||
<string name="feat_setting_common_ui_mode_disabled_description">手机设备不可调整</string>
|
||||
|
||||
<string name="feat_setting_script_management">脚本管理</string>
|
||||
<string name="feat_setting_feed_management">订阅管理</string>
|
||||
<string name="feat_setting_connect_timeout">最大超时时间</string>
|
||||
<string name="feat_setting_god_mode">上帝模式</string>
|
||||
<string name="feat_setting_god_mode_description">通过物理按键调节界面</string>
|
||||
<string name="feat_setting_console_editor">console editor</string>
|
||||
<string name="feat_setting_experimental_mode">试验特性</string>
|
||||
<string name="feat_setting_experimental_mode_description">不稳定的功能可能引发致命错误</string>
|
||||
<string name="feat_setting_label_muted_lives">屏蔽的频道</string>
|
||||
<string name="feat_setting_label_add_feed">新增订阅</string>
|
||||
<string name="feat_setting_label_parse_from_clipboard">解析剪贴板</string>
|
||||
<string name="feat_setting_label_select_from_local_storage">选择文件</string>
|
||||
<string name="feat_setting_label_parse_from_disk">解析本地文件</string>
|
||||
<string name="feat_setting_clip_mode">视频裁剪模式</string>
|
||||
<string name="feat_setting_clip_mode_adaptive">自适应</string>
|
||||
<string name="feat_setting_clip_mode_clip">裁剪</string>
|
||||
<string name="feat_setting_clip_mode_stretched">拉伸</string>
|
||||
<string name="feat_setting_scroll_mode">滑动切换频道</string>
|
||||
<string name="feat_setting_auto_refresh">自动刷新</string>
|
||||
<string name="feat_setting_auto_refresh_description">进入播放列表自动刷新</string>
|
||||
<string name="feat_setting_ssl_verification_enabled">SSL证书校验</string>
|
||||
<string name="feat_setting_ssl_verification_enabled_description">校验网络连接安全性</string>
|
||||
<string name="feat_setting_full_info_player">详细信息的播放器</string>
|
||||
<string name="feat_setting_full_info_player_description">播放器中展示更多的信息</string>
|
||||
<string name="feat_setting_initial_tab">初始界面</string>
|
||||
<string name="feat_setting_no_picture_mode">无图模式</string>
|
||||
<string name="feat_setting_no_picture_mode_description">可能会对性能有所提升</string>
|
||||
<string name="feat_setting_system_setting">系统设置</string>
|
||||
<string name="feat_setting_cinema_mode">影院模式</string>
|
||||
<string name="feat_setting_cinema_mode_description">使用OLED纯黑主题</string>
|
||||
<string name="feat_setting_script_management_import_js">导入Javascript</string>
|
||||
<string name="feat_setting_enqueue_subscribe">订阅任务已添加至队列</string>
|
||||
<string name="feat_setting_dropbox">dropbox</string>
|
||||
<string name="feat_setting_project_about">关于项目</string>
|
||||
<string name="feat_setting_local_storage">本地导入</string>
|
||||
<string name="feat_setting_error_unselected_file">还未选择文件</string>
|
||||
<string name="feat_setting_error_blank_url">目标地址为空</string>
|
||||
</resources>
|
17
i18n/src/main/res/values-zh-rCN/ui.xml
Normal file
17
i18n/src/main/res/values-zh-rCN/ui.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="ui_app_name">M3U</string>
|
||||
|
||||
<string name="ui_destination_main">主页</string>
|
||||
<string name="ui_destination_favourite">喜欢</string>
|
||||
<string name="ui_destination_setting">设置</string>
|
||||
|
||||
<string name="ui_title_setting">设置</string>
|
||||
<string name="ui_title_favourite">喜欢</string>
|
||||
|
||||
<string name="ui_error_unknown">未知错误</string>
|
||||
<string name="ui_cd_top_bar_on_back_pressed">返回</string>
|
||||
|
||||
<string name="ui_theme_card_left">您</string>
|
||||
<string name="ui_theme_card_right">好</string>
|
||||
</resources>
|
4
i18n/src/main/res/values/app.xml
Normal file
4
i18n/src/main/res/values/app.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_label_crash">app crashes</string>
|
||||
</resources>
|
5
i18n/src/main/res/values/data.xml
Normal file
5
i18n/src/main/res/values/data.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="data_error_file_not_found">file not found</string>
|
||||
<string name="data_error_empty_title">playlist name is empty</string>
|
||||
</resources>
|
4
i18n/src/main/res/values/feat_about.xml
Normal file
4
i18n/src/main/res/values/feat_about.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="feat_about_title">about project</string>
|
||||
</resources>
|
4
i18n/src/main/res/values/feat_console.xml
Normal file
4
i18n/src/main/res/values/feat_console.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="feat_console_title">Console Editor</string>
|
||||
</resources>
|
4
i18n/src/main/res/values/feat_favourite.xml
Normal file
4
i18n/src/main/res/values/feat_favourite.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="feat_favorite_scheme_unknown">unknown</string>
|
||||
</resources>
|
11
i18n/src/main/res/values/feat_feed.xml
Normal file
11
i18n/src/main/res/values/feat_feed.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="feat_feed_scheme_unknown">unknown</string>
|
||||
<string name="feat_feed_dialog_menu_title">do you want to ban this live?</string>
|
||||
<string name="feat_feed_dialog_favourite_title">like</string>
|
||||
<string name="feat_feed_dialog_favourite_cancel_title">cancel like</string>
|
||||
<string name="feat_feed_dialog_mute_title">ban</string>
|
||||
<string name="feat_feed_error_observe_feed">playlist is not existed (%s)</string>
|
||||
<string name="feat_feed_dialog_save_picture_title">save to gallery</string>
|
||||
<string name="feat_feed_query_placeholder">enter key word</string>
|
||||
</resources>
|
18
i18n/src/main/res/values/feat_live.xml
Normal file
18
i18n/src/main/res/values/feat_live.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="feat_live_playback_state_idle">idle</string>
|
||||
<string name="feat_live_playback_state_buffering">buffering</string>
|
||||
<string name="feat_live_playback_state_ready">ready</string>
|
||||
<string name="feat_live_playback_state_ended">completed</string>
|
||||
|
||||
<string name="feat_live_tooltip_on_back_pressed">back</string>
|
||||
<string name="feat_live_tooltip_mute">mute</string>
|
||||
<string name="feat_live_tooltip_unmute">unmute</string>
|
||||
<string name="feat_live_tooltip_favourite">favourite</string>
|
||||
<string name="feat_live_tooltip_unfavourite">unfavourite</string>
|
||||
<string name="feat_live_tooltip_record">record</string>
|
||||
<string name="feat_live_tooltip_unrecord">unrecord</string>
|
||||
<string name="feat_live_tooltip_cast">cast screen</string>
|
||||
<string name="feat_live_tooltip_enter_pip_mode">PIP mode</string>
|
||||
<string name="feat_live_dlna_devices">DLNA Devices</string>
|
||||
</resources>
|
9
i18n/src/main/res/values/feat_main.xml
Normal file
9
i18n/src/main/res/values/feat_main.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="feat_main_muted_lives_feed">banned lives</string>
|
||||
<string name="feat_main_unsubscribe_feed">unsubscribe</string>
|
||||
<string name="feat_main_error_unsubscribe_feed">cannot unsubscribe</string>
|
||||
<string name="feat_main_copy_feed_url">copy url</string>
|
||||
<string name="feat_main_rename_feed">rename</string>
|
||||
<string name="feat_main_imported_feed_title">imported</string>
|
||||
</resources>
|
54
i18n/src/main/res/values/feat_setting.xml
Normal file
54
i18n/src/main/res/values/feat_setting.xml
Normal file
@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="feat_setting_placeholder_url">playlist link</string>
|
||||
<string name="feat_setting_app_version">app version</string>
|
||||
<string name="feat_setting_label_subscribe">subscribe</string>
|
||||
<string name="feat_setting_success_subscribe">subscribe successfully</string>
|
||||
<string name="feat_setting_failed_malformed_url">malformed url (%s)</string>
|
||||
<string name="feat_setting_error_empty_title">playlist name is empty</string>
|
||||
<string name="feat_setting_placeholder_title">playlist name</string>
|
||||
<string name="feat_setting_label_subscribing">subscribing</string>
|
||||
<string name="feat_setting_sync_mode_all">all</string>
|
||||
<string name="feat_setting_sync_mode_skip_favourite">skip favourite</string>
|
||||
<string name="feat_setting_sync_mode">synchronization strategy</string>
|
||||
<string name="feat_setting_common_ui_mode">UI mode</string>
|
||||
<string name="feat_setting_common_ui_mode_description">use mobile device UI mode</string>
|
||||
<string name="feat_setting_common_ui_mode_disabled_description">mobile device could not adjust this</string>
|
||||
<string name="feat_setting_script_management">script management</string>
|
||||
<string name="feat_setting_feed_management">playlist management</string>
|
||||
<string name="feat_setting_connect_timeout">connect timeout</string>
|
||||
<string name="feat_setting_god_mode">god mode</string>
|
||||
<string name="feat_setting_god_mode_description">adjust layouts by physical volume buttons</string>
|
||||
<string name="feat_setting_console_editor">Console Editor</string>
|
||||
<string name="feat_setting_experimental_mode">experimental mode</string>
|
||||
<string name="feat_setting_experimental_mode_description">unstable features can throw fatal errors</string>
|
||||
<string name="feat_setting_label_muted_lives">banned lives</string>
|
||||
<string name="feat_setting_label_add_feed">add playlist</string>
|
||||
<string name="feat_setting_label_parse_from_clipboard">parse clipboard</string>
|
||||
<string name="feat_setting_label_select_from_local_storage">select file</string>
|
||||
<string name="feat_setting_label_parse_from_disk">parse file</string>
|
||||
<string name="feat_setting_clip_mode">video clip mode</string>
|
||||
<string name="feat_setting_clip_mode_adaptive">adaptive</string>
|
||||
<string name="feat_setting_clip_mode_clip">clip</string>
|
||||
<string name="feat_setting_clip_mode_stretched">stretched</string>
|
||||
<string name="feat_setting_scroll_mode">scroll to change lives</string>
|
||||
<string name="feat_setting_auto_refresh">auto refresh</string>
|
||||
<string name="feat_setting_auto_refresh_description">automatically refreshed when enter the playlist</string>
|
||||
<string name="feat_setting_ssl_verification_enabled">SSL certificate verification</string>
|
||||
<string name="feat_setting_ssl_verification_enabled_description">ensure valid and trustworthy SSL/TLS certificates for secure communications</string>
|
||||
<string name="feat_setting_full_info_player">full information player</string>
|
||||
<string name="feat_setting_full_info_player_description">display more information in the player</string>
|
||||
<string name="feat_setting_initial_tab">initial Screen</string>
|
||||
<string name="feat_setting_no_picture_mode">no picture mode</string>
|
||||
<string name="feat_setting_no_picture_mode_description">may improve performance</string>
|
||||
<string name="feat_setting_system_setting">system setting</string>
|
||||
<string name="feat_setting_cinema_mode">cinema mode</string>
|
||||
<string name="feat_setting_cinema_mode_description">use OLED black theme</string>
|
||||
<string name="feat_setting_script_management_import_js">import Javascript</string>
|
||||
<string name="feat_setting_enqueue_subscribe">a subscription task has been added to the queue</string>
|
||||
<string name="feat_setting_dropbox">dropbox</string>
|
||||
<string name="feat_setting_project_about">about project</string>
|
||||
<string name="feat_setting_local_storage">local storage</string>
|
||||
<string name="feat_setting_error_unselected_file">no file selected yet</string>
|
||||
<string name="feat_setting_error_blank_url">blank url</string>
|
||||
</resources>
|
17
i18n/src/main/res/values/ui.xml
Normal file
17
i18n/src/main/res/values/ui.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="ui_app_name">M3U</string>
|
||||
|
||||
<string name="ui_destination_main">For You</string>
|
||||
<string name="ui_destination_favourite">Favourite</string>
|
||||
<string name="ui_destination_setting">Settings</string>
|
||||
|
||||
<string name="ui_title_setting">Settings</string>
|
||||
<string name="ui_title_favourite">Favourite</string>
|
||||
|
||||
<string name="ui_error_unknown">unknown error</string>
|
||||
<string name="ui_cd_top_bar_on_back_pressed">back</string>
|
||||
|
||||
<string name="ui_theme_card_left">ho</string>
|
||||
<string name="ui_theme_card_right">la</string>
|
||||
</resources>
|
@ -5,5 +5,5 @@ plugins {
|
||||
}
|
||||
dependencies {
|
||||
compileOnly("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||
compileOnly("com.android.tools.lint:lint:31.1.2")
|
||||
compileOnly(libs.com.android.tools.lint.lint.api)
|
||||
}
|
@ -32,3 +32,4 @@ include(
|
||||
)
|
||||
include(":benchmark")
|
||||
include(":lint")
|
||||
include(":i18n")
|
||||
|
@ -9,6 +9,7 @@ import androidx.compose.material.icons.rounded.Collections
|
||||
import androidx.compose.material.icons.rounded.Home
|
||||
import androidx.compose.material.icons.rounded.Settings
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import com.m3u.i18n.R as I18R
|
||||
|
||||
typealias Navigate = (Destination) -> Unit
|
||||
|
||||
@ -22,20 +23,20 @@ sealed interface Destination {
|
||||
Main(
|
||||
selectedIcon = Icons.Rounded.Home,
|
||||
unselectedIcon = Icons.Outlined.Home,
|
||||
iconTextId = R.string.destination_main,
|
||||
titleTextId = R.string.app_name
|
||||
iconTextId = I18R.string.ui_destination_main,
|
||||
titleTextId = I18R.string.ui_app_name
|
||||
),
|
||||
Favourite(
|
||||
selectedIcon = Icons.Rounded.Collections,
|
||||
unselectedIcon = Icons.Outlined.Collections,
|
||||
iconTextId = R.string.destination_favourite,
|
||||
titleTextId = R.string.title_favourite
|
||||
iconTextId = I18R.string.ui_destination_favourite,
|
||||
titleTextId = I18R.string.ui_title_favourite
|
||||
),
|
||||
Setting(
|
||||
selectedIcon = Icons.Rounded.Settings,
|
||||
unselectedIcon = Icons.Outlined.Settings,
|
||||
iconTextId = R.string.destination_setting,
|
||||
titleTextId = R.string.title_setting
|
||||
iconTextId = I18R.string.ui_destination_setting,
|
||||
titleTextId = I18R.string.ui_title_setting
|
||||
);
|
||||
|
||||
companion object : Key<Root>
|
||||
|
@ -57,7 +57,7 @@ import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.util.lerp
|
||||
import com.m3u.ui.R
|
||||
import com.m3u.i18n.R as I18R
|
||||
import com.m3u.ui.ktx.animated
|
||||
import com.m3u.ui.model.LocalDuration
|
||||
import com.m3u.ui.model.LocalSpacing
|
||||
@ -183,7 +183,7 @@ fun AppTopBar(
|
||||
) {
|
||||
IconButton(
|
||||
icon = Icons.AutoMirrored.Rounded.ArrowBack,
|
||||
contentDescription = stringResource(R.string.cd_top_bar_on_back_pressed),
|
||||
contentDescription = stringResource(I18R.string.ui_cd_top_bar_on_back_pressed),
|
||||
onClick = { if (progress > 0) onBackPressed?.invoke() },
|
||||
modifier = Modifier.wrapContentSize()
|
||||
)
|
||||
|
@ -41,7 +41,7 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.m3u.ui.R
|
||||
import com.m3u.i18n.R as I18R
|
||||
import com.m3u.ui.model.LocalSpacing
|
||||
import com.m3u.ui.model.LocalTheme
|
||||
import com.m3u.ui.model.SugarColors
|
||||
@ -236,8 +236,8 @@ private fun ColorPiece(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
Text(
|
||||
text = if (left) stringResource(R.string.theme_card_left)
|
||||
else stringResource(R.string.theme_card_right),
|
||||
text = if (left) stringResource(I18R.string.ui_theme_card_left)
|
||||
else stringResource(I18R.string.ui_theme_card_right),
|
||||
style = MaterialTheme.typography.bodyLarge
|
||||
.copy(
|
||||
fontSize = if (left) 16.sp
|
||||
|
@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">M3U</string>
|
||||
|
||||
<string name="destination_main">主页</string>
|
||||
<string name="destination_favourite">喜欢</string>
|
||||
<string name="destination_setting">设置</string>
|
||||
|
||||
<string name="title_setting">设置</string>
|
||||
<string name="title_favourite">喜欢</string>
|
||||
|
||||
<string name="error_unknown">未知错误</string>
|
||||
<string name="cd_top_bar_on_back_pressed">返回</string>
|
||||
|
||||
<string name="theme_card_left">您</string>
|
||||
<string name="theme_card_right">好</string>
|
||||
</resources>
|
@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">M3U</string>
|
||||
|
||||
<string name="destination_main">For You</string>
|
||||
<string name="destination_favourite">Favourite</string>
|
||||
<string name="destination_setting">Settings</string>
|
||||
|
||||
<string name="title_setting">Settings</string>
|
||||
<string name="title_favourite">Favourite</string>
|
||||
|
||||
<string name="error_unknown">unknown error</string>
|
||||
<string name="cd_top_bar_on_back_pressed">back</string>
|
||||
|
||||
<string name="theme_card_left">ho</string>
|
||||
<string name="theme_card_right">la</string>
|
||||
</resources>
|
Reference in New Issue
Block a user