Add support for instance property `max_bio_chars` (#1414)
* Migrate getInstance from Call to Single * Add support for instance max_bio_chars. Addresses #1329
This commit is contained in:
parent
9805a985b2
commit
ce01e6de22
|
@ -313,22 +313,9 @@ public final class ComposeActivity
|
|||
getString(R.string.compose_active_account_description,
|
||||
activeAccount.getFullName()));
|
||||
|
||||
mastodonApi.getInstance().enqueue(new Callback<Instance>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<Instance> call, @NonNull Response<Instance> response) {
|
||||
if (response.isSuccessful() && response.body().getMaxTootChars() != null) {
|
||||
maximumTootCharacters = response.body().getMaxTootChars();
|
||||
updateVisibleCharactersLeft();
|
||||
cacheInstanceMetadata(activeAccount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<Instance> call, @NonNull Throwable t) {
|
||||
Log.w(TAG, "error loading instance data", t);
|
||||
loadCachedInstanceMetadata(activeAccount);
|
||||
}
|
||||
});
|
||||
mastodonApi.getInstance()
|
||||
.as(autoDisposable(from(this, Lifecycle.Event.ON_DESTROY)))
|
||||
.subscribe(this::onFetchInstanceSuccess, this::onFetchInstanceFailure);
|
||||
|
||||
mastodonApi.getCustomEmojis().enqueue(new Callback<List<Emoji>>() {
|
||||
@Override
|
||||
|
@ -1851,6 +1838,19 @@ public final class ComposeActivity
|
|||
(mimeType.startsWith("image/") || mimeType.startsWith("video/") || mimeType.equals("text/plain")));
|
||||
}
|
||||
|
||||
private void onFetchInstanceSuccess(Instance instance) {
|
||||
if (instance != null && instance.getMaxTootChars() != null) {
|
||||
maximumTootCharacters = instance.getMaxTootChars();
|
||||
updateVisibleCharactersLeft();
|
||||
cacheInstanceMetadata(accountManager.getActiveAccount());
|
||||
}
|
||||
}
|
||||
|
||||
private void onFetchInstanceFailure(Throwable throwable) {
|
||||
Log.w(TAG, "error loading instance data", throwable);
|
||||
loadCachedInstanceMetadata(accountManager.getActiveAccount());
|
||||
}
|
||||
|
||||
public static final class QueuedMedia {
|
||||
Type type;
|
||||
ProgressImageView preview;
|
||||
|
|
|
@ -41,6 +41,7 @@ import com.keylesspalace.tusky.adapter.AccountFieldEditAdapter
|
|||
import com.keylesspalace.tusky.di.Injectable
|
||||
import com.keylesspalace.tusky.di.ViewModelFactory
|
||||
import com.keylesspalace.tusky.entity.Account
|
||||
import com.keylesspalace.tusky.entity.Instance
|
||||
import com.keylesspalace.tusky.util.*
|
||||
import com.keylesspalace.tusky.viewmodel.EditProfileViewModel
|
||||
import com.mikepenz.google_material_typeface_library.GoogleMaterial
|
||||
|
@ -164,6 +165,18 @@ class EditProfileActivity : BaseActivity(), Injectable {
|
|||
}
|
||||
})
|
||||
|
||||
viewModel.obtainInstance()
|
||||
viewModel.instanceData.observe(this, Observer<Resource<Instance>> { result ->
|
||||
when (result) {
|
||||
is Success -> {
|
||||
val instance = result.data
|
||||
if (instance?.maxBioChars != null && instance.maxBioChars > 0) {
|
||||
noteEditTextLayout.counterMaxLength = instance.maxBioChars
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
observeImage(viewModel.avatarData, avatarPreview, avatarProgressBar, true)
|
||||
observeImage(viewModel.headerData, headerPreview, headerProgressBar, false)
|
||||
|
||||
|
|
|
@ -28,7 +28,8 @@ data class Instance (
|
|||
val thumbnail: String?,
|
||||
val languages: List<String>,
|
||||
@SerializedName("contact_account") val contactAccount: Account,
|
||||
@SerializedName("max_toot_chars") val maxTootChars: Int?
|
||||
@SerializedName("max_toot_chars") val maxTootChars: Int?,
|
||||
@SerializedName("max_bio_chars") val maxBioChars: Int?
|
||||
) {
|
||||
override fun hashCode(): Int {
|
||||
return uri.hashCode()
|
||||
|
|
|
@ -358,7 +358,7 @@ public interface MastodonApi {
|
|||
Call<List<Emoji>> getCustomEmojis();
|
||||
|
||||
@GET("api/v1/instance")
|
||||
Call<Instance> getInstance();
|
||||
Single<Instance> getInstance();
|
||||
|
||||
@GET("/api/v1/conversations")
|
||||
Call<List<Conversation>> getConversations(@Nullable @Query("max_id") String maxId, @Query("limit") int limit);
|
||||
|
|
|
@ -27,6 +27,7 @@ import com.keylesspalace.tusky.EditProfileActivity.Companion.HEADER_WIDTH
|
|||
import com.keylesspalace.tusky.appstore.EventHub
|
||||
import com.keylesspalace.tusky.appstore.ProfileEditedEvent
|
||||
import com.keylesspalace.tusky.entity.Account
|
||||
import com.keylesspalace.tusky.entity.Instance
|
||||
import com.keylesspalace.tusky.entity.StringField
|
||||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import com.keylesspalace.tusky.util.*
|
||||
|
@ -64,6 +65,7 @@ class EditProfileViewModel @Inject constructor(
|
|||
val avatarData = MutableLiveData<Resource<Bitmap>>()
|
||||
val headerData = MutableLiveData<Resource<Bitmap>>()
|
||||
val saveData = MutableLiveData<Resource<Nothing>>()
|
||||
val instanceData = MutableLiveData<Resource<Instance>>()
|
||||
|
||||
private var oldProfileData: Account? = null
|
||||
|
||||
|
@ -267,5 +269,20 @@ class EditProfileViewModel @Inject constructor(
|
|||
disposeables.dispose()
|
||||
}
|
||||
|
||||
fun obtainInstance() {
|
||||
if(instanceData.value == null || instanceData.value is Error) {
|
||||
instanceData.postValue(Loading())
|
||||
|
||||
mastodonApi.instance.subscribe(
|
||||
{instance ->
|
||||
instanceData.postValue(Success(instance))
|
||||
},
|
||||
{
|
||||
instanceData.postValue(Error())
|
||||
})
|
||||
.addTo(disposeables)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -111,6 +111,7 @@
|
|||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/TuskyTextInput"
|
||||
android:id="@+id/noteEditTextLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
|
|
|
@ -39,6 +39,8 @@ import org.mockito.Mockito.`when`
|
|||
import org.mockito.Mockito.mock
|
||||
import org.robolectric.Robolectric
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.SingleObserver
|
||||
import org.robolectric.annotation.Config
|
||||
import org.robolectric.fakes.RoboMenuItem
|
||||
import retrofit2.Call
|
||||
|
@ -77,7 +79,7 @@ class ComposeActivityTest {
|
|||
notificationVibration = true,
|
||||
notificationLight = true
|
||||
)
|
||||
var instanceResponseCallback: ((Call<Instance>?, Callback<Instance>?)->Unit)? = null
|
||||
var instanceResponseCallback: (()->Instance)? = null
|
||||
|
||||
@Before
|
||||
fun setupActivity() {
|
||||
|
@ -109,28 +111,14 @@ class ComposeActivityTest {
|
|||
|
||||
override fun enqueue(callback: Callback<List<Emoji>>?) {}
|
||||
})
|
||||
`when`(apiMock.instance).thenReturn(object: Call<Instance> {
|
||||
override fun isExecuted(): Boolean {
|
||||
return false
|
||||
}
|
||||
override fun clone(): Call<Instance> {
|
||||
throw Error("not implemented")
|
||||
}
|
||||
override fun isCanceled(): Boolean {
|
||||
throw Error("not implemented")
|
||||
}
|
||||
override fun cancel() {
|
||||
throw Error("not implemented")
|
||||
}
|
||||
override fun execute(): Response<Instance> {
|
||||
throw Error("not implemented")
|
||||
}
|
||||
override fun request(): Request {
|
||||
throw Error("not implemented")
|
||||
}
|
||||
|
||||
override fun enqueue(callback: Callback<Instance>?) {
|
||||
instanceResponseCallback?.invoke(this, callback)
|
||||
`when`(apiMock.instance).thenReturn(object: Single<Instance>() {
|
||||
override fun subscribeActual(observer: SingleObserver<in Instance>) {
|
||||
val instance = instanceResponseCallback?.invoke()
|
||||
if (instance == null) {
|
||||
observer.onError(Throwable())
|
||||
} else {
|
||||
observer.onSuccess(instance)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -181,7 +169,7 @@ class ComposeActivityTest {
|
|||
|
||||
@Test
|
||||
fun whenMaximumTootCharsIsNull_defaultLimitIsUsed() {
|
||||
instanceResponseCallback = getSuccessResponseCallbackWithMaximumTootCharacters(null)
|
||||
instanceResponseCallback = { getInstanceWithMaximumTootCharacters(null) }
|
||||
setupActivity()
|
||||
assertEquals(ComposeActivity.STATUS_CHARACTER_LIMIT, activity.maximumTootCharacters)
|
||||
}
|
||||
|
@ -189,23 +177,11 @@ class ComposeActivityTest {
|
|||
@Test
|
||||
fun whenMaximumTootCharsIsPopulated_customLimitIsUsed() {
|
||||
val customMaximum = 1000
|
||||
instanceResponseCallback = getSuccessResponseCallbackWithMaximumTootCharacters(customMaximum)
|
||||
instanceResponseCallback = { getInstanceWithMaximumTootCharacters(customMaximum) }
|
||||
setupActivity()
|
||||
assertEquals(customMaximum, activity.maximumTootCharacters)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenInitialInstanceRequestFails_defaultValueIsUsed() {
|
||||
instanceResponseCallback = {
|
||||
call: Call<Instance>?, callback: Callback<Instance>? ->
|
||||
if (call != null) {
|
||||
callback?.onResponse(call, Response.error(400, ResponseBody.create(null, "")))
|
||||
}
|
||||
}
|
||||
setupActivity()
|
||||
assertEquals(ComposeActivity.STATUS_CHARACTER_LIMIT, activity.maximumTootCharacters)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenTextContainsNoUrl_everyCharacterIsCounted() {
|
||||
val content = "This is test content please ignore thx "
|
||||
|
@ -281,7 +257,8 @@ class ComposeActivityTest {
|
|||
emptyList(),
|
||||
emptyList()
|
||||
),
|
||||
maximumTootCharacters
|
||||
maximumTootCharacters,
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue