mirror of
https://github.com/LiveFastEatTrashRaccoon/RaccoonForLemmy.git
synced 2025-02-09 12:08:47 +01:00
feat(explore): subscription management screen
This commit is contained in:
parent
d2500372c2
commit
6297ef3b97
@ -42,6 +42,7 @@ kotlin {
|
||||
implementation(projects.coreUtils)
|
||||
implementation(projects.corePreferences)
|
||||
implementation(projects.coreCommonui)
|
||||
implementation(projects.coreCommonui.components)
|
||||
implementation(projects.coreNotifications)
|
||||
|
||||
implementation(projects.domainIdentity)
|
||||
|
@ -1,9 +1,16 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.di
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.content.ExploreViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.main.ExploreViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.managesubscriptions.ManageSubscriptionsViewModel
|
||||
import org.koin.java.KoinJavaComponent.inject
|
||||
|
||||
actual fun getExploreViewModel(): ExploreViewModel {
|
||||
val res: ExploreViewModel by inject(ExploreViewModel::class.java)
|
||||
return res
|
||||
}
|
||||
|
||||
actual fun getManageSubscriptionsViewModel(): ManageSubscriptionsViewModel {
|
||||
val res: ManageSubscriptionsViewModel by inject(ManageSubscriptionsViewModel::class.java)
|
||||
return res
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.di
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.content.ExploreMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.content.ExploreViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.main.ExploreMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.main.ExploreViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.managesubscriptions.ManageSubscriptionsMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.managesubscriptions.ManageSubscriptionsViewModel
|
||||
import org.koin.dsl.module
|
||||
|
||||
val searchTabModule = module {
|
||||
@ -20,4 +22,12 @@ val searchTabModule = module {
|
||||
hapticFeedback = get(),
|
||||
)
|
||||
}
|
||||
factory {
|
||||
ManageSubscriptionsViewModel(
|
||||
mvi = DefaultMviModel(ManageSubscriptionsMviModel.UiState()),
|
||||
identityRepository = get(),
|
||||
communityRepository = get(),
|
||||
hapticFeedback = get(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.di
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.content.ExploreViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.main.ExploreViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.managesubscriptions.ManageSubscriptionsViewModel
|
||||
|
||||
expect fun getExploreViewModel(): ExploreViewModel
|
||||
expect fun getExploreViewModel(): ExploreViewModel
|
||||
|
||||
expect fun getManageSubscriptionsViewModel(): ManageSubscriptionsViewModel
|
@ -1,4 +1,4 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.content
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.main
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
@ -1,4 +1,4 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.content
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.main
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@ -73,6 +73,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SearchResultTy
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.di.getExploreViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.managesubscriptions.ManageSubscriptionsScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
|
||||
@ -101,6 +102,7 @@ class ExploreScreen : Screen {
|
||||
scrollBehavior = scrollBehavior,
|
||||
listingType = uiState.listingType,
|
||||
sortType = uiState.sortType,
|
||||
isLogged = uiState.isLogged,
|
||||
onSelectListingType = {
|
||||
val sheet = ListingTypeBottomSheet(
|
||||
isLogged = uiState.isLogged,
|
||||
@ -125,6 +127,10 @@ class ExploreScreen : Screen {
|
||||
}, key, NotificationCenterContractKeys.ChangeSortType)
|
||||
bottomSheetNavigator.show(sheet)
|
||||
},
|
||||
onSettings = {
|
||||
val sheet = ManageSubscriptionsScreen()
|
||||
navigator?.push(sheet)
|
||||
},
|
||||
)
|
||||
},
|
||||
) { padding ->
|
@ -1,10 +1,12 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.content
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.main
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ManageAccounts
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
@ -29,8 +31,10 @@ internal fun CommunityTopBar(
|
||||
scrollBehavior: TopAppBarScrollBehavior? = null,
|
||||
listingType: ListingType,
|
||||
sortType: SortType,
|
||||
onSelectListingType: () -> Unit,
|
||||
onSelectSortType: () -> Unit,
|
||||
isLogged: Boolean = false,
|
||||
onSelectListingType: (() -> Unit)? = null,
|
||||
onSelectSortType: (() -> Unit)? = null,
|
||||
onSettings: (() -> Unit)? = null,
|
||||
) {
|
||||
TopAppBar(
|
||||
scrollBehavior = scrollBehavior,
|
||||
@ -40,7 +44,7 @@ internal fun CommunityTopBar(
|
||||
navigationIcon = {
|
||||
Image(
|
||||
modifier = Modifier.onClick {
|
||||
onSelectListingType()
|
||||
onSelectListingType?.invoke()
|
||||
},
|
||||
imageVector = listingType.toIcon(),
|
||||
contentDescription = null,
|
||||
@ -63,7 +67,9 @@ internal fun CommunityTopBar(
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
Row {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(Spacing.xs),
|
||||
) {
|
||||
val additionalLabel = when (sortType) {
|
||||
SortType.Top.Day -> stringResource(MR.strings.home_sort_type_top_day_short)
|
||||
SortType.Top.Month -> stringResource(MR.strings.home_sort_type_top_month_short)
|
||||
@ -85,12 +91,23 @@ internal fun CommunityTopBar(
|
||||
}
|
||||
Image(
|
||||
modifier = Modifier.onClick {
|
||||
onSelectSortType()
|
||||
onSelectSortType?.invoke()
|
||||
},
|
||||
imageVector = sortType.toIcon(),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground),
|
||||
)
|
||||
|
||||
if (isLogged) {
|
||||
Image(
|
||||
modifier = Modifier.onClick {
|
||||
onSettings?.invoke()
|
||||
},
|
||||
imageVector = Icons.Default.ManageAccounts,
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
@ -1,7 +1,6 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.content
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.main
|
||||
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.HapticFeedback
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.repository.ThemeRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||
@ -9,6 +8,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationC
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.preferences.KeyStoreKeys
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.preferences.TemporaryKeyStore
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.HapticFeedback
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.ApiConfigurationRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommentModel
|
@ -0,0 +1,20 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.managesubscriptions
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
|
||||
|
||||
interface ManageSubscriptionsMviModel :
|
||||
MviModel<ManageSubscriptionsMviModel.Intent, ManageSubscriptionsMviModel.UiState, ManageSubscriptionsMviModel.Effect> {
|
||||
sealed interface Intent {
|
||||
data object HapticIndication : Intent
|
||||
|
||||
data class Unsubscribe(val index: Int) : Intent
|
||||
}
|
||||
|
||||
data class UiState(
|
||||
val loading: Boolean = false,
|
||||
val communities: List<CommunityModel> = emptyList(),
|
||||
)
|
||||
|
||||
sealed interface Effect
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.managesubscriptions
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.DismissDirection
|
||||
import androidx.compose.material.DismissValue
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Unsubscribe
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CommunityItem
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.ProgressHud
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SwipeableCard
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.di.getManageSubscriptionsViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
|
||||
class ManageSubscriptionsScreen : Screen {
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val model = rememberScreenModel { getManageSubscriptionsViewModel() }
|
||||
model.bindToLifecycle(key)
|
||||
val uiState by model.uiState.collectAsState()
|
||||
val navigator = remember { getNavigationCoordinator().getRootNavigator() }
|
||||
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(MR.strings.explore_title_manage_subscriptions),
|
||||
style = MaterialTheme.typography.titleLarge
|
||||
)
|
||||
},
|
||||
scrollBehavior = scrollBehavior,
|
||||
navigationIcon = {
|
||||
Image(
|
||||
modifier = Modifier.onClick {
|
||||
navigator?.pop()
|
||||
},
|
||||
imageVector = Icons.Default.ArrowBack,
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground),
|
||||
)
|
||||
},
|
||||
)
|
||||
},
|
||||
) { paddingValues ->
|
||||
Box(
|
||||
modifier = Modifier.padding(paddingValues),
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.nestedScroll(scrollBehavior.nestedScrollConnection)
|
||||
) {
|
||||
itemsIndexed(uiState.communities) { idx, community ->
|
||||
SwipeableCard(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
directions = setOf(DismissDirection.EndToStart),
|
||||
backgroundColor = {
|
||||
when (it) {
|
||||
DismissValue.DismissedToStart -> MaterialTheme.colorScheme.secondary
|
||||
else -> Color.Transparent
|
||||
}
|
||||
},
|
||||
onGestureBegin = {
|
||||
model.reduce(ManageSubscriptionsMviModel.Intent.HapticIndication)
|
||||
},
|
||||
onDismissToStart = {
|
||||
model.reduce(
|
||||
ManageSubscriptionsMviModel.Intent.Unsubscribe(idx),
|
||||
)
|
||||
},
|
||||
swipeContent = { _ ->
|
||||
Icon(
|
||||
modifier = Modifier.background(
|
||||
color = MaterialTheme.colorScheme.onSecondary,
|
||||
shape = CircleShape,
|
||||
).padding(Spacing.xs),
|
||||
imageVector = Icons.Default.Unsubscribe,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.secondary,
|
||||
)
|
||||
},
|
||||
content = {
|
||||
CommunityItem(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(MaterialTheme.colorScheme.background)
|
||||
.onClick {
|
||||
navigator?.push(
|
||||
CommunityDetailScreen(community),
|
||||
)
|
||||
},
|
||||
community = community,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
if (uiState.loading) {
|
||||
ProgressHud()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.managesubscriptions
|
||||
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.HapticFeedback
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommunityRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.IO
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ManageSubscriptionsViewModel(
|
||||
private val mvi: DefaultMviModel<ManageSubscriptionsMviModel.Intent, ManageSubscriptionsMviModel.UiState, ManageSubscriptionsMviModel.Effect>,
|
||||
private val identityRepository: IdentityRepository,
|
||||
private val communityRepository: CommunityRepository,
|
||||
private val hapticFeedback: HapticFeedback,
|
||||
) : ScreenModel,
|
||||
MviModel<ManageSubscriptionsMviModel.Intent, ManageSubscriptionsMviModel.UiState, ManageSubscriptionsMviModel.Effect> by mvi {
|
||||
|
||||
override fun onStarted() {
|
||||
mvi.onStarted()
|
||||
if (uiState.value.communities.isEmpty()) {
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
|
||||
override fun reduce(intent: ManageSubscriptionsMviModel.Intent) {
|
||||
when (intent) {
|
||||
ManageSubscriptionsMviModel.Intent.HapticIndication -> hapticFeedback.vibrate()
|
||||
is ManageSubscriptionsMviModel.Intent.Unsubscribe -> handleUnsubscription(
|
||||
community = uiState.value.communities[intent.index]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun refresh() {
|
||||
mvi.updateState { it.copy(loading = true) }
|
||||
mvi.scope?.launch(Dispatchers.IO) {
|
||||
val auth = identityRepository.authToken.value
|
||||
val items = communityRepository.getSubscribed(auth).sortedBy { it.name }
|
||||
mvi.updateState {
|
||||
it.copy(
|
||||
loading = false,
|
||||
communities = items,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleUnsubscription(community: CommunityModel) {
|
||||
mvi.scope?.launch {
|
||||
val auth = identityRepository.authToken.value
|
||||
communityRepository.unsubscribe(
|
||||
auth = auth, id = community.id
|
||||
)
|
||||
mvi.updateState {
|
||||
it.copy(communities = it.communities.filter { c -> c.id != community.id })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import cafe.adriel.voyager.navigator.tab.Tab
|
||||
import cafe.adriel.voyager.navigator.tab.TabOptions
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.content.ExploreScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.main.ExploreScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.di.getLanguageRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.resources.di.staticString
|
||||
|
@ -1,11 +1,15 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.feature.search.di
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.content.ExploreViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.main.ExploreViewModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.managesubscriptions.ManageSubscriptionsViewModel
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
actual fun getExploreViewModel() = SearchScreenModelHelper.model
|
||||
|
||||
actual fun getManageSubscriptionsViewModel() = SearchScreenModelHelper.manageSuscriptionsViewModel
|
||||
|
||||
object SearchScreenModelHelper : KoinComponent {
|
||||
val model: ExploreViewModel by inject()
|
||||
val manageSuscriptionsViewModel: ManageSubscriptionsViewModel by inject()
|
||||
}
|
||||
|
@ -63,6 +63,7 @@
|
||||
<string name="explore_result_type_communities">Communities</string>
|
||||
<string name="explore_result_type_users">Users</string>
|
||||
<string name="explore_search_placeholder">Search text</string>
|
||||
<string name="explore_title_manage_subscriptions">Manage subscriptions</string>
|
||||
|
||||
<string name="profile_not_logged_message">You are currently not logged in.\nPlease add an
|
||||
account to continue.
|
||||
|
@ -59,6 +59,7 @@
|
||||
<string name="explore_result_type_communities">Comunidades</string>
|
||||
<string name="explore_result_type_users">Usuarios</string>
|
||||
<string name="explore_search_placeholder">Texto de búsqueda</string>
|
||||
<string name="explore_title_manage_subscriptions">Gestionar subscripciones</string>
|
||||
|
||||
<string name="profile_not_logged_message">Acceso no efectuado.\nAñadir una cuenta para
|
||||
continuar.
|
||||
|
@ -59,6 +59,7 @@
|
||||
<string name="explore_result_type_communities">Comunità</string>
|
||||
<string name="explore_result_type_users">Utenti</string>
|
||||
<string name="explore_search_placeholder">Testo di ricerca</string>
|
||||
<string name="explore_title_manage_subscriptions">Gestione iscruzione</string>
|
||||
|
||||
<string name="profile_not_logged_message">Login non effettuato.\nAggiungi un account per
|
||||
continuare.
|
||||
|
Loading…
x
Reference in New Issue
Block a user