Modularize the codebase (#230)
* Split app into core and app:phone * Use global versionCode and versionName * Clean up gradle dependencies * Use string formatting inside getString function * Move proguard file to app:phone * Move app_navigation and BasePlayerActivity to app:phone * Add buildTypes to core gradle and remove buildFeatures * Add suffix core to core namespace * Split code into 4 more modules: data, preferences, player:core and player:video * Clean up some gradle files * Clean up data gradle * Remove duplicate Constants.kt * Use AppPreferences in more places * Split off strings * Remove unused animations * Make about_libraries strings non-translatable * Move mpv assets to player:video module * Make AppPreferences a Singleton
This commit is contained in:
parent
25efbb6eab
commit
76121925d7
308 changed files with 795 additions and 501 deletions
1
app/.gitignore
vendored
1
app/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
/build
|
|
@ -19,8 +19,12 @@ android {
|
|||
applicationId = "dev.jdtech.jellyfin"
|
||||
minSdk = 27
|
||||
targetSdk = 33
|
||||
versionCode = 14
|
||||
versionName = "0.8.0"
|
||||
|
||||
val appVersionCode: Int by rootProject.extra
|
||||
val appVersionName: String by rootProject.extra
|
||||
|
||||
versionCode = appVersionCode
|
||||
versionName = appVersionName
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
@ -68,6 +72,11 @@ ktlint {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":core"))
|
||||
implementation(project(":data"))
|
||||
implementation(project(":preferences"))
|
||||
implementation(project(":player:core"))
|
||||
implementation(project(":player:video"))
|
||||
implementation(libs.aboutlibraries.core)
|
||||
implementation(libs.aboutlibraries)
|
||||
implementation(libs.androidx.activity)
|
||||
|
@ -85,19 +94,13 @@ dependencies {
|
|||
implementation(libs.androidx.preference)
|
||||
implementation(libs.androidx.recyclerview)
|
||||
implementation(libs.androidx.recyclerview.selection)
|
||||
implementation(libs.androidx.room.runtime)
|
||||
kapt(libs.androidx.room.compiler)
|
||||
implementation(libs.androidx.room.ktx)
|
||||
implementation(libs.androidx.swiperefreshlayout)
|
||||
implementation(libs.glide)
|
||||
kapt(libs.glide.compiler)
|
||||
implementation(libs.hilt.android)
|
||||
kapt(libs.hilt.compiler)
|
||||
implementation(libs.jellyfin.core)
|
||||
implementation(libs.libmpv)
|
||||
compileOnly(libs.libmpv)
|
||||
implementation(libs.material)
|
||||
implementation(libs.timber)
|
||||
|
||||
// Media3 FFmpeg decoder
|
||||
implementation(files("libs/lib-decoder-ffmpeg-release.aar"))
|
||||
}
|
|
@ -2,14 +2,16 @@ package dev.jdtech.jellyfin
|
|||
|
||||
import android.app.Application
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.android.material.color.DynamicColors
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
import dev.jdtech.jellyfin.utils.AppPreferences
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltAndroidApp
|
||||
class BaseApplication : Application() {
|
||||
@Inject
|
||||
lateinit var appPreferences: AppPreferences
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
|
@ -17,8 +19,6 @@ class BaseApplication : Application() {
|
|||
Timber.plant(Timber.DebugTree())
|
||||
}
|
||||
|
||||
val appPreferences = AppPreferences(PreferenceManager.getDefaultSharedPreferences(this))
|
||||
|
||||
when (appPreferences.theme) {
|
||||
"system" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
"light" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
|
|
@ -13,7 +13,7 @@ abstract class BasePlayerActivity : AppCompatActivity() {
|
|||
|
||||
abstract val viewModel: PlayerActivityViewModel
|
||||
|
||||
lateinit var mediaSession: MediaSession
|
||||
private lateinit var mediaSession: MediaSession
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
|
@ -131,11 +131,9 @@ private fun ImageView.loadImage(
|
|||
}
|
||||
|
||||
private fun View.posterDescription(name: String?) {
|
||||
contentDescription =
|
||||
String.format(context.resources.getString(R.string.image_description_poster), name)
|
||||
contentDescription = context.resources.getString(R.string.image_description_poster, name)
|
||||
}
|
||||
|
||||
private fun View.backdropDescription(name: String?) {
|
||||
contentDescription =
|
||||
String.format(context.resources.getString(R.string.image_description_backdrop), name)
|
||||
contentDescription = context.resources.getString(R.string.image_description_backdrop, name)
|
||||
}
|
|
@ -15,7 +15,6 @@ import com.google.android.material.navigation.NavigationBarView
|
|||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.database.ServerDatabaseDao
|
||||
import dev.jdtech.jellyfin.databinding.ActivityMainBinding
|
||||
import dev.jdtech.jellyfin.utils.AppPreferences
|
||||
import dev.jdtech.jellyfin.utils.loadDownloadLocation
|
||||
import dev.jdtech.jellyfin.viewmodels.MainViewModel
|
||||
import javax.inject.Inject
|
||||
|
@ -33,7 +32,7 @@ class MainActivity : AppCompatActivity() {
|
|||
@Inject
|
||||
lateinit var appPreferences: AppPreferences
|
||||
|
||||
lateinit var navController: NavController
|
||||
private lateinit var navController: NavController
|
||||
|
||||
@OptIn(NavigationUiSaveStateControl::class)
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
@ -18,7 +18,6 @@ import dev.jdtech.jellyfin.dialogs.SpeedSelectionDialogFragment
|
|||
import dev.jdtech.jellyfin.dialogs.TrackSelectionDialogFragment
|
||||
import dev.jdtech.jellyfin.mpv.MPVPlayer
|
||||
import dev.jdtech.jellyfin.mpv.TrackType
|
||||
import dev.jdtech.jellyfin.utils.AppPreferences
|
||||
import dev.jdtech.jellyfin.utils.PlayerGestureHelper
|
||||
import dev.jdtech.jellyfin.viewmodels.PlayerActivityViewModel
|
||||
import javax.inject.Inject
|
|
@ -9,10 +9,10 @@ import androidx.recyclerview.widget.ListAdapter
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dev.jdtech.jellyfin.databinding.EpisodeItemBinding
|
||||
import dev.jdtech.jellyfin.databinding.SeasonHeaderBinding
|
||||
import dev.jdtech.jellyfin.models.DownloadEpisodeItem
|
||||
import dev.jdtech.jellyfin.models.DownloadSeriesMetadata
|
||||
import dev.jdtech.jellyfin.models.PlayerItem
|
||||
import dev.jdtech.jellyfin.utils.downloadMetadataToBaseItemDto
|
||||
import java.util.UUID
|
||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||
|
||||
private const val ITEM_VIEW_TYPE_HEADER = 0
|
||||
|
@ -113,16 +113,4 @@ class DownloadEpisodeListAdapter(
|
|||
class OnClickListener(val clickListener: (item: PlayerItem) -> Unit) {
|
||||
fun onClick(item: PlayerItem) = clickListener(item)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class DownloadEpisodeItem {
|
||||
abstract val id: UUID
|
||||
|
||||
object Header : DownloadEpisodeItem() {
|
||||
override val id: UUID = UUID.randomUUID()
|
||||
}
|
||||
|
||||
data class Episode(val episode: PlayerItem) : DownloadEpisodeItem() {
|
||||
override val id = episode.itemId
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ import androidx.recyclerview.widget.ListAdapter
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dev.jdtech.jellyfin.databinding.EpisodeItemBinding
|
||||
import dev.jdtech.jellyfin.databinding.SeasonHeaderBinding
|
||||
import dev.jdtech.jellyfin.models.EpisodeItem
|
||||
import java.util.UUID
|
||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||
|
||||
|
@ -118,15 +119,3 @@ class EpisodeListAdapter(
|
|||
fun onClick(item: BaseItemDto) = clickListener(item)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class EpisodeItem {
|
||||
abstract val id: UUID
|
||||
|
||||
object Header : EpisodeItem() {
|
||||
override val id: UUID = UUID.randomUUID()
|
||||
}
|
||||
|
||||
data class Episode(val episode: BaseItemDto) : EpisodeItem() {
|
||||
override val id = episode.id
|
||||
}
|
||||
}
|
|
@ -5,9 +5,9 @@ import android.view.ViewGroup
|
|||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dev.jdtech.jellyfin.Constants
|
||||
import dev.jdtech.jellyfin.databinding.FavoriteSectionBinding
|
||||
import dev.jdtech.jellyfin.models.FavoriteSection
|
||||
import dev.jdtech.jellyfin.utils.Constants
|
||||
|
||||
class FavoritesListAdapter(
|
||||
private val onClickListener: ViewItemListAdapter.OnClickListener,
|
||||
|
@ -30,6 +30,7 @@ class FavoritesListAdapter(
|
|||
HomeEpisodeListAdapter(onEpisodeClickListener)
|
||||
(binding.itemsRecyclerView.adapter as HomeEpisodeListAdapter).submitList(section.items)
|
||||
}
|
||||
binding.sectionName.text = section.name.asString(binding.root.resources)
|
||||
binding.executePendingBindings()
|
||||
}
|
||||
}
|
|
@ -8,9 +8,8 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import dev.jdtech.jellyfin.R
|
||||
import dev.jdtech.jellyfin.databinding.NextUpSectionBinding
|
||||
import dev.jdtech.jellyfin.databinding.ViewItemBinding
|
||||
import dev.jdtech.jellyfin.models.HomeSection
|
||||
import dev.jdtech.jellyfin.models.HomeItem
|
||||
import dev.jdtech.jellyfin.models.View
|
||||
import java.util.UUID
|
||||
|
||||
private const val ITEM_VIEW_TYPE_NEXT_UP = 0
|
||||
private const val ITEM_VIEW_TYPE_VIEW = 1
|
||||
|
@ -30,7 +29,7 @@ class ViewListAdapter(
|
|||
) {
|
||||
val view = dataItem.view
|
||||
binding.view = view
|
||||
binding.viewName.text = String.format(binding.viewName.context.resources.getString(R.string.latest_library), view.name)
|
||||
binding.viewName.text = binding.viewName.context.resources.getString(R.string.latest_library, view.name)
|
||||
binding.itemsRecyclerView.adapter =
|
||||
ViewItemListAdapter(onItemClickListener, fixedWidth = true)
|
||||
binding.viewAll.setOnClickListener {
|
||||
|
@ -105,19 +104,3 @@ class ViewListAdapter(
|
|||
fun onClick(view: View) = clickListener(view)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class HomeItem {
|
||||
data class Libraries(val section: HomeSection) : HomeItem() {
|
||||
override val id = section.id
|
||||
}
|
||||
|
||||
data class Section(val homeSection: HomeSection) : HomeItem() {
|
||||
override val id = homeSection.id
|
||||
}
|
||||
|
||||
data class ViewItem(val view: View) : HomeItem() {
|
||||
override val id = view.id
|
||||
}
|
||||
|
||||
abstract val id: UUID
|
||||
}
|
|
@ -99,7 +99,7 @@ class AddServerFragment : Fragment() {
|
|||
binding.buttonConnect.isEnabled = true
|
||||
binding.progressCircular.isVisible = false
|
||||
binding.editTextServerAddressLayout.apply {
|
||||
error = uiState.message
|
||||
error = uiState.message.joinToString { it.asString(resources) }
|
||||
isEnabled = true
|
||||
}
|
||||
}
|
|
@ -195,8 +195,8 @@ class EpisodeBottomSheetFragment : BottomSheetDialogFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
binding.episodeName.text = String.format(
|
||||
getString(R.string.episode_name_extended),
|
||||
binding.episodeName.text = getString(
|
||||
R.string.episode_name_extended,
|
||||
episode.parentIndexNumber,
|
||||
episode.indexNumber,
|
||||
episode.name
|
|
@ -1,6 +1,5 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
|
@ -20,12 +19,13 @@ import androidx.navigation.fragment.findNavController
|
|||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.paging.LoadState
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.AppPreferences
|
||||
import dev.jdtech.jellyfin.R
|
||||
import dev.jdtech.jellyfin.adapters.ViewItemPagingAdapter
|
||||
import dev.jdtech.jellyfin.databinding.FragmentLibraryBinding
|
||||
import dev.jdtech.jellyfin.dialogs.ErrorDialogFragment
|
||||
import dev.jdtech.jellyfin.dialogs.SortDialogFragment
|
||||
import dev.jdtech.jellyfin.utils.SortBy
|
||||
import dev.jdtech.jellyfin.models.SortBy
|
||||
import dev.jdtech.jellyfin.utils.checkIfLoginRequired
|
||||
import dev.jdtech.jellyfin.viewmodels.LibraryViewModel
|
||||
import java.lang.IllegalArgumentException
|
||||
|
@ -44,7 +44,7 @@ class LibraryFragment : Fragment() {
|
|||
private lateinit var errorDialog: ErrorDialogFragment
|
||||
|
||||
@Inject
|
||||
lateinit var sp: SharedPreferences
|
||||
lateinit var preferences: AppPreferences
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
|
@ -146,9 +146,9 @@ class LibraryFragment : Fragment() {
|
|||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
// Sorting options
|
||||
val sortBy = SortBy.fromString(sp.getString("sortBy", SortBy.defaultValue.name)!!)
|
||||
val sortBy = SortBy.fromString(preferences.sortBy)
|
||||
val sortOrder = try {
|
||||
SortOrder.valueOf(sp.getString("sortOrder", SortOrder.ASCENDING.name)!!)
|
||||
SortOrder.valueOf(preferences.sortOrder)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
SortOrder.ASCENDING
|
||||
}
|
|
@ -18,7 +18,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||
import dev.jdtech.jellyfin.adapters.UserLoginListAdapter
|
||||
import dev.jdtech.jellyfin.database.ServerDatabaseDao
|
||||
import dev.jdtech.jellyfin.databinding.FragmentLoginBinding
|
||||
import dev.jdtech.jellyfin.utils.AppPreferences
|
||||
import dev.jdtech.jellyfin.AppPreferences
|
||||
import dev.jdtech.jellyfin.viewmodels.LoginViewModel
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -119,7 +119,7 @@ class LoginFragment : Fragment() {
|
|||
binding.buttonLogin.isEnabled = true
|
||||
binding.progressCircular.isVisible = false
|
||||
binding.editTextUsernameLayout.apply {
|
||||
error = uiState.message
|
||||
error = uiState.message.asString(resources)
|
||||
isEnabled = true
|
||||
}
|
||||
binding.editTextPasswordLayout.isEnabled = true
|
|
@ -272,8 +272,8 @@ class MediaInfoFragment : Fragment() {
|
|||
binding.writers.text = writersString
|
||||
binding.description.text = item.overview
|
||||
binding.nextUpLayout.isVisible = nextUp != null
|
||||
binding.nextUpName.text = String.format(
|
||||
getString(R.string.episode_name_extended),
|
||||
binding.nextUpName.text = getString(
|
||||
R.string.episode_name_extended,
|
||||
nextUp?.parentIndexNumber,
|
||||
nextUp?.indexNumber,
|
||||
nextUp?.name
|
|
@ -8,7 +8,7 @@ import androidx.preference.Preference
|
|||
import androidx.preference.PreferenceFragmentCompat
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.R
|
||||
import dev.jdtech.jellyfin.utils.AppPreferences
|
||||
import dev.jdtech.jellyfin.AppPreferences
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
|
@ -4,8 +4,8 @@ import android.os.Bundle
|
|||
import android.text.InputType
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import dev.jdtech.jellyfin.Constants
|
||||
import dev.jdtech.jellyfin.R
|
||||
import dev.jdtech.jellyfin.utils.Constants
|
||||
|
||||
@Suppress("unused")
|
||||
class SettingsNetworkFragment : PreferenceFragmentCompat() {
|
|
@ -0,0 +1,15 @@
|
|||
package dev.jdtech.jellyfin.utils
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import dev.jdtech.jellyfin.AppNavigationDirections
|
||||
import timber.log.Timber
|
||||
|
||||
fun Fragment.checkIfLoginRequired(error: String?) {
|
||||
if (error != null) {
|
||||
if (error.contains("401")) {
|
||||
Timber.d("Login required!")
|
||||
findNavController().navigate(AppNavigationDirections.actionGlobalLoginFragment(reLogin = true))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,6 +12,8 @@ import android.view.WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL
|
|||
import android.view.WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_OFF
|
||||
import androidx.media3.ui.AspectRatioFrameLayout
|
||||
import androidx.media3.ui.PlayerView
|
||||
import dev.jdtech.jellyfin.AppPreferences
|
||||
import dev.jdtech.jellyfin.Constants
|
||||
import dev.jdtech.jellyfin.PlayerActivity
|
||||
import dev.jdtech.jellyfin.mpv.MPVPlayer
|
||||
import kotlin.math.abs
|
|
@ -22,7 +22,6 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:text="@{section.name}"
|
||||
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:textSize="18sp"
|
||||
tools:text="Movies" />
|
|
@ -1,12 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:interpolator="@android:anim/decelerate_interpolator"
|
||||
android:shareInterpolator="true"
|
||||
android:duration="@integer/recyclerview_animation_duration">
|
||||
<translate
|
||||
android:fromXDelta="20%"
|
||||
android:toXDelta="0" />
|
||||
<alpha
|
||||
android:fromAlpha="0"
|
||||
android:toAlpha="1" />
|
||||
</set>
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:animation="@anim/item_animation_slide_in"
|
||||
android:animationOrder="normal"
|
||||
android:delay="15%" />
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
|
@ -1,154 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="add_server_error_outdated">Versão do servidor desatualizada: %1$s. Por favor atualize seu servidor</string>
|
||||
<string name="add_server_error_version">Versão do servidor não suportada: %1$s. Por favor atualize seu servidor</string>
|
||||
<string name="add_server_error_slow">O servidor é lendo demais para responder: %1$s</string>
|
||||
<string name="add_server_error_empty_address">Endereço de servidor vazio</string>
|
||||
<string name="add_server_error_no_id">Servidor não possui id, algo parece errado como servidor</string>
|
||||
<string name="login">Entrar</string>
|
||||
<string name="login_error_wrong_username_password">Nome de usuário ou senha incorretos</string>
|
||||
<string name="select_server">Selecione o servidor</string>
|
||||
<string name="edit_text_server_address_hint">Endereço do servidor</string>
|
||||
<string name="edit_text_password_hint">Senha</string>
|
||||
<string name="button_connect">Conectar</string>
|
||||
<string name="button_login">Entrar</string>
|
||||
<string name="remove_server">Remover servidor</string>
|
||||
<string name="remove">Remover</string>
|
||||
<string name="cancel">Cancelar</string>
|
||||
<string name="title_home">Início</string>
|
||||
<string name="title_media">Minhas mídia</string>
|
||||
<string name="title_favorite">Favoritos</string>
|
||||
<string name="title_settings">Configurações</string>
|
||||
<string name="title_download">Downloads</string>
|
||||
<string name="view_all">Ver tudo</string>
|
||||
<string name="error_loading_data">Erro carregando dados</string>
|
||||
<string name="retry">Tentar novamente</string>
|
||||
<string name="genres">Gêneros</string>
|
||||
<string name="director">Diretor(a)</string>
|
||||
<string name="writers">Escritores(as)</string>
|
||||
<string name="cast_amp_crew">Elenco e equipe</string>
|
||||
<string name="seasons">Temporadas</string>
|
||||
<string name="play_button_description">Tocar a mídia</string>
|
||||
<string name="trailer_button_description">Assistir ao trailer</string>
|
||||
<string name="favorite_button_description">Favoritar</string>
|
||||
<string name="episode_watched_indicator">Indicador de episódio assistido</string>
|
||||
<string name="episode_name">%1$d. %2$s</string>
|
||||
<string name="episode_name_extended">E%1$d:T%2$d - %3$s</string>
|
||||
<string name="next_up">Próximo</string>
|
||||
<string name="continue_watching">Continue assistindo</string>
|
||||
<string name="series_poster">Poster da série</string>
|
||||
<string name="no_favorites">Você não tem favoritos</string>
|
||||
<string name="search">Buscar</string>
|
||||
<string name="no_search_results">Sem resultados</string>
|
||||
<string name="settings_category_language">Idioma</string>
|
||||
<string name="settings_preferred_audio_language">Idioma de áudio preferido</string>
|
||||
<string name="settings_preferred_subtitle_language">Idioma de legenda preferido</string>
|
||||
<string name="initializing">Inicializando…</string>
|
||||
<string name="settings_category_player">Reprodutor</string>
|
||||
<string name="manage_servers">Gerenciar servidores</string>
|
||||
<string name="settings_category_appearance">Aparência</string>
|
||||
<string name="device_name">Nome do dispositivo</string>
|
||||
<string name="settings_category_device">Dispositivo</string>
|
||||
<string name="settings_category_cache">Cache</string>
|
||||
<string name="settings_use_cache_title">Cache de imagens</string>
|
||||
<string name="settings_cache_size">Tamanho do cache (MB)</string>
|
||||
<string name="theme">Tema</string>
|
||||
<string name="error_preparing_player_items">Erro preparando itens a serem reproduzidos.</string>
|
||||
<string name="view_details">Ver detalhes</string>
|
||||
<string name="view_details_underlined"><u>Ver detalhes</u></string>
|
||||
<string name="about">Sobre</string>
|
||||
<string name="privacy_policy">Política de privacidade</string>
|
||||
<string name="app_info">Informações do aplicativo</string>
|
||||
<string name="unknown_error">Erro desconhecido</string>
|
||||
<string name="select_a_version">Selecione uma versão</string>
|
||||
<string name="select_audio_track">Selecione uma faixa de áudio</string>
|
||||
<string name="select_subtile_track">Selecione uma legenda</string>
|
||||
<string name="select_playback_speed">Selecione a velocidade de reprodução</string>
|
||||
<string name="mpv_player">Reprodutor mpv</string>
|
||||
<string name="download_mobile_data">Baixar usando dados móveis</string>
|
||||
<string name="download_button_description">Baixar</string>
|
||||
<string name="delete_button_description">Deletar</string>
|
||||
<string name="person_detail_title">Detalhes</string>
|
||||
<string name="error_getting_person_id">Detalhes indisponíveis</string>
|
||||
<string name="movies_label">Filmes</string>
|
||||
<string name="shows_label">Series de TV</string>
|
||||
<string name="hide">Esconder</string>
|
||||
<string name="sort_by">Ordenar por</string>
|
||||
<string name="sort_order">Ordem</string>
|
||||
<string name="close">Fechar</string>
|
||||
<string name="share">Compartilhar</string>
|
||||
<string name="image_description_poster">%1$s poster</string>
|
||||
<string name="image_description_backdrop">%1$s imagem de fundo</string>
|
||||
<string name="gestures">Gestos</string>
|
||||
<string name="add_server">Adicionar servidor</string>
|
||||
<string name="add_server_error_not_jellyfin">Não é um servidor do jellyfin: %1$s</string>
|
||||
<string name="add_server_error_not_found">Servidor não encontrado</string>
|
||||
<string name="edit_text_username_hint">Nome de usuário</string>
|
||||
<string name="remove_server_dialog_text">Tem certeza que deseja remover o servidor %1$s</string>
|
||||
<string name="check_button_description">Marcar como assistido ou não assistido</string>
|
||||
<string name="no_downloads">Você não tem nada baixado</string>
|
||||
<string name="settings_category_servers">Servidores</string>
|
||||
<string name="settings_category_download">Downloads</string>
|
||||
<string name="settings_use_cache_summary">Armazena imagens no disco para acelerar o tempo de carregamento. Surte efeito após reiniciar o aplicativo.</string>
|
||||
<string name="search_hint">Busca filmes, shows, episódios…</string>
|
||||
<string name="mpv_player_summary">Usa o reprodutor experimental mpv para reproduzir vídeos. mpv tem suporte a mais codecs de vidro, áudio e legenda.</string>
|
||||
<string name="libraries">Biblioteca</string>
|
||||
<string name="settings_category_network">Rede</string>
|
||||
<string name="sort_by_options_5">Data de Lançamento</string>
|
||||
<string name="track_selection">[%1$s] %2$s (%3$s)</string>
|
||||
<string name="pref_player_mpv_ao">Saída de áudio</string>
|
||||
<string name="subtitles">Legendas</string>
|
||||
<string name="subtitles_summary">Personalize a aparência das legendas</string>
|
||||
<string name="sort_by_options_2">Classificação Etária</string>
|
||||
<string name="external">Externo</string>
|
||||
<string name="theme_system">Usar configurações do sistema</string>
|
||||
<string name="theme_light">Claro</string>
|
||||
<string name="theme_dark">Escuro</string>
|
||||
<string name="app_description">Aplicação Jellyfin nativa de terceiros</string>
|
||||
<string name="latest_library">Mais recentes %1$s</string>
|
||||
<string name="jellyfin_banner">Jellyfin banner</string>
|
||||
<string name="download_roaming">Download quando estiver em roaming</string>
|
||||
<string name="settings_cache_size_message">O aplicativo usará essa quantidade em MB do seu espaço em disco para armazenar imagens do servidor Jellyfin. Valores maiores podem ser benéficos em redes mais lentas.</string>
|
||||
<string name="episodes_label">Episódios</string>
|
||||
<string name="player_gestures">Gestos do player</string>
|
||||
<string name="player_brightness_remember">Lembrar do nível de brilho</string>
|
||||
<string name="display_extended_title_summary">Exibe o título estendido do episódio, incluindo informações sobre a temporada e o episódio (SXX:EXX - NomeEpisódio).</string>
|
||||
<string name="display_extended_title">Exibir título estendido</string>
|
||||
<string name="add_server_empty_error">Endereço de servidor vazio</string>
|
||||
<string name="sort_by_options_0">Título</string>
|
||||
<string name="dynamic_colors_summary">Usar cores dinâmicas do Material You (disponível apenas no Android 12+)</string>
|
||||
<string name="dynamic_colors">Cores dinâmicas</string>
|
||||
<string name="player_gestures_vb">Gestos de volume e brilho</string>
|
||||
<string name="player_gestures_zoom">Gestos de zoom</string>
|
||||
<string name="player_gestures_vb_summary">Deslize para cima e para baixo no lado direito da tela para alterar o volume e no lado esquerdo para alterar o brilho</string>
|
||||
<string name="player_gestures_zoom_summary">Aperte para preencher a tela com o vídeo</string>
|
||||
<string name="player_controls_skip">Pular</string>
|
||||
<string name="runtime_minutes">%1$d minutos</string>
|
||||
<string name="select_video_version_title">Selecione a versão</string>
|
||||
<string name="player_controls_exit">Sair do player</string>
|
||||
<string name="player_controls_rewind">Retroceder</string>
|
||||
<string name="player_controls_fast_forward">Avanço rápido</string>
|
||||
<string name="player_controls_pause">Pausar</string>
|
||||
<string name="users">Usuários</string>
|
||||
<string name="add_user">Adicionar usuário</string>
|
||||
<string name="pref_player_mpv_hwdec">Decodificação de hardware</string>
|
||||
<string name="pref_player_mpv_hwdec_codecs">Codecs de decodificação de hardware</string>
|
||||
<string name="sort_by_options_3">Data de Adição</string>
|
||||
<string name="sort_by_options_4">Data de Reprodução</string>
|
||||
<string name="ascending">Crescente</string>
|
||||
<string name="descending">Decrescente</string>
|
||||
<string name="pref_player_mpv_vo">Saida de vídeo</string>
|
||||
<string name="remove_user">Remover usuário</string>
|
||||
<string name="remove_user_dialog_text">Tem certeza que deseja remover o usuário (%1$s)</string>
|
||||
<string name="sort_by_options_1">Avaliação IMDb</string>
|
||||
<string name="addresses">Endereços</string>
|
||||
<string name="add_address">Adicionar endereço</string>
|
||||
<string name="add_server_address">Adicionar endereço do servidor</string>
|
||||
<string name="add">Adicionar</string>
|
||||
<string name="seeking">Buscando</string>
|
||||
<string name="seek_forward_increment">Incremento para frente (ms)</string>
|
||||
<string name="seek_back_increment">Incremento para trás (ms)</string>
|
||||
<string name="settings_socket_timeout">Tempo limite do soquete (ms)</string>
|
||||
<string name="settings_request_timeout">Tempo limite da requisição (ms)</string>
|
||||
<string name="settings_connect_timeout">Tempo limite da conexão (ms)</string>
|
||||
</resources>
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="aboutLibraries_description_showIcon">true</string>
|
||||
<string name="aboutLibraries_description_showVersion">true</string>
|
||||
<string name="aboutLibraries_description_name">@string/app_name</string>
|
||||
<string name="aboutLibraries_description_text">@string/app_description</string>
|
||||
<string name="aboutLibraries_showLicense">true</string>
|
||||
</resources>
|
|
@ -2,6 +2,7 @@
|
|||
@Suppress("DSL_SCOPE_VIOLATION") // False positive
|
||||
plugins {
|
||||
alias(libs.plugins.android.application) apply false
|
||||
alias(libs.plugins.android.library) apply false
|
||||
alias(libs.plugins.kotlin.android) apply false
|
||||
alias(libs.plugins.kotlin.parcelize) apply false
|
||||
alias(libs.plugins.kotlin.kapt) apply false
|
||||
|
@ -20,4 +21,7 @@ allprojects {
|
|||
|
||||
tasks.create<Delete>("clean") {
|
||||
delete(rootProject.buildDir)
|
||||
}
|
||||
}
|
||||
|
||||
val appVersionCode by extra { 14 }
|
||||
val appVersionName by extra { "0.8.0" }
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue