~captainepoch/husky

bf12d6642376c92d74b59df786e7464a9c105248 — Adolfo Santiago a month ago 9e32d3c
Fix nullability problems
M husky/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsActivity.kt => husky/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsActivity.kt +30 -17
@@ 34,13 34,21 @@ import com.keylesspalace.tusky.adapter.OnEmojiSelectedListener
import com.keylesspalace.tusky.di.Injectable
import com.keylesspalace.tusky.di.ViewModelFactory
import com.keylesspalace.tusky.settings.PrefKeys
import com.keylesspalace.tusky.util.*
import com.keylesspalace.tusky.util.Error
import com.keylesspalace.tusky.util.Loading
import com.keylesspalace.tusky.util.Success
import com.keylesspalace.tusky.util.hide
import com.keylesspalace.tusky.util.show
import com.keylesspalace.tusky.view.EmojiPicker
import kotlinx.android.synthetic.main.activity_announcements.*
import kotlinx.android.synthetic.main.toolbar_basic.*
import javax.inject.Inject
import kotlinx.android.synthetic.main.activity_announcements.announcementsList
import kotlinx.android.synthetic.main.activity_announcements.errorMessageView
import kotlinx.android.synthetic.main.activity_announcements.progressBar
import kotlinx.android.synthetic.main.activity_announcements.swipeRefreshLayout
import kotlinx.android.synthetic.main.toolbar_basic.toolbar

class AnnouncementsActivity : BottomSheetActivity(), AnnouncementActionListener, OnEmojiSelectedListener, Injectable {
class AnnouncementsActivity : BottomSheetActivity(), AnnouncementActionListener,
    OnEmojiSelectedListener, Injectable {

    @Inject
    lateinit var viewModelFactory: ViewModelFactory


@@ 52,13 60,13 @@ class AnnouncementsActivity : BottomSheetActivity(), AnnouncementActionListener,
    private val picker by lazy { EmojiPicker(this) }
    private val pickerDialog by lazy {
        PopupWindow(this)
                .apply {
                    contentView = picker
                    isFocusable = true
                    setOnDismissListener {
                        currentAnnouncementId = null
                    }
            .apply {
                contentView = picker
                isFocusable = true
                setOnDismissListener {
                    currentAnnouncementId = null
                }
            }
    }
    private var currentAnnouncementId: String? = null



@@ 89,12 97,15 @@ class AnnouncementsActivity : BottomSheetActivity(), AnnouncementActionListener,
        announcementsList.adapter = adapter

        viewModel.announcements.observe(this) {
            when (it) {
            when(it) {
                is Success -> {
                    progressBar.hide()
                    swipeRefreshLayout.isRefreshing = false
                    if (it.data.isNullOrEmpty()) {
                        errorMessageView.setup(R.drawable.elephant_friend_empty, R.string.no_announcements)
                    if(it.data.isNullOrEmpty()) {
                        errorMessageView.setup(
                            R.drawable.elephant_friend_empty,
                            R.string.no_announcements
                        )
                        errorMessageView.show()
                    } else {
                        errorMessageView.hide()


@@ 116,7 127,9 @@ class AnnouncementsActivity : BottomSheetActivity(), AnnouncementActionListener,
        }

        viewModel.emojis.observe(this) {
            picker.adapter = EmojiAdapter(it, this)
            it?.let { list ->
                picker.adapter = EmojiAdapter(list, this)
            }
        }

        viewModel.load()


@@ 124,7 137,7 @@ class AnnouncementsActivity : BottomSheetActivity(), AnnouncementActionListener,
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
        when(item.itemId) {
            android.R.id.home -> {
                onBackPressed()
                return true


@@ 163,13 176,13 @@ class AnnouncementsActivity : BottomSheetActivity(), AnnouncementActionListener,
    }

    override fun onViewAccount(id: String?) {
        if (id != null) {
        if(id != null) {
            viewAccount(id)
        }
    }

    override fun onViewUrl(url: String?) {
        if (url != null) {
        if(url != null) {
            viewUrl(url)
        }
    }

M husky/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsViewModel.kt => husky/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsViewModel.kt +125 -118
@@ 27,159 27,166 @@ import com.keylesspalace.tusky.entity.Announcement
import com.keylesspalace.tusky.entity.Emoji
import com.keylesspalace.tusky.entity.Instance
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.util.*
import com.keylesspalace.tusky.util.Either
import com.keylesspalace.tusky.util.Error
import com.keylesspalace.tusky.util.Loading
import com.keylesspalace.tusky.util.Resource
import com.keylesspalace.tusky.util.RxAwareViewModel
import com.keylesspalace.tusky.util.Success
import io.reactivex.rxkotlin.Singles
import javax.inject.Inject

class AnnouncementsViewModel @Inject constructor(
        accountManager: AccountManager,
        private val appDatabase: AppDatabase,
        private val mastodonApi: MastodonApi,
        private val eventHub: EventHub
    accountManager: AccountManager,
    private val appDatabase: AppDatabase,
    private val mastodonApi: MastodonApi,
    private val eventHub: EventHub
) : RxAwareViewModel() {

    private val announcementsMutable = MutableLiveData<Resource<List<Announcement>>>()
    val announcements: LiveData<Resource<List<Announcement>>> = announcementsMutable

    private val emojisMutable = MutableLiveData<List<Emoji>>()
    val emojis: LiveData<List<Emoji>> = emojisMutable
    private val emojisMutable = MutableLiveData<List<Emoji>?>()
    val emojis: LiveData<List<Emoji>?>
        get() = emojisMutable

    init {
        Singles.zip(
                mastodonApi.getCustomEmojis(),
                appDatabase.instanceDao().loadMetadataForInstance(accountManager.activeAccount?.domain!!)
                        .map<Either<InstanceEntity, Instance>> { Either.Left(it) }
                        .onErrorResumeNext(
                                mastodonApi.getInstance()
                                        .map { Either.Right(it) }
                        )
            mastodonApi.getCustomEmojis(),
            appDatabase.instanceDao()
                .loadMetadataForInstance(accountManager.activeAccount?.domain!!)
                .map<Either<InstanceEntity, Instance>> { Either.Left(it) }
                .onErrorResumeNext(
                    mastodonApi.getInstance()
                        .map { Either.Right(it) }
                )
        ) { emojis, either ->
            either.asLeftOrNull()?.copy(emojiList = emojis)
                    ?: InstanceEntity(
                            accountManager.activeAccount?.domain!!,
                            emojis,
                            either.asRight().maxTootChars,
                            either.asRight().pollLimits?.maxOptions,
                            either.asRight().pollLimits?.maxOptionChars,
                            either.asRight().version,
                            either.asRight().chatLimit
                    )
                ?: InstanceEntity(
                    accountManager.activeAccount?.domain!!,
                    emojis,
                    either.asRight().maxTootChars,
                    either.asRight().pollLimits?.maxOptions,
                    either.asRight().pollLimits?.maxOptionChars,
                    either.asRight().version,
                    either.asRight().chatLimit
                )
        }
                .doOnSuccess {
                    appDatabase.instanceDao().insertOrReplace(it)
                }
                .subscribe({
                    emojisMutable.postValue(it.emojiList)
                }, {
                    Log.w(TAG, "Failed to get custom emojis.", it)
                })
                .autoDispose()
            .doOnSuccess {
                appDatabase.instanceDao().insertOrReplace(it)
            }
            .subscribe({ instanceEntity ->
                emojisMutable.postValue(instanceEntity.emojiList)
            }, {
                Log.w(TAG, "Failed to get custom emojis.", it)
            })
            .autoDispose()
    }

    fun load() {
        announcementsMutable.postValue(Loading())
        mastodonApi.listAnnouncements()
                .subscribe({
                    announcementsMutable.postValue(Success(it))
                    it.filter { announcement -> !announcement.read }
                            .forEach { announcement ->
                                mastodonApi.dismissAnnouncement(announcement.id)
                                        .subscribe(
                                                {
                                                    eventHub.dispatch(AnnouncementReadEvent(announcement.id))
                                                },
                                                { throwable ->
                                                    Log.d(TAG, "Failed to mark announcement as read.", throwable)
                                                }
                                        )
                                        .autoDispose()
                            }
                }, {
                    announcementsMutable.postValue(Error(cause = it))
                })
                .autoDispose()
            .subscribe({
                announcementsMutable.postValue(Success(it))
                it.filter { announcement -> !announcement.read }
                    .forEach { announcement ->
                        mastodonApi.dismissAnnouncement(announcement.id)
                            .subscribe(
                                {
                                    eventHub.dispatch(AnnouncementReadEvent(announcement.id))
                                },
                                { throwable ->
                                    Log.d(TAG, "Failed to mark announcement as read.", throwable)
                                }
                            )
                            .autoDispose()
                    }
            }, {
                announcementsMutable.postValue(Error(cause = it))
            })
            .autoDispose()
    }

    fun addReaction(announcementId: String, name: String) {
        mastodonApi.addAnnouncementReaction(announcementId, name)
                .subscribe({
                    announcementsMutable.postValue(
                            Success(
                                    announcements.value!!.data!!.map { announcement ->
                                        if (announcement.id == announcementId) {
                                            announcement.copy(
                                                    reactions = if (announcement.reactions.find { reaction -> reaction.name == name } != null) {
                                                        announcement.reactions.map { reaction ->
                                                            if (reaction.name == name) {
                                                                reaction.copy(
                                                                        count = reaction.count + 1,
                                                                        me = true
                                                                )
                                                            } else {
                                                                reaction
                                                            }
                                                        }
                                                    } else {
                                                        listOf(
                                                                *announcement.reactions.toTypedArray(),
                                                                emojis.value!!.find { emoji -> emoji.shortcode == name }
                                                                        !!.run {
                                                                            Announcement.Reaction(
                                                                                    name,
                                                                                    1,
                                                                                    true,
                                                                                    url,
                                                                                    staticUrl
                                                                            )
                                                                        }
                                                        )
                                                    }
                                            )
                                        } else {
                                            announcement
            .subscribe({
                announcementsMutable.postValue(
                    Success(
                        announcements.value!!.data!!.map { announcement ->
                            if(announcement.id == announcementId) {
                                announcement.copy(
                                    reactions = if(announcement.reactions.find { reaction -> reaction.name == name } != null) {
                                        announcement.reactions.map { reaction ->
                                            if(reaction.name == name) {
                                                reaction.copy(
                                                    count = reaction.count + 1,
                                                    me = true
                                                )
                                            } else {
                                                reaction
                                            }
                                        }
                                    } else {
                                        listOf(
                                            *announcement.reactions.toTypedArray(),
                                            emojis.value!!.find { emoji -> emoji.shortcode == name }
                                            !!.run {
                                                Announcement.Reaction(
                                                    name,
                                                    1,
                                                    true,
                                                    url,
                                                    staticUrl
                                                )
                                            }
                                        )
                                    }
                            )
                                )
                            } else {
                                announcement
                            }
                        }
                    )
                }, {
                    Log.w(TAG, "Failed to add reaction to the announcement.", it)
                })
                .autoDispose()
                )
            }, {
                Log.w(TAG, "Failed to add reaction to the announcement.", it)
            })
            .autoDispose()
    }

    fun removeReaction(announcementId: String, name: String) {
        mastodonApi.removeAnnouncementReaction(announcementId, name)
                .subscribe({
                    announcementsMutable.postValue(
                            Success(
                                    announcements.value!!.data!!.map { announcement ->
                                        if (announcement.id == announcementId) {
                                            announcement.copy(
                                                    reactions = announcement.reactions.mapNotNull { reaction ->
                                                        if (reaction.name == name) {
                                                            if (reaction.count > 1) {
                                                                reaction.copy(
                                                                        count = reaction.count - 1,
                                                                        me = false
                                                                )
                                                            } else {
                                                                null
                                                            }
                                                        } else {
                                                            reaction
                                                        }
                                                    }
                                            )
            .subscribe({
                announcementsMutable.postValue(
                    Success(
                        announcements.value!!.data!!.map { announcement ->
                            if(announcement.id == announcementId) {
                                announcement.copy(
                                    reactions = announcement.reactions.mapNotNull { reaction ->
                                        if(reaction.name == name) {
                                            if(reaction.count > 1) {
                                                reaction.copy(
                                                    count = reaction.count - 1,
                                                    me = false
                                                )
                                            } else {
                                                null
                                            }
                                        } else {
                                            announcement
                                            reaction
                                        }
                                    }
                            )
                                )
                            } else {
                                announcement
                            }
                        }
                    )
                }, {
                    Log.w(TAG, "Failed to remove reaction from the announcement.", it)
                })
                .autoDispose()
                )
            }, {
                Log.w(TAG, "Failed to remove reaction from the announcement.", it)
            })
            .autoDispose()
    }

    companion object {

M husky/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsRepository.kt => husky/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsRepository.kt +49 -38
@@ 13,15 13,18 @@ import com.keylesspalace.tusky.util.Listing
import com.keylesspalace.tusky.util.NetworkState
import io.reactivex.Single
import io.reactivex.schedulers.Schedulers
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.util.concurrent.Executors
import javax.inject.Inject
import javax.inject.Singleton
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

@Singleton
class ConversationsRepository @Inject constructor(val mastodonApi: MastodonApi, val db: AppDatabase) {
class ConversationsRepository @Inject constructor(
    val mastodonApi: MastodonApi,
    val db: AppDatabase
) {

    private val ioExecutor = Executors.newSingleThreadExecutor()



@@ 37,23 40,26 @@ class ConversationsRepository @Inject constructor(val mastodonApi: MastodonApi, 
        }

        mastodonApi.getConversations(limit = DEFAULT_PAGE_SIZE).enqueue(
                object : Callback<List<Conversation>> {
                    override fun onFailure(call: Call<List<Conversation>>, t: Throwable) {
                        // retrofit calls this on main thread so safe to call set value
                        networkState.value = NetworkState.error(t.message)
                    }
            object : Callback<List<Conversation>> {
                override fun onFailure(call: Call<List<Conversation>>, t: Throwable) {
                    // retrofit calls this on main thread so safe to call set value
                    networkState.value = NetworkState.error(t.message)
                }

                    override fun onResponse(call: Call<List<Conversation>>, response: Response<List<Conversation>>) {
                        ioExecutor.execute {
                            db.runInTransaction {
                                db.conversationDao().deleteForAccount(accountId)
                                insertResultIntoDb(accountId, response.body())
                            }
                            // since we are in bg thread now, post the result.
                            networkState.postValue(NetworkState.LOADED)
                override fun onResponse(
                    call: Call<List<Conversation>>,
                    response: Response<List<Conversation>>
                ) {
                    ioExecutor.execute {
                        db.runInTransaction {
                            db.conversationDao().deleteForAccount(accountId)
                            insertResultIntoDb(accountId, response.body())
                        }
                        // since we are in bg thread now, post the result.
                        networkState.postValue(NetworkState.LOADED)
                    }
                }
            }
        )
        return networkState
    }


@@ 63,11 69,12 @@ class ConversationsRepository @Inject constructor(val mastodonApi: MastodonApi, 
        // create a boundary callback which will observe when the user reaches to the edges of
        // the list and update the database with extra data.
        val boundaryCallback = ConversationsBoundaryCallback(
                accountId = accountId,
                mastodonApi = mastodonApi,
                handleResponse = this::insertResultIntoDb,
                ioExecutor = ioExecutor,
                networkPageSize = DEFAULT_PAGE_SIZE)
            accountId = accountId,
            mastodonApi = mastodonApi,
            handleResponse = this::insertResultIntoDb,
            ioExecutor = ioExecutor,
            networkPageSize = DEFAULT_PAGE_SIZE
        )
        // we are using a mutable live data to trigger refresh requests which eventually calls
        // refresh method and gets a new live data. Each refresh request by the user becomes a newly
        // dispatched data in refreshTrigger


@@ 77,21 84,25 @@ class ConversationsRepository @Inject constructor(val mastodonApi: MastodonApi, 
        }

        // We use toLiveData Kotlin extension function here, you could also use LivePagedListBuilder
        val livePagedList =  db.conversationDao().conversationsForAccount(accountId).toLiveData(
                config = Config(pageSize = DEFAULT_PAGE_SIZE, prefetchDistance = DEFAULT_PAGE_SIZE / 2, enablePlaceholders = false),
                boundaryCallback = boundaryCallback
        val livePagedList = db.conversationDao().conversationsForAccount(accountId).toLiveData(
            config = Config(
                pageSize = DEFAULT_PAGE_SIZE,
                prefetchDistance = DEFAULT_PAGE_SIZE / 2,
                enablePlaceholders = false
            ),
            boundaryCallback = boundaryCallback
        )

        return Listing(
                pagedList = livePagedList,
                networkState = boundaryCallback.networkState,
                retry = {
                    boundaryCallback.helper.retryAllFailed()
                },
                refresh = {
                    refreshTrigger.value = null
                },
                refreshState = refreshState
            pagedList = livePagedList,
            networkState = boundaryCallback.networkState,
            retry = {
                boundaryCallback.helper.retryAllFailed()
            },
            refresh = {
                refreshTrigger.value = Unit
            },
            refreshState = refreshState
        )
    }



@@ 99,13 110,13 @@ class ConversationsRepository @Inject constructor(val mastodonApi: MastodonApi, 
        Single.fromCallable {
            db.conversationDao().deleteForAccount(accountId)
        }.subscribeOn(Schedulers.io())
                .subscribe()
            .subscribe()
    }

    private fun insertResultIntoDb(accountId: Long, result: List<Conversation>?) {
        result?.filter { it.lastStatus != null }
                ?.map{ it.toEntity(accountId) }
                ?.let { db.conversationDao().insert(it) }
            ?.map { it.toEntity(accountId) }
            ?.let { db.conversationDao().insert(it) }

    }
}
\ No newline at end of file
}

M husky/app/src/main/java/com/keylesspalace/tusky/components/report/ReportViewModel.kt => husky/app/src/main/java/com/keylesspalace/tusky/components/report/ReportViewModel.kt +89 -72
@@ 27,18 27,26 @@ import com.keylesspalace.tusky.components.report.model.StatusViewState
import com.keylesspalace.tusky.entity.Relationship
import com.keylesspalace.tusky.entity.Status
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.util.*
import com.keylesspalace.tusky.util.BiListing
import com.keylesspalace.tusky.util.Error
import com.keylesspalace.tusky.util.Loading
import com.keylesspalace.tusky.util.NetworkState
import com.keylesspalace.tusky.util.Resource
import com.keylesspalace.tusky.util.RxAwareViewModel
import com.keylesspalace.tusky.util.Success
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import javax.inject.Inject

class ReportViewModel @Inject constructor(
        private val mastodonApi: MastodonApi,
        private val eventHub: EventHub,
        private val statusesRepository: StatusesRepository) : RxAwareViewModel() {
    private val mastodonApi: MastodonApi,
    private val eventHub: EventHub,
    private val statusesRepository: StatusesRepository
) : RxAwareViewModel() {

    private val navigationMutable = MutableLiveData<Screen>()
    val navigation: LiveData<Screen> = navigationMutable
    private val navigationMutable = MutableLiveData<Screen?>()
    val navigation: LiveData<Screen?>
        get() = navigationMutable

    private val muteStateMutable = MutableLiveData<Resource<Boolean>>()
    val muteState: LiveData<Resource<Boolean>> = muteStateMutable


@@ 49,14 57,19 @@ class ReportViewModel @Inject constructor(
    private val reportingStateMutable = MutableLiveData<Resource<Boolean>>()
    var reportingState: LiveData<Resource<Boolean>> = reportingStateMutable

    private val checkUrlMutable = MutableLiveData<String>()
    val checkUrl: LiveData<String> = checkUrlMutable
    private val checkUrlMutable = MutableLiveData<String?>()
    val checkUrl: LiveData<String?>
        get() = checkUrlMutable

    private val repoResult = MutableLiveData<BiListing<Status>>()
    val statuses: LiveData<PagedList<Status>> = Transformations.switchMap(repoResult) { it.pagedList }
    val networkStateAfter: LiveData<NetworkState> = Transformations.switchMap(repoResult) { it.networkStateAfter }
    val networkStateBefore: LiveData<NetworkState> = Transformations.switchMap(repoResult) { it.networkStateBefore }
    val networkStateRefresh: LiveData<NetworkState> = Transformations.switchMap(repoResult) { it.refreshState }
    val statuses: LiveData<PagedList<Status>> =
        Transformations.switchMap(repoResult) { it.pagedList }
    val networkStateAfter: LiveData<NetworkState> =
        Transformations.switchMap(repoResult) { it.networkStateAfter }
    val networkStateBefore: LiveData<NetworkState> =
        Transformations.switchMap(repoResult) { it.networkStateBefore }
    val networkStateRefresh: LiveData<NetworkState> =
        Transformations.switchMap(repoResult) { it.refreshState }

    private val selectedIds = HashSet<String>()
    val statusViewState = StatusViewState()


@@ 79,7 92,7 @@ class ReportViewModel @Inject constructor(
        }

        isRemoteAccount = userName.contains('@')
        if (isRemoteAccount) {
        if(isRemoteAccount) {
            remoteServer = userName.substring(userName.indexOf('@') + 1)
        }



@@ 95,29 108,28 @@ class ReportViewModel @Inject constructor(
        navigationMutable.value = null
    }


    private fun obtainRelationship() {
        val ids = listOf(accountId)
        muteStateMutable.value = Loading()
        blockStateMutable.value = Loading()
        mastodonApi.relationships(ids)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                        { data ->
                            updateRelationship(data.getOrNull(0))

                        },
                        {
                            updateRelationship(null)
                        }
                )
                .autoDispose()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                { data ->
                    updateRelationship(data.getOrNull(0))

                },
                {
                    updateRelationship(null)
                }
            )
            .autoDispose()
    }


    private fun updateRelationship(relationship: Relationship?) {
        if (relationship != null) {
        if(relationship != null) {
            muteStateMutable.value = Success(relationship.muting)
            blockStateMutable.value = Success(relationship.blocking)
        } else {


@@ 128,69 140,74 @@ class ReportViewModel @Inject constructor(

    fun toggleMute() {
        val alreadyMuted = muteStateMutable.value?.data == true
        if (alreadyMuted) {
        if(alreadyMuted) {
            mastodonApi.unmuteAccount(accountId)
        } else {
            mastodonApi.muteAccount(accountId)
        }
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                        { relationship ->
                            val muting = relationship?.muting == true
                            muteStateMutable.value = Success(muting)
                            if (muting) {
                                eventHub.dispatch(MuteEvent(accountId, true))
                            }
                        },
                        { error ->
                            muteStateMutable.value = Error(false, error.message)
                        }
                ).autoDispose()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                { relationship ->
                    val muting = relationship?.muting == true
                    muteStateMutable.value = Success(muting)
                    if(muting) {
                        eventHub.dispatch(MuteEvent(accountId, true))
                    }
                },
                { error ->
                    muteStateMutable.value = Error(false, error.message)
                }
            ).autoDispose()

        muteStateMutable.value = Loading()
    }

    fun toggleBlock() {
        val alreadyBlocked = blockStateMutable.value?.data == true
        if (alreadyBlocked) {
        if(alreadyBlocked) {
            mastodonApi.unblockAccount(accountId)
        } else {
            mastodonApi.blockAccount(accountId)
        }
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                        { relationship ->
                            val blocking = relationship?.blocking == true
                            blockStateMutable.value = Success(blocking)
                            if (blocking) {
                                eventHub.dispatch(BlockEvent(accountId))
                            }
                        },
                        { error ->
                            blockStateMutable.value = Error(false, error.message)
                        }
                )
                .autoDispose()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                { relationship ->
                    val blocking = relationship?.blocking == true
                    blockStateMutable.value = Success(blocking)
                    if(blocking) {
                        eventHub.dispatch(BlockEvent(accountId))
                    }
                },
                { error ->
                    blockStateMutable.value = Error(false, error.message)
                }
            )
            .autoDispose()

        blockStateMutable.value = Loading()
    }

    fun doReport() {
        reportingStateMutable.value = Loading()
        mastodonApi.reportObservable(accountId, selectedIds.toList(), reportNote, if (isRemoteAccount) isRemoteNotify else null)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                        {
                            reportingStateMutable.value = Success(true)
                        },
                        { error ->
                            reportingStateMutable.value = Error(cause = error)
                        }
                )
                .autoDispose()
        mastodonApi.reportObservable(
            accountId,
            selectedIds.toList(),
            reportNote,
            if(isRemoteAccount) isRemoteNotify else null
        )
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                {
                    reportingStateMutable.value = Success(true)
                },
                { error ->
                    reportingStateMutable.value = Error(cause = error)
                }
            )
            .autoDispose()

    }



@@ 211,7 228,7 @@ class ReportViewModel @Inject constructor(
    }

    fun setStatusChecked(status: Status, checked: Boolean) {
        if (checked) {
        if(checked) {
            selectedIds.add(status.id)
        } else {
            selectedIds.remove(status.id)


@@ 222,4 239,4 @@ class ReportViewModel @Inject constructor(
        return selectedIds.contains(id)
    }

}
\ No newline at end of file
}