package awais.instagrabber.viewmodels import android.os.Bundle import androidx.lifecycle.* import androidx.savedstate.SavedStateRegistryOwner import awais.instagrabber.db.repositories.AccountRepository import awais.instagrabber.db.repositories.FavoriteRepository import awais.instagrabber.managers.DirectMessagesManager import awais.instagrabber.models.Resource import awais.instagrabber.repositories.responses.User import awais.instagrabber.repositories.responses.directmessages.RankedRecipient import awais.instagrabber.webservices.* import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers class ProfileFragmentViewModel( state: SavedStateHandle, userRepository: UserRepository, friendshipRepository: FriendshipRepository, storiesRepository: StoriesRepository, mediaRepository: MediaRepository, graphQLRepository: GraphQLRepository, accountRepository: AccountRepository, favoriteRepository: FavoriteRepository, ioDispatcher: CoroutineDispatcher, ) : ViewModel() { private val _currentUser = MutableLiveData>(Resource.loading(null)) private var messageManager: DirectMessagesManager? = null val currentUser: LiveData> = _currentUser val isLoggedIn: LiveData = currentUser.map { it.data != null } private val currentUserAndStateUsernameLiveData: LiveData, Resource>> = object : MediatorLiveData, Resource>>() { var user: Resource = Resource.loading(null) var stateUsername: Resource = Resource.loading(null) init { addSource(currentUser) { currentUser -> this.user = currentUser value = currentUser to stateUsername } addSource(state.getLiveData("username")) { username -> this.stateUsername = Resource.success(username) value = user to this.stateUsername } // trigger currentUserAndStateUsernameLiveData switch map with a state username success resource if (!state.contains("username")) { this.stateUsername = Resource.success(null) value = user to this.stateUsername } } } val profile: LiveData> = currentUserAndStateUsernameLiveData.switchMap { val (userResource, stateUsernameResource) = it liveData>(context = viewModelScope.coroutineContext + ioDispatcher) { if (userResource.status == Resource.Status.LOADING || stateUsernameResource.status == Resource.Status.LOADING) { emit(Resource.loading(null)) return@liveData } val user = userResource.data val stateUsername = stateUsernameResource.data if (stateUsername.isNullOrBlank()) { emit(Resource.success(user)) return@liveData } try { val fetchedUser = if (user != null) { userRepository.getUsernameInfo(stateUsername) // logged in } else { graphQLRepository.fetchUser(stateUsername) // anonymous } emit(Resource.success(fetchedUser)) } catch (e: Exception) { emit(Resource.error(e.message, null)) } } } /** * Username of profile without '`@`' */ val username: LiveData = Transformations.map(profile) { return@map when (it.status) { Resource.Status.LOADING, Resource.Status.ERROR -> "" Resource.Status.SUCCESS -> it.data?.username ?: "" } } init { // Log.d(TAG, "${state.keys()} $userRepository $friendshipRepository $storiesRepository $mediaRepository") } fun setCurrentUser(currentUser: Resource) { _currentUser.postValue(currentUser) } fun shareDm(result: RankedRecipient) { if (messageManager == null) { messageManager = DirectMessagesManager } // messageManager?.sendMedia(result, mediaId, BroadcastItemType.PROFILE, viewModelScope) } fun shareDm(recipients: Set) { if (messageManager == null) { messageManager = DirectMessagesManager } // messageManager?.sendMedia(recipients, mediaId, BroadcastItemType.PROFILE, viewModelScope) } } @Suppress("UNCHECKED_CAST") class ProfileFragmentViewModelFactory( private val userRepository: UserRepository, private val friendshipRepository: FriendshipRepository, private val storiesRepository: StoriesRepository, private val mediaRepository: MediaRepository, private val graphQLRepository: GraphQLRepository, private val accountRepository: AccountRepository, private val favoriteRepository: FavoriteRepository, owner: SavedStateRegistryOwner, defaultArgs: Bundle? = null, ) : AbstractSavedStateViewModelFactory(owner, defaultArgs) { override fun create( key: String, modelClass: Class, handle: SavedStateHandle, ): T { return ProfileFragmentViewModel( handle, userRepository, friendshipRepository, storiesRepository, mediaRepository, graphQLRepository, accountRepository, favoriteRepository, Dispatchers.IO, ) as T } }