diff --git a/android/app/src/main/java/com/metallic/chiaki/common/RegisteredHost.kt b/android/app/src/main/java/com/metallic/chiaki/common/RegisteredHost.kt index e15dd07..080f854 100644 --- a/android/app/src/main/java/com/metallic/chiaki/common/RegisteredHost.kt +++ b/android/app/src/main/java/com/metallic/chiaki/common/RegisteredHost.kt @@ -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 diff --git a/android/app/src/main/java/com/metallic/chiaki/settings/ItemTouchSwipeCallback.kt b/android/app/src/main/java/com/metallic/chiaki/settings/ItemTouchSwipeCallback.kt new file mode 100644 index 0000000..1d411a9 --- /dev/null +++ b/android/app/src/main/java/com/metallic/chiaki/settings/ItemTouchSwipeCallback.kt @@ -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 . + */ + +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) + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsRegisteredHostsAdapter.kt b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsRegisteredHostsAdapter.kt new file mode 100644 index 0000000..7cedf2a --- /dev/null +++ b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsRegisteredHostsAdapter.kt @@ -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 . + */ + +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() +{ + class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) + + var hosts: List = 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() + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsRegisteredHostsFragment.kt b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsRegisteredHostsFragment.kt index 23508f3..70c81cf 100644 --- a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsRegisteredHostsFragment.kt +++ b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsRegisteredHostsFragment.kt @@ -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) diff --git a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsRegisteredHostsViewModel.kt b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsRegisteredHostsViewModel.kt index 489a31e..418ae4a 100644 --- a/android/app/src/main/java/com/metallic/chiaki/settings/SettingsRegisteredHostsViewModel.kt +++ b/android/app/src/main/java/com/metallic/chiaki/settings/SettingsRegisteredHostsViewModel.kt @@ -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() + } } \ No newline at end of file diff --git a/android/app/src/main/res/drawable/ic_delete_row.xml b/android/app/src/main/res/drawable/ic_delete_row.xml new file mode 100644 index 0000000..55c8fa4 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_delete_row.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/layout/fragment_settings_registered_hosts.xml b/android/app/src/main/res/layout/fragment_settings_registered_hosts.xml new file mode 100644 index 0000000..fc9fe66 --- /dev/null +++ b/android/app/src/main/res/layout/fragment_settings_registered_hosts.xml @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/android/app/src/main/res/layout/item_registered_host.xml b/android/app/src/main/res/layout/item_registered_host.xml new file mode 100644 index 0000000..002dd78 --- /dev/null +++ b/android/app/src/main/res/layout/item_registered_host.xml @@ -0,0 +1,53 @@ + + + + + + + + + + diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml index f6595cb..ad22c3c 100644 --- a/android/app/src/main/res/values/colors.xml +++ b/android/app/src/main/res/values/colors.xml @@ -12,4 +12,6 @@ #22ffffff #88ffffff + + #B71C1C diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index dd62cf0..6bd60de 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -58,6 +58,9 @@ Bitrate Verbose Logging Warning: This logs a LOT! Don\'t enable for regular use. + Are you sure you want to delete the registered console %s with ID %s? + Delete + Keep discovery_enabled