feat: explore other instance (#620)

This commit is contained in:
Diego Beraldin 2024-03-21 23:39:06 +01:00 committed by GitHub
parent 58f3751dfa
commit 3d8891f8a0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 278 additions and 191 deletions

View File

@ -74,7 +74,7 @@ class DefaultDetailOpenerTest {
val community = CommunityModel(name = communityName, id = 1, host = otherInstance) val community = CommunityModel(name = communityName, id = 1, host = otherInstance)
every { identityRepository.authToken } returns MutableStateFlow(token) every { identityRepository.authToken } returns MutableStateFlow(token)
coEvery { coEvery {
communityRepository.getAll( communityRepository.search(
query = any(), query = any(),
auth = any(), auth = any(),
page = any(), page = any(),
@ -94,7 +94,7 @@ class DefaultDetailOpenerTest {
assertIs<CommunityDetailScreen>(it) assertIs<CommunityDetailScreen>(it)
}, },
) )
communityRepository.getAll( communityRepository.search(
query = communityName, query = communityName,
auth = token, auth = token,
page = any(), page = any(),

View File

@ -40,11 +40,12 @@ class DefaultDetailOpener(
val (actualCommunity, actualInstance) = withContext(Dispatchers.IO) { val (actualCommunity, actualInstance) = withContext(Dispatchers.IO) {
val defaultResult = community to otherInstance val defaultResult = community to otherInstance
if (otherInstance.isEmpty()) { if (otherInstance.isEmpty()) {
return@withContext defaultResult val found = searchCommunity(name = community.name, host = otherInstance)
} if (found != null) {
val found = searchCommunity(name = community.name, host = otherInstance) found to ""
if (found != null) { } else {
found to "" defaultResult
}
} else { } else {
defaultResult defaultResult
} }
@ -165,7 +166,7 @@ class DefaultDetailOpener(
val auth = identityRepository.authToken.value val auth = identityRepository.authToken.value
tailrec suspend fun searchRec(page: Int = 0): CommunityModel? { tailrec suspend fun searchRec(page: Int = 0): CommunityModel? {
val results = communityRepository.getAll( val results = communityRepository.search(
auth = auth, auth = auth,
query = name, query = name,
resultType = SearchResultType.Communities, resultType = SearchResultType.Communities,

View File

@ -32,4 +32,5 @@ sealed class OptionId(val value: Int) {
data object SetCustomSort : OptionId(24) data object SetCustomSort : OptionId(24)
data object Search : OptionId(25) data object Search : OptionId(25)
data object Copy : OptionId(26) data object Copy : OptionId(26)
data object ExploreInstance : OptionId(27)
} }

View File

@ -13,12 +13,13 @@ interface CommunityRepository {
const val DEFAULT_PAGE_SIZE = 20 const val DEFAULT_PAGE_SIZE = 20
} }
suspend fun getAll( suspend fun search(
query: String = "", query: String = "",
auth: String? = null, auth: String? = null,
page: Int, page: Int,
limit: Int = DEFAULT_PAGE_SIZE, limit: Int = DEFAULT_PAGE_SIZE,
communityId: Int? = null, communityId: Int? = null,
instance: String? = null,
listingType: ListingType = ListingType.All, listingType: ListingType = ListingType.All,
sortType: SortType = SortType.Active, sortType: SortType = SortType.Active,
resultType: SearchResultType = SearchResultType.All, resultType: SearchResultType = SearchResultType.All,

View File

@ -23,28 +23,44 @@ internal class DefaultCommunityRepository(
private val customServices: ServiceProvider, private val customServices: ServiceProvider,
) : CommunityRepository { ) : CommunityRepository {
override suspend fun getAll( override suspend fun search(
query: String, query: String,
auth: String?, auth: String?,
page: Int, page: Int,
limit: Int, limit: Int,
communityId: Int?, communityId: Int?,
instance: String?,
listingType: ListingType, listingType: ListingType,
sortType: SortType, sortType: SortType,
resultType: SearchResultType, resultType: SearchResultType,
): List<SearchResult> = withContext(Dispatchers.IO) { ): List<SearchResult> = withContext(Dispatchers.IO) {
runCatching { runCatching {
val searchResponse = services.search.search( val searchResponse = if (instance.isNullOrEmpty()) {
authHeader = auth.toAuthHeader(), services.search.search(
q = query, authHeader = auth.toAuthHeader(),
auth = auth, q = query,
page = page, auth = auth,
limit = limit, page = page,
communityId = communityId, limit = limit,
type = resultType.toDto(), communityId = communityId,
listingType = listingType.toDto(), type = resultType.toDto(),
sort = sortType.toDto(), listingType = listingType.toDto(),
).body() sort = sortType.toDto(),
).body()
} else {
customServices.changeInstance(instance)
customServices.search.search(
authHeader = auth.toAuthHeader(),
q = query,
auth = auth,
page = page,
limit = limit,
communityId = communityId,
type = resultType.toDto(),
listingType = listingType.toDto(),
sort = sortType.toDto(),
).body()
}
buildList<SearchResult> { buildList<SearchResult> {
val posts = searchResponse?.posts?.map { it.toModel() }.orEmpty() val posts = searchResponse?.posts?.map { it.toModel() }.orEmpty()
this += posts.map { SearchResult.Post(it) } this += posts.map { SearchResult.Post(it) }

View File

@ -55,18 +55,19 @@ kotlin {
implementation(projects.domain.lemmy.data) implementation(projects.domain.lemmy.data)
implementation(projects.domain.lemmy.repository) implementation(projects.domain.lemmy.repository)
implementation(projects.unit.zoomableimage)
implementation(projects.unit.web)
implementation(projects.unit.createreport)
implementation(projects.unit.createcomment)
implementation(projects.unit.createpost)
implementation(projects.unit.remove)
implementation(projects.unit.ban) implementation(projects.unit.ban)
implementation(projects.unit.communityinfo) implementation(projects.unit.communityinfo)
implementation(projects.unit.createcomment)
implementation(projects.unit.createpost)
implementation(projects.unit.createreport)
implementation(projects.unit.explore)
implementation(projects.unit.instanceinfo) implementation(projects.unit.instanceinfo)
implementation(projects.unit.reportlist)
implementation(projects.unit.modlog) implementation(projects.unit.modlog)
implementation(projects.unit.rawcontent) implementation(projects.unit.rawcontent)
implementation(projects.unit.remove)
implementation(projects.unit.reportlist)
implementation(projects.unit.web)
implementation(projects.unit.zoomableimage)
} }
} }
val commonTest by getting { val commonTest by getting {

View File

@ -4,7 +4,6 @@ import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.animateScrollBy import androidx.compose.foundation.gestures.animateScrollBy
@ -127,6 +126,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.toInt
import com.github.diegoberaldin.raccoonforlemmy.unit.ban.BanUserScreen import com.github.diegoberaldin.raccoonforlemmy.unit.ban.BanUserScreen
import com.github.diegoberaldin.raccoonforlemmy.unit.communityinfo.CommunityInfoScreen import com.github.diegoberaldin.raccoonforlemmy.unit.communityinfo.CommunityInfoScreen
import com.github.diegoberaldin.raccoonforlemmy.unit.createreport.CreateReportScreen import com.github.diegoberaldin.raccoonforlemmy.unit.createreport.CreateReportScreen
import com.github.diegoberaldin.raccoonforlemmy.unit.explore.ExploreScreen
import com.github.diegoberaldin.raccoonforlemmy.unit.instanceinfo.InstanceInfoScreen import com.github.diegoberaldin.raccoonforlemmy.unit.instanceinfo.InstanceInfoScreen
import com.github.diegoberaldin.raccoonforlemmy.unit.modlog.ModlogScreen import com.github.diegoberaldin.raccoonforlemmy.unit.modlog.ModlogScreen
import com.github.diegoberaldin.raccoonforlemmy.unit.rawcontent.RawContentDialog import com.github.diegoberaldin.raccoonforlemmy.unit.rawcontent.RawContentDialog
@ -147,7 +147,7 @@ class CommunityDetailScreen(
override val key: ScreenKey override val key: ScreenKey
get() = super.key + communityId.toString() get() = super.key + communityId.toString()
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class, ExperimentalFoundationApi::class) @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
@Composable @Composable
override fun Content() { override fun Content() {
val model = getScreenModel<CommunityDetailMviModel>( val model = getScreenModel<CommunityDetailMviModel>(
@ -338,6 +338,17 @@ class CommunityDetailScreen(
OptionId.InfoInstance, OptionId.InfoInstance,
LocalXmlStrings.current.communityDetailInstanceInfo LocalXmlStrings.current.communityDetailInstanceInfo
) )
this += Option(
OptionId.ExploreInstance,
buildString {
append(LocalXmlStrings.current.navigationSearch)
append(" ")
append(uiState.community.host)
append(" (")
append(LocalXmlStrings.current.beta)
append(")")
},
)
this += Option( this += Option(
OptionId.Share, LocalXmlStrings.current.postActionShare OptionId.Share, LocalXmlStrings.current.postActionShare
) )
@ -379,7 +390,7 @@ class CommunityDetailScreen(
Image( Image(
modifier = Modifier.onGloballyPositioned { modifier = Modifier.onGloballyPositioned {
optionsOffset = it.positionInParent() optionsOffset = it.positionInParent()
}.padding(start = Spacing.s).onClick( }.onClick(
onClick = rememberCallback { onClick = rememberCallback {
optionsExpanded = true optionsExpanded = true
}, },
@ -481,6 +492,11 @@ class CommunityDetailScreen(
model.reduce(CommunityDetailMviModel.Intent.ChangeSearching(!uiState.searching)) model.reduce(CommunityDetailMviModel.Intent.ChangeSearching(!uiState.searching))
} }
OptionId.ExploreInstance -> {
val screen = ExploreScreen(otherInstance = uiState.community.host)
navigationCoordinator.pushScreen(screen)
}
else -> Unit else -> Unit
} }
}, },
@ -754,12 +770,12 @@ class CommunityDetailScreen(
onGestureBegin = rememberCallback(model) { onGestureBegin = rememberCallback(model) {
model.reduce(CommunityDetailMviModel.Intent.HapticIndication) model.reduce(CommunityDetailMviModel.Intent.HapticIndication)
}, },
swipeToStartActions = if (uiState.isLogged) { swipeToStartActions = if (uiState.isLogged && !isOnOtherInstance) {
uiState.actionsOnSwipeToStartPosts.toSwipeActions() uiState.actionsOnSwipeToStartPosts.toSwipeActions()
} else { } else {
emptyList() emptyList()
}, },
swipeToEndActions = if (uiState.isLogged) { swipeToEndActions = if (uiState.isLogged && !isOnOtherInstance) {
uiState.actionsOnSwipeToEndPosts.toSwipeActions() uiState.actionsOnSwipeToEndPosts.toSwipeActions()
} else { } else {
emptyList() emptyList()

View File

@ -352,7 +352,7 @@ class CommunityDetailViewModel(
val includeNsfw = settingsRepository.currentSettings.value.includeNsfw val includeNsfw = settingsRepository.currentSettings.value.includeNsfw
val (itemList, nextPage) = if (currentState.searching) { val (itemList, nextPage) = if (currentState.searching) {
communityRepository.getAll( communityRepository.search(
auth = auth, auth = auth,
communityId = community.id, communityId = community.id,
page = currentPage, page = currentPage,

View File

@ -91,6 +91,7 @@ import com.github.diegoberaldin.raccoonforlemmy.unit.zoomableimage.ZoomableImage
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.core.parameter.parametersOf
class ExploreScreen( class ExploreScreen(
private val otherInstance: String = "", private val otherInstance: String = "",
@ -99,7 +100,7 @@ class ExploreScreen(
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class) @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
@Composable @Composable
override fun Content() { override fun Content() {
val model = getScreenModel<ExploreMviModel>() val model = getScreenModel<ExploreMviModel>(parameters = { parametersOf(otherInstance) })
val uiState by model.uiState.collectAsState() val uiState by model.uiState.collectAsState()
val navigationCoordinator = remember { getNavigationCoordinator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val topAppBarState = rememberTopAppBarState() val topAppBarState = rememberTopAppBarState()
@ -133,6 +134,13 @@ class ExploreScreen(
val otherInstanceName = remember { otherInstance } val otherInstanceName = remember { otherInstance }
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }
val errorMessage = LocalXmlStrings.current.messageGenericError val errorMessage = LocalXmlStrings.current.messageGenericError
val notificationEventKey = buildString {
append("explore")
if (isOnOtherInstance) {
append("-")
append(otherInstanceName)
}
}
LaunchedEffect(navigationCoordinator) { LaunchedEffect(navigationCoordinator) {
navigationCoordinator.onDoubleTabSelection.onEach { section -> navigationCoordinator.onDoubleTabSelection.onEach { section ->
@ -172,11 +180,12 @@ class ExploreScreen(
listingType = uiState.listingType, listingType = uiState.listingType,
sortType = uiState.sortType, sortType = uiState.sortType,
resultType = uiState.resultType, resultType = uiState.resultType,
otherInstance = otherInstanceName,
onSelectListingType = rememberCallback { onSelectListingType = rememberCallback {
focusManager.clearFocus() focusManager.clearFocus()
val sheet = ListingTypeBottomSheet( val sheet = ListingTypeBottomSheet(
isLogged = uiState.isLogged, isLogged = uiState.isLogged,
screenKey = "explore", screenKey = notificationEventKey,
) )
navigationCoordinator.showBottomSheet(sheet) navigationCoordinator.showBottomSheet(sheet)
}, },
@ -185,20 +194,12 @@ class ExploreScreen(
val sheet = SortBottomSheet( val sheet = SortBottomSheet(
values = uiState.availableSortTypes.map { it.toInt() }, values = uiState.availableSortTypes.map { it.toInt() },
expandTop = true, expandTop = true,
screenKey = "explore", screenKey = notificationEventKey,
) )
navigationCoordinator.showBottomSheet(sheet) navigationCoordinator.showBottomSheet(sheet)
}, },
onSelectResultTypeType = rememberCallback { onSelectResultTypeType = rememberCallback {
val sheet = ResultTypeBottomSheet( val sheet = ResultTypeBottomSheet(screenKey = notificationEventKey)
screenKey = buildString {
append("explore")
if (isOnOtherInstance) {
append("-")
append(otherInstanceName)
}
}
)
navigationCoordinator.showBottomSheet(sheet) navigationCoordinator.showBottomSheet(sheet)
}, },
onHamburgerTapped = rememberCallback { onHamburgerTapped = rememberCallback {
@ -206,6 +207,9 @@ class ExploreScreen(
drawerCoordinator.toggleDrawer() drawerCoordinator.toggleDrawer()
} }
}, },
onBack = rememberCallback {
navigationCoordinator.popScreen()
}
) )
}, },
snackbarHost = { snackbarHost = {
@ -296,7 +300,10 @@ class ExploreScreen(
CommunityItem( CommunityItem(
modifier = Modifier.fillMaxWidth().onClick( modifier = Modifier.fillMaxWidth().onClick(
onClick = rememberCallback { onClick = rememberCallback {
detailOpener.openCommunityDetail(result.model) detailOpener.openCommunityDetail(
community = result.model,
otherInstance = otherInstanceName,
)
}, },
), ),
community = result.model, community = result.model,
@ -393,7 +400,7 @@ class ExploreScreen(
SwipeActionCard( SwipeActionCard(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
enabled = uiState.swipeActionsEnabled, enabled = uiState.swipeActionsEnabled && !isOnOtherInstance,
onGestureBegin = rememberCallback(model) { onGestureBegin = rememberCallback(model) {
model.reduce(ExploreMviModel.Intent.HapticIndication) model.reduce(ExploreMviModel.Intent.HapticIndication)
}, },
@ -420,9 +427,12 @@ class ExploreScreen(
blurNsfw = uiState.blurNsfw, blurNsfw = uiState.blurNsfw,
actionButtonsActive = uiState.isLogged, actionButtonsActive = uiState.isLogged,
onClick = rememberCallback { onClick = rememberCallback {
detailOpener.openPostDetail(result.model) detailOpener.openPostDetail(
post = result.model,
otherInstance = otherInstanceName,
)
}, },
onDoubleClick = if (!uiState.doubleTapActionEnabled) { onDoubleClick = if (!uiState.doubleTapActionEnabled || isOnOtherInstance) {
null null
} else { } else {
rememberCallback(model) { rememberCallback(model) {
@ -438,37 +448,38 @@ class ExploreScreen(
}, },
onOpenCommunity = rememberCallbackArgs { community, instance -> onOpenCommunity = rememberCallbackArgs { community, instance ->
detailOpener.openCommunityDetail( detailOpener.openCommunityDetail(
community, community = community,
instance, otherInstance = instance.takeIf {
it.isNotEmpty()
} ?: otherInstanceName,
) )
}, },
onOpenCreator = rememberCallbackArgs { user, instance -> onOpenCreator = rememberCallbackArgs { user, instance ->
detailOpener.openUserDetail(user, instance) detailOpener.openUserDetail(
user = user,
otherInstance = instance.takeIf {
it.isNotEmpty()
} ?: otherInstanceName,
)
}, },
onUpVote = rememberCallback(model) { onUpVote = rememberCallback(model) {
if (uiState.isLogged) { if (uiState.isLogged) {
model.reduce( model.reduce(
ExploreMviModel.Intent.UpVotePost( ExploreMviModel.Intent.UpVotePost(result.model.id),
id = result.model.id,
),
) )
} }
}, },
onDownVote = rememberCallback(model) { onDownVote = rememberCallback(model) {
if (uiState.isLogged) { if (uiState.isLogged) {
model.reduce( model.reduce(
ExploreMviModel.Intent.DownVotePost( ExploreMviModel.Intent.DownVotePost(result.model.id),
id = result.model.id,
),
) )
} }
}, },
onSave = rememberCallback(model) { onSave = rememberCallback(model) {
if (uiState.isLogged) { if (uiState.isLogged) {
model.reduce( model.reduce(
ExploreMviModel.Intent.SavePost( ExploreMviModel.Intent.SavePost(result.model.id),
id = result.model.id,
),
) )
} }
}, },
@ -481,7 +492,12 @@ class ExploreScreen(
) )
}, },
onOpenPost = rememberCallbackArgs { post, instance -> onOpenPost = rememberCallbackArgs { post, instance ->
detailOpener.openPostDetail(post, instance) detailOpener.openPostDetail(
post = post,
otherInstance = instance.takeIf {
it.isNotEmpty()
} ?: otherInstanceName,
)
}, },
onOpenWeb = rememberCallbackArgs { url -> onOpenWeb = rememberCallbackArgs { url ->
@ -516,9 +532,7 @@ class ExploreScreen(
?: defaultUpvoteColor, ?: defaultUpvoteColor,
onTriggered = rememberCallback { onTriggered = rememberCallback {
model.reduce( model.reduce(
ExploreMviModel.Intent.UpVoteComment( ExploreMviModel.Intent.UpVoteComment(result.model.id)
result.model.id
)
) )
}, },
) )
@ -535,9 +549,7 @@ class ExploreScreen(
?: defaultDownVoteColor, ?: defaultDownVoteColor,
onTriggered = rememberCallback { onTriggered = rememberCallback {
model.reduce( model.reduce(
ExploreMviModel.Intent.DownVoteComment( ExploreMviModel.Intent.DownVoteComment(result.model.id),
result.model.id
),
) )
}, },
) )
@ -556,6 +568,7 @@ class ExploreScreen(
detailOpener.openPostDetail( detailOpener.openPostDetail(
post = PostModel(id = result.model.postId), post = PostModel(id = result.model.postId),
highlightCommentId = result.model.id, highlightCommentId = result.model.id,
otherInstance = otherInstanceName,
) )
}, },
) )
@ -572,9 +585,7 @@ class ExploreScreen(
?: defaultSaveColor, ?: defaultSaveColor,
onTriggered = rememberCallback { onTriggered = rememberCallback {
model.reduce( model.reduce(
ExploreMviModel.Intent.SaveComment( ExploreMviModel.Intent.SaveComment(result.model.id),
id = result.model.id,
),
) )
}, },
) )
@ -615,6 +626,7 @@ class ExploreScreen(
detailOpener.openPostDetail( detailOpener.openPostDetail(
post = PostModel(id = result.model.postId), post = PostModel(id = result.model.postId),
highlightCommentId = result.model.id, highlightCommentId = result.model.id,
otherInstance = otherInstanceName,
) )
}, },
onDoubleClick = if (!uiState.doubleTapActionEnabled) { onDoubleClick = if (!uiState.doubleTapActionEnabled) {
@ -660,23 +672,30 @@ class ExploreScreen(
}, },
onOpenCommunity = rememberCallbackArgs { community, instance -> onOpenCommunity = rememberCallbackArgs { community, instance ->
detailOpener.openCommunityDetail( detailOpener.openCommunityDetail(
community, community = community,
instance, otherInstance = instance.takeIf {
it.isNotEmpty()
} ?: otherInstanceName,
) )
}, },
onOpenCreator = rememberCallbackArgs { user, instance -> onOpenCreator = rememberCallbackArgs { user, instance ->
detailOpener.openUserDetail(user, instance) detailOpener.openUserDetail(
user = user,
otherInstance = instance.takeIf {
it.isNotEmpty()
} ?: otherInstanceName,
)
}, },
onOpenPost = rememberCallbackArgs { post, instance -> onOpenPost = rememberCallbackArgs { post, instance ->
detailOpener.openPostDetail( detailOpener.openPostDetail(
post = post, post = post,
otherInstance = instance, otherInstance = instance.takeIf {
it.isNotEmpty()
} ?: otherInstanceName,
) )
}, },
onOpenWeb = rememberCallbackArgs { url -> onOpenWeb = rememberCallbackArgs { url ->
navigationCoordinator.pushScreen( navigationCoordinator.pushScreen(WebViewScreen(url))
WebViewScreen(url)
)
}, },
) )
}, },
@ -691,7 +710,10 @@ class ExploreScreen(
UserItem( UserItem(
modifier = Modifier.fillMaxWidth().onClick( modifier = Modifier.fillMaxWidth().onClick(
onClick = rememberCallback { onClick = rememberCallback {
detailOpener.openUserDetail(result.model, "") detailOpener.openUserDetail(
user = result.model,
otherInstance = otherInstanceName,
)
}, },
), ),
user = result.model, user = result.model,

View File

@ -34,6 +34,7 @@ import kotlinx.coroutines.launch
@OptIn(FlowPreview::class) @OptIn(FlowPreview::class)
class ExploreViewModel( class ExploreViewModel(
private val otherInstance: String,
private val apiConfigRepository: ApiConfigurationRepository, private val apiConfigRepository: ApiConfigurationRepository,
private val identityRepository: IdentityRepository, private val identityRepository: IdentityRepository,
private val communityRepository: CommunityRepository, private val communityRepository: CommunityRepository,
@ -52,6 +53,15 @@ class ExploreViewModel(
private var currentPage: Int = 1 private var currentPage: Int = 1
private var searchEventChannel = Channel<Unit>() private var searchEventChannel = Channel<Unit>()
private val isOnOtherInstance: Boolean get() = otherInstance.isNotEmpty()
private val notificationEventKey: String
get() = buildString {
append("explore")
if (isOnOtherInstance) {
append("-")
append(otherInstance)
}
}
init { init {
updateState { updateState {
@ -99,13 +109,13 @@ class ExploreViewModel(
}.launchIn(this) }.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.ChangeFeedType::class) notificationCenter.subscribe(NotificationCenterEvent.ChangeFeedType::class)
.onEach { evt -> .onEach { evt ->
if (evt.screenKey == "explore") { if (evt.screenKey == notificationEventKey) {
changeListingType(evt.value) changeListingType(evt.value)
} }
}.launchIn(this) }.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.ChangeSortType::class) notificationCenter.subscribe(NotificationCenterEvent.ChangeSortType::class)
.onEach { evt -> .onEach { evt ->
if (evt.screenKey == "explore") { if (evt.screenKey == notificationEventKey) {
changeSortType(evt.value) changeSortType(evt.value)
} }
}.launchIn(this) }.launchIn(this)
@ -113,7 +123,7 @@ class ExploreViewModel(
onFirstLoad() onFirstLoad()
}.launchIn(this) }.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.ChangeSearchResultType::class).onEach { evt -> notificationCenter.subscribe(NotificationCenterEvent.ChangeSearchResultType::class).onEach { evt ->
if (evt.screenKey == "explore") { if (evt.screenKey == notificationEventKey) {
changeResultType(evt.value) changeResultType(evt.value)
} }
}.launchIn(this) }.launchIn(this)
@ -129,7 +139,7 @@ class ExploreViewModel(
private fun onFirstLoad() { private fun onFirstLoad() {
val settings = settingsRepository.currentSettings.value val settings = settingsRepository.currentSettings.value
val listingType = settings.defaultExploreType.toListingType() val listingType = if (isOnOtherInstance) ListingType.Local else settings.defaultExploreType.toListingType()
val sortType = settings.defaultPostSortType.toSortType() val sortType = settings.defaultPostSortType.toSortType()
updateState { updateState {
it.copy( it.copy(
@ -297,13 +307,14 @@ class ExploreViewModel(
val sortType = currentState.sortType val sortType = currentState.sortType
val resultType = currentState.resultType val resultType = currentState.resultType
val settings = settingsRepository.currentSettings.value val settings = settingsRepository.currentSettings.value
val itemList = communityRepository.getAll( val itemList = communityRepository.search(
query = searchText, query = searchText,
auth = auth, auth = auth,
resultType = resultType, resultType = resultType,
page = currentPage, page = currentPage,
listingType = listingType, listingType = listingType,
sortType = sortType, sortType = sortType,
instance = otherInstance,
) )
val additionalResolvedCommunity = val additionalResolvedCommunity =
if (resultType == SearchResultType.All || resultType == SearchResultType.Communities && currentPage == 1) { if (resultType == SearchResultType.All || resultType == SearchResultType.Communities && currentPage == 1) {

View File

@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Menu import androidx.compose.material.icons.filled.Menu
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@ -34,15 +35,30 @@ internal fun ExploreTopBar(
listingType: ListingType, listingType: ListingType,
sortType: SortType, sortType: SortType,
resultType: SearchResultType, resultType: SearchResultType,
otherInstance: String = "",
onSelectListingType: (() -> Unit)? = null, onSelectListingType: (() -> Unit)? = null,
onSelectSortType: (() -> Unit)? = null, onSelectSortType: (() -> Unit)? = null,
onSelectResultTypeType: (() -> Unit)? = null, onSelectResultTypeType: (() -> Unit)? = null,
onHamburgerTapped: (() -> Unit)? = null, onHamburgerTapped: (() -> Unit)? = null,
onBack: (() -> Unit)? = null,
) { ) {
TopAppBar( TopAppBar(
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
navigationIcon = { navigationIcon = {
when { when {
otherInstance.isNotEmpty() -> {
Image(
modifier = Modifier.onClick(
onClick = rememberCallback {
onBack?.invoke()
},
),
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = null,
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground),
)
}
onHamburgerTapped != null -> { onHamburgerTapped != null -> {
Image( Image(
modifier = Modifier.onClick( modifier = Modifier.onClick(
@ -77,18 +93,29 @@ internal fun ExploreTopBar(
.padding(horizontal = Spacing.s) .padding(horizontal = Spacing.s)
.onClick( .onClick(
onClick = rememberCallback { onClick = rememberCallback {
onSelectListingType?.invoke() if (otherInstance.isEmpty()) {
onSelectListingType?.invoke()
}
}, },
), ),
) { ) {
Text( Text(
text = LocalXmlStrings.current.navigationSearch, text = buildString {
append(LocalXmlStrings.current.navigationSearch)
if (otherInstance.isNotEmpty()) {
append(" (")
append(otherInstance)
append(")")
}
},
style = MaterialTheme.typography.titleMedium, style = MaterialTheme.typography.titleMedium,
) )
Text( if (otherInstance.isEmpty()) {
text = listingType.toReadableName(), Text(
style = MaterialTheme.typography.titleSmall, text = listingType.toReadableName(),
) style = MaterialTheme.typography.titleSmall,
)
}
} }
}, },
actions = { actions = {

View File

@ -5,8 +5,9 @@ import com.github.diegoberaldin.raccoonforlemmy.unit.explore.ExploreViewModel
import org.koin.dsl.module import org.koin.dsl.module
val exploreModule = module { val exploreModule = module {
factory<ExploreMviModel> { factory<ExploreMviModel> { params ->
ExploreViewModel( ExploreViewModel(
otherInstance = params[0],
apiConfigRepository = get(), apiConfigRepository = get(),
identityRepository = get(), identityRepository = get(),
communityRepository = get(), communityRepository = get(),

View File

@ -293,7 +293,7 @@ class PostDetailScreen(
Image( Image(
modifier = Modifier.onGloballyPositioned { modifier = Modifier.onGloballyPositioned {
optionsOffset = it.positionInParent() optionsOffset = it.positionInParent()
}.padding(start = Spacing.s).onClick( }.onClick(
onClick = rememberCallback { onClick = rememberCallback {
optionsExpanded = true optionsExpanded = true
}, },

View File

@ -55,16 +55,17 @@ kotlin {
implementation(projects.domain.lemmy.data) implementation(projects.domain.lemmy.data)
implementation(projects.domain.lemmy.repository) implementation(projects.domain.lemmy.repository)
implementation(projects.unit.zoomableimage)
implementation(projects.unit.web)
implementation(projects.unit.createreport)
implementation(projects.unit.createcomment)
implementation(projects.unit.createpost)
implementation(projects.unit.remove)
implementation(projects.unit.ban) implementation(projects.unit.ban)
implementation(projects.unit.chat) implementation(projects.unit.chat)
implementation(projects.unit.userinfo) implementation(projects.unit.createcomment)
implementation(projects.unit.createpost)
implementation(projects.unit.createreport)
implementation(projects.unit.explore)
implementation(projects.unit.rawcontent) implementation(projects.unit.rawcontent)
implementation(projects.unit.remove)
implementation(projects.unit.userinfo)
implementation(projects.unit.web)
implementation(projects.unit.zoomableimage)
} }
} }
val commonTest by getting { val commonTest by getting {

View File

@ -113,6 +113,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.toIcon
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.toInt import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.toInt
import com.github.diegoberaldin.raccoonforlemmy.unit.chat.InboxChatScreen import com.github.diegoberaldin.raccoonforlemmy.unit.chat.InboxChatScreen
import com.github.diegoberaldin.raccoonforlemmy.unit.createreport.CreateReportScreen import com.github.diegoberaldin.raccoonforlemmy.unit.createreport.CreateReportScreen
import com.github.diegoberaldin.raccoonforlemmy.unit.explore.ExploreScreen
import com.github.diegoberaldin.raccoonforlemmy.unit.rawcontent.RawContentDialog import com.github.diegoberaldin.raccoonforlemmy.unit.rawcontent.RawContentDialog
import com.github.diegoberaldin.raccoonforlemmy.unit.userinfo.UserInfoScreen import com.github.diegoberaldin.raccoonforlemmy.unit.userinfo.UserInfoScreen
import com.github.diegoberaldin.raccoonforlemmy.unit.web.WebViewScreen import com.github.diegoberaldin.raccoonforlemmy.unit.web.WebViewScreen
@ -246,10 +247,23 @@ class UserDetailScreen(
Box { Box {
val options = buildList { val options = buildList {
this += Option( this += Option(
OptionId.Info, LocalXmlStrings.current.userDetailInfo OptionId.Info,
LocalXmlStrings.current.userDetailInfo
) )
this += Option( this += Option(
OptionId.Share, LocalXmlStrings.current.postActionShare OptionId.ExploreInstance,
buildString {
append(LocalXmlStrings.current.navigationSearch)
append(" ")
append(uiState.user.host)
append(" (")
append(LocalXmlStrings.current.beta)
append(")")
},
)
this += Option(
OptionId.Share,
LocalXmlStrings.current.postActionShare
) )
if (uiState.isLogged) { if (uiState.isLogged) {
this += Option( this += Option(
@ -267,7 +281,7 @@ class UserDetailScreen(
Image( Image(
modifier = Modifier.onGloballyPositioned { modifier = Modifier.onGloballyPositioned {
optionsOffset = it.positionInParent() optionsOffset = it.positionInParent()
}.padding(start = Spacing.s).onClick( }.onClick(
onClick = rememberCallback { onClick = rememberCallback {
optionsExpanded = true optionsExpanded = true
}, },
@ -294,18 +308,16 @@ class UserDetailScreen(
onClick = rememberCallback { onClick = rememberCallback {
optionsExpanded = false optionsExpanded = false
when (option.id) { when (option.id) {
OptionId.BlockInstance -> model.reduce( OptionId.BlockInstance -> {
UserDetailMviModel.Intent.BlockInstance model.reduce(UserDetailMviModel.Intent.BlockInstance)
) }
OptionId.Block -> model.reduce( OptionId.Block -> {
UserDetailMviModel.Intent.Block model.reduce(UserDetailMviModel.Intent.Block)
) }
OptionId.Info -> { OptionId.Info -> {
navigationCoordinator.showBottomSheet( navigationCoordinator.showBottomSheet(UserInfoScreen(uiState.user.id))
UserInfoScreen(uiState.user.id),
)
} }
OptionId.Share -> { OptionId.Share -> {
@ -317,19 +329,19 @@ class UserDetailScreen(
} }
if (urls.size == 1) { if (urls.size == 1) {
model.reduce( model.reduce(
UserDetailMviModel.Intent.Share( UserDetailMviModel.Intent.Share(urls.first())
urls.first()
)
) )
} else { } else {
val screen = val screen = ShareBottomSheet(urls = urls)
ShareBottomSheet(urls = urls) navigationCoordinator.showBottomSheet(screen)
navigationCoordinator.showBottomSheet(
screen
)
} }
} }
OptionId.ExploreInstance -> {
val screen = ExploreScreen(otherInstance = uiState.user.host)
navigationCoordinator.pushScreen(screen)
}
else -> Unit else -> Unit
} }
}, },
@ -495,9 +507,7 @@ class UserDetailScreen(
?: defaultUpvoteColor, ?: defaultUpvoteColor,
onTriggered = rememberCallback { onTriggered = rememberCallback {
model.reduce( model.reduce(
UserDetailMviModel.Intent.UpVotePost( UserDetailMviModel.Intent.UpVotePost(post.id),
post.id,
),
) )
}, },
) )
@ -514,9 +524,7 @@ class UserDetailScreen(
?: defaultDownVoteColor, ?: defaultDownVoteColor,
onTriggered = rememberCallback { onTriggered = rememberCallback {
model.reduce( model.reduce(
UserDetailMviModel.Intent.DownVotePost( UserDetailMviModel.Intent.DownVotePost(post.id)
post.id,
)
) )
}, },
) )
@ -548,9 +556,7 @@ class UserDetailScreen(
?: defaultSaveColor, ?: defaultSaveColor,
onTriggered = rememberCallback { onTriggered = rememberCallback {
model.reduce( model.reduce(
UserDetailMviModel.Intent.SavePost( UserDetailMviModel.Intent.SavePost(id = post.id),
id = post.id,
),
) )
}, },
) )
@ -609,9 +615,7 @@ class UserDetailScreen(
} else { } else {
rememberCallback(model) { rememberCallback(model) {
model.reduce( model.reduce(
UserDetailMviModel.Intent.UpVotePost( UserDetailMviModel.Intent.UpVotePost(id = post.id),
id = post.id,
),
) )
} }
}, },
@ -620,9 +624,7 @@ class UserDetailScreen(
} else { } else {
rememberCallback(model) { rememberCallback(model) {
model.reduce( model.reduce(
UserDetailMviModel.Intent.DownVotePost( UserDetailMviModel.Intent.DownVotePost(post.id),
id = post.id,
),
) )
} }
}, },
@ -631,28 +633,30 @@ class UserDetailScreen(
} else { } else {
rememberCallback(model) { rememberCallback(model) {
model.reduce( model.reduce(
UserDetailMviModel.Intent.SavePost( UserDetailMviModel.Intent.SavePost(post.id),
id = post.id,
),
) )
} }
}, },
onOpenCommunity = rememberCallbackArgs { community, instance -> onOpenCommunity = rememberCallbackArgs { community, instance ->
detailOpener.openCommunityDetail( detailOpener.openCommunityDetail(
community, community = community,
instance, otherInstance = instance,
) )
}, },
onOpenCreator = rememberCallbackArgs { user, instance -> onOpenCreator = rememberCallbackArgs { user, instance ->
detailOpener.openUserDetail(user, instance) detailOpener.openUserDetail(
user = user,
otherInstance = instance
)
}, },
onOpenPost = rememberCallbackArgs { p, instance -> onOpenPost = rememberCallbackArgs { p, instance ->
detailOpener.openPostDetail(p, instance) detailOpener.openPostDetail(
post = p,
otherInstance = instance
)
}, },
onOpenWeb = rememberCallbackArgs { url -> onOpenWeb = rememberCallbackArgs { url ->
navigationCoordinator.pushScreen( navigationCoordinator.pushScreen(WebViewScreen(url))
WebViewScreen(url)
)
}, },
onReply = if (!uiState.isLogged || isOnOtherInstance) { onReply = if (!uiState.isLogged || isOnOtherInstance) {
null null
@ -697,9 +701,7 @@ class UserDetailScreen(
when (optionId) { when (optionId) {
OptionId.Report -> { OptionId.Report -> {
navigationCoordinator.pushScreen( navigationCoordinator.pushScreen(
CreateReportScreen( CreateReportScreen(post.id)
postId = post.id
)
) )
} }
@ -721,16 +723,11 @@ class UserDetailScreen(
).distinct() ).distinct()
if (urls.size == 1) { if (urls.size == 1) {
model.reduce( model.reduce(
UserDetailMviModel.Intent.Share( UserDetailMviModel.Intent.Share(urls.first())
urls.first()
)
) )
} else { } else {
val screen = val screen = ShareBottomSheet(urls = urls)
ShareBottomSheet(urls = urls) navigationCoordinator.showBottomSheet(screen)
navigationCoordinator.showBottomSheet(
screen
)
} }
} }
@ -803,9 +800,7 @@ class UserDetailScreen(
?: defaultUpvoteColor, ?: defaultUpvoteColor,
onTriggered = rememberCallback { onTriggered = rememberCallback {
model.reduce( model.reduce(
UserDetailMviModel.Intent.UpVoteComment( UserDetailMviModel.Intent.UpVoteComment(comment.id)
comment.id
)
) )
}, },
) )
@ -822,9 +817,7 @@ class UserDetailScreen(
?: defaultDownVoteColor, ?: defaultDownVoteColor,
onTriggered = rememberCallback { onTriggered = rememberCallback {
model.reduce( model.reduce(
UserDetailMviModel.Intent.DownVoteComment( UserDetailMviModel.Intent.DownVoteComment(comment.id),
comment.id
),
) )
}, },
) )
@ -859,9 +852,7 @@ class UserDetailScreen(
?: defaultSaveColor, ?: defaultSaveColor,
onTriggered = rememberCallback { onTriggered = rememberCallback {
model.reduce( model.reduce(
UserDetailMviModel.Intent.SaveComment( UserDetailMviModel.Intent.SaveComment(comment.id),
id = comment.id,
),
) )
}, },
) )
@ -930,9 +921,7 @@ class UserDetailScreen(
} else { } else {
rememberCallback(model) { rememberCallback(model) {
model.reduce( model.reduce(
UserDetailMviModel.Intent.SaveComment( UserDetailMviModel.Intent.SaveComment(comment.id),
id = comment.id,
),
) )
} }
}, },
@ -941,9 +930,7 @@ class UserDetailScreen(
} else { } else {
rememberCallback(model) { rememberCallback(model) {
model.reduce( model.reduce(
UserDetailMviModel.Intent.UpVoteComment( UserDetailMviModel.Intent.UpVoteComment(comment.id),
id = comment.id,
),
) )
} }
}, },
@ -952,9 +939,7 @@ class UserDetailScreen(
} else { } else {
rememberCallback(model) { rememberCallback(model) {
model.reduce( model.reduce(
UserDetailMviModel.Intent.DownVoteComment( UserDetailMviModel.Intent.DownVoteComment(comment.id),
id = comment.id,
),
) )
} }
}, },
@ -969,30 +954,35 @@ class UserDetailScreen(
} }
}, },
onOpenCommunity = rememberCallbackArgs { community, instance -> onOpenCommunity = rememberCallbackArgs { community, instance ->
detailOpener.openCommunityDetail(community, instance) detailOpener.openCommunityDetail(
community = community,
otherInstance = instance
)
}, },
onOpenCreator = rememberCallbackArgs { user, instance -> onOpenCreator = rememberCallbackArgs { user, instance ->
detailOpener.openUserDetail(user, instance) detailOpener.openUserDetail(
user = user,
otherInstance = instance
)
}, },
onOpenPost = rememberCallbackArgs { post, instance -> onOpenPost = rememberCallbackArgs { post, instance ->
detailOpener.openPostDetail(post, instance) detailOpener.openPostDetail(
post = post,
otherInstance = instance
)
}, },
onOpenWeb = rememberCallbackArgs { url -> onOpenWeb = rememberCallbackArgs { url ->
navigationCoordinator.pushScreen(WebViewScreen(url)) navigationCoordinator.pushScreen(WebViewScreen(url))
}, },
options = buildList { options = buildList {
add( this += Option(
Option( OptionId.SeeRaw,
OptionId.SeeRaw, LocalXmlStrings.current.postActionSeeRaw,
LocalXmlStrings.current.postActionSeeRaw
)
) )
if (uiState.isLogged && !isOnOtherInstance) { if (uiState.isLogged && !isOnOtherInstance) {
add( this += Option(
Option( OptionId.Report,
OptionId.Report, LocalXmlStrings.current.postActionReport,
LocalXmlStrings.current.postActionReport
)
) )
} }
}, },
@ -1000,9 +990,7 @@ class UserDetailScreen(
when (optionId) { when (optionId) {
OptionId.Report -> { OptionId.Report -> {
navigationCoordinator.pushScreen( navigationCoordinator.pushScreen(
CreateReportScreen( CreateReportScreen(comment.id),
commentId = comment.id
),
) )
} }
@ -1146,7 +1134,8 @@ class UserDetailScreen(
}, },
) )
} }
}) },
)
} }
} }
} }