diff --git a/modules/common_resource/src/main/res/menu/activity_user_menu.xml b/modules/common_resource/src/main/res/menu/activity_user_menu.xml
index 491a0b5d4a..49674e3c2e 100644
--- a/modules/common_resource/src/main/res/menu/activity_user_menu.xml
+++ b/modules/common_resource/src/main/res/menu/activity_user_menu.xml
@@ -45,4 +45,9 @@
+
+
\ No newline at end of file
diff --git a/modules/features/user/src/main/java/net/pantasystem/milktea/user/activity/FollowFollowerActivity.kt b/modules/features/user/src/main/java/net/pantasystem/milktea/user/activity/FollowFollowerActivity.kt
index 88dd12b631..d00e002e28 100644
--- a/modules/features/user/src/main/java/net/pantasystem/milktea/user/activity/FollowFollowerActivity.kt
+++ b/modules/features/user/src/main/java/net/pantasystem/milktea/user/activity/FollowFollowerActivity.kt
@@ -16,7 +16,6 @@ import net.pantasystem.milktea.user.UserCardActionHandler
import net.pantasystem.milktea.user.compose.screen.FollowFollowerRoute
import net.pantasystem.milktea.user.viewmodel.FollowFollowerViewModel
import net.pantasystem.milktea.user.viewmodel.ToggleFollowViewModel
-import net.pantasystem.milktea.user.viewmodel.UserDetailViewModel
import net.pantasystem.milktea.user.viewmodel.provideFactory
import javax.inject.Inject
@@ -42,8 +41,6 @@ class FollowFollowerActivity : AppCompatActivity() {
}
}
- @Inject
- lateinit var assistedFactory: UserDetailViewModel.ViewModelAssistedFactory
@Inject
lateinit var applyTheme: ApplyTheme
diff --git a/modules/features/user/src/main/java/net/pantasystem/milktea/user/activity/UserDetailActivity.kt b/modules/features/user/src/main/java/net/pantasystem/milktea/user/activity/UserDetailActivity.kt
index 9ed6945999..ca0b47eaeb 100644
--- a/modules/features/user/src/main/java/net/pantasystem/milktea/user/activity/UserDetailActivity.kt
+++ b/modules/features/user/src/main/java/net/pantasystem/milktea/user/activity/UserDetailActivity.kt
@@ -51,12 +51,12 @@ import net.pantasystem.milktea.user.activity.binder.UserDetailActivityMenuBinder
import net.pantasystem.milktea.user.databinding.ActivityUserDetailBinding
import net.pantasystem.milktea.user.nickname.EditNicknameDialog
import net.pantasystem.milktea.user.profile.ConfirmUserBlockDialog
+import net.pantasystem.milktea.user.profile.ProfileAccountSwitchDialog
import net.pantasystem.milktea.user.profile.UserProfileFieldListAdapter
import net.pantasystem.milktea.user.profile.mute.SpecifyMuteExpiredAtDialog
import net.pantasystem.milktea.user.reaction.UserReactionsFragment
import net.pantasystem.milktea.user.viewmodel.UserDetailTabType
import net.pantasystem.milktea.user.viewmodel.UserDetailViewModel
-import net.pantasystem.milktea.user.viewmodel.provideFactory
import javax.inject.Inject
class UserDetailNavigationImpl @Inject constructor(
@@ -80,11 +80,11 @@ class UserDetailNavigationImpl @Inject constructor(
@AndroidEntryPoint
class UserDetailActivity : AppCompatActivity() {
companion object {
- private const val EXTRA_USER_ID =
+ internal const val EXTRA_USER_ID =
"net.pantasystem.milktea.user.activity.UserDetailActivity.EXTRA_USER_ID"
- private const val EXTRA_USER_NAME =
+ internal const val EXTRA_USER_NAME =
"net.pantasystem.milktea.user.activity.UserDetailActivity.EXTRA_USER_NAME"
- private const val EXTRA_ACCOUNT_ID =
+ internal const val EXTRA_ACCOUNT_ID =
"jp.panta.misskeyandroiclient.UserDetailActivity.EXTRA_ACCOUNT_ID"
const val EXTRA_IS_MAIN_ACTIVE = "jp.panta.misskeyandroidclient.EXTRA_IS_MAIN_ACTIVE"
@@ -104,8 +104,6 @@ class UserDetailActivity : AppCompatActivity() {
}
}
- @Inject
- lateinit var assistedFactory: UserDetailViewModel.ViewModelAssistedFactory
@Inject
lateinit var accountStore: AccountStore
@@ -117,25 +115,27 @@ class UserDetailActivity : AppCompatActivity() {
lateinit var searchNavigation: SearchNavigation
- @ExperimentalCoroutinesApi
- val mViewModel: UserDetailViewModel by viewModels {
- val remoteUserId: String? = intent.getStringExtra(EXTRA_USER_ID)
- val accountId: Long = intent.getLongExtra(EXTRA_ACCOUNT_ID, -1)
- if (!(remoteUserId == null || accountId == -1L)) {
- val userId = User.Id(accountId, remoteUserId)
- return@viewModels UserDetailViewModel.provideFactory(assistedFactory, userId)
- }
- val userName = intent.data?.getQueryParameter("userName")
- ?: intent.getStringExtra(EXTRA_USER_NAME)
- ?: intent.data?.path?.let { path ->
- if (path.startsWith("/")) {
- path.substring(1, path.length)
- } else {
- path
- }
- }
- return@viewModels UserDetailViewModel.provideFactory(assistedFactory, userName!!)
- }
+// @ExperimentalCoroutinesApi
+// val mViewModel: UserDetailViewModel by viewModels {
+// val remoteUserId: String? = intent.getStringExtra(EXTRA_USER_ID)
+// val accountId: Long = intent.getLongExtra(EXTRA_ACCOUNT_ID, -1)
+// if (!(remoteUserId == null || accountId == -1L)) {
+// val userId = User.Id(accountId, remoteUserId)
+// return@viewModels UserDetailViewModel.provideFactory(assistedFactory, userId)
+// }
+// val userName = intent.data?.getQueryParameter("userName")
+// ?: intent.getStringExtra(EXTRA_USER_NAME)
+// ?: intent.data?.path?.let { path ->
+// if (path.startsWith("/")) {
+// path.substring(1, path.length)
+// } else {
+// path
+// }
+// }
+// return@viewModels UserDetailViewModel.provideFactory(assistedFactory, userName!!)
+// }
+
+ private val mViewModel: UserDetailViewModel by viewModels()
private var mUserId: User.Id? = null
@@ -338,7 +338,6 @@ class UserDetailActivity : AppCompatActivity() {
}
- @OptIn(ExperimentalCoroutinesApi::class)
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.activity_user_menu, menu)
@@ -413,6 +412,9 @@ class UserDetailActivity : AppCompatActivity() {
)
)
}
+ R.id.nav_switch_account -> {
+ ProfileAccountSwitchDialog().show(supportFragmentManager, "switchAccountDialog")
+ }
else -> return false
}
diff --git a/modules/features/user/src/main/java/net/pantasystem/milktea/user/profile/ProfileAccountSwitchDialog.kt b/modules/features/user/src/main/java/net/pantasystem/milktea/user/profile/ProfileAccountSwitchDialog.kt
new file mode 100644
index 0000000000..8380e7297b
--- /dev/null
+++ b/modules/features/user/src/main/java/net/pantasystem/milktea/user/profile/ProfileAccountSwitchDialog.kt
@@ -0,0 +1,70 @@
+package net.pantasystem.milktea.user.profile
+
+import android.app.Dialog
+import android.os.Bundle
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.platform.ComposeView
+import androidx.fragment.app.activityViewModels
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment
+import com.google.android.material.composethemeadapter.MdcTheme
+import dagger.hilt.android.AndroidEntryPoint
+import net.pantasystem.milktea.common_android_ui.account.AccountSwitchingDialogLayout
+import net.pantasystem.milktea.common_navigation.AccountSettingNavigation
+import net.pantasystem.milktea.common_navigation.AuthorizationArgs
+import net.pantasystem.milktea.common_navigation.AuthorizationNavigation
+import net.pantasystem.milktea.common_navigation.UserDetailNavigation
+import net.pantasystem.milktea.common_navigation.UserDetailNavigationArgs
+import net.pantasystem.milktea.user.viewmodel.UserDetailViewModel
+import javax.inject.Inject
+
+@AndroidEntryPoint
+class ProfileAccountSwitchDialog : BottomSheetDialogFragment() {
+ @Inject
+ lateinit var authorizationNavigation: AuthorizationNavigation
+
+ @Inject
+ lateinit var userDetailNavigation: UserDetailNavigation
+
+ @Inject
+ lateinit var accountSettingNavigation: AccountSettingNavigation
+
+ private val userDetailViewModel: UserDetailViewModel by activityViewModels()
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ return super.onCreateDialog(savedInstanceState).apply {
+ val view = ComposeView(requireContext()).apply {
+ setContent {
+ MdcTheme {
+ val uiState by userDetailViewModel.accountUiState.collectAsState()
+ AccountSwitchingDialogLayout(
+ uiState = uiState,
+ onSettingButtonClicked = {
+ startActivity(accountSettingNavigation.newIntent(Unit))
+ dismiss()
+ },
+ onAvatarIconClicked = { accountInfo ->
+ startActivity(
+ userDetailNavigation.newIntent(UserDetailNavigationArgs.UserName(accountInfo.user?.let {
+ "@${it.userName}@${it.host}"
+ } ?: "@${accountInfo.account.userName}@${accountInfo.account.getHost()}"))
+ )
+ dismiss()
+ },
+ onAccountClicked = {
+ userDetailViewModel.setCurrentAccount(it.account.accountId)
+ dismiss()
+ },
+ onAddAccountButtonClicked = {
+ requireActivity().startActivity(authorizationNavigation.newIntent(
+ AuthorizationArgs.New))
+ dismiss()
+ }
+ )
+ }
+ }
+ }
+ setContentView(view)
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/features/user/src/main/java/net/pantasystem/milktea/user/viewmodel/UserDetailViewModel.kt b/modules/features/user/src/main/java/net/pantasystem/milktea/user/viewmodel/UserDetailViewModel.kt
index 8942672e17..95ff624032 100644
--- a/modules/features/user/src/main/java/net/pantasystem/milktea/user/viewmodel/UserDetailViewModel.kt
+++ b/modules/features/user/src/main/java/net/pantasystem/milktea/user/viewmodel/UserDetailViewModel.kt
@@ -1,13 +1,11 @@
package net.pantasystem.milktea.user.viewmodel
import androidx.annotation.StringRes
+import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
-import dagger.assisted.Assisted
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
+import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
@@ -21,12 +19,15 @@ import net.pantasystem.milktea.common.mapCancellableCatching
import net.pantasystem.milktea.common.runCancellableCatching
import net.pantasystem.milktea.common_android.eventbus.EventBus
import net.pantasystem.milktea.common_android.resource.StringSource
+import net.pantasystem.milktea.common_android_ui.account.viewmodel.AccountViewModelUiStateHelper
import net.pantasystem.milktea.model.account.Account
import net.pantasystem.milktea.model.account.AccountRepository
import net.pantasystem.milktea.model.account.page.Pageable
import net.pantasystem.milktea.model.account.page.PageableTemplate
+import net.pantasystem.milktea.model.ap.ApResolverService
import net.pantasystem.milktea.model.instance.FeatureEnables
import net.pantasystem.milktea.model.instance.FeatureType
+import net.pantasystem.milktea.model.instance.InstanceInfoService
import net.pantasystem.milktea.model.user.*
import net.pantasystem.milktea.model.user.block.BlockRepository
import net.pantasystem.milktea.model.user.mute.CreateMute
@@ -35,8 +36,11 @@ import net.pantasystem.milktea.model.user.nickname.DeleteNicknameUseCase
import net.pantasystem.milktea.model.user.nickname.UpdateNicknameUseCase
import net.pantasystem.milktea.model.user.renote.mute.RenoteMuteRepository
import net.pantasystem.milktea.user.R
+import net.pantasystem.milktea.user.activity.UserDetailActivity
+import javax.inject.Inject
-class UserDetailViewModel @AssistedInject constructor(
+@HiltViewModel
+class UserDetailViewModel @Inject constructor(
private val deleteNicknameUseCase: DeleteNicknameUseCase,
private val updateNicknameUseCase: UpdateNicknameUseCase,
private val accountStore: AccountStore,
@@ -47,48 +51,76 @@ class UserDetailViewModel @AssistedInject constructor(
private val muteRepository: MuteRepository,
userDataSource: UserDataSource,
loggerFactory: Logger.Factory,
+ instanceInfoService: InstanceInfoService,
private val userRepository: UserRepository,
private val featureEnables: FeatureEnables,
private val toggleFollowUseCase: ToggleFollowUseCase,
- @Assisted val userId: User.Id?,
- @Assisted private val fqdnUserName: String?,
+ private val apResolverService: ApResolverService,
+ private val savedStateHandle: SavedStateHandle,
) : ViewModel() {
- @AssistedFactory
- interface ViewModelAssistedFactory {
- fun create(userId: User.Id?, fqdnUserName: String?): UserDetailViewModel
- }
-
companion object;
private val logger = loggerFactory.create("UserDetailViewModel")
- private val currentAccountId = MutableStateFlow(userId?.accountId)
+
+ // private val currentAccountId = MutableStateFlow(userId?.accountId)
+ private val userId =
+ savedStateHandle.getStateFlow(UserDetailActivity.EXTRA_USER_ID, null)
+ private val specifiedAccountId =
+ savedStateHandle.getStateFlow(UserDetailActivity.EXTRA_ACCOUNT_ID, null)
+
@OptIn(ExperimentalCoroutinesApi::class)
- val currentAccount = currentAccountId.flatMapLatest { accountId ->
+ val currentAccount = specifiedAccountId.flatMapLatest { accountId ->
accountStore.state.map { state ->
accountId?.let {
state.get(it)
} ?: state.currentAccount
}
- }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), null)
+ }.stateIn(
+ viewModelScope,
+ SharingStarted.WhileSubscribed(5_000),
+ null,
+ )
+
+ private val fqdnUserName =
+ savedStateHandle.getStateFlow(UserDetailActivity.EXTRA_USER_NAME, null)
private val _errors = MutableSharedFlow(extraBufferCapacity = 100)
val errors = _errors.asSharedFlow()
+ private val userProfileArgType = combine(
+ userId,
+ fqdnUserName,
+ currentAccount,
+ ) { userId, fqdnUserName, currentAccount ->
+ when {
+ userId != null && currentAccount != null -> {
+ UserProfileArgType.UserId(User.Id(currentAccount.accountId, userId))
+ }
- @OptIn(ExperimentalCoroutinesApi::class)
- val userState = when {
- userId != null -> {
- userDataSource.observe(userId)
- }
- fqdnUserName != null -> {
- currentAccount.filterNotNull().flatMapLatest {
- userDataSource.observe(it.accountId, fqdnUserName)
+ fqdnUserName != null && currentAccount != null -> {
+ UserProfileArgType.FqdnUserName(fqdnUserName, currentAccount)
+ }
+
+ else -> {
+ UserProfileArgType.None
}
}
- else -> {
- throw IllegalArgumentException()
+ }.stateIn(viewModelScope, SharingStarted.Lazily, UserProfileArgType.None)
+
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ val userState = userProfileArgType.flatMapLatest {
+ when (val type = it) {
+ is UserProfileArgType.FqdnUserName -> {
+ userDataSource.observe(type.currentAccount.accountId, type.fqdnUserName)
+ }
+
+ UserProfileArgType.None -> flowOf(null)
+ is UserProfileArgType.UserId -> {
+ userDataSource.observe(type.userId)
+ }
}
}.mapNotNull {
it as? User.Detail
@@ -97,6 +129,7 @@ class UserDetailViewModel @AssistedInject constructor(
_errors.tryEmit(it)
}.stateIn(viewModelScope, SharingStarted.Lazily, null)
+
val user = userState.asLiveData()
val isMine = combine(userState, currentAccount) { userState, account ->
@@ -112,7 +145,10 @@ class UserDetailViewModel @AssistedInject constructor(
val registrationDate = userState.map {
it?.info?.createdAt?.toLocalDateTime(TimeZone.currentSystemDefault())?.date
}.filterNotNull().map {
- StringSource(R.string.user_registration_date, "${it.year}/${it.monthNumber}/${it.dayOfMonth}")
+ StringSource(
+ R.string.user_registration_date,
+ "${it.year}/${it.monthNumber}/${it.dayOfMonth}"
+ )
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), null)
val tabTypes = combine(
@@ -121,12 +157,12 @@ class UserDetailViewModel @AssistedInject constructor(
val isEnableGallery =
featureEnables.isEnable(account.normalizedInstanceUri, FeatureType.Gallery)
val isPublicReaction = featureEnables.isEnable(
- account.normalizedInstanceUri,
- FeatureType.UserReactionHistory
- ) && (user.info.isPublicReactions || user.id == User.Id(
- account.accountId, account.remoteId
- ))
- when(account.instanceType) {
+ account.normalizedInstanceUri,
+ FeatureType.UserReactionHistory
+ ) && (user.info.isPublicReactions || user.id == User.Id(
+ account.accountId, account.remoteId
+ ))
+ when (account.instanceType) {
Account.InstanceType.MISSKEY -> {
listOfNotNull(
UserDetailTabType.UserTimeline(user.id),
@@ -140,6 +176,7 @@ class UserDetailViewModel @AssistedInject constructor(
if (isPublicReaction) UserDetailTabType.Reactions(user.id) else null,
)
}
+
Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
listOf(
UserDetailTabType.MastodonUserTimeline(user.id),
@@ -154,6 +191,14 @@ class UserDetailViewModel @AssistedInject constructor(
logger.error("ユーザープロフィールのタブの取得に失敗", it)
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), emptyList())
+ val accountUiState = AccountViewModelUiStateHelper(
+ currentAccount,
+ accountStore,
+ userDataSource,
+ instanceInfoService,
+ viewModelScope,
+ ).uiState
+
@OptIn(ExperimentalCoroutinesApi::class)
val renoteMuteState = userState.filterNotNull().flatMapLatest {
renoteMuteRepository.observeOne(it.id)
@@ -163,15 +208,7 @@ class UserDetailViewModel @AssistedInject constructor(
val showFollows = EventBus()
init {
- require(userId != null || fqdnUserName != null) {
- "userIdかfqdnUserNameのいずれかが指定されている必要があります。"
- }
sync()
- accountStore.observeCurrentAccount.onEach {
- if (userId == null) {
- currentAccountId.value = it?.accountId
- }
- }.launchIn(viewModelScope)
}
@@ -227,7 +264,7 @@ class UserDetailViewModel @AssistedInject constructor(
fun unmute() {
viewModelScope.launch {
userState.value?.let { user ->
- muteRepository.delete(user.id).mapCancellableCatching{
+ muteRepository.delete(user.id).mapCancellableCatching {
userRepository.sync(user.id).getOrThrow()
}.onFailure {
logger.error("unmute", e = it)
@@ -338,52 +375,72 @@ class UserDetailViewModel @AssistedInject constructor(
}
}
+ fun setCurrentAccount(accountId: Long) {
+ viewModelScope.launch {
+ accountRepository.get(accountId).mapCancellableCatching {
+ it to apResolverService.resolve(getUserId(), accountId).getOrThrow()
+ }.onSuccess { (account, resolved) ->
+ savedStateHandle[UserDetailActivity.EXTRA_USER_ID] = resolved.id.id
+ savedStateHandle[UserDetailActivity.EXTRA_ACCOUNT_ID] = resolved.id.accountId
+ accountStore.setCurrent(account)
+ }.onFailure {
+ logger.error("setCurrentAccount failed", it)
+ _errors.tryEmit(it)
+ }
+ }
+ }
+
private suspend fun findUser(): User {
return userRepository.find(getUserId())
}
private suspend fun getUserId(): User.Id {
- if (userId != null) {
- return userId
- }
+ val strUserId = savedStateHandle.get(UserDetailActivity.EXTRA_USER_ID)
+ val specifiedAccountId = savedStateHandle.get(UserDetailActivity.EXTRA_ACCOUNT_ID)
+ val fqdnUserName = savedStateHandle.get(UserDetailActivity.EXTRA_USER_NAME)
+ val currentAccount = specifiedAccountId?.let {
+ accountRepository.get(it).getOrThrow()
+ } ?: accountRepository.getCurrentAccount().getOrThrow()
+ val argType = when {
+ strUserId != null -> {
+ UserProfileArgType.UserId(User.Id(currentAccount.accountId, strUserId))
+ }
+
+ fqdnUserName != null -> {
+ UserProfileArgType.FqdnUserName(fqdnUserName, currentAccount)
+ }
- val account = currentAccount.value ?: accountRepository.getCurrentAccount().getOrThrow()
- if (fqdnUserName != null) {
- val (userName, host) = Acct(fqdnUserName).let {
- it.userName to it.host
+ else -> {
+ UserProfileArgType.None
}
- return userRepository.findByUserName(account.accountId, userName, host).id
}
- throw IllegalStateException()
- }
-}
-@Suppress("UNCHECKED_CAST")
-fun UserDetailViewModel.Companion.provideFactory(
- assistedFactory: UserDetailViewModel.ViewModelAssistedFactory, userId: User.Id
-): ViewModelProvider.Factory = object : ViewModelProvider.Factory {
- override fun create(modelClass: Class): T {
- return assistedFactory.create(userId, null) as T
- }
-}
+ return when (argType) {
+ is UserProfileArgType.FqdnUserName -> {
+ val (userName, host) = Acct(argType.fqdnUserName).let {
+ it.userName to it.host
+ }
+ userRepository.findByUserName(currentAccount.accountId, userName, host).id
+ }
+
+ is UserProfileArgType.UserId -> {
+ argType.userId
+ }
+
+ UserProfileArgType.None -> throw IllegalStateException()
+ }
-@Suppress("UNCHECKED_CAST")
-fun UserDetailViewModel.Companion.provideFactory(
- assistedFactory: UserDetailViewModel.ViewModelAssistedFactory,
- fqdnUserName: String,
-): ViewModelProvider.Factory = object : ViewModelProvider.Factory {
- override fun create(modelClass: Class): T {
- return assistedFactory.create(null, fqdnUserName) as T
}
}
sealed class UserDetailTabType(
- @StringRes val title: Int
+ @StringRes val title: Int,
) {
data class UserTimeline(val userId: User.Id) : UserDetailTabType(R.string.post)
- data class UserTimelineWithReplies(val userId: User.Id) : UserDetailTabType(R.string.notes_and_replies)
+ data class UserTimelineWithReplies(val userId: User.Id) :
+ UserDetailTabType(R.string.notes_and_replies)
data class UserTimelineOnlyPosts(val userId: User.Id) : UserDetailTabType(R.string.post_only)
@@ -395,9 +452,21 @@ sealed class UserDetailTabType(
data class Media(val userId: User.Id) : UserDetailTabType(R.string.media)
data class MastodonUserTimeline(val userId: User.Id) : UserDetailTabType(R.string.post)
- data class MastodonUserTimelineWithReplies(val userId: User.Id) : UserDetailTabType(R.string.notes_and_replies)
+ data class MastodonUserTimelineWithReplies(val userId: User.Id) :
+ UserDetailTabType(R.string.notes_and_replies)
- data class MastodonUserTimelineOnlyPosts(val userId: User.Id) : UserDetailTabType(R.string.post_only)
+ data class MastodonUserTimelineOnlyPosts(val userId: User.Id) :
+ UserDetailTabType(R.string.post_only)
data class MastodonMedia(val userId: User.Id) : UserDetailTabType(R.string.media)
+}
+
+sealed interface UserProfileArgType {
+ data class UserId(val userId: User.Id) : UserProfileArgType
+
+ data class FqdnUserName(val fqdnUserName: String, val currentAccount: Account) :
+ UserProfileArgType
+
+ object None : UserProfileArgType
+
}
\ No newline at end of file
diff --git a/modules/model/src/main/java/net/pantasystem/milktea/model/ap/ApResolverService.kt b/modules/model/src/main/java/net/pantasystem/milktea/model/ap/ApResolverService.kt
index 9a61f82f77..80308997c6 100644
--- a/modules/model/src/main/java/net/pantasystem/milktea/model/ap/ApResolverService.kt
+++ b/modules/model/src/main/java/net/pantasystem/milktea/model/ap/ApResolverService.kt
@@ -1,8 +1,11 @@
package net.pantasystem.milktea.model.ap
import net.pantasystem.milktea.common.mapCancellableCatching
+import net.pantasystem.milktea.common.runCancellableCatching
+import net.pantasystem.milktea.model.account.AccountRepository
import net.pantasystem.milktea.model.notes.Note
import net.pantasystem.milktea.model.notes.NoteRepository
+import net.pantasystem.milktea.model.user.User
import net.pantasystem.milktea.model.user.UserRepository
import javax.inject.Inject
@@ -10,6 +13,7 @@ class ApResolverService @Inject constructor(
private val apResolverRepository: ApResolverRepository,
private val noteRepository: NoteRepository,
private val userRepository: UserRepository,
+ private val accountRepository: AccountRepository,
) {
suspend fun resolve(noteId: Note.Id, resolveToAccountId: Long): Result {
@@ -25,5 +29,20 @@ class ApResolverService @Inject constructor(
}
}
-
+ suspend fun resolve(userId: User.Id, resolveToAccountId: Long): Result = runCancellableCatching {
+ val user = (userRepository.find(userId, true) as User.Detail)
+ val resolveAccount = accountRepository.get(resolveToAccountId).getOrThrow()
+ if (resolveAccount.getHost() == user.host) {
+ return@runCancellableCatching userRepository.findByUserName(resolveToAccountId, user.userName, user.host)
+ }
+ val uri = user.getRemoteProfileUrl(
+ accountRepository.get(userId.accountId).getOrThrow()
+ )
+ apResolverRepository.resolve(resolveToAccountId, uri).mapCancellableCatching {
+ when (it) {
+ is ApResolver.TypeNote -> throw IllegalStateException("Cannot resolve note")
+ is ApResolver.TypeUser -> it.user
+ }
+ }.getOrThrow()
+ }
}
\ No newline at end of file