Merge branch 'main' into Skip-credit
This commit is contained in:
commit
9f3be43eac
28 changed files with 234 additions and 199 deletions
|
@ -325,8 +325,8 @@ class MovieFragment : Fragment() {
|
||||||
it.displayProfiles.firstOrNull()?.apply {
|
it.displayProfiles.firstOrNull()?.apply {
|
||||||
videoProfileChip.text = this.raw
|
videoProfileChip.text = this.raw
|
||||||
videoProfileChip.isVisible = when (this) {
|
videoProfileChip.isVisible = when (this) {
|
||||||
DisplayProfile.HDR,
|
|
||||||
DisplayProfile.HDR10,
|
DisplayProfile.HDR10,
|
||||||
|
DisplayProfile.HDR10_PLUS,
|
||||||
DisplayProfile.HLG,
|
DisplayProfile.HLG,
|
||||||
-> {
|
-> {
|
||||||
videoProfileChip.chipStartPadding = .0f
|
videoProfileChip.chipStartPadding = .0f
|
||||||
|
|
|
@ -61,6 +61,7 @@ import dev.jdtech.jellyfin.viewmodels.MovieViewModel
|
||||||
import dev.jdtech.jellyfin.viewmodels.PlayerItemsEvent
|
import dev.jdtech.jellyfin.viewmodels.PlayerItemsEvent
|
||||||
import dev.jdtech.jellyfin.viewmodels.PlayerViewModel
|
import dev.jdtech.jellyfin.viewmodels.PlayerViewModel
|
||||||
import org.jellyfin.sdk.model.api.BaseItemPerson
|
import org.jellyfin.sdk.model.api.BaseItemPerson
|
||||||
|
import org.jellyfin.sdk.model.api.PersonKind
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import dev.jdtech.jellyfin.core.R as CoreR
|
import dev.jdtech.jellyfin.core.R as CoreR
|
||||||
|
|
||||||
|
@ -343,6 +344,7 @@ private fun MovieScreenLayoutPreview() {
|
||||||
director = BaseItemPerson(
|
director = BaseItemPerson(
|
||||||
id = UUID.randomUUID(),
|
id = UUID.randomUUID(),
|
||||||
name = "Robert Rodriguez",
|
name = "Robert Rodriguez",
|
||||||
|
type = PersonKind.DIRECTOR,
|
||||||
),
|
),
|
||||||
writers = emptyList(),
|
writers = emptyList(),
|
||||||
videoMetadata = VideoMetadata(
|
videoMetadata = VideoMetadata(
|
||||||
|
|
1
buildSrc/settings.gradle.kts
Normal file
1
buildSrc/settings.gradle.kts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
rootProject.name = "buildSrc"
|
|
@ -35,8 +35,10 @@ object ApiModule {
|
||||||
val user = serverWithAddressAndUser.user
|
val user = serverWithAddressAndUser.user
|
||||||
|
|
||||||
jellyfinApi.apply {
|
jellyfinApi.apply {
|
||||||
api.baseUrl = serverAddress.address
|
api.update(
|
||||||
api.accessToken = user?.accessToken
|
baseUrl = serverAddress.address,
|
||||||
|
accessToken = user?.accessToken,
|
||||||
|
)
|
||||||
userId = user?.id
|
userId = user?.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ class SortDialogFragment(
|
||||||
when (sortType) {
|
when (sortType) {
|
||||||
"sortBy" -> {
|
"sortBy" -> {
|
||||||
val sortByOptions = resources.getStringArray(R.array.sort_by_options)
|
val sortByOptions = resources.getStringArray(R.array.sort_by_options)
|
||||||
val sortByValues = SortBy.values()
|
val sortByValues = SortBy.entries
|
||||||
builder
|
builder
|
||||||
.setTitle(getString(R.string.sort_by))
|
.setTitle(getString(R.string.sort_by))
|
||||||
.setSingleChoiceItems(
|
.setSingleChoiceItems(
|
||||||
|
@ -64,7 +64,7 @@ class SortDialogFragment(
|
||||||
}
|
}
|
||||||
"sortOrder" -> {
|
"sortOrder" -> {
|
||||||
val sortByOptions = resources.getStringArray(R.array.sort_order_options)
|
val sortByOptions = resources.getStringArray(R.array.sort_order_options)
|
||||||
val sortOrderValues = SortOrder.values()
|
val sortOrderValues = SortOrder.entries
|
||||||
|
|
||||||
builder
|
builder
|
||||||
.setTitle(getString(R.string.sort_order))
|
.setTitle(getString(R.string.sort_order))
|
||||||
|
|
|
@ -18,7 +18,7 @@ fun BaseItemDto.toView(): View {
|
||||||
return View(
|
return View(
|
||||||
id = id,
|
id = id,
|
||||||
name = name ?: "",
|
name = name ?: "",
|
||||||
type = CollectionType.fromString(collectionType),
|
type = CollectionType.fromString(collectionType?.serialName),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -202,8 +202,10 @@ constructor(
|
||||||
appPreferences.currentServer = server.id
|
appPreferences.currentServer = server.id
|
||||||
|
|
||||||
jellyfinApi.apply {
|
jellyfinApi.apply {
|
||||||
api.baseUrl = recommendedServerInfo.address
|
api.update(
|
||||||
api.accessToken = null
|
baseUrl = recommendedServerInfo.address,
|
||||||
|
accessToken = null,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
_uiState.emit(UiState.Normal)
|
_uiState.emit(UiState.Normal)
|
||||||
|
|
|
@ -11,6 +11,7 @@ import dev.jdtech.jellyfin.models.HomeSection
|
||||||
import dev.jdtech.jellyfin.models.UiText
|
import dev.jdtech.jellyfin.models.UiText
|
||||||
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
||||||
import dev.jdtech.jellyfin.utils.toView
|
import dev.jdtech.jellyfin.utils.toView
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
@ -41,13 +42,12 @@ class HomeViewModel @Inject internal constructor(
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
repository.postCapabilities()
|
repository.postCapabilities()
|
||||||
} catch (_: Exception) {
|
} catch (_: Exception) { }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadData() {
|
fun loadData() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch(Dispatchers.Default) {
|
||||||
_uiState.emit(UiState.Loading)
|
_uiState.emit(UiState.Loading)
|
||||||
try {
|
try {
|
||||||
val items = mutableListOf<HomeItem>()
|
val items = mutableListOf<HomeItem>()
|
||||||
|
@ -93,7 +93,7 @@ class HomeViewModel @Inject internal constructor(
|
||||||
|
|
||||||
private suspend fun loadViews() = repository
|
private suspend fun loadViews() = repository
|
||||||
.getUserViews()
|
.getUserViews()
|
||||||
.filter { view -> CollectionType.fromString(view.collectionType) in CollectionType.supported }
|
.filter { view -> CollectionType.fromString(view.collectionType?.serialName) in CollectionType.supported }
|
||||||
.map { view -> view to repository.getLatestMedia(view.id) }
|
.map { view -> view to repository.getLatestMedia(view.id) }
|
||||||
.filter { (_, latest) -> latest.isNotEmpty() }
|
.filter { (_, latest) -> latest.isNotEmpty() }
|
||||||
.map { (view, latest) -> view.toView().apply { items = latest } }
|
.map { (view, latest) -> view.toView().apply { items = latest } }
|
||||||
|
|
|
@ -19,7 +19,6 @@ import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.jellyfin.sdk.api.client.extensions.authenticateWithQuickConnect
|
import org.jellyfin.sdk.api.client.extensions.authenticateWithQuickConnect
|
||||||
import org.jellyfin.sdk.api.client.extensions.brandingApi
|
|
||||||
import org.jellyfin.sdk.model.api.AuthenticateUserByName
|
import org.jellyfin.sdk.model.api.AuthenticateUserByName
|
||||||
import org.jellyfin.sdk.model.api.AuthenticationResult
|
import org.jellyfin.sdk.model.api.AuthenticationResult
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -72,7 +71,7 @@ constructor(
|
||||||
|
|
||||||
private fun loadDisclaimer() {
|
private fun loadDisclaimer() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
loginDisclaimer = jellyfinApi.api.brandingApi.getBrandingOptions().content.loginDisclaimer
|
loginDisclaimer = jellyfinApi.brandingApi.getBrandingOptions().content.loginDisclaimer
|
||||||
_uiState.emit(UiState.Normal(loginDisclaimer))
|
_uiState.emit(UiState.Normal(loginDisclaimer))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +103,7 @@ constructor(
|
||||||
private fun loadQuickConnectAvailable() {
|
private fun loadQuickConnectAvailable() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
val isEnabled by jellyfinApi.quickConnectApi.getEnabled()
|
val isEnabled by jellyfinApi.quickConnectApi.getQuickConnectEnabled()
|
||||||
if (isEnabled) {
|
if (isEnabled) {
|
||||||
_quickConnectUiState.emit(QuickConnectUiState.Normal)
|
_quickConnectUiState.emit(QuickConnectUiState.Normal)
|
||||||
}
|
}
|
||||||
|
@ -155,12 +154,12 @@ constructor(
|
||||||
}
|
}
|
||||||
quickConnectJob = viewModelScope.launch {
|
quickConnectJob = viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
var quickConnectState = jellyfinApi.quickConnectApi.initiate().content
|
var quickConnectState = jellyfinApi.quickConnectApi.initiateQuickConnect().content
|
||||||
_quickConnectUiState.emit(QuickConnectUiState.Waiting(quickConnectState.code))
|
_quickConnectUiState.emit(QuickConnectUiState.Waiting(quickConnectState.code))
|
||||||
|
|
||||||
while (!quickConnectState.authenticated) {
|
while (!quickConnectState.authenticated) {
|
||||||
quickConnectState = jellyfinApi.quickConnectApi.connect(quickConnectState.secret).content
|
|
||||||
delay(5000L)
|
delay(5000L)
|
||||||
|
quickConnectState = jellyfinApi.quickConnectApi.getQuickConnectState(quickConnectState.secret).content
|
||||||
}
|
}
|
||||||
val authenticationResult by jellyfinApi.userApi.authenticateWithQuickConnect(
|
val authenticationResult by jellyfinApi.userApi.authenticateWithQuickConnect(
|
||||||
secret = quickConnectState.secret,
|
secret = quickConnectState.secret,
|
||||||
|
@ -189,7 +188,7 @@ constructor(
|
||||||
insertUser(appPreferences.currentServer!!, user)
|
insertUser(appPreferences.currentServer!!, user)
|
||||||
|
|
||||||
jellyfinApi.apply {
|
jellyfinApi.apply {
|
||||||
api.accessToken = authenticationResult.accessToken
|
api.update(accessToken = authenticationResult.accessToken)
|
||||||
userId = authenticationResult.user?.id
|
userId = authenticationResult.user?.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,8 @@ import kotlinx.coroutines.withContext
|
||||||
import org.jellyfin.sdk.model.api.BaseItemPerson
|
import org.jellyfin.sdk.model.api.BaseItemPerson
|
||||||
import org.jellyfin.sdk.model.api.MediaStream
|
import org.jellyfin.sdk.model.api.MediaStream
|
||||||
import org.jellyfin.sdk.model.api.MediaStreamType
|
import org.jellyfin.sdk.model.api.MediaStreamType
|
||||||
|
import org.jellyfin.sdk.model.api.PersonKind
|
||||||
|
import org.jellyfin.sdk.model.api.VideoRangeType
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -119,7 +121,7 @@ constructor(
|
||||||
private suspend fun getActors(item: FindroidMovie): List<BaseItemPerson> {
|
private suspend fun getActors(item: FindroidMovie): List<BaseItemPerson> {
|
||||||
val actors: List<BaseItemPerson>
|
val actors: List<BaseItemPerson>
|
||||||
withContext(Dispatchers.Default) {
|
withContext(Dispatchers.Default) {
|
||||||
actors = item.people.filter { it.type == "Actor" }
|
actors = item.people.filter { it.type == PersonKind.ACTOR }
|
||||||
}
|
}
|
||||||
return actors
|
return actors
|
||||||
}
|
}
|
||||||
|
@ -127,7 +129,7 @@ constructor(
|
||||||
private suspend fun getDirector(item: FindroidMovie): BaseItemPerson? {
|
private suspend fun getDirector(item: FindroidMovie): BaseItemPerson? {
|
||||||
val director: BaseItemPerson?
|
val director: BaseItemPerson?
|
||||||
withContext(Dispatchers.Default) {
|
withContext(Dispatchers.Default) {
|
||||||
director = item.people.firstOrNull { it.type == "Director" }
|
director = item.people.firstOrNull { it.type == PersonKind.DIRECTOR }
|
||||||
}
|
}
|
||||||
return director
|
return director
|
||||||
}
|
}
|
||||||
|
@ -135,7 +137,7 @@ constructor(
|
||||||
private suspend fun getWriters(item: FindroidMovie): List<BaseItemPerson> {
|
private suspend fun getWriters(item: FindroidMovie): List<BaseItemPerson> {
|
||||||
val writers: List<BaseItemPerson>
|
val writers: List<BaseItemPerson>
|
||||||
withContext(Dispatchers.Default) {
|
withContext(Dispatchers.Default) {
|
||||||
writers = item.people.filter { it.type == "Writer" }
|
writers = item.people.filter { it.type == PersonKind.WRITER }
|
||||||
}
|
}
|
||||||
return writers
|
return writers
|
||||||
}
|
}
|
||||||
|
@ -213,9 +215,9 @@ constructor(
|
||||||
DisplayProfile.DOLBY_VISION
|
DisplayProfile.DOLBY_VISION
|
||||||
} else {
|
} else {
|
||||||
when (videoRangeType) {
|
when (videoRangeType) {
|
||||||
DisplayProfile.HDR.raw -> DisplayProfile.HDR
|
VideoRangeType.HDR10 -> DisplayProfile.HDR10
|
||||||
DisplayProfile.HDR10.raw -> DisplayProfile.HDR10
|
VideoRangeType.HDR10_PLUS -> DisplayProfile.HDR10_PLUS
|
||||||
DisplayProfile.HLG.raw -> DisplayProfile.HLG
|
VideoRangeType.HLG -> DisplayProfile.HLG
|
||||||
else -> DisplayProfile.SDR
|
else -> DisplayProfile.SDR
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -74,7 +74,9 @@ constructor(
|
||||||
server.currentServerAddressId = address.id
|
server.currentServerAddressId = address.id
|
||||||
database.update(server)
|
database.update(server)
|
||||||
|
|
||||||
jellyfinApi.api.baseUrl = address.address
|
jellyfinApi.api.update(
|
||||||
|
baseUrl = address.address,
|
||||||
|
)
|
||||||
|
|
||||||
eventsChannel.send(ServerAddressesEvent.NavigateToHome)
|
eventsChannel.send(ServerAddressesEvent.NavigateToHome)
|
||||||
}
|
}
|
||||||
|
@ -84,7 +86,9 @@ constructor(
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
val jellyfinApi = JellyfinApi(context)
|
val jellyfinApi = JellyfinApi(context)
|
||||||
jellyfinApi.api.baseUrl = address
|
jellyfinApi.api.update(
|
||||||
|
baseUrl = address,
|
||||||
|
)
|
||||||
val systemInfo by jellyfinApi.systemApi.getPublicSystemInfo()
|
val systemInfo by jellyfinApi.systemApi.getPublicSystemInfo()
|
||||||
if (systemInfo.id != currentServerId) {
|
if (systemInfo.id != currentServerId) {
|
||||||
return@launch
|
return@launch
|
||||||
|
|
|
@ -101,8 +101,10 @@ constructor(
|
||||||
// If server has no selected user, navigate to login fragment
|
// If server has no selected user, navigate to login fragment
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
jellyfinApi.apply {
|
jellyfinApi.apply {
|
||||||
api.baseUrl = serverAddress.address
|
api.update(
|
||||||
api.accessToken = null
|
baseUrl = serverAddress.address,
|
||||||
|
accessToken = null,
|
||||||
|
)
|
||||||
userId = null
|
userId = null
|
||||||
}
|
}
|
||||||
appPreferences.currentServer = server.id
|
appPreferences.currentServer = server.id
|
||||||
|
@ -111,8 +113,10 @@ constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
jellyfinApi.apply {
|
jellyfinApi.apply {
|
||||||
api.baseUrl = serverAddress.address
|
api.update(
|
||||||
api.accessToken = user.accessToken
|
baseUrl = serverAddress.address,
|
||||||
|
accessToken = user.accessToken,
|
||||||
|
)
|
||||||
userId = user.id
|
userId = user.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.jellyfin.sdk.model.api.BaseItemPerson
|
import org.jellyfin.sdk.model.api.BaseItemPerson
|
||||||
|
import org.jellyfin.sdk.model.api.PersonKind
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -100,7 +101,7 @@ constructor(
|
||||||
private suspend fun getActors(item: FindroidShow): List<BaseItemPerson> {
|
private suspend fun getActors(item: FindroidShow): List<BaseItemPerson> {
|
||||||
val actors: List<BaseItemPerson>
|
val actors: List<BaseItemPerson>
|
||||||
withContext(Dispatchers.Default) {
|
withContext(Dispatchers.Default) {
|
||||||
actors = item.people.filter { it.type == "Actor" }
|
actors = item.people.filter { it.type == PersonKind.ACTOR }
|
||||||
}
|
}
|
||||||
return actors
|
return actors
|
||||||
}
|
}
|
||||||
|
@ -108,7 +109,7 @@ constructor(
|
||||||
private suspend fun getDirector(item: FindroidShow): BaseItemPerson? {
|
private suspend fun getDirector(item: FindroidShow): BaseItemPerson? {
|
||||||
val director: BaseItemPerson?
|
val director: BaseItemPerson?
|
||||||
withContext(Dispatchers.Default) {
|
withContext(Dispatchers.Default) {
|
||||||
director = item.people.firstOrNull { it.type == "Director" }
|
director = item.people.firstOrNull { it.type == PersonKind.DIRECTOR }
|
||||||
}
|
}
|
||||||
return director
|
return director
|
||||||
}
|
}
|
||||||
|
@ -116,7 +117,7 @@ constructor(
|
||||||
private suspend fun getWriters(item: FindroidShow): List<BaseItemPerson> {
|
private suspend fun getWriters(item: FindroidShow): List<BaseItemPerson> {
|
||||||
val writers: List<BaseItemPerson>
|
val writers: List<BaseItemPerson>
|
||||||
withContext(Dispatchers.Default) {
|
withContext(Dispatchers.Default) {
|
||||||
writers = item.people.filter { it.type == "Writer" }
|
writers = item.people.filter { it.type == PersonKind.WRITER }
|
||||||
}
|
}
|
||||||
return writers
|
return writers
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ import javax.inject.Inject
|
||||||
class UserSelectViewModel
|
class UserSelectViewModel
|
||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
private val appPreferences: AppPreferences,
|
appPreferences: AppPreferences,
|
||||||
private val jellyfinApi: JellyfinApi,
|
private val jellyfinApi: JellyfinApi,
|
||||||
private val database: ServerDatabaseDao,
|
private val database: ServerDatabaseDao,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
@ -71,7 +71,9 @@ constructor(
|
||||||
database.update(server)
|
database.update(server)
|
||||||
|
|
||||||
jellyfinApi.apply {
|
jellyfinApi.apply {
|
||||||
api.accessToken = user.accessToken
|
api.update(
|
||||||
|
accessToken = user.accessToken,
|
||||||
|
)
|
||||||
userId = user.id
|
userId = user.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,9 @@ constructor(
|
||||||
database.update(server)
|
database.update(server)
|
||||||
|
|
||||||
jellyfinApi.apply {
|
jellyfinApi.apply {
|
||||||
api.accessToken = user.accessToken
|
api.update(
|
||||||
|
accessToken = user.accessToken,
|
||||||
|
)
|
||||||
userId = user.id
|
userId = user.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,8 +40,10 @@ class SyncWorker @AssistedInject constructor(
|
||||||
val serverAddress = serverWithAddressesAndUsers.addresses.firstOrNull { it.id == server.currentServerAddressId } ?: continue
|
val serverAddress = serverWithAddressesAndUsers.addresses.firstOrNull { it.id == server.currentServerAddressId } ?: continue
|
||||||
for (user in serverWithAddressesAndUsers.users) {
|
for (user in serverWithAddressesAndUsers.users) {
|
||||||
jellyfinApi.apply {
|
jellyfinApi.apply {
|
||||||
api.baseUrl = serverAddress.address
|
api.update(
|
||||||
api.accessToken = user.accessToken
|
baseUrl = serverAddress.address,
|
||||||
|
accessToken = user.accessToken,
|
||||||
|
)
|
||||||
userId = user.id
|
userId = user.id
|
||||||
}
|
}
|
||||||
val movies = database.getMoviesByServerId(server.id).map { it.toFindroidMovie(database, user.id) }
|
val movies = database.getMoviesByServerId(server.id).map { it.toFindroidMovie(database, user.id) }
|
||||||
|
@ -66,17 +68,16 @@ class SyncWorker @AssistedInject constructor(
|
||||||
|
|
||||||
try {
|
try {
|
||||||
when (userData.played) {
|
when (userData.played) {
|
||||||
true -> jellyfinApi.playStateApi.markPlayedItem(user.id, item.id)
|
true -> jellyfinApi.playStateApi.markPlayedItem(item.id, user.id)
|
||||||
false -> jellyfinApi.playStateApi.markUnplayedItem(user.id, item.id)
|
false -> jellyfinApi.playStateApi.markUnplayedItem(item.id, user.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
when (userData.favorite) {
|
when (userData.favorite) {
|
||||||
true -> jellyfinApi.userLibraryApi.markFavoriteItem(user.id, item.id)
|
true -> jellyfinApi.userLibraryApi.markFavoriteItem(item.id, user.id)
|
||||||
false -> jellyfinApi.userLibraryApi.unmarkFavoriteItem(user.id, item.id)
|
false -> jellyfinApi.userLibraryApi.unmarkFavoriteItem(item.id, user.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
jellyfinApi.playStateApi.onPlaybackStopped(
|
jellyfinApi.playStateApi.onPlaybackStopped(
|
||||||
userId = user.id,
|
|
||||||
itemId = item.id,
|
itemId = item.id,
|
||||||
positionTicks = userData.playbackPositionTicks,
|
positionTicks = userData.playbackPositionTicks,
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="add_server_error_version">Неподдържана версия на сървъра: %1$s. Моля ъпдейтнете вашия сървър</string>
|
<string name="add_server_error_version">Неподдържана версия на сървъра: %1$s. Моля ъпдейтнете вашия сървър</string>
|
||||||
<string name="add_server_error_no_id">Сървърът няма id, изглежда, че има нещо не е наред със сървъра</string>
|
<string name="add_server_error_no_id">Сървърът няма id, изглежда, че нещо не е наред със сървъра</string>
|
||||||
<string name="remove_server">Премахнете сървъра</string>
|
<string name="remove_server">Премахване на сървъра</string>
|
||||||
<string name="sort_by">Сортирайте по</string>
|
<string name="sort_by">Сортирайте по</string>
|
||||||
<string name="download_roaming">Свалете при роуминг</string>
|
<string name="download_roaming">Свалете при роуминг</string>
|
||||||
<string name="mpv_player_summary">Използвайте експерименталният mpv плейър за да пускане на видеа. mpv поддържа повече кодекси за видео, аудио и субтитри.</string>
|
<string name="mpv_player_summary">Използвайте експерименталният mpv плейър за да пускане на видеа. mpv поддържа повече кодекси за видео, аудио и субтитри.</string>
|
||||||
|
@ -13,11 +13,11 @@
|
||||||
<string name="login_error_wrong_username_password">Грешно потребителско име или парола</string>
|
<string name="login_error_wrong_username_password">Грешно потребителско име или парола</string>
|
||||||
<string name="add_server_error_not_jellyfin">Не е Jellyfin сървър: %1$s</string>
|
<string name="add_server_error_not_jellyfin">Не е Jellyfin сървър: %1$s</string>
|
||||||
<string name="add_server_error_slow">Сървърът реагира твърде бавно: %1$s</string>
|
<string name="add_server_error_slow">Сървърът реагира твърде бавно: %1$s</string>
|
||||||
<string name="remove">Премахнете</string>
|
<string name="remove">Премахване</string>
|
||||||
<string name="cancel">Отменете</string>
|
<string name="cancel">Отменяне</string>
|
||||||
<string name="title_home">Начало</string>
|
<string name="title_home">Начало</string>
|
||||||
<string name="button_connect">Свържете се</string>
|
<string name="button_connect">Свързване</string>
|
||||||
<string name="button_login">Влезнете</string>
|
<string name="button_login">Вход</string>
|
||||||
<string name="remove_server_dialog_text">Сигурни ли сте, че искате да премахнете сървъра %1$s</string>
|
<string name="remove_server_dialog_text">Сигурни ли сте, че искате да премахнете сървъра %1$s</string>
|
||||||
<string name="title_media">Моята медия</string>
|
<string name="title_media">Моята медия</string>
|
||||||
<string name="edit_text_server_address_hint">Адрес на сървъра</string>
|
<string name="edit_text_server_address_hint">Адрес на сървъра</string>
|
||||||
|
@ -27,10 +27,10 @@
|
||||||
<string name="title_settings">Настройки</string>
|
<string name="title_settings">Настройки</string>
|
||||||
<string name="title_download">Свалени</string>
|
<string name="title_download">Свалени</string>
|
||||||
<string name="view_all">Вижте всички</string>
|
<string name="view_all">Вижте всички</string>
|
||||||
<string name="error_loading_data">Проблем с зареждането на датата</string>
|
<string name="error_loading_data">Проблем с зареждането на информацията</string>
|
||||||
<string name="retry">Опитайте отново</string>
|
<string name="retry">Опитайте отново</string>
|
||||||
<string name="genres">Жанрове</string>
|
<string name="genres">Жанрове</string>
|
||||||
<string name="director">Директор</string>
|
<string name="director">Режисьор</string>
|
||||||
<string name="writers">Писатели</string>
|
<string name="writers">Писатели</string>
|
||||||
<string name="seasons">Сезони</string>
|
<string name="seasons">Сезони</string>
|
||||||
<string name="play_button_description">Пуснете медията</string>
|
<string name="play_button_description">Пуснете медията</string>
|
||||||
|
@ -46,7 +46,7 @@
|
||||||
<string name="no_downloads">Вие нямате нищо свалено</string>
|
<string name="no_downloads">Вие нямате нищо свалено</string>
|
||||||
<string name="search">Търсене</string>
|
<string name="search">Търсене</string>
|
||||||
<string name="settings_category_language">Език</string>
|
<string name="settings_category_language">Език</string>
|
||||||
<string name="settings_preferred_audio_language">Предпочитан аудо език</string>
|
<string name="settings_preferred_audio_language">Предпочитан аудио език</string>
|
||||||
<string name="settings_preferred_subtitle_language">Предпочитан език на субтитрите</string>
|
<string name="settings_preferred_subtitle_language">Предпочитан език на субтитрите</string>
|
||||||
<string name="settings_category_servers">Сървъри</string>
|
<string name="settings_category_servers">Сървъри</string>
|
||||||
<string name="settings_category_player">Плейър</string>
|
<string name="settings_category_player">Плейър</string>
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
<string name="shows_label">ТВ Предавания</string>
|
<string name="shows_label">ТВ Предавания</string>
|
||||||
<string name="hide">Скрийте</string>
|
<string name="hide">Скрийте</string>
|
||||||
<string name="sort_order">Ред на сортиране</string>
|
<string name="sort_order">Ред на сортиране</string>
|
||||||
<string name="download_mobile_data">Свалете с мобилна дата</string>
|
<string name="download_mobile_data">Свалете с мобилни данни</string>
|
||||||
<string name="ascending">Възходящ</string>
|
<string name="ascending">Възходящ</string>
|
||||||
<string name="mpv_player">mpv плейър</string>
|
<string name="mpv_player">mpv плейър</string>
|
||||||
<string name="download_button_description">Свалете</string>
|
<string name="download_button_description">Свалете</string>
|
||||||
|
@ -71,7 +71,7 @@
|
||||||
<string name="error_preparing_player_items">Проблем при подготовката на елементите на плейъра.</string>
|
<string name="error_preparing_player_items">Проблем при подготовката на елементите на плейъра.</string>
|
||||||
<string name="view_details">Вижте детайли</string>
|
<string name="view_details">Вижте детайли</string>
|
||||||
<string name="view_details_underlined"><u>Вижте детайли</u></string>
|
<string name="view_details_underlined"><u>Вижте детайли</u></string>
|
||||||
<string name="about">За</string>
|
<string name="about">Описание</string>
|
||||||
<string name="privacy_policy">Политика за поверителност</string>
|
<string name="privacy_policy">Политика за поверителност</string>
|
||||||
<string name="app_info">Информация за приложението</string>
|
<string name="app_info">Информация за приложението</string>
|
||||||
<string name="unknown_error">Непозната грешка</string>
|
<string name="unknown_error">Непозната грешка</string>
|
||||||
|
@ -84,95 +84,112 @@
|
||||||
<string name="series_poster">Постер на сериала</string>
|
<string name="series_poster">Постер на сериала</string>
|
||||||
<string name="no_search_results">Няма резултати от търсенето</string>
|
<string name="no_search_results">Няма резултати от търсенето</string>
|
||||||
<string name="settings_category_download">Свалени</string>
|
<string name="settings_category_download">Свалени</string>
|
||||||
<string name="settings_use_cache_summary">Кеширайте снимките на диска за да ускорите времето за зареждане. Ще има ефект след рестартиране на приложението.</string>
|
<string name="settings_use_cache_summary">Кеширайте снимките на диска, за да ускорите времето за зареждане. Ще има ефект след рестартиране на приложението.</string>
|
||||||
<string name="settings_cache_size_message">Приложението ще използва това количество MB от вашето дисково пространство, за да съхранява изображения от сървъра на Jellyfin. По-големи стойности може да са от полза при по-бавни мрежи.</string>
|
<string name="settings_cache_size_message">Приложението ще използва това количество MB от вашето дисково пространство, за да съхранява изображения от сървъра на Jellyfin. По-големи стойности може да са от полза при по-бавни мрежи.</string>
|
||||||
<string name="descending">Низходящ</string>
|
<string name="descending">Низходящ</string>
|
||||||
<string name="track_selection">[%1$s] %2$s (%3$s)</string>
|
<string name="track_selection">[%1$s] %2$s (%3$s)</string>
|
||||||
<string name="runtime_minutes">%1$d мин</string>
|
<string name="runtime_minutes">%1$d мин</string>
|
||||||
<string name="size">Tamanho</string>
|
<string name="size">Размер</string>
|
||||||
<string name="seeking">Buscando</string>
|
<string name="seeking">Търсене</string>
|
||||||
<string name="settings_request_timeout">Tempo limite da solicitação (ms)</string>
|
<string name="settings_request_timeout">Лимит на заявките (ms)</string>
|
||||||
<string name="pref_player_mpv_ao">Saída de áudio</string>
|
<string name="pref_player_mpv_ao">Изход на аудиото</string>
|
||||||
<string name="episode_name_with_end">%1$d-%2$d. %3$s</string>
|
<string name="episode_name_with_end">%1$d-%2$d. %3$s</string>
|
||||||
<string name="episode_name_extended_with_end">S%1$d:E%2$d-%3$d - %4$s</string>
|
<string name="episode_name_extended_with_end">S%1$d:E%2$d-%3$d - %4$s</string>
|
||||||
<string name="image_description_backdrop">Pano de fundo de %1$s</string>
|
<string name="image_description_backdrop">Фон на %1$s</string>
|
||||||
<string name="users">Usuários</string>
|
<string name="users">Потребители</string>
|
||||||
<string name="no_server_connection">Sem conexão com o servidor Jellyfin, para assistir off-line, ative o modo off-line</string>
|
<string name="no_server_connection">Няма връзка към Jellyfin сървъра, за да гледате офлайн пуснете Режим без Интернет</string>
|
||||||
<string name="privacy_policy_notice">Ao usar o Findroid, você concorda com a <a href="https://raw.githubusercontent.com/jarnedemeulemeester/findroid/main/PRIVACY">Política de Privacidade</a>, que afirma que não coletamos quaisquer dados</string>
|
<string name="privacy_policy_notice">При ползването на Findroid, вие се съгласявате с <a href="https://raw.githubusercontent.com/jarnedemeulemeester/findroid/main/PRIVACY">Политиката за поверителност</a> , която гласи, че не събираме никаква информация</string>
|
||||||
<string name="app_description">Aplicativo Jellyfin nativo de terceiros</string>
|
<string name="app_description">Неофициално приложение за Jellyfin с \"native\" елементи</string>
|
||||||
<string name="dynamic_colors">Cores dinâmicas</string>
|
<string name="dynamic_colors">Динамични цветове</string>
|
||||||
<string name="person_detail_title">Detalhes</string>
|
<string name="person_detail_title">Детайли</string>
|
||||||
<string name="player_gestures_zoom_summary">Aperte para preencher a tela com o vídeo</string>
|
<string name="player_gestures_zoom_summary">Плъзнете с два пръста, за да изпълните екрана</string>
|
||||||
<string name="player_brightness_remember">Lembre-se do nível de brilho</string>
|
<string name="player_brightness_remember">Запомни ниво на яркост</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_vb_summary">Плъзнете нагоре и надолу на дяснатата страна на екрана, за да промените звука, и на лявата страна, за да промените яркостта</string>
|
||||||
<string name="sort_by_options_1">Classificação IMDB</string>
|
<string name="sort_by_options_1">IMDB оценка</string>
|
||||||
<string name="sort_by_options_3">data adicionada</string>
|
<string name="sort_by_options_3">Дата Добавен</string>
|
||||||
<string name="seek_back_increment">Buscar incremento de volta (ms)</string>
|
<string name="seek_back_increment">Инкремент за връщане назад(ms)</string>
|
||||||
<string name="pref_player_mpv_vo">Saida de video</string>
|
<string name="pref_player_mpv_vo">Изхода на видеото</string>
|
||||||
<string name="pref_player_intro_skipper_summary">Requer que o plugin Confused Polar Bears Intro Skipper esteja instalado no servidor</string>
|
<string name="pref_player_intro_skipper_summary">Изисква Confused Polar Bears Intro Skipper да бъде инсталиран на сървъра</string>
|
||||||
<string name="remove_user">Remover usuário</string>
|
<string name="remove_user">Премахване на потребител</string>
|
||||||
<string name="remove_user_dialog_text">Tem certeza de que deseja remover o usuário %1$s</string>
|
<string name="remove_user_dialog_text">Сигурни ли сте, че искате да премахнете потребител %1$s</string>
|
||||||
<string name="quick_connect">Conexão rápida</string>
|
<string name="quick_connect">Бързо Свързване</string>
|
||||||
<string name="extra_info_summary">Exibe informações detalhadas sobre áudio, vídeo e legendas</string>
|
<string name="extra_info_summary">Показва детайлна информация за Аудио, Видео и Субтитри</string>
|
||||||
<string name="subtitle_chip_text">CC</string>
|
<string name="subtitle_chip_text">Затворени субтитри</string>
|
||||||
<string name="temp">Temperatura</string>
|
<string name="temp">временно</string>
|
||||||
<string name="offline_mode_icon">Ícone do modo off-line</string>
|
<string name="offline_mode_icon">Режим без Интернет иконка</string>
|
||||||
<string name="offline_mode_go_online">Fique online</string>
|
<string name="offline_mode_go_online">Свържи се с Интернет</string>
|
||||||
<string name="select_storage_location">Selecione o local de armazenamento</string>
|
<string name="select_storage_location">Изберете локация на диска</string>
|
||||||
<string name="theme_light">Luz</string>
|
<string name="theme_light">Светла</string>
|
||||||
<string name="amoled_theme_summary">Use tema AMOLED com fundo preto puro</string>
|
<string name="amoled_theme_summary">Използвайте AMOLED тема с чисто черен фон</string>
|
||||||
<string name="theme_system">Siga o sistema</string>
|
<string name="theme_system">Следвай системата</string>
|
||||||
<string name="libraries">Bibliotecas</string>
|
<string name="libraries">Библиотеки</string>
|
||||||
<string name="amoled_theme">Tema escuro AMOLED</string>
|
<string name="amoled_theme">AMOLED тъмна тема</string>
|
||||||
<string name="player_gestures_seek">Procure gesto</string>
|
<string name="player_gestures_seek">Жест за търсене</string>
|
||||||
<string name="player_gestures_seek_summary">Deslize horizontalmente para avançar ou retroceder</string>
|
<string name="player_gestures_seek_summary">Плъзнете хоризонтално, за да върнете назад или да пропуснете напред</string>
|
||||||
<string name="downloaded_indicator">Indicador baixado</string>
|
<string name="downloaded_indicator">Индикатор за сваленост</string>
|
||||||
<string name="app_language">Idioma do aplicativo</string>
|
<string name="app_language">Език на приложението</string>
|
||||||
<string name="episodes_label">Episódios</string>
|
<string name="episodes_label">Епизоди</string>
|
||||||
<string name="image_description_poster">pôster de %1$s</string>
|
<string name="image_description_poster">Постер на %1$s</string>
|
||||||
<string name="player_gestures">Gestos do jogador</string>
|
<string name="player_gestures">Жестове на плейъра</string>
|
||||||
<string name="player_gestures_vb">Gestos de volume e brilho</string>
|
<string name="player_gestures_vb">Жестове за яркост и звук</string>
|
||||||
<string name="sort_by_options_0">Título</string>
|
<string name="sort_by_options_0">Заглавие</string>
|
||||||
<string name="dynamic_colors_summary">Use cores dinâmicas do Material You (disponível apenas no Android 12+)</string>
|
<string name="dynamic_colors_summary">Използвай динамични Material You цветове (възможно единствено на Android 12+)</string>
|
||||||
<string name="sort_by_options_2">Avaliação parental</string>
|
<string name="sort_by_options_2">Оценка за родителски контрол</string>
|
||||||
<string name="sort_by_options_4">Data de reprodução</string>
|
<string name="sort_by_options_4">Дата пускан</string>
|
||||||
<string name="seek_forward_increment">Procure incremento direto (ms)</string>
|
<string name="seek_forward_increment">Инкремент за пропускане напред(ms)</string>
|
||||||
<string name="subtitles">Legendas</string>
|
<string name="subtitles">Субтитри</string>
|
||||||
<string name="subtitles_summary">Personalize a aparência das legendas</string>
|
<string name="subtitles_summary">Персонализирайте външния вид на субтитрите</string>
|
||||||
<string name="settings_category_network">Rede</string>
|
<string name="settings_category_network">Мрежа</string>
|
||||||
<string name="settings_socket_timeout">Tempo limite do soquete (ms)</string>
|
<string name="settings_socket_timeout">Лимит на сокета (ms)</string>
|
||||||
<string name="pref_player_mpv_hwdec">Decodificação de hardware</string>
|
<string name="pref_player_mpv_hwdec">Хардуерно декодиране</string>
|
||||||
<string name="pref_player_trick_play_summary">Requer que o plugin Jellyscrub do Nicknsy esteja instalado no servidor</string>
|
<string name="pref_player_trick_play_summary">Изисква Jellyscrub на nicknsy да бъде инсталиран на сървъра</string>
|
||||||
<string name="add_address">Adicionar endereço</string>
|
<string name="add_address">Добави адрес</string>
|
||||||
<string name="audio">Audio</string>
|
<string name="audio">Аудио</string>
|
||||||
<string name="video">Vídeo</string>
|
<string name="video">Видео</string>
|
||||||
<string name="extra_info">Exibir informações extras</string>
|
<string name="extra_info">Покажи Допълнителна информация</string>
|
||||||
<string name="external">Externo</string>
|
<string name="external">Външно</string>
|
||||||
<string name="storage_name">%1$s (%2$d MB grátis)</string>
|
<string name="storage_name">%1$s (%2$d MB свободни)</string>
|
||||||
<string name="cancel_download">Cancelar transferência</string>
|
<string name="cancel_download">Отмени свалянето</string>
|
||||||
<string name="preparing_download">Preparando transferência</string>
|
<string name="preparing_download">Подготвяне на свалянето</string>
|
||||||
<string name="cancel_download_message">Tem certeza de que deseja cancelar a transferência\?</string>
|
<string name="cancel_download_message">Сигурни ли сте, че искате на отмените свалянето?</string>
|
||||||
<string name="stop_download">Pare de baixar</string>
|
<string name="stop_download">Спри свалянето</string>
|
||||||
<string name="storage_unavailable">O local de armazenamento não está disponível</string>
|
<string name="storage_unavailable">Локацията на диска е недостъпна</string>
|
||||||
<string name="internal">Interno</string>
|
<string name="internal">Вътрежно</string>
|
||||||
<string name="remove_server_address">Remover endereço do servidor</string>
|
<string name="remove_server_address">Премахване на адрес на сървър</string>
|
||||||
<string name="remove_server_address_dialog_text">Tem certeza de que deseja remover o endereço do servidor %1$s</string>
|
<string name="remove_server_address_dialog_text">Сигурни ли сте, че искате да премахнете адреса на сървъра %1$s</string>
|
||||||
<string name="sort_by_options_5">Data de lançamento</string>
|
<string name="sort_by_options_5">Дата на издаване</string>
|
||||||
<string name="select_video_version_title">Selecione a versão</string>
|
<string name="select_video_version_title">Изберете версия</string>
|
||||||
<string name="theme_dark">Escuro</string>
|
<string name="theme_dark">Тъмна</string>
|
||||||
<string name="pref_player_intro_skipper">Capitão de introdução</string>
|
<string name="pref_player_intro_skipper">Пропускане на интрота</string>
|
||||||
<string name="pref_player_trick_play">Truque</string>
|
<string name="pref_player_trick_play">Trick Play</string>
|
||||||
<string name="addresses">Endereços</string>
|
<string name="addresses">Адреси</string>
|
||||||
<string name="add_server_address">Adicionar endereço do servidor</string>
|
<string name="add_server_address">Добави адрес на сървър</string>
|
||||||
<string name="player_gestures_zoom">Gesto de zoom</string>
|
<string name="player_gestures_zoom">Жест за приближаване (zoom)</string>
|
||||||
<string name="settings_connect_timeout">Tempo limite de conexão (ms)</string>
|
<string name="settings_connect_timeout">Лимит на свързването (ms)</string>
|
||||||
<string name="add_user">Adicionar usuário</string>
|
<string name="add_user">Добави потребител</string>
|
||||||
<string name="add">Adicionar</string>
|
<string name="add">Добави</string>
|
||||||
<string name="picture_in_picture">Imagem em imagem</string>
|
<string name="picture_in_picture">Режим Картина-в-картина</string>
|
||||||
<string name="picture_in_picture_gesture">Gesto inicial picture-in-picture</string>
|
<string name="picture_in_picture_gesture">Жест за Режим Картина-в-картина</string>
|
||||||
<string name="picture_in_picture_gesture_summary">Use o botão home ou gesto para entrar picture-in-picture enquanto o vídeo está sendo reproduzido</string>
|
<string name="picture_in_picture_gesture_summary">Използайте Home бутона или жест, за да влезете в режим Картина-в-картина</string>
|
||||||
<string name="subtitle">Legendas</string>
|
<string name="subtitle">Субтитри</string>
|
||||||
<string name="offline_mode">Modo offline</string>
|
<string name="offline_mode">Режим без Интернет</string>
|
||||||
<string name="downloading_error">Erro ao baixar</string>
|
<string name="downloading_error">Грешка при сваляне</string>
|
||||||
<string name="not_enough_storage">Este item requer %1$s de armazenamento gratuito, mas apenas %2$s está disponível</string>
|
<string name="not_enough_storage">Тази медия изисква %1$s свободно място, но има само %2$s свободно</string>
|
||||||
|
<string name="remove_from_favorites">Махни от любими</string>
|
||||||
|
<string name="collection_no_media">Тази колекция не съдържа никаква медия</string>
|
||||||
|
<string name="player_start_maximized">Започни в максимизиран режим</string>
|
||||||
|
<string name="player_start_maximized_summary">Отвори видео в максимизиран режим по подразбиране</string>
|
||||||
|
<string name="player_gestures_chapter_skip_summary">Дълго задържане на Лявата / Дясната страна, за пропускане на глава (отменя жеста за 2x скорост)</string>
|
||||||
|
<string name="pref_player_chapter_markers">Маркери за глави</string>
|
||||||
|
<string name="pref_player_chapter_markers_summary">Показвай маркери за глави на времевата линия</string>
|
||||||
|
<string name="no_servers_found">Не са намерени сървъри</string>
|
||||||
|
<string name="no_users_found">Не са намерени потребители</string>
|
||||||
|
<string name="select_user">Избери потребител</string>
|
||||||
|
<string name="live_tv">Телевизия На Живо</string>
|
||||||
|
<string name="play">Пусни</string>
|
||||||
|
<string name="mark_as_played">Маркирай като гледано</string>
|
||||||
|
<string name="unmark_as_played">Махни маркирано като гледано</string>
|
||||||
|
<string name="watch_trailer">Гледай трейлър</string>
|
||||||
|
<string name="add_to_favorites">Добави към любими</string>
|
||||||
|
<string name="player_gestures_chapter_skip">Пропусни глава</string>
|
||||||
</resources>
|
</resources>
|
|
@ -4,6 +4,7 @@ import android.content.Context
|
||||||
import dev.jdtech.jellyfin.Constants
|
import dev.jdtech.jellyfin.Constants
|
||||||
import dev.jdtech.jellyfin.data.BuildConfig
|
import dev.jdtech.jellyfin.data.BuildConfig
|
||||||
import org.jellyfin.sdk.api.client.HttpClientOptions
|
import org.jellyfin.sdk.api.client.HttpClientOptions
|
||||||
|
import org.jellyfin.sdk.api.client.extensions.brandingApi
|
||||||
import org.jellyfin.sdk.api.client.extensions.devicesApi
|
import org.jellyfin.sdk.api.client.extensions.devicesApi
|
||||||
import org.jellyfin.sdk.api.client.extensions.itemsApi
|
import org.jellyfin.sdk.api.client.extensions.itemsApi
|
||||||
import org.jellyfin.sdk.api.client.extensions.mediaInfoApi
|
import org.jellyfin.sdk.api.client.extensions.mediaInfoApi
|
||||||
|
@ -19,6 +20,8 @@ import org.jellyfin.sdk.api.client.extensions.videosApi
|
||||||
import org.jellyfin.sdk.createJellyfin
|
import org.jellyfin.sdk.createJellyfin
|
||||||
import org.jellyfin.sdk.model.ClientInfo
|
import org.jellyfin.sdk.model.ClientInfo
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
import kotlin.time.DurationUnit
|
||||||
|
import kotlin.time.toDuration
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Jellyfin API class using org.jellyfin.sdk:jellyfin-platform-android
|
* Jellyfin API class using org.jellyfin.sdk:jellyfin-platform-android
|
||||||
|
@ -40,25 +43,26 @@ class JellyfinApi(
|
||||||
}
|
}
|
||||||
val api = jellyfin.createApi(
|
val api = jellyfin.createApi(
|
||||||
httpClientOptions = HttpClientOptions(
|
httpClientOptions = HttpClientOptions(
|
||||||
requestTimeout = requestTimeout,
|
requestTimeout = requestTimeout.toDuration(DurationUnit.MILLISECONDS),
|
||||||
connectTimeout = connectTimeout,
|
connectTimeout = connectTimeout.toDuration(DurationUnit.MILLISECONDS),
|
||||||
socketTimeout = socketTimeout,
|
socketTimeout = socketTimeout.toDuration(DurationUnit.MILLISECONDS),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
var userId: UUID? = null
|
var userId: UUID? = null
|
||||||
|
|
||||||
|
val brandingApi = api.brandingApi
|
||||||
val devicesApi = api.devicesApi
|
val devicesApi = api.devicesApi
|
||||||
val systemApi = api.systemApi
|
|
||||||
val userApi = api.userApi
|
|
||||||
val viewsApi = api.userViewsApi
|
|
||||||
val itemsApi = api.itemsApi
|
val itemsApi = api.itemsApi
|
||||||
val userLibraryApi = api.userLibraryApi
|
|
||||||
val showsApi = api.tvShowsApi
|
|
||||||
val sessionApi = api.sessionApi
|
|
||||||
val videosApi = api.videosApi
|
|
||||||
val mediaInfoApi = api.mediaInfoApi
|
val mediaInfoApi = api.mediaInfoApi
|
||||||
val playStateApi = api.playStateApi
|
val playStateApi = api.playStateApi
|
||||||
val quickConnectApi = api.quickConnectApi
|
val quickConnectApi = api.quickConnectApi
|
||||||
|
val sessionApi = api.sessionApi
|
||||||
|
val showsApi = api.tvShowsApi
|
||||||
|
val systemApi = api.systemApi
|
||||||
|
val userApi = api.userApi
|
||||||
|
val userLibraryApi = api.userLibraryApi
|
||||||
|
val videosApi = api.videosApi
|
||||||
|
val viewsApi = api.userViewsApi
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@Volatile
|
@Volatile
|
||||||
|
|
|
@ -25,7 +25,7 @@ data class FindroidCollection(
|
||||||
fun BaseItemDto.toFindroidCollection(
|
fun BaseItemDto.toFindroidCollection(
|
||||||
jellyfinRepository: JellyfinRepository,
|
jellyfinRepository: JellyfinRepository,
|
||||||
): FindroidCollection? {
|
): FindroidCollection? {
|
||||||
val type = CollectionType.fromString(collectionType)
|
val type = CollectionType.fromString(collectionType?.serialName)
|
||||||
|
|
||||||
if (type !in CollectionType.supported) {
|
if (type !in CollectionType.supported) {
|
||||||
return null
|
return null
|
||||||
|
|
|
@ -3,6 +3,7 @@ package dev.jdtech.jellyfin.models
|
||||||
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
||||||
import org.jellyfin.sdk.model.api.MediaStream
|
import org.jellyfin.sdk.model.api.MediaStream
|
||||||
import org.jellyfin.sdk.model.api.MediaStreamType
|
import org.jellyfin.sdk.model.api.MediaStreamType
|
||||||
|
import org.jellyfin.sdk.model.api.VideoRangeType
|
||||||
|
|
||||||
data class FindroidMediaStream(
|
data class FindroidMediaStream(
|
||||||
val title: String,
|
val title: String,
|
||||||
|
@ -13,7 +14,7 @@ data class FindroidMediaStream(
|
||||||
val isExternal: Boolean,
|
val isExternal: Boolean,
|
||||||
val path: String?,
|
val path: String?,
|
||||||
val channelLayout: String?,
|
val channelLayout: String?,
|
||||||
val videoRangeType: String?,
|
val videoRangeType: VideoRangeType?,
|
||||||
val height: Int?,
|
val height: Int?,
|
||||||
val width: Int?,
|
val width: Int?,
|
||||||
val videoDoViTitle: String?,
|
val videoDoViTitle: String?,
|
||||||
|
@ -46,7 +47,7 @@ fun FindroidMediaStreamDto.toFindroidMediaStream(): FindroidMediaStream {
|
||||||
isExternal = isExternal,
|
isExternal = isExternal,
|
||||||
path = path,
|
path = path,
|
||||||
channelLayout = channelLayout,
|
channelLayout = channelLayout,
|
||||||
videoRangeType = videoRangeType,
|
videoRangeType = VideoRangeType.fromNameOrNull(videoRangeType ?: ""),
|
||||||
height = height,
|
height = height,
|
||||||
width = width,
|
width = width,
|
||||||
videoDoViTitle = videoDoViTitle,
|
videoDoViTitle = videoDoViTitle,
|
||||||
|
|
|
@ -39,7 +39,7 @@ fun FindroidMediaStream.toFindroidMediaStreamDto(id: UUID, sourceId: String, pat
|
||||||
isExternal = isExternal,
|
isExternal = isExternal,
|
||||||
path = path,
|
path = path,
|
||||||
channelLayout = channelLayout,
|
channelLayout = channelLayout,
|
||||||
videoRangeType = videoRangeType,
|
videoRangeType = videoRangeType?.name,
|
||||||
height = height,
|
height = height,
|
||||||
width = width,
|
width = width,
|
||||||
videoDoViTitle = videoDoViTitle,
|
videoDoViTitle = videoDoViTitle,
|
||||||
|
|
|
@ -18,8 +18,8 @@ enum class Resolution(val raw: String) {
|
||||||
|
|
||||||
enum class DisplayProfile(val raw: String) {
|
enum class DisplayProfile(val raw: String) {
|
||||||
SDR("SDR"),
|
SDR("SDR"),
|
||||||
HDR("HDR"),
|
|
||||||
HDR10("HDR10"),
|
HDR10("HDR10"),
|
||||||
|
HDR10_PLUS("HDR10+"),
|
||||||
DOLBY_VISION("Vision"),
|
DOLBY_VISION("Vision"),
|
||||||
HLG("HLG"),
|
HLG("HLG"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,8 @@ import org.jellyfin.sdk.model.api.DlnaProfileType
|
||||||
import org.jellyfin.sdk.model.api.GeneralCommandType
|
import org.jellyfin.sdk.model.api.GeneralCommandType
|
||||||
import org.jellyfin.sdk.model.api.ItemFields
|
import org.jellyfin.sdk.model.api.ItemFields
|
||||||
import org.jellyfin.sdk.model.api.ItemFilter
|
import org.jellyfin.sdk.model.api.ItemFilter
|
||||||
|
import org.jellyfin.sdk.model.api.ItemSortBy
|
||||||
|
import org.jellyfin.sdk.model.api.MediaType
|
||||||
import org.jellyfin.sdk.model.api.PlaybackInfoDto
|
import org.jellyfin.sdk.model.api.PlaybackInfoDto
|
||||||
import org.jellyfin.sdk.model.api.PublicSystemInfo
|
import org.jellyfin.sdk.model.api.PublicSystemInfo
|
||||||
import org.jellyfin.sdk.model.api.SortOrder
|
import org.jellyfin.sdk.model.api.SortOrder
|
||||||
|
@ -68,38 +70,38 @@ class JellyfinRepositoryImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getItem(itemId: UUID): BaseItemDto = withContext(Dispatchers.IO) {
|
override suspend fun getItem(itemId: UUID): BaseItemDto = withContext(Dispatchers.IO) {
|
||||||
jellyfinApi.userLibraryApi.getItem(jellyfinApi.userId!!, itemId).content
|
jellyfinApi.userLibraryApi.getItem(itemId, jellyfinApi.userId!!).content
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getEpisode(itemId: UUID): FindroidEpisode =
|
override suspend fun getEpisode(itemId: UUID): FindroidEpisode =
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
jellyfinApi.userLibraryApi.getItem(
|
jellyfinApi.userLibraryApi.getItem(
|
||||||
jellyfinApi.userId!!,
|
|
||||||
itemId,
|
itemId,
|
||||||
|
jellyfinApi.userId!!,
|
||||||
).content.toFindroidEpisode(this@JellyfinRepositoryImpl, database)!!
|
).content.toFindroidEpisode(this@JellyfinRepositoryImpl, database)!!
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMovie(itemId: UUID): FindroidMovie =
|
override suspend fun getMovie(itemId: UUID): FindroidMovie =
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
jellyfinApi.userLibraryApi.getItem(
|
jellyfinApi.userLibraryApi.getItem(
|
||||||
jellyfinApi.userId!!,
|
|
||||||
itemId,
|
itemId,
|
||||||
|
jellyfinApi.userId!!,
|
||||||
).content.toFindroidMovie(this@JellyfinRepositoryImpl, database)
|
).content.toFindroidMovie(this@JellyfinRepositoryImpl, database)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getShow(itemId: UUID): FindroidShow =
|
override suspend fun getShow(itemId: UUID): FindroidShow =
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
jellyfinApi.userLibraryApi.getItem(
|
jellyfinApi.userLibraryApi.getItem(
|
||||||
jellyfinApi.userId!!,
|
|
||||||
itemId,
|
itemId,
|
||||||
|
jellyfinApi.userId!!,
|
||||||
).content.toFindroidShow(this@JellyfinRepositoryImpl)
|
).content.toFindroidShow(this@JellyfinRepositoryImpl)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getSeason(itemId: UUID): FindroidSeason =
|
override suspend fun getSeason(itemId: UUID): FindroidSeason =
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
jellyfinApi.userLibraryApi.getItem(
|
jellyfinApi.userLibraryApi.getItem(
|
||||||
jellyfinApi.userId!!,
|
|
||||||
itemId,
|
itemId,
|
||||||
|
jellyfinApi.userId!!,
|
||||||
).content.toFindroidSeason(this@JellyfinRepositoryImpl)
|
).content.toFindroidSeason(this@JellyfinRepositoryImpl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +129,7 @@ class JellyfinRepositoryImpl(
|
||||||
parentId = parentId,
|
parentId = parentId,
|
||||||
includeItemTypes = includeTypes,
|
includeItemTypes = includeTypes,
|
||||||
recursive = recursive,
|
recursive = recursive,
|
||||||
sortBy = listOf(sortBy.sortString),
|
sortBy = listOf(ItemSortBy.fromName(sortBy.sortString)),
|
||||||
sortOrder = listOf(sortOrder),
|
sortOrder = listOf(sortOrder),
|
||||||
startIndex = startIndex,
|
startIndex = startIndex,
|
||||||
limit = limit,
|
limit = limit,
|
||||||
|
@ -253,7 +255,8 @@ class JellyfinRepositoryImpl(
|
||||||
jellyfinApi.showsApi.getNextUp(
|
jellyfinApi.showsApi.getNextUp(
|
||||||
jellyfinApi.userId!!,
|
jellyfinApi.userId!!,
|
||||||
limit = 24,
|
limit = 24,
|
||||||
seriesId = seriesId?.toString(),
|
seriesId = seriesId,
|
||||||
|
enableResumable = false,
|
||||||
).content.items
|
).content.items
|
||||||
.orEmpty()
|
.orEmpty()
|
||||||
.mapNotNull { it.toFindroidEpisode(this@JellyfinRepositoryImpl) }
|
.mapNotNull { it.toFindroidEpisode(this@JellyfinRepositoryImpl) }
|
||||||
|
@ -303,23 +306,10 @@ class JellyfinRepositoryImpl(
|
||||||
DirectPlayProfile(type = DlnaProfileType.AUDIO),
|
DirectPlayProfile(type = DlnaProfileType.AUDIO),
|
||||||
),
|
),
|
||||||
transcodingProfiles = emptyList(),
|
transcodingProfiles = emptyList(),
|
||||||
responseProfiles = emptyList(),
|
|
||||||
subtitleProfiles = listOf(
|
subtitleProfiles = listOf(
|
||||||
SubtitleProfile("srt", SubtitleDeliveryMethod.EXTERNAL),
|
SubtitleProfile("srt", SubtitleDeliveryMethod.EXTERNAL),
|
||||||
SubtitleProfile("ass", SubtitleDeliveryMethod.EXTERNAL),
|
SubtitleProfile("ass", SubtitleDeliveryMethod.EXTERNAL),
|
||||||
),
|
),
|
||||||
xmlRootAttributes = emptyList(),
|
|
||||||
supportedMediaTypes = "",
|
|
||||||
enableAlbumArtInDidl = false,
|
|
||||||
enableMsMediaReceiverRegistrar = false,
|
|
||||||
enableSingleAlbumArtLimit = false,
|
|
||||||
enableSingleSubtitleLimit = false,
|
|
||||||
ignoreTranscodeByteRangeRequests = false,
|
|
||||||
maxAlbumArtHeight = 1_000_000_000,
|
|
||||||
maxAlbumArtWidth = 1_000_000_000,
|
|
||||||
requiresPlainFolders = false,
|
|
||||||
requiresPlainVideoItems = false,
|
|
||||||
timelineOffsetSeconds = 0,
|
|
||||||
),
|
),
|
||||||
maxStreamingBitrate = 1_000_000_000,
|
maxStreamingBitrate = 1_000_000_000,
|
||||||
),
|
),
|
||||||
|
@ -444,7 +434,7 @@ class JellyfinRepositoryImpl(
|
||||||
Timber.d("Sending capabilities")
|
Timber.d("Sending capabilities")
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
jellyfinApi.sessionApi.postCapabilities(
|
jellyfinApi.sessionApi.postCapabilities(
|
||||||
playableMediaTypes = listOf("Video"),
|
playableMediaTypes = listOf(MediaType.VIDEO),
|
||||||
supportedCommands = listOf(
|
supportedCommands = listOf(
|
||||||
GeneralCommandType.VOLUME_UP,
|
GeneralCommandType.VOLUME_UP,
|
||||||
GeneralCommandType.VOLUME_DOWN,
|
GeneralCommandType.VOLUME_DOWN,
|
||||||
|
@ -468,7 +458,7 @@ class JellyfinRepositoryImpl(
|
||||||
override suspend fun postPlaybackStart(itemId: UUID) {
|
override suspend fun postPlaybackStart(itemId: UUID) {
|
||||||
Timber.d("Sending start $itemId")
|
Timber.d("Sending start $itemId")
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
jellyfinApi.playStateApi.onPlaybackStart(jellyfinApi.userId!!, itemId)
|
jellyfinApi.playStateApi.onPlaybackStart(itemId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,7 +485,6 @@ class JellyfinRepositoryImpl(
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
jellyfinApi.playStateApi.onPlaybackStopped(
|
jellyfinApi.playStateApi.onPlaybackStopped(
|
||||||
jellyfinApi.userId!!,
|
|
||||||
itemId,
|
itemId,
|
||||||
positionTicks = positionTicks,
|
positionTicks = positionTicks,
|
||||||
)
|
)
|
||||||
|
@ -515,7 +504,6 @@ class JellyfinRepositoryImpl(
|
||||||
database.setPlaybackPositionTicks(itemId, jellyfinApi.userId!!, positionTicks)
|
database.setPlaybackPositionTicks(itemId, jellyfinApi.userId!!, positionTicks)
|
||||||
try {
|
try {
|
||||||
jellyfinApi.playStateApi.onPlaybackProgress(
|
jellyfinApi.playStateApi.onPlaybackProgress(
|
||||||
jellyfinApi.userId!!,
|
|
||||||
itemId,
|
itemId,
|
||||||
positionTicks = positionTicks,
|
positionTicks = positionTicks,
|
||||||
isPaused = isPaused,
|
isPaused = isPaused,
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
[versions]
|
[versions]
|
||||||
aboutlibraries = "11.2.0"
|
aboutlibraries = "11.2.1"
|
||||||
android-desugar-jdk-libs = "2.0.4"
|
android-desugar-jdk-libs = "2.0.4"
|
||||||
android-plugin = "8.4.1"
|
android-plugin = "8.4.2"
|
||||||
androidx-activity = "1.9.0"
|
androidx-activity = "1.9.0"
|
||||||
androidx-appcompat = "1.6.1"
|
androidx-appcompat = "1.7.0"
|
||||||
androidx-compose-bom = "2024.05.00"
|
androidx-compose-bom = "2024.06.00"
|
||||||
androidx-compose-material3 = "1.2.1"
|
androidx-compose-material3 = "1.2.1"
|
||||||
androidx-constraintlayout = "2.1.4"
|
androidx-constraintlayout = "2.1.4"
|
||||||
androidx-core = "1.13.1"
|
androidx-core = "1.13.1"
|
||||||
androidx-hilt = "1.2.0"
|
androidx-hilt = "1.2.0"
|
||||||
androidx-lifecycle = "2.8.0"
|
androidx-lifecycle = "2.8.2"
|
||||||
androidx-media3 = "1.3.1"
|
androidx-media3 = "1.3.1"
|
||||||
androidx-navigation = "2.7.7"
|
androidx-navigation = "2.7.7"
|
||||||
androidx-paging = "3.3.0"
|
androidx-paging = "3.3.0"
|
||||||
|
@ -28,11 +28,11 @@ androidx-work = "2.9.0"
|
||||||
coil = "2.6.0"
|
coil = "2.6.0"
|
||||||
hilt = "2.51.1"
|
hilt = "2.51.1"
|
||||||
compose-destinations = "1.10.2"
|
compose-destinations = "1.10.2"
|
||||||
jellyfin = "1.4.7"
|
jellyfin = "1.5.0-beta.3"
|
||||||
junit = "4.13.2"
|
junit = "4.13.2"
|
||||||
kotlin = "2.0.0"
|
kotlin = "2.0.0"
|
||||||
kotlinx-serialization = "1.6.3"
|
kotlinx-serialization = "1.7.0"
|
||||||
ksp = "2.0.0-1.0.21"
|
ksp = "2.0.0-1.0.22"
|
||||||
ktlint = "12.1.1"
|
ktlint = "12.1.1"
|
||||||
libmpv = "0.2.0"
|
libmpv = "0.2.0"
|
||||||
material = "1.12.0"
|
material = "1.12.0"
|
||||||
|
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|
2
gradlew
vendored
2
gradlew
vendored
|
@ -55,7 +55,7 @@
|
||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
|
|
@ -4,15 +4,16 @@
|
||||||
<string name="select_subtile_track">Изберете писта за субтитри</string>
|
<string name="select_subtile_track">Изберете писта за субтитри</string>
|
||||||
<string name="select_playback_speed">Изберете скорост на възпроизвеждане</string>
|
<string name="select_playback_speed">Изберете скорост на възпроизвеждане</string>
|
||||||
<string name="select_a_version">Изберете версия</string>
|
<string name="select_a_version">Изберете версия</string>
|
||||||
<string name="external">Externo</string>
|
<string name="external">Външно</string>
|
||||||
<string name="player_controls_skip_back">Voltar</string>
|
<string name="player_controls_skip_back">Пусни предишен</string>
|
||||||
<string name="player_controls_rewind">Retroceder</string>
|
<string name="player_controls_rewind">Върни назад</string>
|
||||||
<string name="player_controls_lock">Bloqueia o reprodutor</string>
|
<string name="player_controls_lock">Заключи контролите</string>
|
||||||
<string name="player_controls_progress">Barra de progresso</string>
|
<string name="player_controls_progress">Индикарор за прогрес</string>
|
||||||
<string name="player_controls_fast_forward">Avanço rápido</string>
|
<string name="player_controls_fast_forward">Пропусни напред</string>
|
||||||
<string name="player_controls_skip_forward">Passe para frente</string>
|
<string name="player_controls_skip_forward">Пусни следващ</string>
|
||||||
<string name="player_trickplay">Truques</string>
|
<string name="player_trickplay">Trickplay</string>
|
||||||
<string name="player_controls_play_pause">Pausa na reprodução</string>
|
<string name="player_controls_play_pause">Начало пауза</string>
|
||||||
<string name="player_controls_exit">Sair do reprodutor</string>
|
<string name="player_controls_exit">Излез от плейъра</string>
|
||||||
<string name="player_controls_picture_in_picture">Insira imagem em imagem</string>
|
<string name="player_controls_picture_in_picture">Влез в режим картина-в-картина</string>
|
||||||
|
<string name="none">Нищо</string>
|
||||||
</resources>
|
</resources>
|
|
@ -1,5 +1,7 @@
|
||||||
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
|
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
|
||||||
|
|
||||||
|
rootProject.name = "findroid"
|
||||||
|
|
||||||
include(":app:phone")
|
include(":app:phone")
|
||||||
include(":app:tv")
|
include(":app:tv")
|
||||||
include(":core")
|
include(":core")
|
||||||
|
|
Loading…
Reference in a new issue