chats: base chat UI
This commit is contained in:
parent
9f57699a3d
commit
a002a76b92
|
@ -87,7 +87,8 @@
|
|||
<string name="title_scheduled_toot">Scheduled posts</string>
|
||||
<string name="title_reblogged_by">Repeated by</string>
|
||||
<string name="title_view_thread">Post</string>
|
||||
|
||||
<string name="chat_message_hint_text">Just landed in L.A.</string>
|
||||
|
||||
<!--
|
||||
<string name="about_tusky_version">Husky %s</string>
|
||||
<string name="about_powered_by_tusky">Powered by Husky</string>
|
||||
|
|
|
@ -106,6 +106,9 @@
|
|||
android:name=".components.compose.ComposeActivity"
|
||||
android:theme="@style/TuskyDialogActivityTheme"
|
||||
android:windowSoftInputMode="stateVisible|adjustResize"/>
|
||||
<activity
|
||||
android:name=".components.chat.ChatActivity"
|
||||
android:windowSoftInputMode="stateVisible|adjustResize"/>
|
||||
<activity
|
||||
android:name=".ViewThreadActivity"
|
||||
android:configChanges="orientation|screenSize" />
|
||||
|
|
|
@ -23,6 +23,8 @@ import android.widget.Toast
|
|||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.keylesspalace.tusky.components.chat.ChatActivity
|
||||
import com.keylesspalace.tusky.entity.Chat
|
||||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import com.keylesspalace.tusky.util.LinkHelper
|
||||
import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider
|
||||
|
@ -112,6 +114,10 @@ abstract class BottomSheetActivity : BaseActivity() {
|
|||
startActivityWithSlideInAnimation(intent)
|
||||
}
|
||||
|
||||
open fun openChat(chat: Chat) {
|
||||
startActivityWithSlideInAnimation(ChatActivity.getIntent(this, chat))
|
||||
}
|
||||
|
||||
protected open fun performUrlFallbackAction(url: String, fallbackBehavior: PostLookupFallbackBehavior) {
|
||||
when (fallbackBehavior) {
|
||||
PostLookupFallbackBehavior.OPEN_IN_BROWSER -> openLink(url)
|
||||
|
|
|
@ -42,7 +42,7 @@ class ChatsViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
|||
if(payload == null) {
|
||||
displayName.text = chat.account.displayName?.emojify(chat.account.emojis, displayName, true)
|
||||
?: ""
|
||||
userName.text = userName.context.getString(R.string.status_username_format, chat.account.localUsername)
|
||||
userName.text = userName.context.getString(R.string.status_username_format, chat.account.username)
|
||||
setUpdatedAt(chat.updatedAt, statusDisplayOptions)
|
||||
setAvatar(chat.account.avatar, chat.account.bot, statusDisplayOptions)
|
||||
if(chat.unread <= 0) {
|
||||
|
@ -57,11 +57,16 @@ class ChatsViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
|||
listener.onMore(chat.id, it)
|
||||
true
|
||||
}
|
||||
val onClickListener = View.OnClickListener {
|
||||
val pos = adapterPosition
|
||||
if(pos != RecyclerView.NO_POSITION)
|
||||
listener.openChat(pos)
|
||||
}
|
||||
|
||||
content.setOnLongClickListener(onLongClickListener)
|
||||
itemView.setOnLongClickListener(onLongClickListener)
|
||||
content.setOnClickListener { }
|
||||
itemView.setOnClickListener { }
|
||||
content.setOnClickListener(onClickListener)
|
||||
itemView.setOnClickListener(onClickListener)
|
||||
|
||||
chat.lastMessage?.let {
|
||||
content.text = it.content.emojify(it.emojis, content, true)
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
package com.keylesspalace.tusky.components.chat
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.request.target.CustomTarget
|
||||
import com.bumptech.glide.request.transition.Transition
|
||||
import com.keylesspalace.tusky.BaseActivity
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.appstore.EventHub
|
||||
import com.keylesspalace.tusky.di.Injectable
|
||||
import com.keylesspalace.tusky.entity.Chat
|
||||
import com.keylesspalace.tusky.entity.Emoji
|
||||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import com.keylesspalace.tusky.repository.ChatRepository
|
||||
import com.keylesspalace.tusky.util.StatusDisplayOptions
|
||||
import com.keylesspalace.tusky.util.emojify
|
||||
import com.keylesspalace.tusky.util.loadAvatar
|
||||
import kotlinx.android.synthetic.main.activity_chat.*
|
||||
import kotlinx.android.synthetic.main.toolbar_basic.*
|
||||
import kotlinx.android.synthetic.main.toolbar_basic.toolbar
|
||||
import javax.inject.Inject
|
||||
|
||||
class ChatActivity: BaseActivity(),
|
||||
Injectable {
|
||||
|
||||
@Inject
|
||||
lateinit var eventHub: EventHub
|
||||
|
||||
@Inject
|
||||
lateinit var api: MastodonApi
|
||||
|
||||
@Inject
|
||||
lateinit var chatsRepo: ChatRepository
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val chatId = intent.getStringExtra(ID)
|
||||
val avatarUrl = intent.getStringExtra(AVATAR_URL)
|
||||
val displayName = intent.getStringExtra(DISPLAY_NAME)
|
||||
val username = intent.getStringExtra(USERNAME)
|
||||
val emojis = intent.getParcelableArrayListExtra<Emoji>(EMOJIS)
|
||||
|
||||
if(chatId == null || avatarUrl == null || displayName == null || username == null || emojis == null) {
|
||||
throw IllegalArgumentException("Can't open ChatActivity without chat id")
|
||||
}
|
||||
|
||||
setContentView(R.layout.activity_chat)
|
||||
setSupportActionBar(toolbar)
|
||||
|
||||
supportActionBar?.run {
|
||||
title = ""
|
||||
setDisplayHomeAsUpEnabled(true)
|
||||
setDisplayShowHomeEnabled(true)
|
||||
}
|
||||
|
||||
loadAvatar(avatarUrl, chatAvatar,
|
||||
resources.getDimensionPixelSize(R.dimen.avatar_radius_24dp),true)
|
||||
|
||||
chatTitle.text = displayName.emojify(emojis, chatTitle, true)
|
||||
chatUsername.text = username
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
onBackPressed()
|
||||
return true
|
||||
}
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getIntent(context: Context, chat: Chat) : Intent {
|
||||
val intent = Intent(context, ChatActivity::class.java)
|
||||
intent.putExtra(ID, chat.id)
|
||||
intent.putExtra(AVATAR_URL, chat.account.avatar)
|
||||
intent.putExtra(DISPLAY_NAME, chat.account.displayName ?: chat.account.localUsername)
|
||||
intent.putParcelableArrayListExtra(EMOJIS, ArrayList(chat.account.emojis ?: emptyList<Emoji>()))
|
||||
intent.putExtra(USERNAME, chat.account.username)
|
||||
return intent
|
||||
}
|
||||
|
||||
const val ID = "id"
|
||||
const val AVATAR_URL = "avatar_url"
|
||||
const val DISPLAY_NAME = "display_name"
|
||||
const val USERNAME = "username"
|
||||
const val EMOJIS = "emojis"
|
||||
}
|
||||
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
package com.keylesspalace.tusky.di
|
||||
|
||||
import com.keylesspalace.tusky.*
|
||||
import com.keylesspalace.tusky.components.chat.ChatActivity
|
||||
import com.keylesspalace.tusky.components.compose.ComposeActivity
|
||||
import com.keylesspalace.tusky.components.instancemute.InstanceListActivity
|
||||
import com.keylesspalace.tusky.components.report.ReportActivity
|
||||
|
@ -46,6 +47,9 @@ abstract class ActivitiesModule {
|
|||
@ContributesAndroidInjector
|
||||
abstract fun contributesComposeActivity(): ComposeActivity
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesChatActivity(): ChatActivity
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesEditProfileActivity(): EditProfileActivity
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
package com.keylesspalace.tusky.entity
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
|
@ -23,7 +24,33 @@ data class Emoji(
|
|||
val shortcode: String,
|
||||
val url: String,
|
||||
@SerializedName("visible_in_picker") val visibleInPicker: Boolean?
|
||||
)
|
||||
) : Parcelable {
|
||||
constructor(parcel: Parcel) : this(
|
||||
parcel.readString()!!,
|
||||
parcel.readString()!!,
|
||||
parcel.readValue(Boolean::class.java.classLoader) as? Boolean) {
|
||||
}
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeString(shortcode)
|
||||
parcel.writeString(url)
|
||||
parcel.writeValue(visibleInPicker)
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<Emoji> {
|
||||
override fun createFromParcel(parcel: Parcel): Emoji {
|
||||
return Emoji(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<Emoji?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class EmojiReaction(
|
||||
val name: String,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.keylesspalace.tusky.fragment
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
|
@ -19,6 +20,7 @@ import com.keylesspalace.tusky.adapter.ChatsAdapter
|
|||
import com.keylesspalace.tusky.adapter.StatusBaseViewHolder
|
||||
import com.keylesspalace.tusky.adapter.TimelineAdapter
|
||||
import com.keylesspalace.tusky.appstore.*
|
||||
import com.keylesspalace.tusky.components.chat.ChatActivity
|
||||
import com.keylesspalace.tusky.db.AccountManager
|
||||
import com.keylesspalace.tusky.di.Injectable
|
||||
import com.keylesspalace.tusky.entity.Chat
|
||||
|
@ -719,4 +721,11 @@ class ChatsFragment : BaseFragment(), Injectable, RefreshableFragment, Reselecta
|
|||
}
|
||||
popup.show()
|
||||
}
|
||||
|
||||
override fun openChat(position: Int) {
|
||||
val chat = chats[position].asRightOrNull()
|
||||
chat?.let {
|
||||
bottomSheetActivity.openChat(it)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,4 +7,6 @@ interface ChatActionListener: LinkListener {
|
|||
fun onLoadMore(position: Int)
|
||||
|
||||
fun onMore(chatId: String, v: View)
|
||||
|
||||
fun openChat(position: Int)
|
||||
}
|
|
@ -0,0 +1,193 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
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"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="@dimen/actionbar_elevation"
|
||||
app:layout_collapseMode="pin">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/chatAvatar"
|
||||
android:layout_width="?attr/actionBarSize"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:padding="8dp"
|
||||
android:contentDescription="@string/action_view_profile"
|
||||
android:importantForAccessibility="no"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@drawable/avatar_default" />
|
||||
|
||||
<androidx.emoji.widget.EmojiTextView
|
||||
android:id="@+id/chatTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:importantForAccessibility="no"
|
||||
android:maxLines="1"
|
||||
android:paddingEnd="@dimen/status_display_name_padding_end"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="?attr/status_text_large"
|
||||
android:textStyle="normal|bold"
|
||||
tools:text="Ente r the void you foooooo" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/chatUsername"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:importantForAccessibility="no"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="?attr/status_text_large"
|
||||
tools:text="\@Entenhausen@birbsarecooooooooooool.site" />
|
||||
|
||||
</androidx.appcompat.widget.Toolbar>
|
||||
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/composeLayout"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/appbar" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@+id/composeLayout"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.keylesspalace.tusky.view.BackgroundMessageView
|
||||
android:id="@+id/messageView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@+id/composeLayout"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/appbar"
|
||||
tools:visibility="visible"
|
||||
app:layout_constrainedHeight="true" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/composeLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:background="?attr/colorSurface"
|
||||
android:animateLayoutChanges="true"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/recycler"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/attachmentLayout"
|
||||
android:layout_width="120dp"
|
||||
android:layout_height="120dp"
|
||||
android:layout_margin="8dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
tools:visibility="visible">
|
||||
|
||||
<com.keylesspalace.tusky.components.compose.view.ProgressImageView
|
||||
android:id="@+id/imageAttachment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
/>
|
||||
|
||||
<com.keylesspalace.tusky.components.compose.view.ProgressTextView
|
||||
android:id="@+id/textAttachment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone"
|
||||
android:ellipsize="marquee"
|
||||
android:marqueeRepeatLimit="-1"
|
||||
android:singleLine="true"
|
||||
android:textSize="?attr/status_text_small"
|
||||
tools:visibility="visible"
|
||||
/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/attachmentButton"
|
||||
style="@style/TuskyImageButton"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:contentDescription="@string/action_add_media"
|
||||
android:tooltipText="@string/action_add_media"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/attachmentLayout"
|
||||
app:srcCompat="@drawable/ic_attach_file_24dp" />
|
||||
|
||||
<androidx.emoji.widget.EmojiEditText
|
||||
android:id="@+id/editText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:textSize="?attr/status_text_large"
|
||||
android:singleLine="false"
|
||||
android:background="@null"
|
||||
android:hint="@string/chat_message_hint_text"
|
||||
app:layout_constraintEnd_toStartOf="@+id/emojiButton"
|
||||
app:layout_constraintRight_toLeftOf="@id/emojiButton"
|
||||
app:layout_constraintStart_toEndOf="@+id/attachmentButton"
|
||||
app:layout_constraintTop_toBottomOf="@id/attachmentLayout"
|
||||
tools:text="Just landed in L.A." />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/emojiButton"
|
||||
style="@style/TuskyImageButton"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:contentDescription="@string/action_emoji_keyboard"
|
||||
android:tooltipText="@string/action_emoji_keyboard"
|
||||
app:srcCompat="@drawable/ic_emoji_24dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/attachmentLayout"
|
||||
app:layout_constraintRight_toLeftOf="@id/sendButton"
|
||||
/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/sendButton"
|
||||
style="@style/TuskyImageButton"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:contentDescription="@string/action_send"
|
||||
android:tooltipText="@string/action_send"
|
||||
app:srcCompat="@drawable/ic_send_24dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/attachmentLayout"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
Loading…
Reference in New Issue