Personal account notes (#1978)
* add personal notes to AccountActivity * use RxJava instead of plain okhttp calls * make AccountViewModel rx aware * hide note input until data is loaded
This commit is contained in:
parent
0d644e8fe3
commit
9ea9926469
|
@ -25,6 +25,7 @@ import android.graphics.Color
|
||||||
import android.graphics.PorterDuff
|
import android.graphics.PorterDuff
|
||||||
import android.graphics.PorterDuffColorFilter
|
import android.graphics.PorterDuffColorFilter
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.text.Editable
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -142,6 +143,9 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
|
||||||
|
|
||||||
if (viewModel.isSelf) {
|
if (viewModel.isSelf) {
|
||||||
updateButtons()
|
updateButtons()
|
||||||
|
saveNoteInfo.hide()
|
||||||
|
} else {
|
||||||
|
saveNoteInfo.visibility = View.INVISIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,8 +352,10 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
|
||||||
viewModel.accountFieldData.observe(this, Observer<List<Either<IdentityProof, Field>>> {
|
viewModel.accountFieldData.observe(this, Observer<List<Either<IdentityProof, Field>>> {
|
||||||
accountFieldAdapter.fields = it
|
accountFieldAdapter.fields = it
|
||||||
accountFieldAdapter.notifyDataSetChanged()
|
accountFieldAdapter.notifyDataSetChanged()
|
||||||
|
|
||||||
})
|
})
|
||||||
|
viewModel.noteSaved.observe(this) {
|
||||||
|
saveNoteInfo.visible(it, View.INVISIBLE)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -636,9 +642,22 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
|
||||||
subscribing = relation.subscribing
|
subscribing = relation.subscribing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
accountNoteTextInputLayout.visible(relation.note != null)
|
||||||
|
accountNoteTextInputLayout.editText?.setText(relation.note)
|
||||||
|
|
||||||
|
// add the listener late to avoid it firing on the first change
|
||||||
|
accountNoteTextInputLayout.editText?.removeTextChangedListener(noteWatcher)
|
||||||
|
accountNoteTextInputLayout.editText?.addTextChangedListener(noteWatcher)
|
||||||
|
|
||||||
updateButtons()
|
updateButtons()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val noteWatcher = object: DefaultTextWatcher() {
|
||||||
|
override fun afterTextChanged(s: Editable) {
|
||||||
|
viewModel.noteChanged(s.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateFollowButton() {
|
private fun updateFollowButton() {
|
||||||
if (viewModel.isSelf) {
|
if (viewModel.isSelf) {
|
||||||
accountFollowButton.setText(R.string.action_edit_own_profile)
|
accountFollowButton.setText(R.string.action_edit_own_profile)
|
||||||
|
|
|
@ -100,7 +100,7 @@ class ReportViewModel @Inject constructor(
|
||||||
val ids = listOf(accountId)
|
val ids = listOf(accountId)
|
||||||
muteStateMutable.value = Loading()
|
muteStateMutable.value = Loading()
|
||||||
blockStateMutable.value = Loading()
|
blockStateMutable.value = Loading()
|
||||||
mastodonApi.relationshipsObservable(ids)
|
mastodonApi.relationships(ids)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(
|
.subscribe(
|
||||||
|
@ -129,9 +129,9 @@ class ReportViewModel @Inject constructor(
|
||||||
fun toggleMute() {
|
fun toggleMute() {
|
||||||
val alreadyMuted = muteStateMutable.value?.data == true
|
val alreadyMuted = muteStateMutable.value?.data == true
|
||||||
if (alreadyMuted) {
|
if (alreadyMuted) {
|
||||||
mastodonApi.unmuteAccountObservable(accountId)
|
mastodonApi.unmuteAccount(accountId)
|
||||||
} else {
|
} else {
|
||||||
mastodonApi.muteAccountObservable(accountId)
|
mastodonApi.muteAccount(accountId)
|
||||||
}
|
}
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
@ -154,9 +154,9 @@ class ReportViewModel @Inject constructor(
|
||||||
fun toggleBlock() {
|
fun toggleBlock() {
|
||||||
val alreadyBlocked = blockStateMutable.value?.data == true
|
val alreadyBlocked = blockStateMutable.value?.data == true
|
||||||
if (alreadyBlocked) {
|
if (alreadyBlocked) {
|
||||||
mastodonApi.unblockAccountObservable(accountId)
|
mastodonApi.unblockAccount(accountId)
|
||||||
} else {
|
} else {
|
||||||
mastodonApi.blockAccountObservable(accountId)
|
mastodonApi.blockAccount(accountId)
|
||||||
}
|
}
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
|
|
@ -27,4 +27,5 @@ data class Relationship (
|
||||||
@SerializedName("showing_reblogs") val showingReblogs: Boolean,
|
@SerializedName("showing_reblogs") val showingReblogs: Boolean,
|
||||||
val subscribing: Boolean? = null, // Pleroma extension
|
val subscribing: Boolean? = null, // Pleroma extension
|
||||||
@SerializedName("domain_blocking") val blockingDomain: Boolean
|
@SerializedName("domain_blocking") val blockingDomain: Boolean
|
||||||
|
val note: String? // nullable for backward compatibility / feature detection
|
||||||
)
|
)
|
||||||
|
|
|
@ -49,7 +49,6 @@ import retrofit2.Response
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
||||||
class AccountListFragment : BaseFragment(), AccountActionListener, Injectable {
|
class AccountListFragment : BaseFragment(), AccountActionListener, Injectable {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
|
@ -113,28 +112,18 @@ class AccountListFragment : BaseFragment(), AccountActionListener, Injectable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMute(mute: Boolean, id: String, position: Int) {
|
override fun onMute(mute: Boolean, id: String, position: Int, notifications: Boolean) {
|
||||||
val callback = object : Callback<Relationship> {
|
if (!mute) {
|
||||||
override fun onResponse(call: Call<Relationship>, response: Response<Relationship>) {
|
|
||||||
if (response.isSuccessful) {
|
|
||||||
onMuteSuccess(mute, id, position)
|
|
||||||
} else {
|
|
||||||
onMuteFailure(mute, id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(call: Call<Relationship>, t: Throwable) {
|
|
||||||
onMuteFailure(mute, id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val call = if (!mute) {
|
|
||||||
api.unmuteAccount(id)
|
api.unmuteAccount(id)
|
||||||
} else {
|
} else {
|
||||||
api.muteAccount(id)
|
api.muteAccount(id)
|
||||||
}
|
}
|
||||||
callList.add(call)
|
.autoDispose(from(this))
|
||||||
call.enqueue(callback)
|
.subscribe({
|
||||||
|
onMuteSuccess(mute, id, position, notifications)
|
||||||
|
}, {
|
||||||
|
onMuteFailure(mute, id, notifications)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onMuteSuccess(muted: Boolean, id: String, position: Int) {
|
private fun onMuteSuccess(muted: Boolean, id: String, position: Int) {
|
||||||
|
@ -164,27 +153,17 @@ class AccountListFragment : BaseFragment(), AccountActionListener, Injectable {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBlock(block: Boolean, id: String, position: Int) {
|
override fun onBlock(block: Boolean, id: String, position: Int) {
|
||||||
val cb = object : Callback<Relationship> {
|
if (!block) {
|
||||||
override fun onResponse(call: Call<Relationship>, response: Response<Relationship>) {
|
|
||||||
if (response.isSuccessful) {
|
|
||||||
onBlockSuccess(block, id, position)
|
|
||||||
} else {
|
|
||||||
onBlockFailure(block, id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(call: Call<Relationship>, t: Throwable) {
|
|
||||||
onBlockFailure(block, id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val call = if (!block) {
|
|
||||||
api.unblockAccount(id)
|
api.unblockAccount(id)
|
||||||
} else {
|
} else {
|
||||||
api.blockAccount(id)
|
api.blockAccount(id)
|
||||||
}
|
}
|
||||||
callList.add(call)
|
.autoDispose(from(this))
|
||||||
call.enqueue(cb)
|
.subscribe({
|
||||||
|
onBlockSuccess(block, id, position)
|
||||||
|
}, {
|
||||||
|
onBlockFailure(block, id)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onBlockSuccess(blocked: Boolean, id: String, position: Int) {
|
private fun onBlockSuccess(blocked: Boolean, id: String, position: Int) {
|
||||||
|
@ -366,6 +345,28 @@ class AccountListFragment : BaseFragment(), AccountActionListener, Injectable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
private fun fetchRelationships(ids: List<String>) {
|
||||||
|
api.relationships(ids)
|
||||||
|
.autoDispose(from(this))
|
||||||
|
.subscribe(::onFetchRelationshipsSuccess) {
|
||||||
|
onFetchRelationshipsFailure(ids)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onFetchRelationshipsSuccess(relationships: List<Relationship>) {
|
||||||
|
val mutesAdapter = adapter as MutesAdapter
|
||||||
|
val mutingNotificationsMap = HashMap<String, Boolean>()
|
||||||
|
relationships.map { mutingNotificationsMap.put(it.id, it.mutingNotifications) }
|
||||||
|
mutesAdapter.updateMutingNotificationsMap(mutingNotificationsMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onFetchRelationshipsFailure(ids: List<String>) {
|
||||||
|
Log.e(TAG, "Fetch failure for relationships of accounts: $ids")
|
||||||
|
}
|
||||||
|
|
||||||
|
>>>>>>> ce973ea7... Personal account notes (#1978)
|
||||||
private fun onFetchAccountsFailure(throwable: Throwable) {
|
private fun onFetchAccountsFailure(throwable: Throwable) {
|
||||||
fetching = false
|
fetching = false
|
||||||
Log.e(TAG, "Fetch failure", throwable)
|
Log.e(TAG, "Fetch failure", throwable)
|
||||||
|
|
|
@ -271,7 +271,7 @@ interface MastodonApi {
|
||||||
@GET("api/v1/accounts/{id}")
|
@GET("api/v1/accounts/{id}")
|
||||||
fun account(
|
fun account(
|
||||||
@Path("id") accountId: String
|
@Path("id") accountId: String
|
||||||
): Call<Account>
|
): Single<Account>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to fetch statuses for the specified account.
|
* Method to fetch statuses for the specified account.
|
||||||
|
@ -310,42 +310,43 @@ interface MastodonApi {
|
||||||
fun followAccount(
|
fun followAccount(
|
||||||
@Path("id") accountId: String,
|
@Path("id") accountId: String,
|
||||||
@Field("reblogs") showReblogs: Boolean
|
@Field("reblogs") showReblogs: Boolean
|
||||||
): Call<Relationship>
|
): Single<Relationship>
|
||||||
|
|
||||||
@POST("api/v1/accounts/{id}/unfollow")
|
@POST("api/v1/accounts/{id}/unfollow")
|
||||||
fun unfollowAccount(
|
fun unfollowAccount(
|
||||||
@Path("id") accountId: String
|
@Path("id") accountId: String
|
||||||
): Call<Relationship>
|
): Single<Relationship>
|
||||||
|
|
||||||
@POST("api/v1/accounts/{id}/block")
|
@POST("api/v1/accounts/{id}/block")
|
||||||
fun blockAccount(
|
fun blockAccount(
|
||||||
@Path("id") accountId: String
|
@Path("id") accountId: String
|
||||||
): Call<Relationship>
|
): Single<Relationship>
|
||||||
|
|
||||||
@POST("api/v1/accounts/{id}/unblock")
|
@POST("api/v1/accounts/{id}/unblock")
|
||||||
fun unblockAccount(
|
fun unblockAccount(
|
||||||
@Path("id") accountId: String
|
@Path("id") accountId: String
|
||||||
): Call<Relationship>
|
): Single<Relationship>
|
||||||
|
|
||||||
@POST("api/v1/accounts/{id}/mute")
|
@POST("api/v1/accounts/{id}/mute")
|
||||||
fun muteAccount(
|
fun muteAccount(
|
||||||
@Path("id") accountId: String
|
@Path("id") accountId: String,
|
||||||
): Call<Relationship>
|
@Field("notifications") notifications: Boolean? = null
|
||||||
|
): Single<Relationship>
|
||||||
|
|
||||||
@POST("api/v1/accounts/{id}/unmute")
|
@POST("api/v1/accounts/{id}/unmute")
|
||||||
fun unmuteAccount(
|
fun unmuteAccount(
|
||||||
@Path("id") accountId: String
|
@Path("id") accountId: String
|
||||||
): Call<Relationship>
|
): Single<Relationship>
|
||||||
|
|
||||||
@GET("api/v1/accounts/relationships")
|
@GET("api/v1/accounts/relationships")
|
||||||
fun relationships(
|
fun relationships(
|
||||||
@Query("id[]") accountIds: List<String>
|
@Query("id[]") accountIds: List<String>
|
||||||
): Call<List<Relationship>>
|
): Single<List<Relationship>>
|
||||||
|
|
||||||
@GET("api/v1/accounts/{id}/identity_proofs")
|
@GET("api/v1/accounts/{id}/identity_proofs")
|
||||||
fun identityProofs(
|
fun identityProofs(
|
||||||
@Path("id") accountId: String
|
@Path("id") accountId: String
|
||||||
): Call<List<IdentityProof>>
|
): Single<List<IdentityProof>>
|
||||||
|
|
||||||
@POST("api/v1/pleroma/accounts/{id}/subscribe")
|
@POST("api/v1/pleroma/accounts/{id}/subscribe")
|
||||||
fun subscribeAccount(
|
fun subscribeAccount(
|
||||||
|
@ -519,6 +520,7 @@ interface MastodonApi {
|
||||||
@Field("choices[]") choices: List<Int>
|
@Field("choices[]") choices: List<Int>
|
||||||
): Single<Poll>
|
): Single<Poll>
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
@POST("api/v1/accounts/{id}/block")
|
@POST("api/v1/accounts/{id}/block")
|
||||||
fun blockAccountObservable(
|
fun blockAccountObservable(
|
||||||
@Path("id") accountId: String
|
@Path("id") accountId: String
|
||||||
|
@ -554,6 +556,8 @@ interface MastodonApi {
|
||||||
@Query("id[]") accountIds: List<String>
|
@Query("id[]") accountIds: List<String>
|
||||||
): Single<List<Relationship>>
|
): Single<List<Relationship>>
|
||||||
|
|
||||||
|
=======
|
||||||
|
>>>>>>> ce973ea7... Personal account notes (#1978)
|
||||||
@FormUrlEncoded
|
@FormUrlEncoded
|
||||||
@POST("api/v1/reports")
|
@POST("api/v1/reports")
|
||||||
fun reportObservable(
|
fun reportObservable(
|
||||||
|
@ -673,8 +677,18 @@ interface MastodonApi {
|
||||||
@Path("id") accountId: String
|
@Path("id") accountId: String
|
||||||
): Single<Chat>
|
): Single<Chat>
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
@GET("api/v1/pleroma/chats/{id}")
|
@GET("api/v1/pleroma/chats/{id}")
|
||||||
fun getChat(
|
fun getChat(
|
||||||
@Path("id") chatId: String
|
@Path("id") chatId: String
|
||||||
): Single<Chat>
|
): Single<Chat>
|
||||||
|
=======
|
||||||
|
@FormUrlEncoded
|
||||||
|
@POST("api/v1/accounts/{id}/note")
|
||||||
|
fun updateAccountNote(
|
||||||
|
@Path("id") accountId: String,
|
||||||
|
@Field("comment") note: String
|
||||||
|
): Single<Relationship>
|
||||||
|
|
||||||
|
>>>>>>> ce973ea7... Personal account notes (#1978)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,17 +15,14 @@
|
||||||
|
|
||||||
package com.keylesspalace.tusky.network
|
package com.keylesspalace.tusky.network
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import com.keylesspalace.tusky.appstore.*
|
import com.keylesspalace.tusky.appstore.*
|
||||||
import com.keylesspalace.tusky.entity.DeletedStatus
|
import com.keylesspalace.tusky.entity.DeletedStatus
|
||||||
import com.keylesspalace.tusky.entity.Poll
|
import com.keylesspalace.tusky.entity.Poll
|
||||||
import com.keylesspalace.tusky.entity.Relationship
|
|
||||||
import com.keylesspalace.tusky.entity.Status
|
import com.keylesspalace.tusky.entity.Status
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxkotlin.addTo
|
import io.reactivex.rxkotlin.addTo
|
||||||
import retrofit2.Call
|
|
||||||
import retrofit2.Callback
|
|
||||||
import retrofit2.Response
|
|
||||||
import java.lang.IllegalStateException
|
import java.lang.IllegalStateException
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
|
||||||
|
@ -96,36 +93,37 @@ class TimelineCasesImpl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mute(id: String) {
|
override fun muteConversation(status: Status, mute: Boolean): Single<Status> {
|
||||||
val call = mastodonApi.muteAccount(id)
|
|
||||||
call.enqueue(object : Callback<Relationship> {
|
|
||||||
override fun onResponse(call: Call<Relationship>, response: Response<Relationship>) {}
|
|
||||||
|
|
||||||
override fun onFailure(call: Call<Relationship>, t: Throwable) {}
|
|
||||||
})
|
|
||||||
eventHub.dispatch(MuteEvent(id, true))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun muteStatus(status: Status, mute: Boolean) {
|
|
||||||
val id = status.actionableId
|
val id = status.actionableId
|
||||||
|
|
||||||
(if (mute) {
|
val call = if (mute) {
|
||||||
mastodonApi.muteStatus(id)
|
mastodonApi.muteConversation(id)
|
||||||
} else {
|
} else {
|
||||||
mastodonApi.unmuteStatus(id)
|
mastodonApi.unmuteConversation(id)
|
||||||
}).subscribe( { status ->
|
}
|
||||||
eventHub.dispatch(MuteStatusEvent(status.id, mute))
|
return call.doAfterSuccess {
|
||||||
}, {}).addTo(this.cancelDisposable)
|
eventHub.dispatch(MuteConversationEvent(status.id, mute))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mute(id: String, notifications: Boolean) {
|
||||||
|
mastodonApi.muteAccount(id, notifications)
|
||||||
|
.subscribe({
|
||||||
|
eventHub.dispatch(MuteEvent(id))
|
||||||
|
}, { t ->
|
||||||
|
Log.w("Failed to mute account", t)
|
||||||
|
})
|
||||||
|
.addTo(cancelDisposable)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun block(id: String) {
|
override fun block(id: String) {
|
||||||
val call = mastodonApi.blockAccount(id)
|
mastodonApi.blockAccount(id)
|
||||||
call.enqueue(object : Callback<Relationship> {
|
.subscribe({
|
||||||
override fun onResponse(call: Call<Relationship>, response: Response<Relationship>) {}
|
eventHub.dispatch(BlockEvent(id))
|
||||||
|
}, { t ->
|
||||||
override fun onFailure(call: Call<Relationship>, t: Throwable) {}
|
Log.w("Failed to block account", t)
|
||||||
})
|
})
|
||||||
eventHub.dispatch(BlockEvent(id))
|
.addTo(cancelDisposable)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun delete(id: String): Single<DeletedStatus> {
|
override fun delete(id: String): Single<DeletedStatus> {
|
||||||
|
|
|
@ -2,7 +2,6 @@ package com.keylesspalace.tusky.viewmodel
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import com.keylesspalace.tusky.appstore.*
|
import com.keylesspalace.tusky.appstore.*
|
||||||
import com.keylesspalace.tusky.db.AccountManager
|
import com.keylesspalace.tusky.db.AccountManager
|
||||||
import com.keylesspalace.tusky.entity.Account
|
import com.keylesspalace.tusky.entity.Account
|
||||||
|
@ -11,21 +10,25 @@ import com.keylesspalace.tusky.entity.IdentityProof
|
||||||
import com.keylesspalace.tusky.entity.Relationship
|
import com.keylesspalace.tusky.entity.Relationship
|
||||||
import com.keylesspalace.tusky.network.MastodonApi
|
import com.keylesspalace.tusky.network.MastodonApi
|
||||||
import com.keylesspalace.tusky.util.*
|
import com.keylesspalace.tusky.util.*
|
||||||
|
import io.reactivex.Single
|
||||||
import io.reactivex.disposables.Disposable
|
import io.reactivex.disposables.Disposable
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.Callback
|
import retrofit2.Callback
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class AccountViewModel @Inject constructor(
|
class AccountViewModel @Inject constructor(
|
||||||
private val mastodonApi: MastodonApi,
|
private val mastodonApi: MastodonApi,
|
||||||
private val eventHub: EventHub,
|
private val eventHub: EventHub,
|
||||||
private val accountManager: AccountManager
|
private val accountManager: AccountManager
|
||||||
) : ViewModel() {
|
) : RxAwareViewModel() {
|
||||||
|
|
||||||
val accountData = MutableLiveData<Resource<Account>>()
|
val accountData = MutableLiveData<Resource<Account>>()
|
||||||
val relationshipData = MutableLiveData<Resource<Relationship>>()
|
val relationshipData = MutableLiveData<Resource<Relationship>>()
|
||||||
|
|
||||||
|
val noteSaved = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
private val identityProofData = MutableLiveData<List<IdentityProof>>()
|
private val identityProofData = MutableLiveData<List<IdentityProof>>()
|
||||||
|
|
||||||
val accountFieldData = combineOptionalLiveData(accountData, identityProofData) { accountRes, identityProofs ->
|
val accountFieldData = combineOptionalLiveData(accountData, identityProofData) { accountRes, identityProofs ->
|
||||||
|
@ -33,48 +36,40 @@ class AccountViewModel @Inject constructor(
|
||||||
.plus(accountRes?.data?.fields.orEmpty().map { Either.Right<IdentityProof, Field>(it) })
|
.plus(accountRes?.data?.fields.orEmpty().map { Either.Right<IdentityProof, Field>(it) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private val callList: MutableList<Call<*>> = mutableListOf()
|
|
||||||
private val disposable: Disposable = eventHub.events
|
|
||||||
.subscribe { event ->
|
|
||||||
if (event is ProfileEditedEvent && event.newProfileData.id == accountData.value?.data?.id) {
|
|
||||||
accountData.postValue(Success(event.newProfileData))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val isRefreshing = MutableLiveData<Boolean>().apply { value = false }
|
val isRefreshing = MutableLiveData<Boolean>().apply { value = false }
|
||||||
private var isDataLoading = false
|
private var isDataLoading = false
|
||||||
|
|
||||||
lateinit var accountId: String
|
lateinit var accountId: String
|
||||||
var isSelf = false
|
var isSelf = false
|
||||||
|
|
||||||
|
private var noteDisposable: Disposable? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
eventHub.events
|
||||||
|
.subscribe { event ->
|
||||||
|
if (event is ProfileEditedEvent && event.newProfileData.id == accountData.value?.data?.id) {
|
||||||
|
accountData.postValue(Success(event.newProfileData))
|
||||||
|
}
|
||||||
|
}.autoDispose()
|
||||||
|
}
|
||||||
|
|
||||||
private fun obtainAccount(reload: Boolean = false) {
|
private fun obtainAccount(reload: Boolean = false) {
|
||||||
if (accountData.value == null || reload) {
|
if (accountData.value == null || reload) {
|
||||||
isDataLoading = true
|
isDataLoading = true
|
||||||
accountData.postValue(Loading())
|
accountData.postValue(Loading())
|
||||||
|
|
||||||
val call = mastodonApi.account(accountId)
|
mastodonApi.account(accountId)
|
||||||
call.enqueue(object : Callback<Account> {
|
.subscribe({ account ->
|
||||||
override fun onResponse(call: Call<Account>,
|
accountData.postValue(Success(account))
|
||||||
response: Response<Account>) {
|
isDataLoading = false
|
||||||
if (response.isSuccessful) {
|
isRefreshing.postValue(false)
|
||||||
accountData.postValue(Success(response.body()))
|
}, {t ->
|
||||||
} else {
|
Log.w(TAG, "failed obtaining account", t)
|
||||||
accountData.postValue(Error())
|
accountData.postValue(Error())
|
||||||
}
|
isDataLoading = false
|
||||||
isDataLoading = false
|
isRefreshing.postValue(false)
|
||||||
isRefreshing.postValue(false)
|
})
|
||||||
}
|
.autoDispose()
|
||||||
|
|
||||||
override fun onFailure(call: Call<Account>, t: Throwable) {
|
|
||||||
Log.w(TAG, "failed obtaining account", t)
|
|
||||||
accountData.postValue(Error())
|
|
||||||
isDataLoading = false
|
|
||||||
isRefreshing.postValue(false)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
callList.add(call)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,51 +78,27 @@ class AccountViewModel @Inject constructor(
|
||||||
|
|
||||||
relationshipData.postValue(Loading())
|
relationshipData.postValue(Loading())
|
||||||
|
|
||||||
val ids = listOf(accountId)
|
mastodonApi.relationships(listOf(accountId))
|
||||||
val call = mastodonApi.relationships(ids)
|
.subscribe({ relationships ->
|
||||||
call.enqueue(object : Callback<List<Relationship>> {
|
relationshipData.postValue(Success(relationships[0]))
|
||||||
override fun onResponse(call: Call<List<Relationship>>,
|
}, { t ->
|
||||||
response: Response<List<Relationship>>) {
|
Log.w(TAG, "failed obtaining relationships", t)
|
||||||
val relationships = response.body()
|
|
||||||
if (response.isSuccessful && relationships != null && relationships.getOrNull(0) != null) {
|
|
||||||
val relationship = relationships[0]
|
|
||||||
relationshipData.postValue(Success(relationship))
|
|
||||||
} else {
|
|
||||||
relationshipData.postValue(Error())
|
relationshipData.postValue(Error())
|
||||||
}
|
})
|
||||||
}
|
.autoDispose()
|
||||||
|
|
||||||
override fun onFailure(call: Call<List<Relationship>>, t: Throwable) {
|
|
||||||
Log.w(TAG, "failed obtaining relationships", t)
|
|
||||||
relationshipData.postValue(Error())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
callList.add(call)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun obtainIdentityProof(reload: Boolean = false) {
|
private fun obtainIdentityProof(reload: Boolean = false) {
|
||||||
if (identityProofData.value == null || reload) {
|
if (identityProofData.value == null || reload) {
|
||||||
|
|
||||||
val call = mastodonApi.identityProofs(accountId)
|
mastodonApi.identityProofs(accountId)
|
||||||
call.enqueue(object : Callback<List<IdentityProof>> {
|
.subscribe({ proofs ->
|
||||||
override fun onResponse(call: Call<List<IdentityProof>>,
|
|
||||||
response: Response<List<IdentityProof>>) {
|
|
||||||
val proofs = response.body()
|
|
||||||
if (response.isSuccessful && proofs != null ) {
|
|
||||||
identityProofData.postValue(proofs)
|
identityProofData.postValue(proofs)
|
||||||
} else {
|
}, { t ->
|
||||||
identityProofData.postValue(emptyList())
|
Log.w(TAG, "failed obtaining identity proofs", t)
|
||||||
}
|
})
|
||||||
}
|
.autoDispose()
|
||||||
|
|
||||||
override fun onFailure(call: Call<List<IdentityProof>>, t: Throwable) {
|
|
||||||
Log.w(TAG, "failed obtaining identity proofs", t)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
callList.add(call)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,11 +208,17 @@ class AccountViewModel @Inject constructor(
|
||||||
relationshipData.postValue(Loading(newRelation))
|
relationshipData.postValue(Loading(newRelation))
|
||||||
}
|
}
|
||||||
|
|
||||||
val callback = object : Callback<Relationship> {
|
when (relationshipAction) {
|
||||||
override fun onResponse(call: Call<Relationship>,
|
RelationShipAction.FOLLOW -> mastodonApi.followAccount(accountId, parameter ?: true)
|
||||||
response: Response<Relationship>) {
|
RelationShipAction.UNFOLLOW -> mastodonApi.unfollowAccount(accountId)
|
||||||
val relationship = response.body()
|
RelationShipAction.BLOCK -> mastodonApi.blockAccount(accountId)
|
||||||
if (response.isSuccessful && relationship != null) {
|
RelationShipAction.UNBLOCK -> mastodonApi.unblockAccount(accountId)
|
||||||
|
RelationShipAction.MUTE -> mastodonApi.muteAccount(accountId, parameter ?: true)
|
||||||
|
RelationShipAction.UNMUTE -> mastodonApi.unmuteAccount(accountId)
|
||||||
|
RelationShipAction.SUBSCRIBE -> mastodonApi.subscribeAccount(accountId)
|
||||||
|
RelationShipAction.UNSUBSCRIBE -> mastodonApi.unsubscribeAccount(accountId)
|
||||||
|
}.subscribe(
|
||||||
|
{ relationship ->
|
||||||
relationshipData.postValue(Success(relationship))
|
relationshipData.postValue(Success(relationship))
|
||||||
|
|
||||||
when (relationshipAction) {
|
when (relationshipAction) {
|
||||||
|
@ -252,38 +229,35 @@ class AccountViewModel @Inject constructor(
|
||||||
else -> {
|
else -> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
} else {
|
{
|
||||||
relationshipData.postValue(Error(relation))
|
relationshipData.postValue(Error(relation))
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
.autoDispose()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
fun noteChanged(newNote: String) {
|
||||||
|
noteSaved.postValue(false)
|
||||||
override fun onFailure(call: Call<Relationship>, t: Throwable) {
|
noteDisposable?.dispose()
|
||||||
relationshipData.postValue(Error(relation))
|
noteDisposable = Single.timer(1500, TimeUnit.MILLISECONDS)
|
||||||
}
|
.flatMap {
|
||||||
}
|
mastodonApi.updateAccountNote(accountId, newNote)
|
||||||
|
}
|
||||||
val call = when (relationshipAction) {
|
.doOnSuccess {
|
||||||
RelationShipAction.FOLLOW -> mastodonApi.followAccount(accountId, showReblogs)
|
noteSaved.postValue(true)
|
||||||
RelationShipAction.UNFOLLOW -> mastodonApi.unfollowAccount(accountId)
|
}
|
||||||
RelationShipAction.BLOCK -> mastodonApi.blockAccount(accountId)
|
.delay(4, TimeUnit.SECONDS)
|
||||||
RelationShipAction.UNBLOCK -> mastodonApi.unblockAccount(accountId)
|
.subscribe({
|
||||||
RelationShipAction.MUTE -> mastodonApi.muteAccount(accountId)
|
noteSaved.postValue(false)
|
||||||
RelationShipAction.UNMUTE -> mastodonApi.unmuteAccount(accountId)
|
}, {
|
||||||
RelationShipAction.SUBSCRIBE -> mastodonApi.subscribeAccount(accountId)
|
Log.e(TAG, "Error updating note", it)
|
||||||
RelationShipAction.UNSUBSCRIBE -> mastodonApi.unsubscribeAccount(accountId)
|
})
|
||||||
}
|
|
||||||
|
|
||||||
call.enqueue(callback)
|
|
||||||
callList.add(call)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
callList.forEach {
|
super.onCleared()
|
||||||
it.cancel()
|
noteDisposable?.dispose()
|
||||||
}
|
|
||||||
disposable.dispose()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun refresh() {
|
fun refresh() {
|
||||||
|
|
|
@ -218,16 +218,43 @@
|
||||||
app:barrierDirection="bottom"
|
app:barrierDirection="bottom"
|
||||||
app:constraint_referenced_ids="accountAdminTextView,accountModeratorTextView,accountFollowsYouTextView,accountBadgeTextView" />
|
app:constraint_referenced_ids="accountAdminTextView,accountModeratorTextView,accountFollowsYouTextView,accountBadgeTextView" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/accountNoteTextInputLayout"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.Dense"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/labelBarrier"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/account_note_hint" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/saveNoteInfo"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/account_note_saved"
|
||||||
|
android:textColor="@color/tusky_blue"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/accountNoteTextInputLayout" />
|
||||||
|
|
||||||
<androidx.emoji.widget.EmojiTextView
|
<androidx.emoji.widget.EmojiTextView
|
||||||
android:id="@+id/accountNoteTextView"
|
android:id="@+id/accountNoteTextView"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hyphenationFrequency="full"
|
android:hyphenationFrequency="full"
|
||||||
android:lineSpacingMultiplier="1.1"
|
android:lineSpacingMultiplier="1.1"
|
||||||
android:paddingTop="10dp"
|
android:paddingTop="2dp"
|
||||||
android:textColor="?android:textColorTertiary"
|
android:textColor="?android:textColorTertiary"
|
||||||
android:textSize="?attr/status_text_medium"
|
android:textSize="?attr/status_text_medium"
|
||||||
app:layout_constraintTop_toBottomOf="@id/labelBarrier"
|
app:layout_constraintTop_toBottomOf="@id/saveNoteInfo"
|
||||||
tools:text="This is a test description. Descriptions can be quite looooong." />
|
tools:text="This is a test description. Descriptions can be quite looooong." />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
@ -294,6 +321,7 @@
|
||||||
android:text="@string/title_statuses"
|
android:text="@string/title_statuses"
|
||||||
android:textColor="@color/account_tab_font_color"
|
android:textColor="@color/account_tab_font_color"
|
||||||
android:textSize="?attr/status_text_medium" />
|
android:textSize="?attr/status_text_medium" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|
|
@ -573,5 +573,7 @@
|
||||||
<string name="pref_title_show_cards_in_timelines">Show link previews in timelines</string>
|
<string name="pref_title_show_cards_in_timelines">Show link previews in timelines</string>
|
||||||
<string name="pref_title_confirm_reblogs">Show confirmation dialog before boosting</string>
|
<string name="pref_title_confirm_reblogs">Show confirmation dialog before boosting</string>
|
||||||
<string name="pref_title_hide_top_toolbar">Hide the title of the top toolbar</string>
|
<string name="pref_title_hide_top_toolbar">Hide the title of the top toolbar</string>
|
||||||
|
<string name="account_note_hint">Your private note about this account</string>
|
||||||
|
<string name="account_note_saved">Saved!</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue