ComposeActivity refactor (#1541)

* Convert ComposeActivity to Kotlin

* More ComposeActivity cleanups

* Move ComposeActivity to it's own package

* Remove ComposeActivity.IntentBuilder

* Re-do part of the media downsizing/uploading

* Add sending of status to ViewModel, draft media descriptions

* Allow uploading video, update description after uploading

* Enable camera, enable upload cancelling

* Cleanup of ComposeActivity

* Extract CaptionDialog, extract ComposeActivity methods

* Fix handling of redrafted media

* Add initial state and media uploading out of Activity

* Change ComposeOptions.mentionedUsernames to be Set rather than List

We probably don't want repeated usernames when we are writing a post
and Set provides such guarantee for free plus it tells it to the
callers. The only disadvantage is lack of order but it shouldn't be a
problem.

* Add combineOptionalLiveData. Add docs.

It it useful for nullable LiveData's. I think we cannot differentiate
between value not being set and value being null so I just added the
variant without null check.

* Add poll support to Compose.

* cleanup code

* move more classes into compose package

* cleanup code

* fix button behavior

* add error handling for media upload

* add caching for instance data again

* merge develop

* fix scheduled toots

* delete unused string

* cleanup ComposeActivity

* fix restoring media from drafts

* make media upload code a little bit clearer

* cleanup autocomplete search code

* avoid duplicate object creation in SavedTootActivity

* perf: avoid unnecessary work when initializing ComposeActivity

* add license header to new files

* use small toot button on bigger displays

* fix ComposeActivityTest

* fix bad merge

* use Singles.zip instead of Single.zip
This commit is contained in:
Ivan Kupalov 2019-12-19 19:09:40 +01:00 committed by Konrad Pozniak
commit 8770fbe986
68 changed files with 3162 additions and 2666 deletions

View file

@ -8,7 +8,6 @@ import android.content.ClipData
import android.content.ClipDescription
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.IBinder
import android.os.Parcelable
@ -19,7 +18,6 @@ import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.appstore.StatusComposedEvent
import com.keylesspalace.tusky.appstore.StatusScheduledEvent
import com.keylesspalace.tusky.db.AccountEntity
import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.db.AppDatabase
import com.keylesspalace.tusky.di.Injectable
@ -28,7 +26,6 @@ import com.keylesspalace.tusky.entity.NewStatus
import com.keylesspalace.tusky.entity.Status
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.util.SaveTootHelper
import com.keylesspalace.tusky.util.randomAlphanumericString
import dagger.android.AndroidInjection
import kotlinx.android.parcel.Parcelize
import retrofit2.Call
@ -50,7 +47,8 @@ class SendTootService : Service(), Injectable {
@Inject
lateinit var database: AppDatabase
private lateinit var saveTootHelper: SaveTootHelper
@Inject
lateinit var saveTootHelper: SaveTootHelper
private val tootsToSend = ConcurrentHashMap<Int, TootToSend>()
private val sendCalls = ConcurrentHashMap<Int, Call<Status>>()
@ -61,7 +59,6 @@ class SendTootService : Service(), Injectable {
override fun onCreate() {
AndroidInjection.inject(this)
saveTootHelper = SaveTootHelper(database.tootDao(), this)
super.onCreate()
}
@ -284,54 +281,19 @@ class SendTootService : Service(), Injectable {
@JvmStatic
fun sendTootIntent(context: Context,
text: String,
warningText: String,
visibility: Status.Visibility,
sensitive: Boolean,
mediaIds: List<String>,
mediaUris: List<Uri>,
mediaDescriptions: List<String>,
scheduledAt: String?,
inReplyToId: String?,
poll: NewPoll?,
replyingStatusContent: String?,
replyingStatusAuthorUsername: String?,
savedJsonUrls: String?,
account: AccountEntity,
savedTootUid: Int
tootToSend: TootToSend
): Intent {
val intent = Intent(context, SendTootService::class.java)
val idempotencyKey = randomAlphanumericString(16)
val tootToSend = TootToSend(text,
warningText,
visibility.serverString(),
sensitive,
mediaIds,
mediaUris.map { it.toString() },
mediaDescriptions,
scheduledAt,
inReplyToId,
poll,
replyingStatusContent,
replyingStatusAuthorUsername,
savedJsonUrls,
account.id,
savedTootUid,
idempotencyKey,
0)
intent.putExtra(KEY_TOOT, tootToSend)
if(mediaUris.isNotEmpty()) {
if (tootToSend.mediaUris.isNotEmpty()) {
// forward uri permissions
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
val uriClip = ClipData(
ClipDescription("Toot Media", arrayOf("image/*", "video/*")),
ClipData.Item(mediaUris[0])
ClipData.Item(tootToSend.mediaUris[0])
)
mediaUris
tootToSend.mediaUris
.drop(1)
.forEach { mediaUri ->
uriClip.addItem(ClipData.Item(mediaUri))
@ -348,20 +310,22 @@ class SendTootService : Service(), Injectable {
}
@Parcelize
data class TootToSend(val text: String,
val warningText: String,
val visibility: String,
val sensitive: Boolean,
val mediaIds: List<String>,
val mediaUris: List<String>,
val mediaDescriptions: List<String>,
val scheduledAt: String?,
val inReplyToId: String?,
val poll: NewPoll?,
val replyingStatusContent: String?,
val replyingStatusAuthorUsername: String?,
val savedJsonUrls: String?,
val accountId: Long,
val savedTootUid: Int,
val idempotencyKey: String,
var retries: Int) : Parcelable
data class TootToSend(
val text: String,
val warningText: String,
val visibility: String,
val sensitive: Boolean,
val mediaIds: List<String>,
val mediaUris: List<String>,
val mediaDescriptions: List<String>,
val scheduledAt: String?,
val inReplyToId: String?,
val poll: NewPoll?,
val replyingStatusContent: String?,
val replyingStatusAuthorUsername: String?,
val savedJsonUrls: List<String>?,
val accountId: Long,
val savedTootUid: Int,
val idempotencyKey: String,
var retries: Int
) : Parcelable

View file

@ -0,0 +1,34 @@
/* Copyright 2019 Tusky Contributors
*
* This file is a part of Tusky.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */
package com.keylesspalace.tusky.service
import android.content.Context
import android.os.Build
interface ServiceClient {
fun sendToot(tootToSend: TootToSend)
}
class ServiceClientImpl(private val context: Context) : ServiceClient {
override fun sendToot(tootToSend: TootToSend) {
val intent = SendTootService.sendTootIntent(context, tootToSend)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent)
} else {
context.startService(intent)
}
}
}

View file

@ -18,7 +18,6 @@ package com.keylesspalace.tusky.service
import android.annotation.TargetApi
import android.content.Intent
import android.service.quicksettings.TileService
import com.keylesspalace.tusky.MainActivity
/**