Merge pull request #13054 from t895/lifecycle-utils
android: Create lifecycle utility to simplify common StateFlow operations
This commit is contained in:
commit
acfc4d6dfb
|
@ -6,11 +6,7 @@ package org.yuzu.yuzu_emu.adapters
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding
|
import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding
|
||||||
import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding
|
import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding
|
||||||
import org.yuzu.yuzu_emu.model.GameProperty
|
import org.yuzu.yuzu_emu.model.GameProperty
|
||||||
|
@ -18,6 +14,7 @@ import org.yuzu.yuzu_emu.model.InstallableProperty
|
||||||
import org.yuzu.yuzu_emu.model.SubmenuProperty
|
import org.yuzu.yuzu_emu.model.SubmenuProperty
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
|
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||||
|
import org.yuzu.yuzu_emu.utils.collect
|
||||||
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
|
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
|
||||||
|
|
||||||
class GamePropertiesAdapter(
|
class GamePropertiesAdapter(
|
||||||
|
@ -82,11 +79,7 @@ class GamePropertiesAdapter(
|
||||||
binding.details.text = submenuProperty.details.invoke()
|
binding.details.text = submenuProperty.details.invoke()
|
||||||
} else if (submenuProperty.detailsFlow != null) {
|
} else if (submenuProperty.detailsFlow != null) {
|
||||||
binding.details.setVisible(true)
|
binding.details.setVisible(true)
|
||||||
viewLifecycle.lifecycleScope.launch {
|
submenuProperty.detailsFlow.collect(viewLifecycle) { binding.details.text = it }
|
||||||
viewLifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
|
||||||
submenuProperty.detailsFlow.collect { binding.details.text = it }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
binding.details.setVisible(false)
|
binding.details.setVisible(false)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,17 +8,14 @@ import android.view.ViewGroup
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding
|
import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding
|
||||||
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
||||||
import org.yuzu.yuzu_emu.model.HomeSetting
|
import org.yuzu.yuzu_emu.model.HomeSetting
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
|
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||||
|
import org.yuzu.yuzu_emu.utils.collect
|
||||||
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
|
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
|
||||||
|
|
||||||
class HomeSettingAdapter(
|
class HomeSettingAdapter(
|
||||||
|
@ -59,11 +56,7 @@ class HomeSettingAdapter(
|
||||||
binding.optionIcon.alpha = 0.5f
|
binding.optionIcon.alpha = 0.5f
|
||||||
}
|
}
|
||||||
|
|
||||||
viewLifecycle.lifecycleScope.launch {
|
model.details.collect(viewLifecycle) { updateOptionDetails(it) }
|
||||||
viewLifecycle.repeatOnLifecycle(Lifecycle.State.CREATED) {
|
|
||||||
model.details.collect { updateOptionDetails(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
binding.optionDetail.marquee()
|
binding.optionDetail.marquee()
|
||||||
|
|
||||||
binding.root.setOnClickListener { onClick(model) }
|
binding.root.setOnClickListener { onClick(model) }
|
||||||
|
|
|
@ -11,16 +11,13 @@ import android.view.ViewGroup
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.databinding.DialogInputProfilesBinding
|
import org.yuzu.yuzu_emu.databinding.DialogInputProfilesBinding
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.view.InputProfileSetting
|
import org.yuzu.yuzu_emu.features.settings.model.view.InputProfileSetting
|
||||||
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
||||||
|
import org.yuzu.yuzu_emu.utils.collect
|
||||||
|
|
||||||
class InputProfileDialogFragment : DialogFragment() {
|
class InputProfileDialogFragment : DialogFragment() {
|
||||||
private var position = 0
|
private var position = 0
|
||||||
|
@ -110,25 +107,21 @@ class InputProfileDialogFragment : DialogFragment() {
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
settingsViewModel.shouldShowDeleteProfileDialog.collect(viewLifecycleOwner) {
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
if (it.isNotEmpty()) {
|
||||||
settingsViewModel.shouldShowDeleteProfileDialog.collect {
|
MessageDialogFragment.newInstance(
|
||||||
if (it.isNotEmpty()) {
|
activity = requireActivity(),
|
||||||
MessageDialogFragment.newInstance(
|
titleId = R.string.delete_input_profile,
|
||||||
activity = requireActivity(),
|
descriptionId = R.string.delete_input_profile_description,
|
||||||
titleId = R.string.delete_input_profile,
|
positiveAction = {
|
||||||
descriptionId = R.string.delete_input_profile_description,
|
setting.deleteProfile(it)
|
||||||
positiveAction = {
|
settingsViewModel.setReloadListAndNotifyDataset(true)
|
||||||
setting.deleteProfile(it)
|
},
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
negativeAction = {},
|
||||||
},
|
negativeButtonTitleId = android.R.string.cancel
|
||||||
negativeAction = {},
|
).show(parentFragmentManager, MessageDialogFragment.TAG)
|
||||||
negativeButtonTitleId = android.R.string.cancel
|
settingsViewModel.setShouldShowDeleteProfileDialog("")
|
||||||
).show(parentFragmentManager, MessageDialogFragment.TAG)
|
dismiss()
|
||||||
settingsViewModel.setShouldShowDeleteProfileDialog("")
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,14 +13,9 @@ import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
import androidx.navigation.navArgs
|
import androidx.navigation.navArgs
|
||||||
import com.google.android.material.color.MaterialColors
|
import com.google.android.material.color.MaterialColors
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.yuzu.yuzu_emu.NativeLibrary
|
import org.yuzu.yuzu_emu.NativeLibrary
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
|
@ -70,39 +65,23 @@ class SettingsActivity : AppCompatActivity() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
lifecycleScope.apply {
|
settingsViewModel.shouldRecreate.collect(
|
||||||
launch {
|
this,
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
resetState = { settingsViewModel.setShouldRecreate(false) }
|
||||||
settingsViewModel.shouldRecreate.collectLatest {
|
) { if (it) recreate() }
|
||||||
if (it) {
|
settingsViewModel.shouldNavigateBack.collect(
|
||||||
settingsViewModel.setShouldRecreate(false)
|
this,
|
||||||
recreate()
|
resetState = { settingsViewModel.setShouldNavigateBack(false) }
|
||||||
}
|
) { if (it) navigateBack() }
|
||||||
}
|
settingsViewModel.shouldShowResetSettingsDialog.collect(
|
||||||
}
|
this,
|
||||||
}
|
resetState = { settingsViewModel.setShouldShowResetSettingsDialog(false) }
|
||||||
launch {
|
) {
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
if (it) {
|
||||||
settingsViewModel.shouldNavigateBack.collectLatest {
|
ResetSettingsDialogFragment().show(
|
||||||
if (it) {
|
supportFragmentManager,
|
||||||
settingsViewModel.setShouldNavigateBack(false)
|
ResetSettingsDialogFragment.TAG
|
||||||
navigateBack()
|
)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
launch {
|
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
|
||||||
settingsViewModel.shouldShowResetSettingsDialog.collectLatest {
|
|
||||||
if (it) {
|
|
||||||
settingsViewModel.setShouldShowResetSettingsDialog(false)
|
|
||||||
ResetSettingsDialogFragment().show(
|
|
||||||
supportFragmentManager,
|
|
||||||
ResetSettingsDialogFragment.TAG
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,8 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.slider.Slider
|
import com.google.android.material.slider.Slider
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
|
import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
|
||||||
import org.yuzu.yuzu_emu.features.input.NativeInput
|
import org.yuzu.yuzu_emu.features.input.NativeInput
|
||||||
|
@ -29,6 +25,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
|
import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
|
import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
|
||||||
import org.yuzu.yuzu_emu.utils.ParamPackage
|
import org.yuzu.yuzu_emu.utils.ParamPackage
|
||||||
|
import org.yuzu.yuzu_emu.utils.collect
|
||||||
|
|
||||||
class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener {
|
class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener {
|
||||||
private var type = 0
|
private var type = 0
|
||||||
|
@ -169,17 +166,11 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
when (type) {
|
when (type) {
|
||||||
SettingsItem.TYPE_SLIDER -> {
|
SettingsItem.TYPE_SLIDER -> {
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
settingsViewModel.sliderTextValue.collect(viewLifecycleOwner) {
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
sliderBinding.textValue.text = it
|
||||||
settingsViewModel.sliderTextValue.collect {
|
}
|
||||||
sliderBinding.textValue.text = it
|
settingsViewModel.sliderProgress.collect(viewLifecycleOwner) {
|
||||||
}
|
sliderBinding.slider.value = it.toFloat()
|
||||||
}
|
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
|
||||||
settingsViewModel.sliderProgress.collect {
|
|
||||||
sliderBinding.slider.value = it.toFloat()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,21 +13,17 @@ import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.google.android.material.transition.MaterialSharedAxis
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.databinding.FragmentSettingsBinding
|
import org.yuzu.yuzu_emu.databinding.FragmentSettingsBinding
|
||||||
import org.yuzu.yuzu_emu.features.input.NativeInput
|
import org.yuzu.yuzu_emu.features.input.NativeInput
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||||
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
||||||
|
import org.yuzu.yuzu_emu.utils.collect
|
||||||
|
|
||||||
class SettingsFragment : Fragment() {
|
class SettingsFragment : Fragment() {
|
||||||
private lateinit var presenter: SettingsFragmentPresenter
|
private lateinit var presenter: SettingsFragmentPresenter
|
||||||
|
@ -63,8 +59,7 @@ class SettingsFragment : Fragment() {
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is using the correct scope, lint is just acting up
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
@SuppressLint("UnsafeRepeatOnLifecycleDetector", "NotifyDataSetChanged")
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
settingsAdapter = SettingsAdapter(this, requireContext())
|
settingsAdapter = SettingsAdapter(this, requireContext())
|
||||||
|
@ -100,65 +95,37 @@ class SettingsFragment : Fragment() {
|
||||||
settingsViewModel.setShouldNavigateBack(true)
|
settingsViewModel.setShouldNavigateBack(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.apply {
|
settingsViewModel.shouldReloadSettingsList.collect(
|
||||||
launch {
|
viewLifecycleOwner,
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
resetState = { settingsViewModel.setShouldReloadSettingsList(false) }
|
||||||
settingsViewModel.shouldReloadSettingsList.collectLatest {
|
) { if (it) presenter.loadSettingsList() }
|
||||||
if (it) {
|
settingsViewModel.adapterItemChanged.collect(
|
||||||
settingsViewModel.setShouldReloadSettingsList(false)
|
viewLifecycleOwner,
|
||||||
presenter.loadSettingsList()
|
resetState = { settingsViewModel.setAdapterItemChanged(-1) }
|
||||||
}
|
) { if (it != -1) settingsAdapter?.notifyItemChanged(it) }
|
||||||
}
|
settingsViewModel.datasetChanged.collect(
|
||||||
}
|
viewLifecycleOwner,
|
||||||
}
|
resetState = { settingsViewModel.setDatasetChanged(false) }
|
||||||
launch {
|
) { if (it) settingsAdapter?.notifyDataSetChanged() }
|
||||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
settingsViewModel.reloadListAndNotifyDataset.collect(
|
||||||
settingsViewModel.adapterItemChanged.collect {
|
viewLifecycleOwner,
|
||||||
if (it != -1) {
|
resetState = { settingsViewModel.setReloadListAndNotifyDataset(false) }
|
||||||
settingsAdapter?.notifyItemChanged(it)
|
) { if (it) presenter.loadSettingsList(true) }
|
||||||
settingsViewModel.setAdapterItemChanged(-1)
|
settingsViewModel.shouldShowResetInputDialog.collect(
|
||||||
}
|
viewLifecycleOwner,
|
||||||
}
|
resetState = { settingsViewModel.setShouldShowResetInputDialog(false) }
|
||||||
}
|
) {
|
||||||
}
|
if (it) {
|
||||||
launch {
|
MessageDialogFragment.newInstance(
|
||||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
activity = requireActivity(),
|
||||||
settingsViewModel.datasetChanged.collect {
|
titleId = R.string.reset_mapping,
|
||||||
if (it) {
|
descriptionId = R.string.reset_mapping_description,
|
||||||
settingsAdapter?.notifyDataSetChanged()
|
positiveAction = {
|
||||||
settingsViewModel.setDatasetChanged(false)
|
NativeInput.resetControllerMappings(getPlayerIndex())
|
||||||
}
|
settingsViewModel.setReloadListAndNotifyDataset(true)
|
||||||
}
|
},
|
||||||
}
|
negativeAction = {}
|
||||||
}
|
).show(parentFragmentManager, MessageDialogFragment.TAG)
|
||||||
launch {
|
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
|
||||||
settingsViewModel.reloadListAndNotifyDataset.collectLatest {
|
|
||||||
if (it) {
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(false)
|
|
||||||
presenter.loadSettingsList(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
launch {
|
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
|
||||||
settingsViewModel.shouldShowResetInputDialog.collectLatest {
|
|
||||||
if (it) {
|
|
||||||
MessageDialogFragment.newInstance(
|
|
||||||
activity = requireActivity(),
|
|
||||||
titleId = R.string.reset_mapping,
|
|
||||||
descriptionId = R.string.reset_mapping_description,
|
|
||||||
positiveAction = {
|
|
||||||
NativeInput.resetControllerMappings(getPlayerIndex())
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
},
|
|
||||||
negativeAction = {}
|
|
||||||
).show(parentFragmentManager, MessageDialogFragment.TAG)
|
|
||||||
settingsViewModel.setShouldShowResetInputDialog(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,20 +15,17 @@ import androidx.core.view.updatePadding
|
||||||
import androidx.core.widget.doOnTextChanged
|
import androidx.core.widget.doOnTextChanged
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.google.android.material.divider.MaterialDividerItemDecoration
|
import com.google.android.material.divider.MaterialDividerItemDecoration
|
||||||
import com.google.android.material.transition.MaterialSharedAxis
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
import info.debatty.java.stringsimilarity.Cosine
|
import info.debatty.java.stringsimilarity.Cosine
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.databinding.FragmentSettingsSearchBinding
|
import org.yuzu.yuzu_emu.databinding.FragmentSettingsSearchBinding
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
|
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
|
||||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
||||||
|
import org.yuzu.yuzu_emu.utils.collect
|
||||||
|
|
||||||
class SettingsSearchFragment : Fragment() {
|
class SettingsSearchFragment : Fragment() {
|
||||||
private var _binding: FragmentSettingsSearchBinding? = null
|
private var _binding: FragmentSettingsSearchBinding? = null
|
||||||
|
@ -84,14 +81,10 @@ class SettingsSearchFragment : Fragment() {
|
||||||
search()
|
search()
|
||||||
binding.settingsList.smoothScrollToPosition(0)
|
binding.settingsList.smoothScrollToPosition(0)
|
||||||
}
|
}
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
settingsViewModel.shouldReloadSettingsList.collect(viewLifecycleOwner) {
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
if (it) {
|
||||||
settingsViewModel.shouldReloadSettingsList.collect {
|
settingsViewModel.setShouldReloadSettingsList(false)
|
||||||
if (it) {
|
search()
|
||||||
settingsViewModel.setShouldReloadSettingsList(false)
|
|
||||||
search()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.fragments
|
package org.yuzu.yuzu_emu.fragments
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
@ -16,9 +15,6 @@ import androidx.core.view.updatePadding
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
@ -32,6 +28,7 @@ import org.yuzu.yuzu_emu.model.HomeViewModel
|
||||||
import org.yuzu.yuzu_emu.utils.AddonUtil
|
import org.yuzu.yuzu_emu.utils.AddonUtil
|
||||||
import org.yuzu.yuzu_emu.utils.FileUtil.copyFilesTo
|
import org.yuzu.yuzu_emu.utils.FileUtil.copyFilesTo
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
||||||
|
import org.yuzu.yuzu_emu.utils.collect
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class AddonsFragment : Fragment() {
|
class AddonsFragment : Fragment() {
|
||||||
|
@ -60,8 +57,6 @@ class AddonsFragment : Fragment() {
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is using the correct scope, lint is just acting up
|
|
||||||
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
homeViewModel.setNavigationVisibility(visible = false, animated = false)
|
homeViewModel.setNavigationVisibility(visible = false, animated = false)
|
||||||
|
@ -78,57 +73,41 @@ class AddonsFragment : Fragment() {
|
||||||
adapter = AddonAdapter(addonViewModel)
|
adapter = AddonAdapter(addonViewModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.apply {
|
addonViewModel.addonList.collect(viewLifecycleOwner) {
|
||||||
launch {
|
(binding.listAddons.adapter as AddonAdapter).submitList(it)
|
||||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
}
|
||||||
addonViewModel.addonList.collect {
|
addonViewModel.showModInstallPicker.collect(
|
||||||
(binding.listAddons.adapter as AddonAdapter).submitList(it)
|
viewLifecycleOwner,
|
||||||
}
|
resetState = { addonViewModel.showModInstallPicker(false) }
|
||||||
}
|
) { if (it) installAddon.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data) }
|
||||||
|
addonViewModel.showModNoticeDialog.collect(
|
||||||
|
viewLifecycleOwner,
|
||||||
|
resetState = { addonViewModel.showModNoticeDialog(false) }
|
||||||
|
) {
|
||||||
|
if (it) {
|
||||||
|
MessageDialogFragment.newInstance(
|
||||||
|
requireActivity(),
|
||||||
|
titleId = R.string.addon_notice,
|
||||||
|
descriptionId = R.string.addon_notice_description,
|
||||||
|
dismissible = false,
|
||||||
|
positiveAction = { addonViewModel.showModInstallPicker(true) },
|
||||||
|
negativeAction = {},
|
||||||
|
negativeButtonTitleId = R.string.close
|
||||||
|
).show(parentFragmentManager, MessageDialogFragment.TAG)
|
||||||
}
|
}
|
||||||
launch {
|
}
|
||||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
addonViewModel.addonToDelete.collect(
|
||||||
addonViewModel.showModInstallPicker.collect {
|
viewLifecycleOwner,
|
||||||
if (it) {
|
resetState = { addonViewModel.setAddonToDelete(null) }
|
||||||
installAddon.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data)
|
) {
|
||||||
addonViewModel.showModInstallPicker(false)
|
if (it != null) {
|
||||||
}
|
MessageDialogFragment.newInstance(
|
||||||
}
|
requireActivity(),
|
||||||
}
|
titleId = R.string.confirm_uninstall,
|
||||||
}
|
descriptionId = R.string.confirm_uninstall_description,
|
||||||
launch {
|
positiveAction = { addonViewModel.onDeleteAddon(it) },
|
||||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
negativeAction = {}
|
||||||
addonViewModel.showModNoticeDialog.collect {
|
).show(parentFragmentManager, MessageDialogFragment.TAG)
|
||||||
if (it) {
|
|
||||||
MessageDialogFragment.newInstance(
|
|
||||||
requireActivity(),
|
|
||||||
titleId = R.string.addon_notice,
|
|
||||||
descriptionId = R.string.addon_notice_description,
|
|
||||||
dismissible = false,
|
|
||||||
positiveAction = { addonViewModel.showModInstallPicker(true) },
|
|
||||||
negativeAction = {},
|
|
||||||
negativeButtonTitleId = R.string.close
|
|
||||||
).show(parentFragmentManager, MessageDialogFragment.TAG)
|
|
||||||
addonViewModel.showModNoticeDialog(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
launch {
|
|
||||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
|
||||||
addonViewModel.addonToDelete.collect {
|
|
||||||
if (it != null) {
|
|
||||||
MessageDialogFragment.newInstance(
|
|
||||||
requireActivity(),
|
|
||||||
titleId = R.string.confirm_uninstall,
|
|
||||||
descriptionId = R.string.confirm_uninstall_description,
|
|
||||||
positiveAction = { addonViewModel.onDeleteAddon(it) },
|
|
||||||
negativeAction = {}
|
|
||||||
).show(parentFragmentManager, MessageDialogFragment.TAG)
|
|
||||||
addonViewModel.setAddonToDelete(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.fragments
|
package org.yuzu.yuzu_emu.fragments
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -14,9 +13,6 @@ import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
@ -35,6 +31,7 @@ import org.yuzu.yuzu_emu.utils.FileUtil
|
||||||
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
||||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
||||||
|
import org.yuzu.yuzu_emu.utils.collect
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
|
@ -63,8 +60,6 @@ class DriverManagerFragment : Fragment() {
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is using the correct scope, lint is just acting up
|
|
||||||
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
homeViewModel.setNavigationVisibility(visible = false, animated = true)
|
homeViewModel.setNavigationVisibility(visible = false, animated = true)
|
||||||
|
@ -89,15 +84,8 @@ class DriverManagerFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.apply {
|
driverViewModel.showClearButton.collect(viewLifecycleOwner) {
|
||||||
launch {
|
binding.toolbarDrivers.menu.findItem(R.id.menu_driver_use_global).isVisible = it
|
||||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
|
||||||
driverViewModel.showClearButton.collect {
|
|
||||||
binding.toolbarDrivers.menu
|
|
||||||
.findItem(R.id.menu_driver_use_global).isVisible = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,14 +10,11 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
|
import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
|
||||||
import org.yuzu.yuzu_emu.model.DriverViewModel
|
import org.yuzu.yuzu_emu.model.DriverViewModel
|
||||||
|
import org.yuzu.yuzu_emu.utils.collect
|
||||||
|
|
||||||
class DriversLoadingDialogFragment : DialogFragment() {
|
class DriversLoadingDialogFragment : DialogFragment() {
|
||||||
private val driverViewModel: DriverViewModel by activityViewModels()
|
private val driverViewModel: DriverViewModel by activityViewModels()
|
||||||
|
@ -44,13 +41,7 @@ class DriversLoadingDialogFragment : DialogFragment() {
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
viewLifecycleOwner.lifecycleScope.apply {
|
driverViewModel.isInteractionAllowed.collect(viewLifecycleOwner) { if (it) dismiss() }
|
||||||
launch {
|
|
||||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
|
||||||
driverViewModel.isInteractionAllowed.collect { if (it) dismiss() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -32,9 +32,6 @@ import androidx.drawerlayout.widget.DrawerLayout
|
||||||
import androidx.drawerlayout.widget.DrawerLayout.DrawerListener
|
import androidx.drawerlayout.widget.DrawerLayout.DrawerListener
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.window.layout.FoldingFeature
|
import androidx.window.layout.FoldingFeature
|
||||||
|
@ -42,9 +39,6 @@ import androidx.window.layout.WindowInfoTracker
|
||||||
import androidx.window.layout.WindowLayoutInfo
|
import androidx.window.layout.WindowLayoutInfo
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.slider.Slider
|
import com.google.android.material.slider.Slider
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
||||||
import org.yuzu.yuzu_emu.NativeLibrary
|
import org.yuzu.yuzu_emu.NativeLibrary
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
|
@ -91,14 +85,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
if (context is EmulationActivity) {
|
if (context is EmulationActivity) {
|
||||||
emulationActivity = context
|
emulationActivity = context
|
||||||
NativeLibrary.setEmulationActivity(context)
|
NativeLibrary.setEmulationActivity(context)
|
||||||
|
|
||||||
lifecycleScope.launch(Dispatchers.Main) {
|
|
||||||
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
|
||||||
WindowInfoTracker.getOrCreate(context)
|
|
||||||
.windowLayoutInfo(context)
|
|
||||||
.collect { updateFoldableLayout(context, it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
throw IllegalStateException("EmulationFragment must have EmulationActivity parent")
|
throw IllegalStateException("EmulationFragment must have EmulationActivity parent")
|
||||||
}
|
}
|
||||||
|
@ -169,8 +155,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is using the correct scope, lint is just acting up
|
|
||||||
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
if (requireActivity().isFinishing) {
|
if (requireActivity().isFinishing) {
|
||||||
|
@ -351,129 +335,86 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
binding.loadingTitle.isSelected = true
|
binding.loadingTitle.isSelected = true
|
||||||
binding.loadingText.isSelected = true
|
binding.loadingText.isSelected = true
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.apply {
|
WindowInfoTracker.getOrCreate(requireContext())
|
||||||
launch {
|
.windowLayoutInfo(requireActivity()).collect(viewLifecycleOwner) {
|
||||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
updateFoldableLayout(requireActivity() as EmulationActivity, it)
|
||||||
WindowInfoTracker.getOrCreate(requireContext())
|
|
||||||
.windowLayoutInfo(requireActivity())
|
|
||||||
.collect {
|
|
||||||
updateFoldableLayout(requireActivity() as EmulationActivity, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
launch {
|
emulationViewModel.shaderProgress.collect(viewLifecycleOwner) {
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
if (it > 0 && it != emulationViewModel.totalShaders.value) {
|
||||||
emulationViewModel.shaderProgress.collectLatest {
|
binding.loadingProgressIndicator.isIndeterminate = false
|
||||||
if (it > 0 && it != emulationViewModel.totalShaders.value) {
|
|
||||||
binding.loadingProgressIndicator.isIndeterminate = false
|
|
||||||
|
|
||||||
if (it < binding.loadingProgressIndicator.max) {
|
if (it < binding.loadingProgressIndicator.max) {
|
||||||
binding.loadingProgressIndicator.progress = it
|
binding.loadingProgressIndicator.progress = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (it == emulationViewModel.totalShaders.value) {
|
if (it == emulationViewModel.totalShaders.value) {
|
||||||
binding.loadingText.setText(R.string.loading)
|
binding.loadingText.setText(R.string.loading)
|
||||||
binding.loadingProgressIndicator.isIndeterminate = true
|
binding.loadingProgressIndicator.isIndeterminate = true
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
launch {
|
}
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
emulationViewModel.totalShaders.collect(viewLifecycleOwner) {
|
||||||
emulationViewModel.totalShaders.collectLatest {
|
binding.loadingProgressIndicator.max = it
|
||||||
binding.loadingProgressIndicator.max = it
|
}
|
||||||
}
|
emulationViewModel.shaderMessage.collect(viewLifecycleOwner) {
|
||||||
}
|
if (it.isNotEmpty()) {
|
||||||
|
binding.loadingText.text = it
|
||||||
}
|
}
|
||||||
launch {
|
}
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
|
||||||
emulationViewModel.shaderMessage.collectLatest {
|
|
||||||
if (it.isNotEmpty()) {
|
|
||||||
binding.loadingText.text = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
launch {
|
|
||||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
|
||||||
driverViewModel.isInteractionAllowed.collect {
|
|
||||||
if (it) {
|
|
||||||
startEmulation()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
launch {
|
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
|
||||||
emulationViewModel.emulationStarted.collectLatest {
|
|
||||||
if (it) {
|
|
||||||
binding.drawerLayout.setDrawerLockMode(IntSetting.LOCK_DRAWER.getInt())
|
|
||||||
ViewUtils.showView(binding.surfaceInputOverlay)
|
|
||||||
ViewUtils.hideView(binding.loadingIndicator)
|
|
||||||
|
|
||||||
emulationState.updateSurface()
|
emulationViewModel.emulationStarted.collect(viewLifecycleOwner) {
|
||||||
|
if (it) {
|
||||||
|
binding.drawerLayout.setDrawerLockMode(IntSetting.LOCK_DRAWER.getInt())
|
||||||
|
ViewUtils.showView(binding.surfaceInputOverlay)
|
||||||
|
ViewUtils.hideView(binding.loadingIndicator)
|
||||||
|
|
||||||
// Setup overlays
|
emulationState.updateSurface()
|
||||||
updateShowFpsOverlay()
|
|
||||||
updateThermalOverlay()
|
// Setup overlays
|
||||||
}
|
updateShowFpsOverlay()
|
||||||
}
|
updateThermalOverlay()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
launch {
|
}
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
emulationViewModel.isEmulationStopping.collect(viewLifecycleOwner) {
|
||||||
emulationViewModel.isEmulationStopping.collectLatest {
|
if (it) {
|
||||||
if (it) {
|
binding.loadingText.setText(R.string.shutting_down)
|
||||||
binding.loadingText.setText(R.string.shutting_down)
|
ViewUtils.showView(binding.loadingIndicator)
|
||||||
ViewUtils.showView(binding.loadingIndicator)
|
ViewUtils.hideView(binding.inputContainer)
|
||||||
ViewUtils.hideView(binding.inputContainer)
|
ViewUtils.hideView(binding.showFpsText)
|
||||||
ViewUtils.hideView(binding.showFpsText)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
launch {
|
}
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
emulationViewModel.drawerOpen.collect(viewLifecycleOwner) {
|
||||||
emulationViewModel.drawerOpen.collect {
|
if (it) {
|
||||||
if (it) {
|
binding.drawerLayout.open()
|
||||||
binding.drawerLayout.open()
|
binding.inGameMenu.requestFocus()
|
||||||
binding.inGameMenu.requestFocus()
|
} else {
|
||||||
} else {
|
binding.drawerLayout.close()
|
||||||
binding.drawerLayout.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
launch {
|
}
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
emulationViewModel.programChanged.collect(viewLifecycleOwner) {
|
||||||
emulationViewModel.programChanged.collect {
|
if (it != 0) {
|
||||||
if (it != 0) {
|
emulationViewModel.setEmulationStarted(false)
|
||||||
emulationViewModel.setEmulationStarted(false)
|
binding.drawerLayout.close()
|
||||||
binding.drawerLayout.close()
|
binding.drawerLayout
|
||||||
binding.drawerLayout
|
.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
|
||||||
.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
|
ViewUtils.hideView(binding.surfaceInputOverlay)
|
||||||
ViewUtils.hideView(binding.surfaceInputOverlay)
|
ViewUtils.showView(binding.loadingIndicator)
|
||||||
ViewUtils.showView(binding.loadingIndicator)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
launch {
|
}
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
emulationViewModel.emulationStopped.collect(viewLifecycleOwner) {
|
||||||
emulationViewModel.emulationStopped.collect {
|
if (it && emulationViewModel.programChanged.value != -1) {
|
||||||
if (it && emulationViewModel.programChanged.value != -1) {
|
if (perfStatsUpdater != null) {
|
||||||
if (perfStatsUpdater != null) {
|
perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!)
|
||||||
perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!)
|
|
||||||
}
|
|
||||||
emulationState.changeProgram(emulationViewModel.programChanged.value)
|
|
||||||
emulationViewModel.setProgramChanged(-1)
|
|
||||||
emulationViewModel.setEmulationStopped(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
emulationState.changeProgram(emulationViewModel.programChanged.value)
|
||||||
|
emulationViewModel.setProgramChanged(-1)
|
||||||
|
emulationViewModel.setEmulationStopped(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
driverViewModel.isInteractionAllowed.collect(viewLifecycleOwner) {
|
||||||
|
if (it) startEmulation()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startEmulation(programIndex: Int = 0) {
|
private fun startEmulation(programIndex: Int = 0) {
|
||||||
|
|
|
@ -13,9 +13,6 @@ import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import com.google.android.material.transition.MaterialSharedAxis
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
|
@ -27,6 +24,7 @@ import org.yuzu.yuzu_emu.model.GamesViewModel
|
||||||
import org.yuzu.yuzu_emu.model.HomeViewModel
|
import org.yuzu.yuzu_emu.model.HomeViewModel
|
||||||
import org.yuzu.yuzu_emu.ui.main.MainActivity
|
import org.yuzu.yuzu_emu.ui.main.MainActivity
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
||||||
|
import org.yuzu.yuzu_emu.utils.collect
|
||||||
|
|
||||||
class GameFoldersFragment : Fragment() {
|
class GameFoldersFragment : Fragment() {
|
||||||
private var _binding: FragmentFoldersBinding? = null
|
private var _binding: FragmentFoldersBinding? = null
|
||||||
|
@ -70,12 +68,8 @@ class GameFoldersFragment : Fragment() {
|
||||||
adapter = FolderAdapter(requireActivity(), gamesViewModel)
|
adapter = FolderAdapter(requireActivity(), gamesViewModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
gamesViewModel.folders.collect(viewLifecycleOwner) {
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
(binding.listFolders.adapter as FolderAdapter).submitList(it)
|
||||||
gamesViewModel.folders.collect {
|
|
||||||
(binding.listFolders.adapter as FolderAdapter).submitList(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val mainActivity = requireActivity() as MainActivity
|
val mainActivity = requireActivity() as MainActivity
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.fragments
|
package org.yuzu.yuzu_emu.fragments
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.content.pm.ShortcutInfo
|
import android.content.pm.ShortcutInfo
|
||||||
import android.content.pm.ShortcutManager
|
import android.content.pm.ShortcutManager
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
@ -17,9 +16,7 @@ import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
@ -47,6 +44,7 @@ import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
||||||
import org.yuzu.yuzu_emu.utils.MemoryUtil
|
import org.yuzu.yuzu_emu.utils.MemoryUtil
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
|
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
||||||
|
import org.yuzu.yuzu_emu.utils.collect
|
||||||
import java.io.BufferedOutputStream
|
import java.io.BufferedOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
@ -76,8 +74,6 @@ class GamePropertiesFragment : Fragment() {
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is using the correct scope, lint is just acting up
|
|
||||||
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
homeViewModel.setNavigationVisibility(visible = false, animated = true)
|
homeViewModel.setNavigationVisibility(visible = false, animated = true)
|
||||||
|
@ -116,28 +112,14 @@ class GamePropertiesFragment : Fragment() {
|
||||||
|
|
||||||
reloadList()
|
reloadList()
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.apply {
|
homeViewModel.openImportSaves.collect(
|
||||||
launch {
|
viewLifecycleOwner,
|
||||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
resetState = { homeViewModel.setOpenImportSaves(false) }
|
||||||
homeViewModel.openImportSaves.collect {
|
) { if (it) importSaves.launch(arrayOf("application/zip")) }
|
||||||
if (it) {
|
homeViewModel.reloadPropertiesList.collect(
|
||||||
importSaves.launch(arrayOf("application/zip"))
|
viewLifecycleOwner,
|
||||||
homeViewModel.setOpenImportSaves(false)
|
resetState = { homeViewModel.reloadPropertiesList(false) }
|
||||||
}
|
) { if (it) reloadList() }
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
launch {
|
|
||||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
|
||||||
homeViewModel.reloadPropertiesList.collect {
|
|
||||||
if (it) {
|
|
||||||
reloadList()
|
|
||||||
homeViewModel.reloadPropertiesList(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setInsets()
|
setInsets()
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,6 @@ import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import com.google.android.material.transition.MaterialSharedAxis
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
|
@ -35,6 +32,7 @@ import org.yuzu.yuzu_emu.ui.main.MainActivity
|
||||||
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
||||||
import org.yuzu.yuzu_emu.utils.FileUtil
|
import org.yuzu.yuzu_emu.utils.FileUtil
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
||||||
|
import org.yuzu.yuzu_emu.utils.collect
|
||||||
import java.io.BufferedOutputStream
|
import java.io.BufferedOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
|
@ -75,14 +73,10 @@ class InstallableFragment : Fragment() {
|
||||||
binding.root.findNavController().popBackStack()
|
binding.root.findNavController().popBackStack()
|
||||||
}
|
}
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
homeViewModel.openImportSaves.collect(viewLifecycleOwner) {
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
if (it) {
|
||||||
homeViewModel.openImportSaves.collect {
|
importSaves.launch(arrayOf("application/zip"))
|
||||||
if (it) {
|
homeViewModel.setOpenImportSaves(false)
|
||||||
importSaves.launch(arrayOf("application/zip"))
|
|
||||||
homeViewModel.setOpenImportSaves(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,16 +13,13 @@ import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
|
import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
|
||||||
import org.yuzu.yuzu_emu.model.TaskViewModel
|
import org.yuzu.yuzu_emu.model.TaskViewModel
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||||
|
import org.yuzu.yuzu_emu.utils.collect
|
||||||
|
|
||||||
class ProgressDialogFragment : DialogFragment() {
|
class ProgressDialogFragment : DialogFragment() {
|
||||||
private val taskViewModel: TaskViewModel by activityViewModels()
|
private val taskViewModel: TaskViewModel by activityViewModels()
|
||||||
|
@ -65,70 +62,50 @@ class ProgressDialogFragment : DialogFragment() {
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
binding.message.isSelected = true
|
binding.message.isSelected = true
|
||||||
viewLifecycleOwner.lifecycleScope.apply {
|
taskViewModel.isComplete.collect(viewLifecycleOwner) {
|
||||||
launch {
|
if (it) {
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
dismiss()
|
||||||
taskViewModel.isComplete.collect {
|
when (val result = taskViewModel.result.value) {
|
||||||
if (it) {
|
is String -> Toast.makeText(
|
||||||
dismiss()
|
requireContext(),
|
||||||
when (val result = taskViewModel.result.value) {
|
result,
|
||||||
is String -> Toast.makeText(
|
Toast.LENGTH_LONG
|
||||||
requireContext(),
|
).show()
|
||||||
result,
|
|
||||||
Toast.LENGTH_LONG
|
|
||||||
).show()
|
|
||||||
|
|
||||||
is MessageDialogFragment -> result.show(
|
is MessageDialogFragment -> result.show(
|
||||||
requireActivity().supportFragmentManager,
|
requireActivity().supportFragmentManager,
|
||||||
MessageDialogFragment.TAG
|
MessageDialogFragment.TAG
|
||||||
)
|
)
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
|
||||||
}
|
|
||||||
taskViewModel.clear()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
taskViewModel.clear()
|
||||||
}
|
}
|
||||||
launch {
|
}
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
taskViewModel.cancelled.collect(viewLifecycleOwner) {
|
||||||
taskViewModel.cancelled.collect {
|
if (it) {
|
||||||
if (it) {
|
dialog?.setTitle(R.string.cancelling)
|
||||||
dialog?.setTitle(R.string.cancelling)
|
}
|
||||||
}
|
}
|
||||||
}
|
taskViewModel.progress.collect(viewLifecycleOwner) {
|
||||||
}
|
if (it != 0.0) {
|
||||||
}
|
binding.progressBar.apply {
|
||||||
launch {
|
isIndeterminate = false
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
progress = (
|
||||||
taskViewModel.progress.collect {
|
(it / taskViewModel.maxProgress.value) *
|
||||||
if (it != 0.0) {
|
PROGRESS_BAR_RESOLUTION
|
||||||
binding.progressBar.apply {
|
).toInt()
|
||||||
isIndeterminate = false
|
min = 0
|
||||||
progress = (
|
max = PROGRESS_BAR_RESOLUTION
|
||||||
(it / taskViewModel.maxProgress.value) *
|
|
||||||
PROGRESS_BAR_RESOLUTION
|
|
||||||
).toInt()
|
|
||||||
min = 0
|
|
||||||
max = PROGRESS_BAR_RESOLUTION
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
launch {
|
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
|
||||||
taskViewModel.message.collect {
|
|
||||||
binding.message.setVisible(it.isNotEmpty())
|
|
||||||
if (it.isNotEmpty()) {
|
|
||||||
binding.message.text = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
taskViewModel.message.collect(viewLifecycleOwner) {
|
||||||
|
binding.message.setVisible(it.isNotEmpty())
|
||||||
|
binding.message.text = it
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// By default, the ProgressDialog will immediately dismiss itself upon a button being pressed.
|
// By default, the ProgressDialog will immediately dismiss itself upon a button being pressed.
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.fragments
|
package org.yuzu.yuzu_emu.fragments
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
@ -18,14 +17,9 @@ import androidx.core.view.updatePadding
|
||||||
import androidx.core.widget.doOnTextChanged
|
import androidx.core.widget.doOnTextChanged
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import info.debatty.java.stringsimilarity.Jaccard
|
import info.debatty.java.stringsimilarity.Jaccard
|
||||||
import info.debatty.java.stringsimilarity.JaroWinkler
|
import info.debatty.java.stringsimilarity.JaroWinkler
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.YuzuApplication
|
import org.yuzu.yuzu_emu.YuzuApplication
|
||||||
|
@ -36,6 +30,7 @@ import org.yuzu.yuzu_emu.model.Game
|
||||||
import org.yuzu.yuzu_emu.model.GamesViewModel
|
import org.yuzu.yuzu_emu.model.GamesViewModel
|
||||||
import org.yuzu.yuzu_emu.model.HomeViewModel
|
import org.yuzu.yuzu_emu.model.HomeViewModel
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||||
|
import org.yuzu.yuzu_emu.utils.collect
|
||||||
|
|
||||||
class SearchFragment : Fragment() {
|
class SearchFragment : Fragment() {
|
||||||
private var _binding: FragmentSearchBinding? = null
|
private var _binding: FragmentSearchBinding? = null
|
||||||
|
@ -59,8 +54,6 @@ class SearchFragment : Fragment() {
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is using the correct scope, lint is just acting up
|
|
||||||
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
homeViewModel.setNavigationVisibility(visible = true, animated = true)
|
homeViewModel.setNavigationVisibility(visible = true, animated = true)
|
||||||
|
@ -86,30 +79,14 @@ class SearchFragment : Fragment() {
|
||||||
filterAndSearch()
|
filterAndSearch()
|
||||||
}
|
}
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.apply {
|
gamesViewModel.searchFocused.collect(
|
||||||
launch {
|
viewLifecycleOwner,
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
resetState = { gamesViewModel.setSearchFocused(false) }
|
||||||
gamesViewModel.searchFocused.collect {
|
) { if (it) focusSearch() }
|
||||||
if (it) {
|
gamesViewModel.games.collect(viewLifecycleOwner) { filterAndSearch() }
|
||||||
focusSearch()
|
gamesViewModel.searchedGames.collect(viewLifecycleOwner) {
|
||||||
gamesViewModel.setSearchFocused(false)
|
(binding.gridGamesSearch.adapter as GameAdapter).submitList(it)
|
||||||
}
|
binding.noResultsView.setVisible(it.isNotEmpty())
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
launch {
|
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
|
||||||
gamesViewModel.games.collectLatest { filterAndSearch() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
launch {
|
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
|
||||||
gamesViewModel.searchedGames.collect {
|
|
||||||
(binding.gridGamesSearch.adapter as GameAdapter).submitList(it)
|
|
||||||
binding.noResultsView.setVisible(it.isEmpty())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.clearButton.setOnClickListener { binding.searchText.setText("") }
|
binding.clearButton.setOnClickListener { binding.searchText.setText("") }
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
package org.yuzu.yuzu_emu.fragments
|
package org.yuzu.yuzu_emu.fragments
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
@ -23,9 +22,6 @@ import androidx.core.view.isVisible
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
|
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
|
||||||
|
@ -47,6 +43,7 @@ import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
||||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils
|
import org.yuzu.yuzu_emu.utils.ViewUtils
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||||
|
import org.yuzu.yuzu_emu.utils.collect
|
||||||
|
|
||||||
class SetupFragment : Fragment() {
|
class SetupFragment : Fragment() {
|
||||||
private var _binding: FragmentSetupBinding? = null
|
private var _binding: FragmentSetupBinding? = null
|
||||||
|
@ -78,8 +75,6 @@ class SetupFragment : Fragment() {
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is using the correct scope, lint is just acting up
|
|
||||||
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
mainActivity = requireActivity() as MainActivity
|
mainActivity = requireActivity() as MainActivity
|
||||||
|
|
||||||
|
@ -211,28 +206,14 @@ class SetupFragment : Fragment() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.apply {
|
homeViewModel.shouldPageForward.collect(
|
||||||
launch {
|
viewLifecycleOwner,
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
resetState = { homeViewModel.setShouldPageForward(false) }
|
||||||
homeViewModel.shouldPageForward.collect {
|
) { if (it) pageForward() }
|
||||||
if (it) {
|
homeViewModel.gamesDirSelected.collect(
|
||||||
pageForward()
|
viewLifecycleOwner,
|
||||||
homeViewModel.setShouldPageForward(false)
|
resetState = { homeViewModel.setGamesDirSelected(false) }
|
||||||
}
|
) { if (it) gamesDirCallback.onStepCompleted() }
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
launch {
|
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
|
||||||
homeViewModel.gamesDirSelected.collect {
|
|
||||||
if (it) {
|
|
||||||
gamesDirCallback.onStepCompleted()
|
|
||||||
homeViewModel.setGamesDirSelected(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.viewPager2.apply {
|
binding.viewPager2.apply {
|
||||||
adapter = SetupAdapter(requireActivity() as AppCompatActivity, pages)
|
adapter = SetupAdapter(requireActivity() as AppCompatActivity, pages)
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.ui
|
package org.yuzu.yuzu_emu.ui
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -14,12 +13,7 @@ import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import com.google.android.material.color.MaterialColors
|
import com.google.android.material.color.MaterialColors
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.adapters.GameAdapter
|
import org.yuzu.yuzu_emu.adapters.GameAdapter
|
||||||
import org.yuzu.yuzu_emu.databinding.FragmentGamesBinding
|
import org.yuzu.yuzu_emu.databinding.FragmentGamesBinding
|
||||||
|
@ -28,6 +22,7 @@ import org.yuzu.yuzu_emu.model.GamesViewModel
|
||||||
import org.yuzu.yuzu_emu.model.HomeViewModel
|
import org.yuzu.yuzu_emu.model.HomeViewModel
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
||||||
|
import org.yuzu.yuzu_emu.utils.collect
|
||||||
|
|
||||||
class GamesFragment : Fragment() {
|
class GamesFragment : Fragment() {
|
||||||
private var _binding: FragmentGamesBinding? = null
|
private var _binding: FragmentGamesBinding? = null
|
||||||
|
@ -45,8 +40,6 @@ class GamesFragment : Fragment() {
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is using the correct scope, lint is just acting up
|
|
||||||
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
homeViewModel.setNavigationVisibility(visible = true, animated = true)
|
homeViewModel.setNavigationVisibility(visible = true, animated = true)
|
||||||
|
@ -89,48 +82,28 @@ class GamesFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.apply {
|
gamesViewModel.isReloading.collect(viewLifecycleOwner) {
|
||||||
launch {
|
binding.swipeRefresh.isRefreshing = it
|
||||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
binding.noticeText.setVisible(
|
||||||
gamesViewModel.isReloading.collect {
|
visible = gamesViewModel.games.value.isEmpty() && !it,
|
||||||
binding.swipeRefresh.isRefreshing = it
|
gone = false
|
||||||
binding.noticeText.setVisible(
|
)
|
||||||
visible = gamesViewModel.games.value.isEmpty() && !it,
|
}
|
||||||
gone = false
|
gamesViewModel.games.collect(viewLifecycleOwner) {
|
||||||
)
|
(binding.gridGames.adapter as GameAdapter).submitList(it)
|
||||||
}
|
}
|
||||||
}
|
gamesViewModel.shouldSwapData.collect(
|
||||||
}
|
viewLifecycleOwner,
|
||||||
launch {
|
resetState = { gamesViewModel.setShouldSwapData(false) }
|
||||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
) {
|
||||||
gamesViewModel.games.collectLatest {
|
if (it) {
|
||||||
(binding.gridGames.adapter as GameAdapter).submitList(it)
|
(binding.gridGames.adapter as GameAdapter).submitList(gamesViewModel.games.value)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
launch {
|
|
||||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
|
||||||
gamesViewModel.shouldSwapData.collect {
|
|
||||||
if (it) {
|
|
||||||
(binding.gridGames.adapter as GameAdapter).submitList(
|
|
||||||
gamesViewModel.games.value
|
|
||||||
)
|
|
||||||
gamesViewModel.setShouldSwapData(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
launch {
|
|
||||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
|
||||||
gamesViewModel.shouldScrollToTop.collect {
|
|
||||||
if (it) {
|
|
||||||
scrollToTop()
|
|
||||||
gamesViewModel.setShouldScrollToTop(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
gamesViewModel.shouldScrollToTop.collect(
|
||||||
|
viewLifecycleOwner,
|
||||||
|
resetState = { gamesViewModel.setShouldScrollToTop(false) }
|
||||||
|
) { if (it) scrollToTop() }
|
||||||
|
|
||||||
setInsets()
|
setInsets()
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,6 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
import androidx.navigation.ui.setupWithNavController
|
import androidx.navigation.ui.setupWithNavController
|
||||||
|
@ -30,7 +27,6 @@ import com.google.android.material.color.MaterialColors
|
||||||
import com.google.android.material.navigation.NavigationBarView
|
import com.google.android.material.navigation.NavigationBarView
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FilenameFilter
|
import java.io.FilenameFilter
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
||||||
import org.yuzu.yuzu_emu.NativeLibrary
|
import org.yuzu.yuzu_emu.NativeLibrary
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
|
@ -144,38 +140,19 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
binding.statusBarShade.setVisible(visible = false, gone = false)
|
binding.statusBarShade.setVisible(visible = false, gone = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
lifecycleScope.apply {
|
homeViewModel.navigationVisible.collect(this) { showNavigation(it.first, it.second) }
|
||||||
launch {
|
homeViewModel.statusBarShadeVisible.collect(this) { showStatusBarShade(it) }
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
homeViewModel.contentToInstall.collect(
|
||||||
homeViewModel.navigationVisible.collect { showNavigation(it.first, it.second) }
|
this,
|
||||||
}
|
resetState = { homeViewModel.setContentToInstall(null) }
|
||||||
}
|
) {
|
||||||
launch {
|
if (it != null) {
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
installContent(it)
|
||||||
homeViewModel.statusBarShadeVisible.collect { showStatusBarShade(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
launch {
|
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
|
||||||
homeViewModel.contentToInstall.collect {
|
|
||||||
if (it != null) {
|
|
||||||
installContent(it)
|
|
||||||
homeViewModel.setContentToInstall(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
launch {
|
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
|
||||||
homeViewModel.checkKeys.collect {
|
|
||||||
if (it) {
|
|
||||||
checkKeys()
|
|
||||||
homeViewModel.setCheckKeys(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
homeViewModel.checkKeys.collect(this, resetState = { homeViewModel.setCheckKeys(false) }) {
|
||||||
|
if (it) checkKeys()
|
||||||
|
}
|
||||||
|
|
||||||
setInsets()
|
setInsets()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
package org.yuzu.yuzu_emu.utils
|
||||||
|
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects this [Flow] with a given [LifecycleOwner].
|
||||||
|
* @param scope [LifecycleOwner] that this [Flow] will be collected with.
|
||||||
|
* @param repeatState When to repeat collection on this [Flow].
|
||||||
|
* @param resetState Optional lambda to reset state of an underlying [MutableStateFlow] after
|
||||||
|
* [stateCollector] has been run.
|
||||||
|
* @param stateCollector Lambda that receives new state.
|
||||||
|
*/
|
||||||
|
inline fun <reified T> Flow<T>.collect(
|
||||||
|
scope: LifecycleOwner,
|
||||||
|
repeatState: Lifecycle.State = Lifecycle.State.CREATED,
|
||||||
|
crossinline resetState: () -> Unit = {},
|
||||||
|
crossinline stateCollector: (state: T) -> Unit
|
||||||
|
) {
|
||||||
|
scope.apply {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
repeatOnLifecycle(repeatState) {
|
||||||
|
this@collect.collect {
|
||||||
|
stateCollector(it)
|
||||||
|
resetState()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue