ComposeActivity: preview ability for Pleroma, WIP
This commit is contained in:
parent
0e6ad0eee7
commit
c3c92fadcd
|
@ -14,6 +14,7 @@ data class UnfollowEvent(val accountId: String) : Dispatchable
|
|||
data class BlockEvent(val accountId: String) : Dispatchable
|
||||
data class MuteEvent(val accountId: String) : Dispatchable
|
||||
data class StatusDeletedEvent(val statusId: String) : Dispatchable
|
||||
data class StatusPreviewEvent(val status: Status) : Dispatchable
|
||||
data class StatusComposedEvent(val status: Status) : Dispatchable
|
||||
data class StatusScheduledEvent(val status: Status) : Dispatchable
|
||||
data class ProfileEditedEvent(val newProfileData: Account) : Dispatchable
|
||||
|
|
|
@ -70,6 +70,7 @@ import com.keylesspalace.tusky.R
|
|||
import com.keylesspalace.tusky.adapter.ComposeAutoCompleteAdapter
|
||||
import com.keylesspalace.tusky.adapter.EmojiAdapter
|
||||
import com.keylesspalace.tusky.adapter.OnEmojiSelectedListener
|
||||
import com.keylesspalace.tusky.appstore.*
|
||||
import com.keylesspalace.tusky.components.compose.dialog.makeCaptionDialog
|
||||
import com.keylesspalace.tusky.components.compose.dialog.showAddPollDialog
|
||||
import com.keylesspalace.tusky.components.compose.view.ComposeOptionsListener
|
||||
|
@ -108,12 +109,16 @@ class ComposeActivity : BaseActivity(),
|
|||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: ViewModelFactory
|
||||
|
||||
@Inject
|
||||
lateinit var eventHub: EventHub
|
||||
|
||||
private lateinit var composeOptionsBehavior: BottomSheetBehavior<*>
|
||||
private lateinit var addMediaBehavior: BottomSheetBehavior<*>
|
||||
private lateinit var emojiBehavior: BottomSheetBehavior<*>
|
||||
private lateinit var scheduleBehavior: BottomSheetBehavior<*>
|
||||
private lateinit var stickerBehavior: BottomSheetBehavior<*>
|
||||
private lateinit var previewBehavior: BottomSheetBehavior<*>
|
||||
|
||||
// this only exists when a status is trying to be sent, but uploads are still occurring
|
||||
private var finishingUploadDialog: ProgressDialog? = null
|
||||
|
@ -192,6 +197,12 @@ class ComposeActivity : BaseActivity(),
|
|||
viewModel.setupComplete.value = true
|
||||
|
||||
stickerKeyboard.isSticky = true
|
||||
|
||||
eventHub.events.subscribe { event ->
|
||||
when(event) {
|
||||
is StatusPreviewEvent -> onStatusPreviewReady(event.status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun uriToFilename(uri: Uri): String {
|
||||
|
@ -383,6 +394,7 @@ class ComposeActivity : BaseActivity(),
|
|||
}
|
||||
|
||||
if(instanceData.software.equals("pleroma")) {
|
||||
composePreviewButton.visibility = View.VISIBLE
|
||||
reenableAttachments()
|
||||
}
|
||||
}
|
||||
|
@ -455,13 +467,15 @@ class ComposeActivity : BaseActivity(),
|
|||
scheduleBehavior = BottomSheetBehavior.from(composeScheduleView)
|
||||
emojiBehavior = BottomSheetBehavior.from(emojiView)
|
||||
stickerBehavior = BottomSheetBehavior.from(stickerKeyboard)
|
||||
previewBehavior = BottomSheetBehavior.from(previewScroll)
|
||||
|
||||
emojiView.layoutManager = GridLayoutManager(this, 3, GridLayoutManager.HORIZONTAL, false)
|
||||
enableButton(composeEmojiButton, clickable = false, colorActive = false)
|
||||
enableButton(composeStickerButton, false, false)
|
||||
|
||||
// Setup the interface buttons.
|
||||
composeTootButton.setOnClickListener { onSendClicked() }
|
||||
composeTootButton.setOnClickListener { onSendClicked(false) }
|
||||
composePreviewButton.setOnClickListener { onSendClicked(true) }
|
||||
composeAddMediaButton.setOnClickListener { openPickDialog() }
|
||||
composeToggleVisibilityButton.setOnClickListener { showComposeOptions() }
|
||||
composeContentWarningButton.setOnClickListener { onContentWarningChanged() }
|
||||
|
@ -771,6 +785,7 @@ class ComposeActivity : BaseActivity(),
|
|||
composeScheduleButton.isClickable = enable
|
||||
composeFormattingSyntax.isClickable = enable
|
||||
composeTootButton.isEnabled = enable
|
||||
composePreviewButton.isEnabled = enable
|
||||
composeStickerButton.isEnabled = enable
|
||||
}
|
||||
|
||||
|
@ -796,6 +811,7 @@ class ComposeActivity : BaseActivity(),
|
|||
emojiBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
stickerBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
scheduleBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
previewBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
} else {
|
||||
composeOptionsBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
}
|
||||
|
@ -816,6 +832,7 @@ class ComposeActivity : BaseActivity(),
|
|||
addMediaBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
emojiBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
stickerBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
previewBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
} else {
|
||||
scheduleBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
}
|
||||
|
@ -833,6 +850,7 @@ class ComposeActivity : BaseActivity(),
|
|||
composeOptionsBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
addMediaBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
scheduleBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
previewBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
} else {
|
||||
emojiBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
}
|
||||
|
@ -847,6 +865,7 @@ class ComposeActivity : BaseActivity(),
|
|||
emojiBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
stickerBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
scheduleBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
previewBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
} else {
|
||||
addMediaBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
}
|
||||
|
@ -947,13 +966,31 @@ class ComposeActivity : BaseActivity(),
|
|||
return composeScheduleView.verifyScheduledTime(composeScheduleView.getDateTime(viewModel.scheduledAt.value))
|
||||
}
|
||||
|
||||
private fun onSendClicked() {
|
||||
private fun onSendClicked(preview: Boolean) {
|
||||
if(preview && previewBehavior.state == BottomSheetBehavior.STATE_EXPANDED) {
|
||||
previewBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
return
|
||||
}
|
||||
|
||||
if (verifyScheduledTime()) {
|
||||
sendStatus()
|
||||
sendStatus(preview)
|
||||
} else {
|
||||
showScheduleView()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onStatusPreviewReady(status: Status) {
|
||||
enableButtons(true)
|
||||
previewView.setupWithStatus(status)
|
||||
previewBehavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
addMediaBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
composeOptionsBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
emojiBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
scheduleBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
stickerBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
|
||||
// Log.d("ComposeActivityPreview", "Preview: " + status.content)
|
||||
}
|
||||
|
||||
/** This is for the fancy keyboards which can insert images and stuff. */
|
||||
override fun onCommitContent(inputContentInfo: InputContentInfoCompat, flags: Int, opts: Bundle?): Boolean {
|
||||
|
@ -977,7 +1014,7 @@ class ComposeActivity : BaseActivity(),
|
|||
return false
|
||||
}
|
||||
|
||||
private fun sendStatus() {
|
||||
private fun sendStatus(preview: Boolean) {
|
||||
enableButtons(false)
|
||||
val contentText = composeEditField.text.toString()
|
||||
var spoilerText = ""
|
||||
|
@ -993,9 +1030,10 @@ class ComposeActivity : BaseActivity(),
|
|||
this, getString(R.string.dialog_title_finishing_media_upload),
|
||||
getString(R.string.dialog_message_uploading_media), true, true)
|
||||
|
||||
viewModel.sendStatus(contentText, spoilerText).observe(this, Observer {
|
||||
viewModel.sendStatus(contentText, spoilerText, preview).observe(this, Observer {
|
||||
finishingUploadDialog?.dismiss()
|
||||
deleteDraftAndFinish()
|
||||
if(!preview)
|
||||
deleteDraftAndFinish()
|
||||
})
|
||||
|
||||
} else {
|
||||
|
@ -1156,6 +1194,7 @@ class ComposeActivity : BaseActivity(),
|
|||
emojiBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
scheduleBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
stickerBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
previewBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1168,7 +1207,7 @@ class ComposeActivity : BaseActivity(),
|
|||
if (event.isCtrlPressed) {
|
||||
if (keyCode == KeyEvent.KEYCODE_ENTER) {
|
||||
// send toot by pressing CTRL + ENTER
|
||||
this.onSendClicked()
|
||||
this.onSendClicked(false)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -1229,6 +1268,7 @@ class ComposeActivity : BaseActivity(),
|
|||
composeOptionsBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
emojiBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
scheduleBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
previewBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
} else {
|
||||
stickerBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
}
|
||||
|
|
|
@ -302,7 +302,8 @@ class ComposeViewModel
|
|||
*/
|
||||
fun sendStatus(
|
||||
content: String,
|
||||
spoilerText: String
|
||||
spoilerText: String,
|
||||
preview: Boolean
|
||||
): LiveData<Unit> {
|
||||
return media
|
||||
.filter { items -> items.all { it.uploadPercent == -1 } }
|
||||
|
@ -330,6 +331,7 @@ class ComposeViewModel
|
|||
replyingStatusContent = null,
|
||||
replyingStatusAuthorUsername = null,
|
||||
formattingSyntax = formattingSyntax,
|
||||
preview = preview,
|
||||
savedJsonUrls = null,
|
||||
accountId = accountManager.activeAccount!!.id,
|
||||
savedTootUid = 0,
|
||||
|
|
|
@ -30,7 +30,8 @@ data class Instance (
|
|||
@SerializedName("contact_account") val contactAccount: Account,
|
||||
@SerializedName("max_toot_chars") val maxTootChars: Int?,
|
||||
@SerializedName("max_bio_chars") val maxBioChars: Int?,
|
||||
@SerializedName("poll_limits") val pollLimits: PollLimits?
|
||||
@SerializedName("poll_limits") val pollLimits: PollLimits?,
|
||||
val pleroma: InstancePleroma
|
||||
) {
|
||||
override fun hashCode(): Int {
|
||||
return uri.hashCode()
|
||||
|
@ -45,6 +46,14 @@ data class Instance (
|
|||
}
|
||||
}
|
||||
|
||||
data class InstancePleroma (
|
||||
val metadata: InstancePleromaMetadata
|
||||
)
|
||||
|
||||
data class InstancePleromaMetadata (
|
||||
val features: List<String>
|
||||
)
|
||||
|
||||
data class PollLimits (
|
||||
@SerializedName("max_options") val maxOptions: Int?,
|
||||
@SerializedName("max_option_chars") val maxOptionChars: Int?
|
||||
|
|
|
@ -28,7 +28,8 @@ data class NewStatus(
|
|||
@SerializedName("media_ids") val mediaIds: List<String>?,
|
||||
@SerializedName("scheduled_at") val scheduledAt: String?,
|
||||
val poll: NewPoll?,
|
||||
var content_type: String?
|
||||
var content_type: String?,
|
||||
val preview: Boolean?
|
||||
)
|
||||
|
||||
@Parcelize
|
||||
|
|
|
@ -103,6 +103,7 @@ class SendStatusBroadcastReceiver : BroadcastReceiver() {
|
|||
null,
|
||||
null,
|
||||
"",
|
||||
false,
|
||||
account.id,
|
||||
0,
|
||||
randomAlphanumericString(16),
|
||||
|
|
|
@ -16,8 +16,7 @@ import androidx.core.app.ServiceCompat
|
|||
import androidx.core.content.ContextCompat
|
||||
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.appstore.*
|
||||
import com.keylesspalace.tusky.components.notifications.NotificationHelper
|
||||
import com.keylesspalace.tusky.db.AccountManager
|
||||
import com.keylesspalace.tusky.db.AppDatabase
|
||||
|
@ -132,6 +131,7 @@ class SendTootService : Service(), Injectable {
|
|||
tootToSend.retries++
|
||||
|
||||
val contentType : String? = if(tootToSend.formattingSyntax.length == 0) null else tootToSend.formattingSyntax
|
||||
val preview : Boolean? = if(tootToSend.preview) tootToSend.preview else null
|
||||
|
||||
val newStatus = NewStatus(
|
||||
tootToSend.text,
|
||||
|
@ -142,7 +142,8 @@ class SendTootService : Service(), Injectable {
|
|||
tootToSend.mediaIds,
|
||||
tootToSend.scheduledAt,
|
||||
tootToSend.poll,
|
||||
contentType
|
||||
contentType,
|
||||
preview
|
||||
)
|
||||
|
||||
val sendCall = mastodonApi.createStatus(
|
||||
|
@ -166,7 +167,9 @@ class SendTootService : Service(), Injectable {
|
|||
saveTootHelper.deleteDraft(tootToSend.savedTootUid)
|
||||
}
|
||||
|
||||
if (scheduled) {
|
||||
if (tootToSend.preview) {
|
||||
response.body()?.let(::StatusPreviewEvent)?.let(eventHub::dispatch)
|
||||
} else if (scheduled) {
|
||||
response.body()?.let(::StatusScheduledEvent)?.let(eventHub::dispatch)
|
||||
} else {
|
||||
response.body()?.let(::StatusComposedEvent)?.let(eventHub::dispatch)
|
||||
|
@ -328,6 +331,7 @@ data class TootToSend(
|
|||
val replyingStatusAuthorUsername: String?,
|
||||
val savedJsonUrls: List<String>?,
|
||||
val formattingSyntax: String,
|
||||
val preview: Boolean,
|
||||
val accountId: Long,
|
||||
val savedTootUid: Int,
|
||||
val idempotencyKey: String,
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
package com.keylesspalace.tusky.view
|
||||
|
||||
import android.view.*
|
||||
import android.content.*
|
||||
import android.util.*
|
||||
import android.widget.*
|
||||
import android.app.*
|
||||
import android.text.*
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.preference.PreferenceManager
|
||||
|
||||
import com.keylesspalace.tusky.adapter.StatusViewHolder
|
||||
import com.keylesspalace.tusky.entity.Status
|
||||
import com.keylesspalace.tusky.interfaces.StatusActionListener
|
||||
import com.keylesspalace.tusky.util.CardViewMode
|
||||
import com.keylesspalace.tusky.util.ViewDataUtils
|
||||
import com.keylesspalace.tusky.util.StatusDisplayOptions
|
||||
import com.keylesspalace.tusky.R
|
||||
|
||||
import java.util.*;
|
||||
|
||||
class StatusView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0)
|
||||
: ConstraintLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
private var viewHolder : StatusViewHolder
|
||||
private var statusDisplayOptions : StatusDisplayOptions
|
||||
init {
|
||||
View.inflate(context, R.layout.item_status, this)
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
statusDisplayOptions = StatusDisplayOptions(
|
||||
animateAvatars = preferences.getBoolean("animateGifAvatars", false),
|
||||
mediaPreviewEnabled = true,
|
||||
useAbsoluteTime = preferences.getBoolean("absoluteTimeView", false),
|
||||
showBotOverlay = false,
|
||||
useBlurhash = preferences.getBoolean("useBlurhash", true),
|
||||
cardViewMode = CardViewMode.NONE,
|
||||
confirmReblogs = preferences.getBoolean("confirmReblogs", true)
|
||||
)
|
||||
viewHolder = StatusViewHolder(this)
|
||||
}
|
||||
|
||||
fun setupWithStatus(status: Status) {
|
||||
val concrete = ViewDataUtils.statusToViewData(status, false, false)
|
||||
viewHolder.setupWithStatus(concrete, DummyStatusActionListener(), statusDisplayOptions)
|
||||
}
|
||||
|
||||
class DummyStatusActionListener: StatusActionListener {
|
||||
override fun onReply(position: Int) { }
|
||||
override fun onReblog(reblog: Boolean, position: Int) { }
|
||||
override fun onFavourite(favourite: Boolean, position: Int) { }
|
||||
override fun onBookmark(bookmark: Boolean, position: Int) { }
|
||||
override fun onMore(view: View, position: Int) { }
|
||||
override fun onViewMedia(position: Int, attachmentIndex: Int, view: View?) { }
|
||||
override fun onViewThread(position: Int) { }
|
||||
override fun onOpenReblog(position: Int) { }
|
||||
override fun onExpandedChange(expanded: Boolean, position: Int) { }
|
||||
override fun onContentHiddenChange(isShowing: Boolean, position: Int) { }
|
||||
override fun onLoadMore(position: Int) { }
|
||||
override fun onContentCollapsedChange(isCollapsed: Boolean, position: Int) { }
|
||||
override fun onVoteInPoll(position: Int, choices: MutableList<Int>) { }
|
||||
override fun onViewAccount(id: String) { }
|
||||
override fun onViewTag(id: String) { }
|
||||
override fun onViewUrl(id: String) { }
|
||||
}
|
||||
}
|
|
@ -301,10 +301,29 @@
|
|||
android:layout_height="300dp"
|
||||
android:background="?attr/colorSurface"
|
||||
android:elevation="12dp"
|
||||
android:layout_marginBottom="56dp"
|
||||
android:paddingBottom="60dp"
|
||||
app:behavior_hideable="true"
|
||||
app:behavior_peekHeight="0dp"
|
||||
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior" />
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/previewScroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorSurface"
|
||||
android:elevation="12dp"
|
||||
android:paddingBottom="60dp"
|
||||
app:behavior_hideable="true"
|
||||
app:behavior_peekHeight="0dp"
|
||||
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
|
||||
>
|
||||
<com.keylesspalace.tusky.view.StatusView
|
||||
android:id="@+id/previewView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorSurface"
|
||||
/>
|
||||
</ScrollView>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@ -429,16 +448,29 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:textColor="?android:textColorTertiary"
|
||||
android:textSize="?attr/status_text_medium"
|
||||
android:layout_toLeftOf="@+id/composeTootButton"
|
||||
android:layout_toLeftOf="@+id/composePreviewButton"
|
||||
android:layout_centerVertical="true"
|
||||
tools:text="500" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/composePreviewButton"
|
||||
style="@style/TuskyButton"
|
||||
android:padding="4dp"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
app:icon="@drawable/ic_eye_24dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:visibility="gone"
|
||||
android:layout_toLeftOf="@+id/composeTootButton"
|
||||
android:layout_centerVertical="true"/>
|
||||
|
||||
<com.keylesspalace.tusky.components.compose.view.TootButton
|
||||
android:id="@+id/composeTootButton"
|
||||
style="@style/TuskyButton"
|
||||
android:layout_width="@dimen/toot_button_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:textSize="?attr/status_text_medium"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"/>
|
||||
|
|
Loading…
Reference in New Issue