Skip to content
Snippets Groups Projects
Commit 9e1583e6 authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

Improved user and channel info screen

parent 6b39632a
Branches
Tags
No related merge requests found
Showing
with 386 additions and 420 deletions
...@@ -36,16 +36,22 @@ ...@@ -36,16 +36,22 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
android:name=".ui.chat.info.InfoActivity" android:name=".ui.chat.info.user.UserInfoActivity"
android:exported="false" android:exported="false"
android:label="@string/label_details" android:label="@string/label_info_user"
android:parentActivityName=".ui.chat.ChatActivity"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".ui.chat.info.channel.ChannelInfoActivity"
android:exported="false"
android:label="@string/label_info_channel"
android:parentActivityName=".ui.chat.ChatActivity" android:parentActivityName=".ui.chat.ChatActivity"
android:windowSoftInputMode="adjustResize" /> android:windowSoftInputMode="adjustResize" />
<activity <activity
android:name=".ui.chat.topic.TopicActivity" android:name=".ui.chat.topic.TopicActivity"
android:exported="false" android:exported="false"
android:label="@string/label_topic" android:label="@string/label_topic"
android:parentActivityName=".ui.chat.info.InfoActivity" android:parentActivityName=".ui.chat.info.channel.ChannelInfoActivity"
android:windowSoftInputMode="adjustResize" /> android:windowSoftInputMode="adjustResize" />
<!-- Client Settings --> <!-- Client Settings -->
......
...@@ -6,8 +6,10 @@ import de.kuschku.quasseldroid.service.QuasselService ...@@ -6,8 +6,10 @@ import de.kuschku.quasseldroid.service.QuasselService
import de.kuschku.quasseldroid.ui.chat.ChatActivity import de.kuschku.quasseldroid.ui.chat.ChatActivity
import de.kuschku.quasseldroid.ui.chat.ChatActivityModule import de.kuschku.quasseldroid.ui.chat.ChatActivityModule
import de.kuschku.quasseldroid.ui.chat.ChatFragmentProvider import de.kuschku.quasseldroid.ui.chat.ChatFragmentProvider
import de.kuschku.quasseldroid.ui.chat.info.InfoActivity import de.kuschku.quasseldroid.ui.chat.info.channel.ChannelInfoActivity
import de.kuschku.quasseldroid.ui.chat.info.InfoFragmentProvider import de.kuschku.quasseldroid.ui.chat.info.channel.ChannelInfoFragmentProvider
import de.kuschku.quasseldroid.ui.chat.info.user.UserInfoActivity
import de.kuschku.quasseldroid.ui.chat.info.user.UserInfoFragmentProvider
import de.kuschku.quasseldroid.ui.chat.topic.TopicActivity import de.kuschku.quasseldroid.ui.chat.topic.TopicActivity
import de.kuschku.quasseldroid.ui.chat.topic.TopicFragmentProvider import de.kuschku.quasseldroid.ui.chat.topic.TopicFragmentProvider
import de.kuschku.quasseldroid.ui.clientsettings.about.AboutSettingsActivity import de.kuschku.quasseldroid.ui.clientsettings.about.AboutSettingsActivity
...@@ -37,8 +39,11 @@ abstract class ActivityModule { ...@@ -37,8 +39,11 @@ abstract class ActivityModule {
@ContributesAndroidInjector(modules = [ChatActivityModule::class, ChatFragmentProvider::class]) @ContributesAndroidInjector(modules = [ChatActivityModule::class, ChatFragmentProvider::class])
abstract fun bindChatActivity(): ChatActivity abstract fun bindChatActivity(): ChatActivity
@ContributesAndroidInjector(modules = [InfoFragmentProvider::class]) @ContributesAndroidInjector(modules = [UserInfoFragmentProvider::class])
abstract fun bindInfoActivity(): InfoActivity abstract fun bindUserInfoActivity(): UserInfoActivity
@ContributesAndroidInjector(modules = [ChannelInfoFragmentProvider::class])
abstract fun bindChannelInfoActivity(): ChannelInfoActivity
@ContributesAndroidInjector(modules = [TopicFragmentProvider::class]) @ContributesAndroidInjector(modules = [TopicFragmentProvider::class])
abstract fun bindTopicActivity(): TopicActivity abstract fun bindTopicActivity(): TopicActivity
......
...@@ -87,6 +87,11 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc ...@@ -87,6 +87,11 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
when { when {
intent.type == "text/plain" -> { intent.type == "text/plain" -> {
chatlineFragment?.editorHelper?.replaceText(intent.getStringExtra(Intent.EXTRA_TEXT)) chatlineFragment?.editorHelper?.replaceText(intent.getStringExtra(Intent.EXTRA_TEXT))
drawerLayout.closeDrawers()
}
intent.hasExtra("bufferId") -> {
viewModel.buffer.onNext(intent.getIntExtra("bufferId", -1))
drawerLayout.closeDrawers()
} }
} }
} }
...@@ -230,7 +235,12 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc ...@@ -230,7 +235,12 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
viewModel.connectionProgress_liveData.observe(this, Observer { viewModel.connectionProgress_liveData.observe(this, Observer {
val (state, progress, max) = it ?: Triple(ConnectionState.DISCONNECTED, 0, 0) val (state, progress, max) = it ?: Triple(ConnectionState.DISCONNECTED, 0, 0)
when (state) { when (state) {
ConnectionState.CONNECTED, ConnectionState.CONNECTED -> {
if (resources.getBoolean(R.bool.buffer_drawer_exists) && viewModel.buffer.value == -1) {
drawerLayout.openDrawer(Gravity.START)
}
progressBar.visibility = View.INVISIBLE
}
ConnectionState.DISCONNECTED, ConnectionState.DISCONNECTED,
ConnectionState.CLOSED -> { ConnectionState.CLOSED -> {
progressBar.visibility = View.INVISIBLE progressBar.visibility = View.INVISIBLE
...@@ -260,10 +270,10 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc ...@@ -260,10 +270,10 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
invalidateOptionsMenu() invalidateOptionsMenu()
}) })
onNewIntent(intent)
editorPanel.panelState = SlidingUpPanelLayout.PanelState.COLLAPSED editorPanel.panelState = SlidingUpPanelLayout.PanelState.COLLAPSED
chatlineFragment?.panelSlideListener?.let(editorPanel::addPanelSlideListener) chatlineFragment?.panelSlideListener?.let(editorPanel::addPanelSlideListener)
onNewIntent(intent)
} }
var bufferData: BufferData? = null var bufferData: BufferData? = null
......
...@@ -16,9 +16,8 @@ import de.kuschku.libquassel.util.helpers.value ...@@ -16,9 +16,8 @@ import de.kuschku.libquassel.util.helpers.value
import de.kuschku.quasseldroid.R import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.settings.AppearanceSettings import de.kuschku.quasseldroid.settings.AppearanceSettings
import de.kuschku.quasseldroid.settings.MessageSettings import de.kuschku.quasseldroid.settings.MessageSettings
import de.kuschku.quasseldroid.ui.chat.info.InfoActivity import de.kuschku.quasseldroid.ui.chat.info.channel.ChannelInfoActivity
import de.kuschku.quasseldroid.ui.chat.info.InfoDescriptor import de.kuschku.quasseldroid.ui.chat.info.user.UserInfoActivity
import de.kuschku.quasseldroid.ui.chat.info.InfoType
import de.kuschku.quasseldroid.util.helper.combineLatest import de.kuschku.quasseldroid.util.helper.combineLatest
import de.kuschku.quasseldroid.util.helper.toLiveData import de.kuschku.quasseldroid.util.helper.toLiveData
import de.kuschku.quasseldroid.util.helper.visibleIf import de.kuschku.quasseldroid.util.helper.visibleIf
...@@ -100,30 +99,21 @@ class ToolbarFragment : ServiceBoundFragment() { ...@@ -100,30 +99,21 @@ class ToolbarFragment : ServiceBoundFragment() {
actionArea.setOnClickListener { actionArea.setOnClickListener {
viewModel.bufferData.value?.info?.let { info -> viewModel.bufferData.value?.info?.let { info ->
when (info.type.toInt()) { when (info.type.toInt()) {
BufferInfo.Type.QueryBuffer.toInt() -> InfoDescriptor( BufferInfo.Type.QueryBuffer.toInt() -> {
type = InfoType.User, val intent = Intent(requireContext(), UserInfoActivity::class.java)
nick = info.bufferName, intent.putExtra("bufferId", info.bufferId)
buffer = info.bufferId, intent.putExtra("openBuffer", true)
network = info.networkId startActivity(intent)
)
BufferInfo.Type.ChannelBuffer.toInt() -> InfoDescriptor(
type = InfoType.Channel,
channel = info.bufferName,
buffer = info.bufferId,
network = info.networkId
)
BufferInfo.Type.StatusBuffer.toInt() -> InfoDescriptor(
type = InfoType.Network,
buffer = info.bufferId,
network = info.networkId
)
else -> null
} }
}?.let { infoDescriptor -> BufferInfo.Type.ChannelBuffer.toInt() -> {
val intent = Intent(requireContext(), InfoActivity::class.java) val intent = Intent(requireContext(), ChannelInfoActivity::class.java)
intent.putExtra("info", infoDescriptor) intent.putExtra("bufferId", info.bufferId)
intent.putExtra("openBuffer", true)
startActivity(intent) startActivity(intent)
} }
else -> null
}
}
} }
return view return view
......
package de.kuschku.quasseldroid.ui.chat.info
import de.kuschku.libquassel.quassel.syncables.IrcChannel
import de.kuschku.libquassel.quassel.syncables.IrcUser
import de.kuschku.libquassel.quassel.syncables.Network
data class InfoData(
val type: InfoType,
val user: IrcUser? = null,
val channel: IrcChannel? = null,
val network: Network,
val properties: List<InfoGroup> = emptyList()
)
\ No newline at end of file
package de.kuschku.quasseldroid.ui.chat.info
import java.io.Serializable
data class InfoDescriptor(
val type: InfoType,
val nick: String? = null,
val channel: String? = null,
val buffer: Int,
val network: Int
) : Serializable
package de.kuschku.quasseldroid.ui.chat.info
import android.arch.lifecycle.Observer
import android.content.Intent
import android.os.Bundle
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import butterknife.BindView
import butterknife.ButterKnife
import de.kuschku.libquassel.util.Optional
import de.kuschku.libquassel.util.compatibility.LoggingHandler
import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.ui.chat.topic.TopicActivity
import de.kuschku.quasseldroid.util.helper.toLiveData
import de.kuschku.quasseldroid.util.irc.format.ContentFormatter
import de.kuschku.quasseldroid.util.service.ServiceBoundFragment
import io.reactivex.Observable
import javax.inject.Inject
class InfoFragment : ServiceBoundFragment() {
@BindView(R.id.groups)
lateinit var groups: RecyclerView
@Inject
lateinit var contentFormatter: ContentFormatter
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_info, container, false)
ButterKnife.bind(this, view)
val adapter = InfoGroupAdapter()
groups.layoutManager = LinearLayoutManager(requireContext())
groups.adapter = adapter
val info = arguments?.getSerializable("info") as? InfoDescriptor
viewModel.session.switchMap { sessionOptional ->
val network = sessionOptional.orNull()?.networks?.get(info?.network)
if (info == null || network == null) {
Observable.just(Optional.empty())
} else {
when (info.type) {
InfoType.User -> {
network.liveIrcUser(info.nick).switchMap {
it.updates().map { user ->
Optional.of(InfoData(
type = info.type,
user = user,
network = network,
properties = listOf(
InfoGroup(
name = getString(R.string.property_group_ircuser_identity),
properties = listOf(
InfoProperty(
name = getString(R.string.property_ircuser_nick),
value = user.nick()
),
InfoProperty(
name = getString(R.string.property_ircuser_user),
value = user.user()
),
InfoProperty(
name = getString(R.string.property_ircuser_host),
value = user.host()
),
InfoProperty(
name = getString(R.string.property_ircuser_realname),
value = contentFormatter.format(requireContext(), user.realName())
),
InfoProperty(
name = getString(R.string.property_ircuser_account),
value = user.account()
)
)
)
)
))
}
}
}
InfoType.Channel -> {
network.liveIrcChannel(info.channel).map { channel ->
Optional.of(InfoData(
type = info.type,
channel = channel,
network = network,
properties = listOf(
InfoGroup(
name = getString(R.string.property_group_ircchannel_channel),
properties = listOf(
InfoProperty(
name = getString(R.string.property_ircchannel_topic),
value = contentFormatter.format(requireContext(), channel.topic()),
actions = listOf(
InfoPropertyAction(
name = getString(R.string.property_ircchannel_topic_action_edit),
featured = true,
onClick = {
val intent = Intent(requireContext(), TopicActivity::class.java)
intent.putExtra("buffer", info.buffer)
startActivity(intent)
}
)
)
)
)
)
)
))
}
}
InfoType.Network -> {
network.live_connectionState.map {
Optional.of(InfoData(
type = info.type,
network = network
))
}
}
}
}
}.toLiveData().observe(this, Observer {
LoggingHandler.log(LoggingHandler.LogLevel.ERROR, "DEBUG", "data: $it")
adapter.submitList(it?.orNull()?.properties.orEmpty())
})
return view
}
}
package de.kuschku.quasseldroid.ui.chat.info
data class InfoGroup(
val name: CharSequence,
val properties: List<InfoProperty>
)
package de.kuschku.quasseldroid.ui.chat.info
import android.support.v7.recyclerview.extensions.ListAdapter
import android.support.v7.util.DiffUtil
import android.support.v7.widget.DividerItemDecoration
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import butterknife.BindView
import butterknife.ButterKnife
import de.kuschku.quasseldroid.R
class InfoGroupAdapter :
ListAdapter<InfoGroup, InfoGroupAdapter.InfoGroupViewHolder>(
object : DiffUtil.ItemCallback<InfoGroup>() {
override fun areItemsTheSame(oldItem: InfoGroup, newItem: InfoGroup) =
oldItem.name == newItem.name
override fun areContentsTheSame(oldItem: InfoGroup, newItem: InfoGroup) =
oldItem == newItem
}
) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = InfoGroupViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.widget_info_group, parent, false)
)
override fun onBindViewHolder(holder: InfoGroupViewHolder, position: Int) =
holder.bind(getItem(position))
class InfoGroupViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
@BindView(R.id.title)
lateinit var title: TextView
@BindView(R.id.properties)
lateinit var properties: RecyclerView
private val adapter = InfoPropertyAdapter()
init {
ButterKnife.bind(this, itemView)
properties.layoutManager = LinearLayoutManager(itemView.context)
properties.adapter = adapter
properties.addItemDecoration(
DividerItemDecoration(itemView.context, DividerItemDecoration.VERTICAL)
)
}
fun bind(item: InfoGroup) {
title.text = item.name
adapter.submitList(item.properties)
}
}
}
\ No newline at end of file
package de.kuschku.quasseldroid.ui.chat.info
import android.support.annotation.DrawableRes
data class InfoProperty(
val name: CharSequence? = null,
@DrawableRes val icon: Int? = null,
val value: CharSequence,
val actions: List<InfoPropertyAction> = emptyList()
)
\ No newline at end of file
package de.kuschku.quasseldroid.ui.chat.info
data class InfoPropertyAction(
val name: CharSequence,
val featured: Boolean = false,
val onClick: () -> Unit
)
\ No newline at end of file
package de.kuschku.quasseldroid.ui.chat.info
import android.support.v7.recyclerview.extensions.ListAdapter
import android.support.v7.util.DiffUtil
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import butterknife.BindView
import butterknife.ButterKnife
import de.kuschku.quasseldroid.R
class InfoPropertyActionAdapter :
ListAdapter<InfoPropertyAction, InfoPropertyActionAdapter.InfoPropertyActionViewHolder>(
object : DiffUtil.ItemCallback<InfoPropertyAction>() {
override fun areItemsTheSame(oldItem: InfoPropertyAction, newItem: InfoPropertyAction) =
oldItem.name == newItem.name
override fun areContentsTheSame(oldItem: InfoPropertyAction, newItem: InfoPropertyAction) =
oldItem == newItem
}
) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = InfoPropertyActionViewHolder(
LayoutInflater.from(parent.context).inflate(
if (viewType == VIEWTYPE_FEATURED)
R.layout.widget_info_action_main
else
R.layout.widget_info_action,
parent,
false
)
)
override fun onBindViewHolder(holder: InfoPropertyActionViewHolder, position: Int) {
holder.bind(getItem(position))
}
override fun getItemViewType(position: Int) =
if (getItem(position).featured) VIEWTYPE_FEATURED else VIEWTYPE_NORMAL
class InfoPropertyActionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
@BindView(R.id.button)
lateinit var button: Button
private var onClick: (() -> Unit)? = null
init {
ButterKnife.bind(this, itemView)
button.setOnClickListener {
onClick?.invoke()
}
}
fun bind(item: InfoPropertyAction) {
this.onClick = item.onClick
button.text = item.name
}
}
companion object {
const val VIEWTYPE_NORMAL = 0
const val VIEWTYPE_FEATURED = 1
}
}
\ No newline at end of file
package de.kuschku.quasseldroid.ui.chat.info
import android.support.v7.recyclerview.extensions.ListAdapter
import android.support.v7.util.DiffUtil
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import butterknife.BindView
import butterknife.ButterKnife
import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.util.helper.visibleIf
import me.saket.bettermovementmethod.BetterLinkMovementMethod
class InfoPropertyAdapter :
ListAdapter<InfoProperty, InfoPropertyAdapter.InfoPropertyViewHolder>(
object : DiffUtil.ItemCallback<InfoProperty>() {
override fun areItemsTheSame(oldItem: InfoProperty, newItem: InfoProperty) =
oldItem.name == newItem.name
override fun areContentsTheSame(oldItem: InfoProperty, newItem: InfoProperty) =
oldItem == newItem
}
) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = InfoPropertyViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.widget_info_property, parent, false)
)
override fun onBindViewHolder(holder: InfoPropertyViewHolder, position: Int) =
holder.bind(getItem(position))
class InfoPropertyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
@BindView(R.id.icon_frame)
lateinit var iconFrame: View
@BindView(R.id.icon)
lateinit var icon: ImageView
@BindView(R.id.name)
lateinit var name: TextView
@BindView(R.id.value)
lateinit var value: TextView
@BindView(R.id.actions)
lateinit var actions: RecyclerView
private val adapter = InfoPropertyActionAdapter()
init {
ButterKnife.bind(this, itemView)
actions.layoutManager = LinearLayoutManager(itemView.context, RecyclerView.HORIZONTAL, false)
actions.adapter = adapter
value.movementMethod = BetterLinkMovementMethod.getInstance()
}
fun bind(item: InfoProperty) {
item.icon?.let(icon::setImageResource)
name.text = item.name
value.text = item.value
adapter.submitList(item.actions)
iconFrame.visibleIf(item.icon != null)
}
}
}
package de.kuschku.quasseldroid.ui.chat.info
enum class InfoType {
User,
Channel,
Network
}
\ No newline at end of file
package de.kuschku.quasseldroid.ui.chat.info.channel
import de.kuschku.quasseldroid.util.ui.SettingsActivity
class ChannelInfoActivity : SettingsActivity(ChannelInfoFragment())
package de.kuschku.quasseldroid.ui.chat.info.channel
import android.arch.lifecycle.Observer
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import butterknife.BindView
import butterknife.ButterKnife
import de.kuschku.libquassel.protocol.Buffer_Type
import de.kuschku.libquassel.quassel.syncables.IrcChannel
import de.kuschku.libquassel.util.helpers.value
import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.ui.chat.topic.TopicActivity
import de.kuschku.quasseldroid.util.helper.combineLatest
import de.kuschku.quasseldroid.util.helper.toLiveData
import de.kuschku.quasseldroid.util.irc.format.ContentFormatter
import de.kuschku.quasseldroid.util.service.ServiceBoundFragment
import de.kuschku.quasseldroid.util.ui.LinkLongClickMenuHelper
import me.saket.bettermovementmethod.BetterLinkMovementMethod
import javax.inject.Inject
class ChannelInfoFragment : ServiceBoundFragment() {
@BindView(R.id.name)
lateinit var name: TextView
@BindView(R.id.topic)
lateinit var topic: TextView
@BindView(R.id.action_edit_topic)
lateinit var actionEditTopic: Button
@BindView(R.id.action_part)
lateinit var actionPart: Button
@Inject
lateinit var contentFormatter: ContentFormatter
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_info_channel, container, false)
ButterKnife.bind(this, view)
val openBuffer = arguments?.getBoolean("openBuffer")
combineLatest(viewModel.session, viewModel.networks).map { (sessionOptional, networks) ->
if (openBuffer == true) {
val session = sessionOptional?.orNull()
val bufferSyncer = session?.bufferSyncer
val bufferInfo = bufferSyncer?.bufferInfo(arguments?.getInt("bufferId") ?: -1)
bufferInfo?.let {
networks[it.networkId]?.ircChannel(it.bufferName)
}
} else {
networks[arguments?.getInt("networkId")]?.ircChannel(arguments?.getString("nick"))
} ?: IrcChannel.NULL
}.filter {
it != IrcChannel.NULL
}.switchMap(IrcChannel::updates).firstElement().toLiveData().observe(this, Observer { channel ->
if (channel != null) {
name.text = channel.name()
topic.text = contentFormatter.format(requireContext(), channel.topic())
actionEditTopic.setOnClickListener {
val intent = Intent(requireContext(), TopicActivity::class.java)
intent.putExtra("buffer", arguments?.getInt("bufferId") ?: -1)
startActivity(intent)
}
actionPart.setOnClickListener {
viewModel.session.value?.orNull()?.let { session ->
session.bufferSyncer?.find(
networkId = channel.network().networkId(),
type = Buffer_Type.of(Buffer_Type.StatusBuffer)
)?.let { statusInfo ->
session.rpcHandler?.sendInput(statusInfo, "/part ${channel.name()}")
requireActivity().finish()
}
}
}
}
})
val movementMethod = BetterLinkMovementMethod.newInstance()
movementMethod.setOnLinkLongClickListener(LinkLongClickMenuHelper())
topic.movementMethod = movementMethod
return view
}
}
package de.kuschku.quasseldroid.ui.chat.info.channel
import dagger.Module
import dagger.android.ContributesAndroidInjector
@Module
abstract class ChannelInfoFragmentProvider {
@ContributesAndroidInjector
abstract fun bindChannelInfoFragment(): ChannelInfoFragment
}
package de.kuschku.quasseldroid.ui.chat.info package de.kuschku.quasseldroid.ui.chat.info.user
import de.kuschku.quasseldroid.util.ui.SettingsActivity import de.kuschku.quasseldroid.util.ui.SettingsActivity
class InfoActivity : SettingsActivity(InfoFragment()) class UserInfoActivity : SettingsActivity(UserInfoFragment())
\ No newline at end of file
package de.kuschku.quasseldroid.ui.chat.info.user
import android.arch.lifecycle.Observer
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import butterknife.BindView
import butterknife.ButterKnife
import de.kuschku.libquassel.protocol.Buffer_Type
import de.kuschku.libquassel.quassel.syncables.IrcUser
import de.kuschku.libquassel.util.IrcUserUtils
import de.kuschku.quasseldroid.GlideApp
import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.ui.chat.ChatActivity
import de.kuschku.quasseldroid.ui.chat.input.AutoCompleteHelper.Companion.IGNORED_CHARS
import de.kuschku.quasseldroid.util.helper.*
import de.kuschku.quasseldroid.util.irc.format.ContentFormatter
import de.kuschku.quasseldroid.util.service.ServiceBoundFragment
import de.kuschku.quasseldroid.util.ui.LinkLongClickMenuHelper
import de.kuschku.quasseldroid.util.ui.TextDrawable
import me.saket.bettermovementmethod.BetterLinkMovementMethod
import javax.inject.Inject
class UserInfoFragment : ServiceBoundFragment() {
@BindView(R.id.avatar)
lateinit var avatar: ImageView
@BindView(R.id.nick)
lateinit var nick: TextView
@BindView(R.id.real_name)
lateinit var realName: TextView
@BindView(R.id.action_query)
lateinit var actionQuery: Button
@BindView(R.id.action_ignore)
lateinit var actionIgnore: Button
@BindView(R.id.action_mention)
lateinit var actionMention: Button
@BindView(R.id.away_container)
lateinit var awayContainer: ViewGroup
@BindView(R.id.away_message)
lateinit var awayMessage: TextView
@BindView(R.id.account_container)
lateinit var accountContainer: ViewGroup
@BindView(R.id.account)
lateinit var account: TextView
@BindView(R.id.ident_container)
lateinit var identContainer: ViewGroup
@BindView(R.id.ident)
lateinit var ident: TextView
@BindView(R.id.host_container)
lateinit var hostContainer: ViewGroup
@BindView(R.id.host)
lateinit var host: TextView
@BindView(R.id.server_container)
lateinit var serverContainer: ViewGroup
@BindView(R.id.server)
lateinit var server: TextView
@Inject
lateinit var contentFormatter: ContentFormatter
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_info_user, container, false)
ButterKnife.bind(this, view)
val openBuffer = arguments?.getBoolean("openBuffer")
val senderColors = requireContext().theme.styledAttributes(
R.attr.senderColor0, R.attr.senderColor1, R.attr.senderColor2, R.attr.senderColor3,
R.attr.senderColor4, R.attr.senderColor5, R.attr.senderColor6, R.attr.senderColor7,
R.attr.senderColor8, R.attr.senderColor9, R.attr.senderColorA, R.attr.senderColorB,
R.attr.senderColorC, R.attr.senderColorD, R.attr.senderColorE, R.attr.senderColorF
) {
IntArray(length()) {
getColor(it, 0)
}
}
val networkId = arguments?.getInt("networkId")
val nickName = arguments?.getString("nick")
combineLatest(viewModel.session, viewModel.networks).map { (sessionOptional, networks) ->
if (openBuffer == true) {
val session = sessionOptional?.orNull()
val bufferSyncer = session?.bufferSyncer
val bufferInfo = bufferSyncer?.bufferInfo(arguments?.getInt("bufferId") ?: -1)
bufferInfo?.let {
networks[it.networkId]?.ircUser(it.bufferName)
}
} else {
networks[networkId]?.ircUser(nickName)
} ?: IrcUser.NULL
}.filter {
it != IrcUser.NULL
}.switchMap(IrcUser::updates).firstElement().toLiveData().observe(this, Observer { user ->
if (user != null) {
val senderColorIndex = IrcUserUtils.senderColor(user.nick())
val rawInitial = user.nick().trimStart(*IGNORED_CHARS).firstOrNull()
?: user.nick().firstOrNull()
val initial = rawInitial?.toUpperCase().toString()
val senderColor = senderColors[senderColorIndex]
val fallbackDrawable = TextDrawable.builder().buildRect(initial, senderColor)
val avatarUrl = Regex("[us]id(\\d+)").matchEntire(user.user())?.groupValues?.lastOrNull()?.let {
"https://www.irccloud.com/avatar-redirect/$it"
}
if (avatarUrl != null) {
GlideApp.with(avatar)
.load(avatarUrl)
.placeholder(fallbackDrawable)
.into(avatar)
} else {
avatar.setImageDrawable(fallbackDrawable)
}
nick.text = user.nick()
realName.text = contentFormatter.format(requireContext(), user.realName())
realName.visibleIf(user.realName().isNotBlank() && user.realName() != user.nick())
awayMessage.text = user.awayMessage()
awayContainer.visibleIf(user.awayMessage().isNotBlank())
account.text = user.user()
accountContainer.visibleIf(user.account().isNotBlank())
ident.text = user.user()
identContainer.visibleIf(user.user().isNotBlank())
host.text = user.host()
hostContainer.visibleIf(user.host().isNotBlank())
server.text = user.server()
serverContainer.visibleIf(user.server().isNotBlank())
actionQuery.setOnClickListener {
viewModel.session {
it.orNull()?.let { session ->
val info = session.bufferSyncer?.find(
bufferName = user.nick(),
networkId = user.network().networkId(),
type = Buffer_Type.of(Buffer_Type.QueryBuffer)
)
val intent = Intent(requireContext(), ChatActivity::class.java)
if (info != null) {
intent.putExtra("bufferId", info.bufferId)
startActivity(intent)
} else {
viewModel.allBuffers.map {
listOfNotNull(it.find {
it.networkId == user.network().networkId() && it.bufferName == user.nick()
})
}.filter {
it.isNotEmpty()
}.firstElement().toLiveData().observe(this, Observer {
it?.firstOrNull()?.let { info ->
intent.putExtra("bufferId", info.bufferId)
startActivity(intent)
}
})
session.bufferSyncer?.find(
networkId = networkId,
type = Buffer_Type.of(Buffer_Type.StatusBuffer)
)?.let { statusInfo ->
session.rpcHandler?.sendInput(statusInfo, "/query ${user.nick()}")
}
}
}
}
}
actionMention.setOnClickListener {
val intent = Intent(requireContext(), ChatActivity::class.java)
intent.type = "text/plain"
intent.putExtra(Intent.EXTRA_TEXT, "${user.nick()}: ")
startActivity(intent)
}
actionMention.visibleIf(arguments?.getBoolean("openBuffer") == false)
actionIgnore.setOnClickListener {
Toast.makeText(requireContext(), "Not Implemented", Toast.LENGTH_SHORT).show()
}
}
})
val movementMethod = BetterLinkMovementMethod.newInstance()
movementMethod.setOnLinkLongClickListener(LinkLongClickMenuHelper())
realName.movementMethod = movementMethod
return view
}
}
package de.kuschku.quasseldroid.ui.chat.info package de.kuschku.quasseldroid.ui.chat.info.user
import dagger.Module import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
@Module @Module
abstract class InfoFragmentProvider { abstract class UserInfoFragmentProvider {
@ContributesAndroidInjector @ContributesAndroidInjector
abstract fun bindInfoFragment(): InfoFragment abstract fun bindUserInfoFragment(): UserInfoFragment
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment