mirror of
https://git.sr.ht/~thestr4ng3r/chiaki
synced 2025-08-14 02:36:51 -07:00
Finish Registered Hosts List on Android
This commit is contained in:
parent
950b86454d
commit
c6d84d0b22
10 changed files with 279 additions and 15 deletions
|
@ -65,6 +65,9 @@ interface RegisteredHostDao
|
|||
@Query("DELETE FROM registered_host WHERE ps4_mac == :mac")
|
||||
fun deleteByMac(mac: MacAddress): Completable
|
||||
|
||||
@Delete
|
||||
fun delete(host: RegisteredHost): Completable
|
||||
|
||||
@Query("SELECT COUNT(*) FROM registered_host")
|
||||
fun count(): Flowable<Int>
|
||||
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* This file is part of Chiaki.
|
||||
*
|
||||
* Chiaki 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.
|
||||
*
|
||||
* Chiaki 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 Chiaki. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.metallic.chiaki.settings
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Rect
|
||||
import androidx.core.graphics.withClip
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.metallic.chiaki.R
|
||||
|
||||
abstract class ItemTouchSwipeCallback(context: Context): ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT)
|
||||
{
|
||||
private val backgroundDrawable = context.getDrawable(R.color.item_delete_background)
|
||||
private val icon = context.getDrawable(R.drawable.ic_delete_row)
|
||||
|
||||
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder) = false
|
||||
|
||||
override fun onChildDraw(canvas: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean)
|
||||
{
|
||||
val itemView = viewHolder.itemView
|
||||
val itemHeight = itemView.bottom - itemView.top
|
||||
|
||||
val bounds = Rect(
|
||||
itemView.right + dX.toInt(),
|
||||
itemView.top,
|
||||
itemView.right,
|
||||
itemView.bottom
|
||||
)
|
||||
|
||||
backgroundDrawable?.bounds = bounds
|
||||
backgroundDrawable?.draw(canvas)
|
||||
|
||||
val icon = icon
|
||||
if(icon != null)
|
||||
{
|
||||
val iconMargin = (itemHeight - icon.intrinsicHeight) / 2
|
||||
val iconTop = itemView.top + iconMargin
|
||||
val iconLeft = itemView.right - iconMargin - icon.intrinsicWidth
|
||||
val iconRight = itemView.right - iconMargin
|
||||
val iconBottom = iconTop + icon.intrinsicHeight
|
||||
canvas.withClip(bounds) {
|
||||
icon.setBounds(iconLeft, iconTop, iconRight, iconBottom)
|
||||
icon.draw(canvas)
|
||||
}
|
||||
}
|
||||
|
||||
super.onChildDraw(canvas, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* This file is part of Chiaki.
|
||||
*
|
||||
* Chiaki 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.
|
||||
*
|
||||
* Chiaki 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 Chiaki. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.metallic.chiaki.settings
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.metallic.chiaki.R
|
||||
import com.metallic.chiaki.common.RegisteredHost
|
||||
import com.metallic.chiaki.common.ext.inflate
|
||||
import kotlinx.android.synthetic.main.item_registered_host.view.*
|
||||
|
||||
class SettingsRegisteredHostsAdapter: RecyclerView.Adapter<SettingsRegisteredHostsAdapter.ViewHolder>()
|
||||
{
|
||||
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView)
|
||||
|
||||
var hosts: List<RegisteredHost> = listOf()
|
||||
set(value)
|
||||
{
|
||||
field = value
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(parent.inflate(R.layout.item_registered_host))
|
||||
|
||||
override fun getItemCount() = hosts.size
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int)
|
||||
{
|
||||
val view = holder.itemView
|
||||
val host = hosts[position]
|
||||
view.nameTextView.text = host.ps4Nickname
|
||||
view.summaryTextView.text = host.ps4Mac.toString()
|
||||
}
|
||||
}
|
|
@ -17,40 +17,72 @@
|
|||
|
||||
package com.metallic.chiaki.settings
|
||||
|
||||
import android.app.ActivityOptions
|
||||
import android.content.Intent
|
||||
import android.content.res.Resources
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatDialogFragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.metallic.chiaki.R
|
||||
import com.metallic.chiaki.common.ext.putRevealExtra
|
||||
import com.metallic.chiaki.common.ext.viewModelFactory
|
||||
import com.metallic.chiaki.common.getDatabase
|
||||
import com.metallic.chiaki.regist.RegistActivity
|
||||
import kotlinx.android.synthetic.main.fragment_settings_registered_hosts.*
|
||||
|
||||
class SettingsRegisteredHostsFragment: PreferenceFragmentCompat(), TitleFragment
|
||||
class SettingsRegisteredHostsFragment: AppCompatDialogFragment(), TitleFragment
|
||||
{
|
||||
private lateinit var viewModel: SettingsRegisteredHostsViewModel
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?)
|
||||
{
|
||||
val context = preferenceManager.context
|
||||
preferenceScreen = preferenceManager.createPreferenceScreen(context)
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||
inflater.inflate(R.layout.fragment_settings_registered_hosts, container, false)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?)
|
||||
{
|
||||
viewModel = ViewModelProviders
|
||||
.of(this, viewModelFactory { SettingsRegisteredHostsViewModel(getDatabase(context!!)) })
|
||||
.get(SettingsRegisteredHostsViewModel::class.java)
|
||||
|
||||
viewModel.registeredHosts.observe(this, Observer {
|
||||
preferenceScreen.removeAll()
|
||||
it.forEach { host ->
|
||||
val pref = Preference(context)
|
||||
pref.title = host.ps4Nickname
|
||||
pref.summary = host.ps4Mac.toString()
|
||||
pref.setIcon(R.drawable.ic_console_simple)
|
||||
preferenceScreen.addPreference(pref)
|
||||
val adapter = SettingsRegisteredHostsAdapter()
|
||||
hostsRecyclerView.layoutManager = LinearLayoutManager(context)
|
||||
hostsRecyclerView.adapter = adapter
|
||||
val itemTouchSwipeCallback = object : ItemTouchSwipeCallback(context!!)
|
||||
{
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int)
|
||||
{
|
||||
val pos = viewHolder.adapterPosition
|
||||
val host = viewModel.registeredHosts.value?.getOrNull(pos) ?: return
|
||||
MaterialAlertDialogBuilder(viewHolder.itemView.context)
|
||||
.setMessage(getString(R.string.alert_message_delete_registered_host, host.ps4Nickname, host.ps4Mac.toString()))
|
||||
.setPositiveButton(R.string.alert_action_delete_registered_host) { _, _ ->
|
||||
viewModel.deleteHost(host)
|
||||
}
|
||||
.setNegativeButton(R.string.alert_action_keep_registered_host) { _, _ ->
|
||||
adapter.notifyItemChanged(pos) // to reset the swipe
|
||||
}
|
||||
.create()
|
||||
.show()
|
||||
}
|
||||
}
|
||||
ItemTouchHelper(itemTouchSwipeCallback).attachToRecyclerView(hostsRecyclerView)
|
||||
viewModel.registeredHosts.observe(this, Observer {
|
||||
adapter.hosts = it
|
||||
})
|
||||
|
||||
floatingActionButton.setOnClickListener {
|
||||
Intent(context, RegistActivity::class.java).also {
|
||||
it.putRevealExtra(floatingActionButton, rootLayout)
|
||||
startActivity(it, ActivityOptions.makeSceneTransitionAnimation(activity).toBundle())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getTitle(resources: Resources): String = resources.getString(R.string.preferences_registered_hosts_title)
|
||||
|
|
|
@ -19,11 +19,32 @@ package com.metallic.chiaki.settings
|
|||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.metallic.chiaki.common.AppDatabase
|
||||
import com.metallic.chiaki.common.RegisteredHost
|
||||
import com.metallic.chiaki.common.ext.toLiveData
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.rxkotlin.addTo
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
class SettingsRegisteredHostsViewModel(val database: AppDatabase): ViewModel()
|
||||
{
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
val registeredHosts by lazy {
|
||||
database.registeredHostDao().getAll().toLiveData()
|
||||
}
|
||||
|
||||
fun deleteHost(host: RegisteredHost)
|
||||
{
|
||||
database.registeredHostDao()
|
||||
.delete(host)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe()
|
||||
.addTo(disposable)
|
||||
}
|
||||
|
||||
override fun onCleared()
|
||||
{
|
||||
super.onCleared()
|
||||
disposable.dispose()
|
||||
}
|
||||
}
|
9
android/app/src/main/res/drawable/ic_delete_row.xml
Normal file
9
android/app/src/main/res/drawable/ic_delete_row.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
|
||||
</vector>
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/rootLayout"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/hostsRecyclerView"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/floatingActionButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/selector_add_fab"
|
||||
android:layout_margin="16dp"
|
||||
app:fabSize="normal"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
53
android/app/src/main/res/layout/item_registered_host.xml
Normal file
53
android/app/src/main/res/layout/item_registered_host.xml
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingEnd="?android:attr/scrollbarSize"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iconImageView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxWidth="48dp"
|
||||
android:maxHeight="48dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_marginStart="16dp"
|
||||
android:src="@drawable/ic_console_simple"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/nameTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:ellipsize="marquee"
|
||||
android:fadingEdge="horizontal"
|
||||
app:layout_constraintStart_toEndOf="@id/iconImageView"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_marginStart="32dp"
|
||||
tools:text="Name" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/summaryTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@android:id/title"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:maxLines="4"
|
||||
app:layout_constraintStart_toStartOf="@id/nameTextView"
|
||||
app:layout_constraintTop_toBottomOf="@id/nameTextView"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
tools:text="Summary"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -12,4 +12,6 @@
|
|||
|
||||
<color name="control_primary">#22ffffff</color>
|
||||
<color name="control_pressed">#88ffffff</color>
|
||||
|
||||
<color name="item_delete_background">#B71C1C</color>
|
||||
</resources>
|
||||
|
|
|
@ -58,6 +58,9 @@
|
|||
<string name="preferences_bitrate_title">Bitrate</string>
|
||||
<string name="preferences_log_verbose_title">Verbose Logging</string>
|
||||
<string name="preferences_log_verbose_summary">Warning: This logs a LOT! Don\'t enable for regular use.</string>
|
||||
<string name="alert_message_delete_registered_host">Are you sure you want to delete the registered console %s with ID %s?</string>
|
||||
<string name="alert_action_delete_registered_host">Delete</string>
|
||||
<string name="alert_action_keep_registered_host">Keep</string>
|
||||
|
||||
<!-- Don't localize these -->
|
||||
<string name="preferences_discovery_enabled_key">discovery_enabled</string>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue