[append-text] Implement append-text feature
This commit is contained in:
parent
e63102712b
commit
b1eb412970
|
@ -2,7 +2,7 @@
|
|||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 51,
|
||||
"identityHash": "446158bf571fbd08787628bb829fa3c0",
|
||||
"identityHash": "a1f530a7165bdd0e44932d9bb12ea4d3",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "DraftEntity",
|
||||
|
@ -104,7 +104,7 @@
|
|||
},
|
||||
{
|
||||
"tableName": "AccountEntity",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `domain` TEXT NOT NULL, `accessToken` TEXT NOT NULL, `clientId` TEXT, `clientSecret` TEXT, `isActive` INTEGER NOT NULL, `accountId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `profilePictureUrl` TEXT NOT NULL, `notificationsEnabled` INTEGER NOT NULL, `notificationsMentioned` INTEGER NOT NULL, `notificationsFollowed` INTEGER NOT NULL, `notificationsFollowRequested` INTEGER NOT NULL, `notificationsReblogged` INTEGER NOT NULL, `notificationsFavorited` INTEGER NOT NULL, `notificationsPolls` INTEGER NOT NULL, `notificationsSubscriptions` INTEGER NOT NULL, `notificationsSignUps` INTEGER NOT NULL, `notificationsUpdates` INTEGER NOT NULL, `notificationsReports` INTEGER NOT NULL, `notificationSound` INTEGER NOT NULL, `notificationVibration` INTEGER NOT NULL, `notificationLight` INTEGER NOT NULL, `defaultPostPrivacy` INTEGER NOT NULL, `defaultMediaSensitivity` INTEGER NOT NULL, `defaultPostLanguage` TEXT NOT NULL, `alwaysShowSensitiveMedia` INTEGER NOT NULL, `alwaysOpenSpoiler` INTEGER NOT NULL, `mediaPreviewEnabled` INTEGER NOT NULL, `lastNotificationId` TEXT NOT NULL, `notificationMarkerId` TEXT NOT NULL DEFAULT '0', `emojis` TEXT NOT NULL, `tabPreferences` TEXT NOT NULL, `notificationsFilter` TEXT NOT NULL, `oauthScopes` TEXT NOT NULL, `unifiedPushUrl` TEXT NOT NULL, `pushPubKey` TEXT NOT NULL, `pushPrivKey` TEXT NOT NULL, `pushAuth` TEXT NOT NULL, `pushServerKey` TEXT NOT NULL, `lastVisibleHomeTimelineStatusId` TEXT)",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `domain` TEXT NOT NULL, `accessToken` TEXT NOT NULL, `clientId` TEXT, `clientSecret` TEXT, `isActive` INTEGER NOT NULL, `accountId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `profilePictureUrl` TEXT NOT NULL, `notificationsEnabled` INTEGER NOT NULL, `notificationsMentioned` INTEGER NOT NULL, `notificationsFollowed` INTEGER NOT NULL, `notificationsFollowRequested` INTEGER NOT NULL, `notificationsReblogged` INTEGER NOT NULL, `notificationsFavorited` INTEGER NOT NULL, `notificationsPolls` INTEGER NOT NULL, `notificationsSubscriptions` INTEGER NOT NULL, `notificationsSignUps` INTEGER NOT NULL, `notificationsUpdates` INTEGER NOT NULL, `notificationsReports` INTEGER NOT NULL, `notificationSound` INTEGER NOT NULL, `notificationVibration` INTEGER NOT NULL, `notificationLight` INTEGER NOT NULL, `defaultPostPrivacy` INTEGER NOT NULL, `defaultMediaSensitivity` INTEGER NOT NULL, `defaultPostLanguage` TEXT NOT NULL, `alwaysShowSensitiveMedia` INTEGER NOT NULL, `alwaysOpenSpoiler` INTEGER NOT NULL, `mediaPreviewEnabled` INTEGER NOT NULL, `lastNotificationId` TEXT NOT NULL, `notificationMarkerId` TEXT NOT NULL DEFAULT '0', `emojis` TEXT NOT NULL, `tabPreferences` TEXT NOT NULL, `notificationsFilter` TEXT NOT NULL, `oauthScopes` TEXT NOT NULL, `unifiedPushUrl` TEXT NOT NULL, `pushPubKey` TEXT NOT NULL, `pushPrivKey` TEXT NOT NULL, `pushAuth` TEXT NOT NULL, `pushServerKey` TEXT NOT NULL, `lastVisibleHomeTimelineStatusId` TEXT, `appendText` TEXT NOT NULL DEFAULT '', `appendTextEnabled` INTEGER NOT NULL DEFAULT FALSE)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
|
@ -358,6 +358,20 @@
|
|||
"columnName": "lastVisibleHomeTimelineStatusId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "appendText",
|
||||
"columnName": "appendText",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true,
|
||||
"defaultValue": "''"
|
||||
},
|
||||
{
|
||||
"fieldPath": "appendTextEnabled",
|
||||
"columnName": "appendTextEnabled",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true,
|
||||
"defaultValue": "FALSE"
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
|
@ -996,7 +1010,7 @@
|
|||
"views": [],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '446158bf571fbd08787628bb829fa3c0')"
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a1f530a7165bdd0e44932d9bb12ea4d3')"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -31,6 +31,7 @@ import android.os.Build
|
|||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.provider.MediaStore
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.text.style.URLSpan
|
||||
import android.util.Log
|
||||
|
@ -141,6 +142,7 @@ class ComposeActivity :
|
|||
private lateinit var addMediaBehavior: BottomSheetBehavior<*>
|
||||
private lateinit var emojiBehavior: BottomSheetBehavior<*>
|
||||
private lateinit var scheduleBehavior: BottomSheetBehavior<*>
|
||||
private lateinit var appendTextBehavior: BottomSheetBehavior<*>
|
||||
|
||||
/** The account that is being used to compose the status */
|
||||
private lateinit var activeAccount: AccountEntity
|
||||
|
@ -281,6 +283,7 @@ class ComposeActivity :
|
|||
setupComposeField(preferences, viewModel.startingText)
|
||||
setupContentWarningField(composeOptions?.contentWarning)
|
||||
setupPollView()
|
||||
setupAppendTextField()
|
||||
applyShareIntent(intent, savedInstanceState)
|
||||
|
||||
/* Finally, overwrite state with data from saved instance state. */
|
||||
|
@ -382,6 +385,13 @@ class ComposeActivity :
|
|||
binding.composeContentWarningField.doOnTextChanged { _, _, _, _ -> updateVisibleCharactersLeft() }
|
||||
}
|
||||
|
||||
private fun setupAppendTextField() {
|
||||
binding.composeAppendTextView.setup(activeAccount.appendTextEnabled, activeAccount.appendText)
|
||||
|
||||
binding.composeAppendTextView.onEnabledChange { _, enabled -> updateAppendTextEnabled(enabled) }
|
||||
binding.composeAppendTextView.onTextChange { text -> updateAppendText(text.toString()) }
|
||||
}
|
||||
|
||||
private fun setupComposeField(preferences: SharedPreferences, startingText: String?) {
|
||||
binding.composeEditField.setOnReceiveContentListener(this)
|
||||
|
||||
|
@ -495,6 +505,7 @@ class ComposeActivity :
|
|||
addMediaBehavior = BottomSheetBehavior.from(binding.addMediaBottomSheet)
|
||||
scheduleBehavior = BottomSheetBehavior.from(binding.composeScheduleView)
|
||||
emojiBehavior = BottomSheetBehavior.from(binding.emojiView)
|
||||
appendTextBehavior = BottomSheetBehavior.from(binding.composeAppendTextView)
|
||||
|
||||
enableButton(binding.composeEmojiButton, clickable = false, colorActive = false)
|
||||
|
||||
|
@ -508,6 +519,7 @@ class ComposeActivity :
|
|||
binding.composeScheduleButton.setOnClickListener { onScheduleClick() }
|
||||
binding.composeScheduleView.setResetOnClickListener { resetSchedule() }
|
||||
binding.composeScheduleView.setListener(this)
|
||||
binding.composeAppendTextButton.setOnClickListener { showAppendText() }
|
||||
binding.atButton.setOnClickListener { atButtonClicked() }
|
||||
binding.hashButton.setOnClickListener { hashButtonClicked() }
|
||||
binding.descriptionMissingWarningButton.setOnClickListener {
|
||||
|
@ -538,12 +550,14 @@ class ComposeActivity :
|
|||
if (composeOptionsBehavior.state == BottomSheetBehavior.STATE_EXPANDED ||
|
||||
addMediaBehavior.state == BottomSheetBehavior.STATE_EXPANDED ||
|
||||
emojiBehavior.state == BottomSheetBehavior.STATE_EXPANDED ||
|
||||
scheduleBehavior.state == BottomSheetBehavior.STATE_EXPANDED
|
||||
scheduleBehavior.state == BottomSheetBehavior.STATE_EXPANDED ||
|
||||
appendTextBehavior.state == BottomSheetBehavior.STATE_EXPANDED
|
||||
) {
|
||||
composeOptionsBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
addMediaBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
emojiBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
scheduleBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
appendTextBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -763,6 +777,7 @@ class ComposeActivity :
|
|||
composeOptionsBehavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
addMediaBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
emojiBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
appendTextBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
scheduleBehavior.setState(BottomSheetBehavior.STATE_HIDDEN)
|
||||
} else {
|
||||
composeOptionsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN)
|
||||
|
@ -782,6 +797,7 @@ class ComposeActivity :
|
|||
scheduleBehavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
composeOptionsBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
addMediaBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
appendTextBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
emojiBehavior.setState(BottomSheetBehavior.STATE_HIDDEN)
|
||||
} else {
|
||||
scheduleBehavior.setState(BottomSheetBehavior.STATE_HIDDEN)
|
||||
|
@ -798,6 +814,7 @@ class ComposeActivity :
|
|||
emojiBehavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
composeOptionsBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
addMediaBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
appendTextBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
scheduleBehavior.setState(BottomSheetBehavior.STATE_HIDDEN)
|
||||
} else {
|
||||
emojiBehavior.setState(BottomSheetBehavior.STATE_HIDDEN)
|
||||
|
@ -806,11 +823,38 @@ class ComposeActivity :
|
|||
}
|
||||
}
|
||||
|
||||
private fun showAppendText() {
|
||||
if (appendTextBehavior.state == BottomSheetBehavior.STATE_HIDDEN || appendTextBehavior.state == BottomSheetBehavior.STATE_COLLAPSED) {
|
||||
appendTextBehavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
composeOptionsBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
addMediaBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
emojiBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
scheduleBehavior.setState(BottomSheetBehavior.STATE_HIDDEN)
|
||||
} else {
|
||||
appendTextBehavior.setState(BottomSheetBehavior.STATE_HIDDEN)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateAppendTextEnabled(enabled: Boolean) {
|
||||
activeAccount.appendTextEnabled = enabled
|
||||
updateVisibleCharactersLeft()
|
||||
accountManager.saveAccount(activeAccount)
|
||||
}
|
||||
|
||||
private fun updateAppendText(text: String) {
|
||||
activeAccount.appendText = text
|
||||
if (activeAccount.appendTextEnabled) {
|
||||
updateVisibleCharactersLeft()
|
||||
}
|
||||
accountManager.saveAccount(activeAccount)
|
||||
}
|
||||
|
||||
private fun openPickDialog() {
|
||||
if (addMediaBehavior.state == BottomSheetBehavior.STATE_HIDDEN || addMediaBehavior.state == BottomSheetBehavior.STATE_COLLAPSED) {
|
||||
addMediaBehavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
composeOptionsBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
emojiBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
appendTextBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
scheduleBehavior.setState(BottomSheetBehavior.STATE_HIDDEN)
|
||||
} else {
|
||||
addMediaBehavior.setState(BottomSheetBehavior.STATE_HIDDEN)
|
||||
|
@ -893,8 +937,13 @@ class ComposeActivity :
|
|||
|
||||
@VisibleForTesting
|
||||
fun calculateTextLength(): Int {
|
||||
val text = SpannableStringBuilder(binding.composeEditField.text)
|
||||
if (activeAccount.appendTextEnabled && activeAccount.appendText.isNotEmpty()) {
|
||||
text.append(" ${activeAccount.appendText}")
|
||||
}
|
||||
|
||||
return statusLength(
|
||||
binding.composeEditField.text,
|
||||
text,
|
||||
binding.composeContentWarningField.text,
|
||||
charactersReservedPerUrl
|
||||
)
|
||||
|
@ -950,7 +999,11 @@ class ComposeActivity :
|
|||
|
||||
private fun sendStatus() {
|
||||
enableButtons(false, viewModel.editing)
|
||||
val contentText = binding.composeEditField.text.toString()
|
||||
var contentText = binding.composeEditField.text.toString()
|
||||
if (activeAccount.appendTextEnabled && activeAccount.appendText.isNotEmpty()) {
|
||||
contentText += " ${activeAccount.appendText}"
|
||||
}
|
||||
|
||||
var spoilerText = ""
|
||||
if (viewModel.showContentWarning.value) {
|
||||
spoilerText = binding.composeContentWarningField.text.toString()
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package com.keylesspalace.tusky.components.compose.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.widget.doAfterTextChanged
|
||||
import com.keylesspalace.tusky.databinding.ViewComposeAppendTextBinding
|
||||
|
||||
class ComposeAppendTextView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : ConstraintLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
private val binding = ViewComposeAppendTextBinding.inflate(
|
||||
(context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater),
|
||||
this,
|
||||
)
|
||||
|
||||
val onEnabledChange = binding.switchAppendText::setOnCheckedChangeListener
|
||||
val onTextChange = binding.editAppendText::doAfterTextChanged
|
||||
|
||||
fun setup(enabled: Boolean, appendText: String) {
|
||||
binding.switchAppendText.isChecked = enabled
|
||||
binding.editAppendText.setText(appendText)
|
||||
}
|
||||
}
|
|
@ -100,7 +100,12 @@ data class AccountEntity(
|
|||
* ID of the status at the top of the visible list in the home timeline when the
|
||||
* user navigated away.
|
||||
*/
|
||||
var lastVisibleHomeTimelineStatusId: String? = null
|
||||
var lastVisibleHomeTimelineStatusId: String? = null,
|
||||
|
||||
@ColumnInfo(defaultValue = "")
|
||||
var appendText: String = "",
|
||||
@ColumnInfo(defaultValue = "FALSE")
|
||||
var appendTextEnabled: Boolean = false,
|
||||
) {
|
||||
|
||||
val identifier: String
|
||||
|
|
|
@ -278,6 +278,20 @@
|
|||
app:behavior_peekHeight="0dp"
|
||||
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior" />
|
||||
|
||||
<com.keylesspalace.tusky.components.compose.view.ComposeAppendTextView
|
||||
android:id="@+id/composeAppendTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorSurface"
|
||||
android:elevation="12dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingBottom="52dp"
|
||||
app:behavior_hideable="true"
|
||||
app:behavior_peekHeight="0dp"
|
||||
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/composeBottomBar"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -292,6 +306,16 @@
|
|||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="4dp">
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/composeAddMediaButton"
|
||||
style="@style/TuskyImageButton"
|
||||
|
@ -359,10 +383,20 @@
|
|||
app:srcCompat="@drawable/ic_access_time"
|
||||
app:tooltipText="@string/action_schedule_post" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
<ImageButton
|
||||
android:id="@+id/composeAppendTextButton"
|
||||
style="@style/TuskyImageButton"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:contentDescription="@string/action_append_text"
|
||||
android:padding="4dp"
|
||||
app:srcCompat="@drawable/ic_hashtag"
|
||||
app:tooltipText="@string/action_append_text" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/composeCharactersLeftView"
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
android:id="@+id/switchAppendText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/desc_append_text"
|
||||
android:textColor="?android:textColorTertiary"
|
||||
android:textSize="?attr/status_text_medium"
|
||||
app:layout_constraintBottom_toTopOf="@+id/appendTextInputLayout"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/appendTextInputLayout"
|
||||
style="@style/TuskyTextInput"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="8dp"
|
||||
android:hint="@string/action_append_text"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/editAppendText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
</merge>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="action_append_text">Append Text</string>
|
||||
<string name="desc_append_text">Append fixed text at the end of every posts</string>
|
||||
</resources>
|
Loading…
Reference in New Issue