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

Improved channel list

parent 564dae48
No related branches found
No related tags found
No related merge requests found
Showing
with 606 additions and 52 deletions
......@@ -30,6 +30,7 @@ class QuasselService : LifecycleService() {
@SuppressLint("TrustAllX509TrustManager")
override fun checkServerTrusted(p0: Array<out X509Certificate>?, p1: String?) = Unit
override fun getAcceptedIssuers(): Array<X509Certificate> = emptyArray()
}
......
......@@ -2,38 +2,75 @@ package de.kuschku.quasseldroid_ng.ui.chat
import android.arch.lifecycle.LifecycleOwner
import android.arch.lifecycle.LiveData
import android.arch.lifecycle.MutableLiveData
import android.arch.lifecycle.Observer
import android.graphics.drawable.Drawable
import android.support.v4.graphics.drawable.DrawableCompat
import android.support.v7.util.DiffUtil
import android.support.v7.widget.AppCompatImageButton
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.libquassel.protocol.BufferId
import de.kuschku.libquassel.protocol.NetworkId
import de.kuschku.libquassel.quassel.BufferInfo
import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
import de.kuschku.libquassel.util.hasFlag
import de.kuschku.quasseldroid_ng.R
import de.kuschku.quasseldroid_ng.util.helper.getCompatDrawable
import de.kuschku.quasseldroid_ng.util.helper.styledAttributes
import de.kuschku.quasseldroid_ng.util.helper.zip
class BufferListAdapter(
lifecycleOwner: LifecycleOwner,
liveData: LiveData<List<BufferInfo>?>,
liveData: LiveData<List<BufferProps>?>,
runInBackground: (() -> Unit) -> Any,
runOnUiThread: (Runnable) -> Any,
private val clickListener: ((BufferId) -> Unit)? = null
) : RecyclerView.Adapter<BufferListAdapter.BufferViewHolder>() {
var data = mutableListOf<BufferInfo>()
var data = mutableListOf<BufferListItem>()
var collapsedNetworks = MutableLiveData<Set<NetworkId>>()
fun expandListener(networkId: NetworkId) {
if (collapsedNetworks.value.orEmpty().contains(networkId))
collapsedNetworks.postValue(collapsedNetworks.value.orEmpty() - networkId)
else
collapsedNetworks.postValue(collapsedNetworks.value.orEmpty() + networkId)
}
init {
liveData.observe(
lifecycleOwner, Observer { list: List<BufferInfo>? ->
collapsedNetworks.value = emptySet()
liveData.zip(collapsedNetworks).observe(
lifecycleOwner, Observer { it: Pair<List<BufferProps>?, Set<NetworkId>>? ->
runInBackground {
val old = data
val new = list?.sortedBy(BufferInfo::networkId) ?: emptyList()
val list = it?.first ?: emptyList()
val collapsedNetworks = it?.second ?: emptySet()
val old: List<BufferListItem> = data
val new: List<BufferListItem> = list.sortedBy { props ->
props.network.networkName
}.map { props ->
BufferListItem(
props,
BufferState(
networkExpanded = !collapsedNetworks.contains(props.network.networkId)
)
)
}.filter { (props, state) ->
props.info.type.hasFlag(BufferInfo.Type.StatusBuffer) || state.networkExpanded
}
val result = DiffUtil.calculateDiff(
object : DiffUtil.Callback() {
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int)
= old[oldItemPosition].bufferId == new[newItemPosition].bufferId
= old[oldItemPosition].props.info.bufferId == new[newItemPosition].props.info.bufferId
override fun getOldListSize() = old.size
override fun getNewListSize() = new.size
......@@ -54,25 +91,129 @@ class BufferListAdapter(
)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = BufferViewHolder(
LayoutInflater.from(parent.context).inflate(android.R.layout.simple_list_item_1, parent, false),
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = when (viewType) {
BufferInfo.Type.ChannelBuffer.toInt() -> BufferViewHolder.ChannelBuffer(
LayoutInflater.from(parent.context).inflate(
R.layout.widget_buffer, parent, false
),
clickListener = clickListener
)
BufferInfo.Type.QueryBuffer.toInt() -> BufferViewHolder.QueryBuffer(
LayoutInflater.from(parent.context).inflate(
R.layout.widget_buffer, parent, false
),
clickListener = clickListener
)
BufferInfo.Type.GroupBuffer.toInt() -> BufferViewHolder.GroupBuffer(
LayoutInflater.from(parent.context).inflate(
R.layout.widget_buffer, parent, false
),
clickListener = clickListener
)
BufferInfo.Type.StatusBuffer.toInt() -> BufferViewHolder.StatusBuffer(
LayoutInflater.from(parent.context).inflate(
R.layout.widget_network, parent, false
),
clickListener = clickListener,
expansionListener = ::expandListener
)
else -> throw IllegalArgumentException(
"No such viewType: $viewType"
)
}
override fun onBindViewHolder(holder: BufferViewHolder, position: Int)
= holder.bind(data[position])
= holder.bind(data[position].props, data[position].state)
override fun getItemCount() = data.size
class BufferViewHolder(
override fun getItemViewType(position: Int) = data[position].props.info.type.toInt()
data class BufferListItem(
val props: BufferProps,
val state: BufferState
)
data class BufferProps(
val info: BufferInfo,
val network: INetwork.NetworkInfo,
val bufferStatus: BufferStatus,
val description: String
)
data class BufferState(
val networkExpanded: Boolean
)
abstract class BufferViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
abstract fun bind(props: BufferProps, state: BufferState)
fun <T> status(target: T, actual: T) = if (target == actual) {
View.VISIBLE
} else {
View.GONE
}
class StatusBuffer(
itemView: View,
private val clickListener: ((BufferId) -> Unit)? = null,
private val expansionListener: ((NetworkId) -> Unit)? = null
) : BufferViewHolder(itemView) {
@BindView(R.id.status)
lateinit var status: AppCompatImageButton
@BindView(R.id.name)
lateinit var name: TextView
var bufferId: BufferId? = null
var networkId: NetworkId? = null
init {
ButterKnife.bind(this, itemView)
itemView.setOnClickListener {
val buffer = bufferId
if (buffer != null)
clickListener?.invoke(buffer)
}
status.setOnClickListener {
val network = networkId
if (network != null)
expansionListener?.invoke(network)
}
}
override fun bind(props: BufferProps, state: BufferState) {
name.text = props.network.networkName
bufferId = props.info.bufferId
networkId = props.info.networkId
if (state.networkExpanded) {
status.setImageDrawable(itemView.context.getCompatDrawable(R.drawable.ic_chevron_up))
} else {
status.setImageDrawable(itemView.context.getCompatDrawable(R.drawable.ic_chevron_down))
}
}
}
class GroupBuffer(
itemView: View,
private val clickListener: ((BufferId) -> Unit)? = null
) : RecyclerView.ViewHolder(itemView) {
@BindView(android.R.id.text1)
lateinit var text: TextView
) : BufferViewHolder(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 bufferId: BufferId? = null
private val online: Drawable
private val offline: Drawable
init {
ButterKnife.bind(this, itemView)
itemView.setOnClickListener {
......@@ -80,14 +221,157 @@ class BufferListAdapter(
if (buffer != null)
clickListener?.invoke(buffer)
}
online = itemView.context.getCompatDrawable(R.drawable.ic_status)
offline = itemView.context.getCompatDrawable(R.drawable.ic_status_offline)
itemView.context.theme.styledAttributes(R.attr.colorAccent, R.attr.colorAway) {
DrawableCompat.setTint(online, getColor(0, 0))
DrawableCompat.setTint(offline, getColor(1, 0))
}
}
fun bind(info: BufferInfo) {
text.text = when {
info.type.hasFlag(BufferInfo.Type.StatusBuffer) -> "Network ${info.networkId}"
else -> "${info.networkId}/${info.bufferName}"
override fun bind(props: BufferProps, state: BufferState) {
bufferId = props.info.bufferId
name.text = props.info.bufferName
description.text = props.description
description.visibility = if (props.description == "") {
View.GONE
} else {
View.VISIBLE
}
bufferId = info.bufferId
status.setImageDrawable(
when (props.bufferStatus) {
BufferStatus.ONLINE -> online
else -> offline
}
)
}
}
class ChannelBuffer(
itemView: View,
private val clickListener: ((BufferId) -> Unit)? = null
) : BufferViewHolder(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 bufferId: BufferId? = null
private val online: Drawable
private val offline: Drawable
init {
ButterKnife.bind(this, itemView)
itemView.setOnClickListener {
val buffer = bufferId
if (buffer != null)
clickListener?.invoke(buffer)
}
online = itemView.context.getCompatDrawable(R.drawable.ic_status_channel)
offline = itemView.context.getCompatDrawable(R.drawable.ic_status_channel_offline)
itemView.context.theme.styledAttributes(R.attr.colorAccent, R.attr.colorAway) {
DrawableCompat.setTint(online, getColor(0, 0))
DrawableCompat.setTint(offline, getColor(1, 0))
}
}
override fun bind(props: BufferProps, state: BufferState) {
bufferId = props.info.bufferId
name.text = props.info.bufferName
description.text = props.description
description.visibility = if (props.description == "") {
View.GONE
} else {
View.VISIBLE
}
status.setImageDrawable(
when (props.bufferStatus) {
BufferStatus.ONLINE -> online
else -> offline
}
)
}
}
class QueryBuffer(
itemView: View,
private val clickListener: ((BufferId) -> Unit)? = null
) : BufferViewHolder(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 bufferId: BufferId? = null
private val online: Drawable
private val away: Drawable
private val offline: Drawable
init {
ButterKnife.bind(this, itemView)
itemView.setOnClickListener {
val buffer = bufferId
if (buffer != null)
clickListener?.invoke(buffer)
}
online = itemView.context.getCompatDrawable(R.drawable.ic_status)
away = itemView.context.getCompatDrawable(R.drawable.ic_status)
offline = itemView.context.getCompatDrawable(R.drawable.ic_status_offline)
itemView.context.theme.styledAttributes(R.attr.colorAccent, R.attr.colorAway) {
DrawableCompat.setTint(online, getColor(0, 0))
DrawableCompat.setTint(away, getColor(1, 0))
DrawableCompat.setTint(offline, getColor(1, 0))
}
}
override fun bind(props: BufferProps, state: BufferState) {
bufferId = props.info.bufferId
name.text = props.info.bufferName
description.text = props.description
description.visibility = if (props.description == "") {
View.GONE
} else {
View.VISIBLE
}
status.setImageDrawable(
when (props.bufferStatus) {
BufferStatus.ONLINE -> online
BufferStatus.AWAY -> away
else -> offline
}
)
}
}
}
enum class BufferStatus {
ONLINE,
AWAY,
OFFLINE
}
}
......@@ -12,9 +12,8 @@ import butterknife.BindView
import butterknife.ButterKnife
import de.kuschku.libquassel.protocol.BufferId
import de.kuschku.libquassel.protocol.NetworkId
import de.kuschku.libquassel.quassel.syncables.BufferViewConfig
import de.kuschku.libquassel.quassel.syncables.BufferViewManager
import de.kuschku.libquassel.quassel.syncables.Network
import de.kuschku.libquassel.quassel.BufferInfo
import de.kuschku.libquassel.quassel.syncables.*
import de.kuschku.libquassel.session.Backend
import de.kuschku.libquassel.session.ISession
import de.kuschku.libquassel.session.SessionManager
......@@ -25,6 +24,7 @@ import de.kuschku.quasseldroid_ng.util.helper.or
import de.kuschku.quasseldroid_ng.util.helper.switchMap
import de.kuschku.quasseldroid_ng.util.helper.switchMapRx
import de.kuschku.quasseldroid_ng.util.service.ServiceBoundFragment
import io.reactivex.Observable
class BufferViewConfigFragment : ServiceBoundFragment() {
private val handlerThread = AndroidHandlerThread("ChatList")
......@@ -74,12 +74,79 @@ class BufferViewConfigFragment : ServiceBoundFragment() {
private val bufferIdList = selectedBufferViewConfig.switchMapRx(BufferViewConfig::live_buffers)
private val bufferList = sessionManager.switchMap { manager ->
bufferIdList.map { ids ->
ids.mapNotNull {
manager.bufferSyncer?.bufferInfo(it)
private val bufferList: LiveData<List<BufferListAdapter.BufferProps>?> = sessionManager.switchMap { manager ->
bufferIdList.switchMapRx { ids ->
Observable.combineLatest(
ids.mapNotNull { id ->
manager.bufferSyncer?.bufferInfo(
id
)
}.mapNotNull {
val network = manager.networks[it.networkId]
if (network == null) {
null
} else {
it to network
}
}.map { (info, network) ->
when (info.type.toInt()) {
BufferInfo.Type.QueryBuffer.toInt() -> {
network.liveIrcUser(info.bufferName).distinctUntilChanged().switchMap { user ->
user.live_away.switchMap { away ->
user.live_realName.map { realName ->
BufferListAdapter.BufferProps(
info = info,
network = network.networkInfo(),
bufferStatus = when {
user == IrcUser.NULL -> BufferListAdapter.BufferStatus.OFFLINE
away -> BufferListAdapter.BufferStatus.AWAY
else -> BufferListAdapter.BufferStatus.ONLINE
},
description = realName
)
}
}
}
}
BufferInfo.Type.ChannelBuffer.toInt() -> {
network.liveIrcChannel(info.bufferName).distinctUntilChanged().switchMap { channel ->
channel.live_topic.map { topic ->
BufferListAdapter.BufferProps(
info = info,
network = network.networkInfo(),
bufferStatus = when (channel) {
IrcChannel.NULL -> BufferListAdapter.BufferStatus.OFFLINE
else -> BufferListAdapter.BufferStatus.ONLINE
},
description = topic
)
}
}
}
BufferInfo.Type.StatusBuffer.toInt() -> {
network.liveConnectionState.map {
BufferListAdapter.BufferProps(
info = info,
network = network.networkInfo(),
bufferStatus = BufferListAdapter.BufferStatus.OFFLINE,
description = ""
)
}
}
else -> Observable.just(
BufferListAdapter.BufferProps(
info = info,
network = network.networkInfo(),
bufferStatus = BufferListAdapter.BufferStatus.OFFLINE,
description = ""
)
)
}
}, { array: Array<Any> ->
array.toList() as List<BufferListAdapter.BufferProps>
}
)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
......
package de.kuschku.quasseldroid_ng.util.helper
import android.content.Context
import android.graphics.drawable.Drawable
import android.os.Build
import android.support.annotation.ColorInt
import android.support.annotation.ColorRes
import android.support.annotation.DrawableRes
fun Context.getStatusBarHeight(): Int {
var result = 0
......@@ -17,3 +21,20 @@ inline fun <reified T> Context.systemService(): T = if (Build.VERSION.SDK_INT >=
} else {
getSystemService(T::class.java.simpleName) as T
}
fun Context.getCompatDrawable(@DrawableRes id: Int): Drawable {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
this.resources.getDrawable(id, this.theme)
} else {
this.resources.getDrawable(id)
}
}
@ColorInt
fun Context.getCompatColor(@ColorRes id: Int): Int {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
this.resources.getColor(id, this.theme)
} else {
this.resources.getColor(id)
}
}
/*
* Copyright (C) 2017 Mitchell Skaggs, Keturah Gadson, Ethan Holtgrieve, Nathan Skelton,
* Pattonville School District
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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_ng.util.helper
import android.arch.lifecycle.LiveData
import android.arch.lifecycle.MediatorLiveData
/**
* This function creates a [LiveData] of a [Pair] of the two types provided. The resulting LiveData
* is updated whenever either input LiveData updates and both LiveData have updated at least once
* before.
*
* If the zip of A and B is C, and A and B are updated in this pattern: `AABA`, C would be updated
* twice (once with the second A value and first B value, and once with the third A value and first
* B value).
*
* @param a the first LiveData
* @param b the second LiveData
* @author Mitchell Skaggs
*/
fun <A, B> zipLiveData(a: LiveData<A>, b: LiveData<B>): LiveData<Pair<A, B>> {
return MediatorLiveData<Pair<A, B>>().apply {
var lastA: A? = null
var lastB: B? = null
fun update() {
val localLastA = lastA
val localLastB = lastB
if (localLastA != null && localLastB != null)
this.value = Pair(localLastA, localLastB)
}
addSource(a) {
lastA = it
update()
}
addSource(b) {
lastB = it
update()
}
}
}
/**
* This is merely an extension function for [zipLiveData].
*
* @see zipLiveData
* @author Mitchell Skaggs
*/
fun <A, B> LiveData<A>.zip(b: LiveData<B>): LiveData<Pair<A, B>> = zipLiveData(this, b)
\ No newline at end of file
package de.kuschku.quasseldroid_ng.util.helper
import android.content.res.Resources
import android.content.res.TypedArray
inline fun Resources.Theme.styledAttributes(vararg attributes: Int, f: TypedArray.() -> Unit) {
this.obtainStyledAttributes(attributes).use {
it.apply(f)
}
}
inline fun <R> TypedArray.use(block: (TypedArray) -> R): R {
val result = block(this)
recycle()
return result
}
\ No newline at end of file
<!-- drawable/chevron_down.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#000"
android:pathData="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z" />
</vector>
\ No newline at end of file
<!-- drawable/chevron_up.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#000"
android:pathData="M7.41,15.41L12,10.83L16.59,15.41L18,14L12,8L6,14L7.41,15.41Z" />
</vector>
\ No newline at end of file
......@@ -4,7 +4,8 @@
android:id="@+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
android:fitsSystemWindows="true"
tools:theme="@style/Theme.ChatTheme.Quassel_Light">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
......
......@@ -2,7 +2,8 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
tools:theme="@style/Theme.SetupTheme">
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
......
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
android:orientation="vertical"
tools:background="@android:color/background_light"
tools:theme="@style/Theme.ChatTheme.Quassel_Light">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
......@@ -30,5 +33,6 @@
<android.support.v7.widget.RecyclerView
android:id="@+id/chatList"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="match_parent"
tools:listitem="@layout/widget_buffer" />
</LinearLayout>
......@@ -4,7 +4,9 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorBackground">
android:background="?attr/colorBackground"
tools:background="@android:color/background_light"
tools:theme="@style/Theme.ChatTheme.Quassel_Light">
<android.support.v7.widget.RecyclerView
android:id="@+id/messages"
......
......@@ -2,10 +2,13 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="32dp">
android:padding="32dp"
tools:background="@android:color/background_light"
tools:theme="@style/Theme.SetupTheme">
<android.support.design.widget.TextInputLayout
android:id="@+id/hostWrapper"
......
......@@ -2,7 +2,9 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
tools:background="@android:color/background_light"
tools:theme="@style/Theme.SetupTheme">
<LinearLayout
android:layout_width="match_parent"
......
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="32dp">
android:padding="32dp"
tools:background="@android:color/background_light"
tools:theme="@style/Theme.SetupTheme">
<android.support.design.widget.TextInputLayout
android:id="@+id/nameWrapper"
......
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="32dp">
android:padding="32dp"
tools:background="@android:color/background_light"
tools:theme="@style/Theme.SetupTheme">
<android.support.design.widget.TextInputLayout
android:id="@+id/userWrapper"
......
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/account_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="match_parent"
tools:background="@android:color/background_light"
tools:theme="@style/Theme.SetupTheme" />
......@@ -2,7 +2,9 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
tools:background="@android:color/background_light"
tools:theme="@style/Theme.SetupTheme">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
......
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:paddingBottom="8dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="8dp"
tools:background="@android:color/background_light"
tools:theme="@style/Theme.ChatTheme.Quassel_Light">
<ImageView
android:id="@+id/status"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center"
android:layout_marginEnd="32dp"
android:layout_marginRight="32dp"
tools:src="@drawable/ic_status_channel"
tools:tint="?attr/colorAccent" />
<LinearLayout
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:singleLine="true"
android:textColor="?attr/colorForeground"
android:textSize="13sp"
android:textStyle="bold"
tools:text="#quasseldroid" />
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:singleLine="true"
android:textColor="?attr/colorForegroundSecondary"
android:textSize="12sp"
tools:text="QuasselDroid is an Android client for #quassel ♥ justJanne's much improved version: https://dl.kuschku.de/releases/quasseldroid/ ♥ http://github.com/sandsmark/QuasselDroid ♥ Quasseldroid on play https://market.android.com/details?id=com.iskrembilen.quasseldroid ♥ Sign up for beta: https://plus.google.com/communities/104094956084217666662" />
</LinearLayout>
</LinearLayout>
\ No newline at end of file
......@@ -20,6 +20,7 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
......@@ -32,7 +33,9 @@
android:paddingRight="@dimen/message_horizontal"
android:paddingStart="@dimen/message_horizontal"
android:paddingTop="@dimen/message_vertical"
android:textAppearance="?android:attr/textAppearanceListItemSmall">
android:textAppearance="?android:attr/textAppearanceListItemSmall"
tools:background="@android:color/background_light"
tools:theme="@style/Theme.ChatTheme.Quassel_Light">
<TextView
android:id="@+id/time"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment