Skip to content
Snippets Groups Projects
Verified Commit 0c0cc852 authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

Implement common channels UI in user info page

parent 72818ec2
No related branches found
No related tags found
No related merge requests found
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2019 Janne Koschinski
* Copyright (c) 2019 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.ui.info.user
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import butterknife.BindView
import butterknife.ButterKnife
import de.kuschku.libquassel.protocol.NetworkId
import de.kuschku.libquassel.quassel.BufferInfo
import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.ui.chat.ChatActivity
import de.kuschku.quasseldroid.util.helper.visibleIf
import de.kuschku.quasseldroid.util.lists.ListAdapter
import de.kuschku.quasseldroid.viewmodel.data.BufferProps
class ChannelAdapter : ListAdapter<BufferProps, ChannelAdapter.ChannelViewHolder>(
object : DiffUtil.ItemCallback<BufferProps>() {
override fun areItemsTheSame(oldItem: BufferProps, newItem: BufferProps) =
oldItem.info.bufferId == newItem.info.bufferId
override fun areContentsTheSame(oldItem: BufferProps, newItem: BufferProps) =
oldItem == newItem
}
) {
private var clickListener: ((NetworkId, String) -> Unit)? = null
fun setOnClickListener(listener: ((NetworkId, String) -> Unit)?) {
this.clickListener = listener
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ChannelViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.widget_buffer, parent, false
),
clickListener = clickListener
)
override fun onBindViewHolder(holder: ChannelViewHolder, position: Int) =
holder.bind(getItem(position))
class ChannelViewHolder(
itemView: View,
private val clickListener: ((NetworkId, String) -> Unit)? = null
) : RecyclerView.ViewHolder(itemView) {
@BindView(R.id.status)
lateinit var status: ImageView
@BindView(R.id.name)
lateinit var name: TextView
@BindView(R.id.description)
lateinit var description: TextView
var info: BufferInfo? = null
init {
ButterKnife.bind(this, itemView)
itemView.setOnClickListener {
info?.let {
ChatActivity.launch(
itemView.context,
networkId = it.networkId,
channel = it.bufferName
)
}
}
}
fun bind(props: BufferProps) {
info = props.info
name.text = props.info.bufferName
description.text = props.description
description.visibleIf(props.description.isNotBlank())
status.setImageDrawable(props.fallbackDrawable)
}
}
}
......@@ -23,6 +23,7 @@ import de.kuschku.libquassel.protocol.NetworkId
import de.kuschku.libquassel.quassel.BufferInfo
import de.kuschku.libquassel.quassel.syncables.IrcUser
import de.kuschku.libquassel.quassel.syncables.Network
import de.kuschku.quasseldroid.viewmodel.data.BufferProps
data class IrcUserInfo(
val networkId: NetworkId,
......@@ -37,5 +38,6 @@ data class IrcUserInfo(
val network: Network? = null,
val knownToCore: Boolean = false,
val info: BufferInfo? = null,
val ircUser: IrcUser? = null
val ircUser: IrcUser? = null,
val channels: List<BufferProps> = emptyList()
)
......@@ -31,12 +31,18 @@ import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import butterknife.BindView
import butterknife.ButterKnife
import de.kuschku.libquassel.protocol.BufferId
import de.kuschku.libquassel.protocol.Buffer_Type
import de.kuschku.libquassel.protocol.Message_Type
import de.kuschku.libquassel.protocol.NetworkId
import de.kuschku.libquassel.quassel.BufferInfo
import de.kuschku.libquassel.quassel.syncables.BufferSyncer
import de.kuschku.libquassel.quassel.syncables.IrcChannel
import de.kuschku.libquassel.quassel.syncables.IrcUser
import de.kuschku.libquassel.util.Optional
import de.kuschku.libquassel.util.helpers.nullIf
......@@ -46,6 +52,7 @@ import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.settings.MessageSettings
import de.kuschku.quasseldroid.ui.chat.ChatActivity
import de.kuschku.quasseldroid.ui.coresettings.ignorelist.IgnoreListActivity
import de.kuschku.quasseldroid.util.ColorContext
import de.kuschku.quasseldroid.util.ShortcutCreationHelper
import de.kuschku.quasseldroid.util.avatars.AvatarHelper
import de.kuschku.quasseldroid.util.avatars.MatrixApi
......@@ -57,6 +64,9 @@ import de.kuschku.quasseldroid.util.service.ServiceBoundFragment
import de.kuschku.quasseldroid.util.ui.BetterLinkMovementMethod
import de.kuschku.quasseldroid.util.ui.LinkLongClickMenuHelper
import de.kuschku.quasseldroid.viewmodel.data.Avatar
import de.kuschku.quasseldroid.viewmodel.data.BufferHiddenState
import de.kuschku.quasseldroid.viewmodel.data.BufferProps
import de.kuschku.quasseldroid.viewmodel.data.BufferStatus
import io.reactivex.Observable
import javax.inject.Inject
......@@ -115,6 +125,9 @@ class UserInfoFragment : ServiceBoundFragment() {
@BindView(R.id.server)
lateinit var server: TextView
@BindView(R.id.common_channels)
lateinit var commonChannels: RecyclerView
@Inject
lateinit var contentFormatter: ContentFormatter
......@@ -144,18 +157,66 @@ class UserInfoFragment : ServiceBoundFragment() {
actionShortcut.visibleIf(currentBufferInfo != null)
}
val commonChannelsAdapter = ChannelAdapter()
commonChannels.layoutManager = LinearLayoutManager(context)
commonChannels.itemAnimator = DefaultItemAnimator()
commonChannels.adapter = commonChannelsAdapter
val colorContext = ColorContext(requireContext(), messageSettings)
val colorAccent = requireContext().theme.styledAttributes(R.attr.colorAccent) {
getColor(0, 0)
}
val colorAway = requireContext().theme.styledAttributes(R.attr.colorAway) {
getColor(0, 0)
}
combineLatest(viewModel.session, viewModel.networks).switchMap { (sessionOptional, networks) ->
fun processUser(user: IrcUser, info: BufferInfo? = null): Optional<IrcUserInfo> {
fun processUser(user: IrcUser, bufferSyncer: BufferSyncer? = null,
info: BufferInfo? = null): Observable<Optional<IrcUserInfo>> {
actionShortcut.post(::updateShortcutVisibility)
return when {
user == IrcUser.NULL && info != null -> Optional.of(IrcUserInfo(
user == IrcUser.NULL && info != null -> Observable.just(Optional.of(IrcUserInfo(
networkId = info.networkId,
nick = info.bufferName ?: "",
knownToCore = true,
info = info
))
user == IrcUser.NULL -> Optional.empty()
else -> Optional.of(IrcUserInfo(
)))
user == IrcUser.NULL -> Observable.just(Optional.empty())
else -> {
combineLatest(user.channels().map { channelName ->
user.network().liveIrcChannel(
channelName
).switchMap { channel ->
channel.updates().map {
bufferSyncer?.find(
bufferName = channelName,
networkId = user.network().networkId()
)?.let { info ->
val bufferStatus =
if (it == IrcChannel.NULL) BufferStatus.OFFLINE
else BufferStatus.ONLINE
val color =
if (bufferStatus == BufferStatus.ONLINE) colorAccent
else colorAway
val fallbackDrawable = colorContext.buildTextDrawable("#", color)
BufferProps(
info = info,
network = user.network().networkInfo(),
description = it.topic(),
activity = Message_Type.of(),
bufferStatus = bufferStatus,
hiddenState = BufferHiddenState.VISIBLE,
networkConnectionState = user.network().connectionState(),
fallbackDrawable = fallbackDrawable
)
}
}
}
}).map {
Optional.of(IrcUserInfo(
networkId = user.network().networkId(),
nick = user.nick(),
user = user.user(),
......@@ -168,26 +229,29 @@ class UserInfoFragment : ServiceBoundFragment() {
network = user.network(),
knownToCore = true,
info = info,
ircUser = user
ircUser = user,
channels = it.filterNotNull()
))
}
}
}
}
if (openBuffer == true) {
val session = sessionOptional?.orNull()
val bufferSyncer = session?.bufferSyncer
val bufferInfo = bufferSyncer?.bufferInfo(bufferId)
bufferInfo?.let {
networks[it.networkId]?.liveIrcUser(it.bufferName)?.switchMap(IrcUser::updates)?.map {
processUser(it, bufferInfo)
networks[it.networkId]?.liveIrcUser(it.bufferName)?.switchMap(IrcUser::updates)?.switchMap {
processUser(it, bufferSyncer, bufferInfo)
}
}
} else {
networks[networkId]
?.liveIrcUser(nickName)
?.switchMap(IrcUser::updates)
?.map { user -> processUser(user) }
} ?: Observable.just(IrcUser.NULL).map { user -> processUser(user) }
?.switchMap { user -> processUser(user, sessionOptional?.orNull()?.bufferSyncer) }
} ?: Observable.just(IrcUser.NULL).switchMap { user -> processUser(user, null, null) }
}.toLiveData().observe(this, Observer {
val user = it.orNull()
if (user != null) {
......@@ -322,6 +386,8 @@ class UserInfoFragment : ServiceBoundFragment() {
}
}
}
commonChannelsAdapter.submitList(user.channels)
}
})
......
......@@ -251,6 +251,15 @@
style="@style/Widget.Info.Item.Description"
android:text="@string/label_user_server" />
</LinearLayout>
<TextView
style="@style/Widget.Info.Section"
android:text="@string/label_user_common_channels" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/common_channels"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
......@@ -25,6 +25,7 @@
<string name="label_user_ident">Ident</string>
<string name="label_user_host">Host</string>
<string name="label_user_server">Server</string>
<string name="label_user_common_channels">Common Channels</string>
<string name="label_core_version">Version</string>
<string name="label_core_uptime">Uptime</string>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment