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

Allow selecting buffers

parent f3c489de
No related branches found
No related tags found
No related merge requests found
Showing with 199 additions and 20 deletions
...@@ -30,11 +30,14 @@ class BufferListAdapter( ...@@ -30,11 +30,14 @@ class BufferListAdapter(
liveData: LiveData<List<BufferProps>?>, liveData: LiveData<List<BufferProps>?>,
runInBackground: (() -> Unit) -> Any, runInBackground: (() -> Unit) -> Any,
runOnUiThread: (Runnable) -> Any, runOnUiThread: (Runnable) -> Any,
private val clickListener: ((BufferId) -> Unit)? = null private val clickListener: ((BufferId) -> Unit)? = null,
private val longClickListener: ((BufferId) -> Unit)? = null
) : RecyclerView.Adapter<BufferListAdapter.BufferViewHolder>() { ) : RecyclerView.Adapter<BufferListAdapter.BufferViewHolder>() {
var data = mutableListOf<BufferListItem>() var data = mutableListOf<BufferListItem>()
var collapsedNetworks = MutableLiveData<Set<NetworkId>>() private val collapsedNetworks = MutableLiveData<Set<NetworkId>>()
val selectedBuffers = MutableLiveData<Set<BufferId>>()
fun expandListener(networkId: NetworkId) { fun expandListener(networkId: NetworkId) {
if (collapsedNetworks.value.orEmpty().contains(networkId)) if (collapsedNetworks.value.orEmpty().contains(networkId))
...@@ -43,14 +46,29 @@ class BufferListAdapter( ...@@ -43,14 +46,29 @@ class BufferListAdapter(
collapsedNetworks.postValue(collapsedNetworks.value.orEmpty() + networkId) collapsedNetworks.postValue(collapsedNetworks.value.orEmpty() + networkId)
} }
fun toggleSelection(buffer: BufferId) {
val value = selectedBuffers.value.orEmpty()
if (value.contains(buffer)) {
selectedBuffers.value = value - buffer
} else {
selectedBuffers.value = value + buffer
}
}
fun unselectAll() {
selectedBuffers.value = emptySet()
}
init { init {
collapsedNetworks.value = emptySet() collapsedNetworks.value = emptySet()
selectedBuffers.value = emptySet()
liveData.zip(collapsedNetworks).observe( liveData.zip(collapsedNetworks, selectedBuffers).observe(
lifecycleOwner, Observer { it: Pair<List<BufferProps>?, Set<NetworkId>>? -> lifecycleOwner, Observer { it: Triple<List<BufferProps>?, Set<NetworkId>, Set<BufferId>>? ->
runInBackground { runInBackground {
val list = it?.first ?: emptyList() val list = it?.first ?: emptyList()
val collapsedNetworks = it?.second ?: emptySet() val collapsedNetworks = it?.second ?: emptySet()
val selected = it?.third ?: emptySet()
val old: List<BufferListItem> = data val old: List<BufferListItem> = data
val new: List<BufferListItem> = list.sortedBy { props -> val new: List<BufferListItem> = list.sortedBy { props ->
...@@ -61,7 +79,8 @@ class BufferListAdapter( ...@@ -61,7 +79,8 @@ class BufferListAdapter(
BufferListItem( BufferListItem(
props, props,
BufferState( BufferState(
networkExpanded = !collapsedNetworks.contains(props.network.networkId) networkExpanded = !collapsedNetworks.contains(props.network.networkId),
selected = selected.contains(props.info.bufferId)
) )
) )
}.filter { (props, state) -> }.filter { (props, state) ->
...@@ -97,25 +116,29 @@ class BufferListAdapter( ...@@ -97,25 +116,29 @@ class BufferListAdapter(
LayoutInflater.from(parent.context).inflate( LayoutInflater.from(parent.context).inflate(
R.layout.widget_buffer, parent, false R.layout.widget_buffer, parent, false
), ),
clickListener = clickListener clickListener = clickListener,
longClickListener = longClickListener
) )
BufferInfo.Type.QueryBuffer.toInt() -> BufferViewHolder.QueryBuffer( BufferInfo.Type.QueryBuffer.toInt() -> BufferViewHolder.QueryBuffer(
LayoutInflater.from(parent.context).inflate( LayoutInflater.from(parent.context).inflate(
R.layout.widget_buffer, parent, false R.layout.widget_buffer, parent, false
), ),
clickListener = clickListener clickListener = clickListener,
longClickListener = longClickListener
) )
BufferInfo.Type.GroupBuffer.toInt() -> BufferViewHolder.GroupBuffer( BufferInfo.Type.GroupBuffer.toInt() -> BufferViewHolder.GroupBuffer(
LayoutInflater.from(parent.context).inflate( LayoutInflater.from(parent.context).inflate(
R.layout.widget_buffer, parent, false R.layout.widget_buffer, parent, false
), ),
clickListener = clickListener clickListener = clickListener,
longClickListener = longClickListener
) )
BufferInfo.Type.StatusBuffer.toInt() -> BufferViewHolder.StatusBuffer( BufferInfo.Type.StatusBuffer.toInt() -> BufferViewHolder.StatusBuffer(
LayoutInflater.from(parent.context).inflate( LayoutInflater.from(parent.context).inflate(
R.layout.widget_network, parent, false R.layout.widget_network, parent, false
), ),
clickListener = clickListener, clickListener = clickListener,
longClickListener = longClickListener,
expansionListener = ::expandListener expansionListener = ::expandListener
) )
else -> throw IllegalArgumentException( else -> throw IllegalArgumentException(
...@@ -146,7 +169,8 @@ class BufferListAdapter( ...@@ -146,7 +169,8 @@ class BufferListAdapter(
) )
data class BufferState( data class BufferState(
val networkExpanded: Boolean val networkExpanded: Boolean,
val selected: Boolean
) )
abstract class BufferViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { abstract class BufferViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
...@@ -155,6 +179,7 @@ class BufferListAdapter( ...@@ -155,6 +179,7 @@ class BufferListAdapter(
class StatusBuffer( class StatusBuffer(
itemView: View, itemView: View,
private val clickListener: ((BufferId) -> Unit)? = null, private val clickListener: ((BufferId) -> Unit)? = null,
private val longClickListener: ((BufferId) -> Unit)? = null,
private val expansionListener: ((NetworkId) -> Unit)? = null private val expansionListener: ((NetworkId) -> Unit)? = null
) : BufferViewHolder(itemView) { ) : BufferViewHolder(itemView) {
@BindView(R.id.status) @BindView(R.id.status)
...@@ -179,6 +204,16 @@ class BufferListAdapter( ...@@ -179,6 +204,16 @@ class BufferListAdapter(
clickListener?.invoke(buffer) clickListener?.invoke(buffer)
} }
itemView.setOnLongClickListener {
val buffer = bufferId
if (buffer != null) {
longClickListener?.invoke(buffer)
true
} else {
false
}
}
status.setOnClickListener { status.setOnClickListener {
val network = networkId val network = networkId
if (network != null) if (network != null)
...@@ -210,6 +245,8 @@ class BufferListAdapter( ...@@ -210,6 +245,8 @@ class BufferListAdapter(
} }
) )
itemView.isSelected = state.selected
if (state.networkExpanded) { if (state.networkExpanded) {
status.setImageDrawable(itemView.context.getCompatDrawable(R.drawable.ic_chevron_up)) status.setImageDrawable(itemView.context.getCompatDrawable(R.drawable.ic_chevron_up))
} else { } else {
...@@ -220,7 +257,8 @@ class BufferListAdapter( ...@@ -220,7 +257,8 @@ class BufferListAdapter(
class GroupBuffer( class GroupBuffer(
itemView: View, itemView: View,
private val clickListener: ((BufferId) -> Unit)? = null private val clickListener: ((BufferId) -> Unit)? = null,
private val longClickListener: ((BufferId) -> Unit)? = null
) : BufferViewHolder(itemView) { ) : BufferViewHolder(itemView) {
@BindView(R.id.status) @BindView(R.id.status)
lateinit var status: ImageView lateinit var status: ImageView
...@@ -249,6 +287,16 @@ class BufferListAdapter( ...@@ -249,6 +287,16 @@ class BufferListAdapter(
clickListener?.invoke(buffer) clickListener?.invoke(buffer)
} }
itemView.setOnLongClickListener {
val buffer = bufferId
if (buffer != null) {
longClickListener?.invoke(buffer)
true
} else {
false
}
}
online = itemView.context.getCompatDrawable(R.drawable.ic_status).mutate() online = itemView.context.getCompatDrawable(R.drawable.ic_status).mutate()
offline = itemView.context.getCompatDrawable(R.drawable.ic_status_offline).mutate() offline = itemView.context.getCompatDrawable(R.drawable.ic_status_offline).mutate()
...@@ -282,6 +330,8 @@ class BufferListAdapter( ...@@ -282,6 +330,8 @@ class BufferListAdapter(
} }
) )
itemView.isSelected = state.selected
description.visibleIf(props.description.isNotBlank()) description.visibleIf(props.description.isNotBlank())
status.setImageDrawable( status.setImageDrawable(
...@@ -295,7 +345,8 @@ class BufferListAdapter( ...@@ -295,7 +345,8 @@ class BufferListAdapter(
class ChannelBuffer( class ChannelBuffer(
itemView: View, itemView: View,
private val clickListener: ((BufferId) -> Unit)? = null private val clickListener: ((BufferId) -> Unit)? = null,
private val longClickListener: ((BufferId) -> Unit)? = null
) : BufferViewHolder(itemView) { ) : BufferViewHolder(itemView) {
@BindView(R.id.status) @BindView(R.id.status)
lateinit var status: ImageView lateinit var status: ImageView
...@@ -324,6 +375,16 @@ class BufferListAdapter( ...@@ -324,6 +375,16 @@ class BufferListAdapter(
clickListener?.invoke(buffer) clickListener?.invoke(buffer)
} }
itemView.setOnLongClickListener {
val buffer = bufferId
if (buffer != null) {
longClickListener?.invoke(buffer)
true
} else {
false
}
}
online = itemView.context.getCompatDrawable(R.drawable.ic_status_channel).mutate() online = itemView.context.getCompatDrawable(R.drawable.ic_status_channel).mutate()
offline = itemView.context.getCompatDrawable(R.drawable.ic_status_channel_offline).mutate() offline = itemView.context.getCompatDrawable(R.drawable.ic_status_channel_offline).mutate()
...@@ -357,6 +418,8 @@ class BufferListAdapter( ...@@ -357,6 +418,8 @@ class BufferListAdapter(
} }
) )
itemView.isSelected = state.selected
description.visibleIf(props.description.isNotBlank()) description.visibleIf(props.description.isNotBlank())
status.setImageDrawable( status.setImageDrawable(
...@@ -370,7 +433,8 @@ class BufferListAdapter( ...@@ -370,7 +433,8 @@ class BufferListAdapter(
class QueryBuffer( class QueryBuffer(
itemView: View, itemView: View,
private val clickListener: ((BufferId) -> Unit)? = null private val clickListener: ((BufferId) -> Unit)? = null,
private val longClickListener: ((BufferId) -> Unit)? = null
) : BufferViewHolder(itemView) { ) : BufferViewHolder(itemView) {
@BindView(R.id.status) @BindView(R.id.status)
lateinit var status: ImageView lateinit var status: ImageView
...@@ -400,6 +464,16 @@ class BufferListAdapter( ...@@ -400,6 +464,16 @@ class BufferListAdapter(
clickListener?.invoke(buffer) clickListener?.invoke(buffer)
} }
itemView.setOnLongClickListener {
val buffer = bufferId
if (buffer != null) {
longClickListener?.invoke(buffer)
true
} else {
false
}
}
online = itemView.context.getCompatDrawable(R.drawable.ic_status).mutate() online = itemView.context.getCompatDrawable(R.drawable.ic_status).mutate()
away = itemView.context.getCompatDrawable(R.drawable.ic_status).mutate() away = itemView.context.getCompatDrawable(R.drawable.ic_status).mutate()
offline = itemView.context.getCompatDrawable(R.drawable.ic_status_offline).mutate() offline = itemView.context.getCompatDrawable(R.drawable.ic_status_offline).mutate()
...@@ -435,6 +509,8 @@ class BufferListAdapter( ...@@ -435,6 +509,8 @@ class BufferListAdapter(
} }
) )
itemView.isSelected = state.selected
description.visibleIf(props.description.isNotBlank()) description.visibleIf(props.description.isNotBlank())
status.setImageDrawable( status.setImageDrawable(
......
...@@ -3,9 +3,7 @@ package de.kuschku.quasseldroid_ng.ui.chat.buffers ...@@ -3,9 +3,7 @@ package de.kuschku.quasseldroid_ng.ui.chat.buffers
import android.arch.lifecycle.ViewModelProviders import android.arch.lifecycle.ViewModelProviders
import android.os.Bundle import android.os.Bundle
import android.support.v7.widget.* import android.support.v7.widget.*
import android.view.LayoutInflater import android.view.*
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView import android.widget.AdapterView
import butterknife.BindView import butterknife.BindView
import butterknife.ButterKnife import butterknife.ButterKnife
...@@ -44,6 +42,30 @@ class BufferViewConfigFragment : ServiceBoundFragment() { ...@@ -44,6 +42,30 @@ class BufferViewConfigFragment : ServiceBoundFragment() {
private var ircFormatDeserializer: IrcFormatDeserializer? = null private var ircFormatDeserializer: IrcFormatDeserializer? = null
private lateinit var appearanceSettings: AppearanceSettings private lateinit var appearanceSettings: AppearanceSettings
private var isInActionMode = false
private val actionModeCallback = object : ActionMode.Callback {
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
return true
}
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
isInActionMode = true
return true
}
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
return false
}
override fun onDestroyActionMode(mode: ActionMode?) {
isInActionMode = false
listAdapter.unselectAll()
}
}
private lateinit var listAdapter: BufferListAdapter
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
handlerThread.onCreate() handlerThread.onCreate()
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
...@@ -75,7 +97,7 @@ class BufferViewConfigFragment : ServiceBoundFragment() { ...@@ -75,7 +97,7 @@ class BufferViewConfigFragment : ServiceBoundFragment() {
} }
} }
chatList.adapter = BufferListAdapter( listAdapter = BufferListAdapter(
this, this,
viewModel.bufferList.zip(database.filtered().listen(accountId)).map { viewModel.bufferList.zip(database.filtered().listen(accountId)).map {
val (data, activityList) = it val (data, activityList) = it
...@@ -107,8 +129,12 @@ class BufferViewConfigFragment : ServiceBoundFragment() { ...@@ -107,8 +129,12 @@ class BufferViewConfigFragment : ServiceBoundFragment() {
}, },
handlerThread::post, handlerThread::post,
activity!!::runOnUiThread, activity!!::runOnUiThread,
clickListener clickListener,
longClickListener
) )
chatList.adapter = listAdapter
chatListToolbar.startActionMode(actionModeCallback)
chatList.layoutManager = LinearLayoutManager(context) chatList.layoutManager = LinearLayoutManager(context)
chatList.itemAnimator = DefaultItemAnimator() chatList.itemAnimator = DefaultItemAnimator()
chatList.setItemViewCacheSize(10) chatList.setItemViewCacheSize(10)
...@@ -121,6 +147,17 @@ class BufferViewConfigFragment : ServiceBoundFragment() { ...@@ -121,6 +147,17 @@ class BufferViewConfigFragment : ServiceBoundFragment() {
} }
private val clickListener: ((BufferId) -> Unit)? = { private val clickListener: ((BufferId) -> Unit)? = {
if (isInActionMode) {
longClickListener?.invoke(it)
} else {
viewModel.setBuffer(it) viewModel.setBuffer(it)
} }
} }
private val longClickListener: ((BufferId) -> Unit)? = {
if (!isInActionMode) {
chatListToolbar.startActionMode(actionModeCallback)
}
listAdapter.toggleSelection(it)
}
}
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<shape android:shape="rectangle">
<solid android:color="@color/ripple_dark" />
</shape>
</item>
<item>
<ripple android:color="@color/ripple_dark" />
</item>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<shape android:shape="rectangle">
<solid android:color="@color/ripple_light" />
</shape>
</item>
<item>
<ripple android:color="@color/ripple_light" />
</item>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<shape android:shape="rectangle">
<solid android:color="@color/ripple_dark" />
</shape>
</item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="@color/ripple_dark" />
</shape>
</item>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<shape android:shape="rectangle">
<solid android:color="@color/ripple_light" />
</shape>
</item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="@color/ripple_light" />
</shape>
</item>
</selector>
\ No newline at end of file
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:foreground="?attr/selectableItemBackgroundBorderless" android:background="?attr/backgroundMenuItem"
android:minHeight="48dp" android:minHeight="48dp"
android:paddingBottom="8dp" android:paddingBottom="8dp"
android:paddingLeft="16dp" android:paddingLeft="16dp"
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground" android:background="?attr/backgroundMenuItem"
android:orientation="vertical"> android:orientation="vertical">
<View <View
......
...@@ -71,4 +71,7 @@ ...@@ -71,4 +71,7 @@
<attr name="buttonTheme" format="reference" /> <attr name="buttonTheme" format="reference" />
<attr name="buttonThemeColored" format="reference" /> <attr name="buttonThemeColored" format="reference" />
<attr name="cardStyle" format="reference" /> <attr name="cardStyle" format="reference" />
<!-- Menu Items -->
<attr name="backgroundMenuItem" format="reference" />
</resources> </resources>
...@@ -12,4 +12,7 @@ ...@@ -12,4 +12,7 @@
<color name="colorAwayLight">#959595</color> <color name="colorAwayLight">#959595</color>
<color name="colorAwayDark">#939393</color> <color name="colorAwayDark">#939393</color>
<color name="ripple_dark">#33ffffff</color>
<color name="ripple_light">#1f000000</color>
</resources> </resources>
...@@ -4,22 +4,30 @@ ...@@ -4,22 +4,30 @@
<item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item> <item name="colorAccent">@color/colorAccent</item>
<item name="backgroundMenuItem">@drawable/bg_menuitem_dark</item>
</style> </style>
<style name="Theme.AppTheme.Light" parent="Theme.AppCompat.Light.DarkActionBar"> <style name="Theme.AppTheme.Light" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item> <item name="colorAccent">@color/colorAccent</item>
<item name="backgroundMenuItem">@drawable/bg_menuitem_light</item>
</style> </style>
<style name="Theme.AppTheme.NoActionBar" parent="Theme.AppTheme"> <style name="Theme.AppTheme.NoActionBar" parent="Theme.AppTheme">
<item name="windowActionBar">false</item> <item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item> <item name="windowNoTitle">true</item>
<item name="backgroundMenuItem">@drawable/bg_menuitem_dark</item>
</style> </style>
<style name="Theme.AppTheme.Light.NoActionBar" parent="Theme.AppTheme.Light"> <style name="Theme.AppTheme.Light.NoActionBar" parent="Theme.AppTheme.Light">
<item name="windowActionBar">false</item> <item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item> <item name="windowNoTitle">true</item>
<item name="backgroundMenuItem">@drawable/bg_menuitem_light</item>
</style> </style>
<style name="Theme.Base.ChatTheme" parent="Theme.AppTheme.NoActionBar" /> <style name="Theme.Base.ChatTheme" parent="Theme.AppTheme.NoActionBar" />
...@@ -38,6 +46,8 @@ ...@@ -38,6 +46,8 @@
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item> <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
<item name="actionBarPopupTheme">@style/Widget.PopupOverlay</item> <item name="actionBarPopupTheme">@style/Widget.PopupOverlay</item>
<item name="backgroundMenuItem">@drawable/bg_menuitem_dark</item>
<item name="windowActionModeOverlay">true</item> <item name="windowActionModeOverlay">true</item>
<item name="colorTextPrimary">#dedede</item> <item name="colorTextPrimary">#dedede</item>
...@@ -85,6 +95,8 @@ ...@@ -85,6 +95,8 @@
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item> <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
<item name="actionBarPopupTheme">@style/Widget.PopupOverlay.Light</item> <item name="actionBarPopupTheme">@style/Widget.PopupOverlay.Light</item>
<item name="backgroundMenuItem">@drawable/bg_menuitem_light</item>
<item name="windowActionModeOverlay">true</item> <item name="windowActionModeOverlay">true</item>
<item name="colorTextPrimary">#212121</item> <item name="colorTextPrimary">#212121</item>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment