android: Rework driver fragment
Applies settings upon selection and uses a new Driver model to represent the information in-view. Also switches from an async diff list to a plain one.
This commit is contained in:
		@@ -13,16 +13,16 @@ import androidx.core.view.WindowInsetsCompat
 | 
			
		||||
import androidx.core.view.updatePadding
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import androidx.fragment.app.activityViewModels
 | 
			
		||||
import androidx.lifecycle.lifecycleScope
 | 
			
		||||
import androidx.navigation.findNavController
 | 
			
		||||
import androidx.navigation.fragment.navArgs
 | 
			
		||||
import androidx.recyclerview.widget.GridLayoutManager
 | 
			
		||||
import com.google.android.material.transition.MaterialSharedAxis
 | 
			
		||||
import kotlinx.coroutines.flow.collectLatest
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
import kotlinx.coroutines.withContext
 | 
			
		||||
import org.yuzu.yuzu_emu.R
 | 
			
		||||
import org.yuzu.yuzu_emu.adapters.DriverAdapter
 | 
			
		||||
import org.yuzu.yuzu_emu.databinding.FragmentDriverManagerBinding
 | 
			
		||||
import org.yuzu.yuzu_emu.model.Driver.Companion.toDriver
 | 
			
		||||
import org.yuzu.yuzu_emu.model.DriverViewModel
 | 
			
		||||
import org.yuzu.yuzu_emu.model.HomeViewModel
 | 
			
		||||
import org.yuzu.yuzu_emu.utils.FileUtil
 | 
			
		||||
@@ -85,25 +85,6 @@ class DriverManagerFragment : Fragment() {
 | 
			
		||||
            adapter = DriverAdapter(driverViewModel)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        viewLifecycleOwner.lifecycleScope.apply {
 | 
			
		||||
            launch {
 | 
			
		||||
                driverViewModel.driverList.collectLatest {
 | 
			
		||||
                    (binding.listDrivers.adapter as DriverAdapter).submitList(it)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            launch {
 | 
			
		||||
                driverViewModel.newDriverInstalled.collect {
 | 
			
		||||
                    if (_binding != null && it) {
 | 
			
		||||
                        (binding.listDrivers.adapter as DriverAdapter).apply {
 | 
			
		||||
                            notifyItemChanged(driverViewModel.previouslySelectedDriver)
 | 
			
		||||
                            notifyItemChanged(driverViewModel.selectedDriver)
 | 
			
		||||
                            driverViewModel.setNewDriverInstalled(false)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        setInsets()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -177,12 +158,20 @@ class DriverManagerFragment : Fragment() {
 | 
			
		||||
 | 
			
		||||
                val driverData = GpuDriverHelper.getMetadataFromZip(driverFile)
 | 
			
		||||
                val driverInList =
 | 
			
		||||
                    driverViewModel.driverList.value.firstOrNull { it.second == driverData }
 | 
			
		||||
                    driverViewModel.driverData.firstOrNull { it.second == driverData }
 | 
			
		||||
                if (driverInList != null) {
 | 
			
		||||
                    return@newInstance getString(R.string.driver_already_installed)
 | 
			
		||||
                } else {
 | 
			
		||||
                    driverViewModel.addDriver(Pair(driverPath, driverData))
 | 
			
		||||
                    driverViewModel.setNewDriverInstalled(true)
 | 
			
		||||
                    driverViewModel.onDriverAdded(Pair(driverPath, driverData))
 | 
			
		||||
                    withContext(Dispatchers.Main) {
 | 
			
		||||
                        if (_binding != null) {
 | 
			
		||||
                            val adapter = binding.listDrivers.adapter as DriverAdapter
 | 
			
		||||
                            adapter.addItem(driverData.toDriver())
 | 
			
		||||
                            adapter.selectItem(adapter.currentList.indices.last)
 | 
			
		||||
                            binding.listDrivers
 | 
			
		||||
                                .smoothScrollToPosition(adapter.currentList.indices.last)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                return@newInstance Any()
 | 
			
		||||
            }.show(childFragmentManager, IndeterminateProgressDialogFragment.TAG)
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,27 @@
 | 
			
		||||
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
package org.yuzu.yuzu_emu.model
 | 
			
		||||
 | 
			
		||||
import org.yuzu.yuzu_emu.utils.GpuDriverMetadata
 | 
			
		||||
 | 
			
		||||
data class Driver(
 | 
			
		||||
    override var selected: Boolean,
 | 
			
		||||
    val title: String,
 | 
			
		||||
    val version: String = "",
 | 
			
		||||
    val description: String = ""
 | 
			
		||||
) : SelectableItem {
 | 
			
		||||
    override fun onSelectionStateChanged(selected: Boolean) {
 | 
			
		||||
        this.selected = selected
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        fun GpuDriverMetadata.toDriver(selected: Boolean = false): Driver =
 | 
			
		||||
            Driver(
 | 
			
		||||
                selected,
 | 
			
		||||
                this.name ?: "",
 | 
			
		||||
                this.version ?: "",
 | 
			
		||||
                this.description ?: ""
 | 
			
		||||
            )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -17,11 +17,10 @@ import org.yuzu.yuzu_emu.R
 | 
			
		||||
import org.yuzu.yuzu_emu.YuzuApplication
 | 
			
		||||
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
 | 
			
		||||
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
 | 
			
		||||
import org.yuzu.yuzu_emu.utils.FileUtil
 | 
			
		||||
import org.yuzu.yuzu_emu.model.Driver.Companion.toDriver
 | 
			
		||||
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
 | 
			
		||||
import org.yuzu.yuzu_emu.utils.GpuDriverMetadata
 | 
			
		||||
import org.yuzu.yuzu_emu.utils.NativeConfig
 | 
			
		||||
import java.io.BufferedOutputStream
 | 
			
		||||
import java.io.File
 | 
			
		||||
 | 
			
		||||
class DriverViewModel : ViewModel() {
 | 
			
		||||
@@ -38,97 +37,74 @@ class DriverViewModel : ViewModel() {
 | 
			
		||||
            !loading && ready && !deleting
 | 
			
		||||
        }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), initialValue = false)
 | 
			
		||||
 | 
			
		||||
    private val _driverList = MutableStateFlow(GpuDriverHelper.getDrivers())
 | 
			
		||||
    val driverList: StateFlow<MutableList<Pair<String, GpuDriverMetadata>>> get() = _driverList
 | 
			
		||||
    var driverData = GpuDriverHelper.getDrivers()
 | 
			
		||||
 | 
			
		||||
    var previouslySelectedDriver = 0
 | 
			
		||||
    var selectedDriver = -1
 | 
			
		||||
    private val _driverList = MutableStateFlow(emptyList<Driver>())
 | 
			
		||||
    val driverList: StateFlow<List<Driver>> get() = _driverList
 | 
			
		||||
 | 
			
		||||
    // Used for showing which driver is currently installed within the driver manager card
 | 
			
		||||
    private val _selectedDriverTitle = MutableStateFlow("")
 | 
			
		||||
    val selectedDriverTitle: StateFlow<String> get() = _selectedDriverTitle
 | 
			
		||||
 | 
			
		||||
    private val _newDriverInstalled = MutableStateFlow(false)
 | 
			
		||||
    val newDriverInstalled: StateFlow<Boolean> get() = _newDriverInstalled
 | 
			
		||||
 | 
			
		||||
    val driversToDelete = mutableListOf<String>()
 | 
			
		||||
    private val driversToDelete = mutableListOf<String>()
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        val currentDriverMetadata = GpuDriverHelper.installedCustomDriverData
 | 
			
		||||
        findSelectedDriver(currentDriverMetadata)
 | 
			
		||||
 | 
			
		||||
        // If a user had installed a driver before the manager was implemented, this zips
 | 
			
		||||
        // the installed driver to UserData/gpu_drivers/CustomDriver.zip so that it can
 | 
			
		||||
        // be indexed and exported as expected.
 | 
			
		||||
        if (selectedDriver == -1) {
 | 
			
		||||
            val driverToSave =
 | 
			
		||||
                File(GpuDriverHelper.driverStoragePath, "CustomDriver.zip")
 | 
			
		||||
            driverToSave.createNewFile()
 | 
			
		||||
            FileUtil.zipFromInternalStorage(
 | 
			
		||||
                File(GpuDriverHelper.driverInstallationPath!!),
 | 
			
		||||
                GpuDriverHelper.driverInstallationPath!!,
 | 
			
		||||
                BufferedOutputStream(driverToSave.outputStream())
 | 
			
		||||
            )
 | 
			
		||||
            _driverList.value.add(Pair(driverToSave.path, currentDriverMetadata))
 | 
			
		||||
            setSelectedDriverIndex(_driverList.value.size - 1)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // If a user had installed a driver before the config was reworked to be multiplatform,
 | 
			
		||||
        // we have save the path of the previously selected driver to the new setting.
 | 
			
		||||
        if (StringSetting.DRIVER_PATH.getString(true).isEmpty() && selectedDriver > 0 &&
 | 
			
		||||
            StringSetting.DRIVER_PATH.global
 | 
			
		||||
        ) {
 | 
			
		||||
            StringSetting.DRIVER_PATH.setString(_driverList.value[selectedDriver].first)
 | 
			
		||||
            NativeConfig.saveGlobalConfig()
 | 
			
		||||
        } else {
 | 
			
		||||
            findSelectedDriver(GpuDriverHelper.customDriverSettingData)
 | 
			
		||||
        }
 | 
			
		||||
        updateDriverList()
 | 
			
		||||
        updateDriverNameForGame(null)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun setSelectedDriverIndex(value: Int) {
 | 
			
		||||
        if (selectedDriver != -1) {
 | 
			
		||||
            previouslySelectedDriver = selectedDriver
 | 
			
		||||
    fun reloadDriverData() {
 | 
			
		||||
        _areDriversLoading.value = true
 | 
			
		||||
        driverData = GpuDriverHelper.getDrivers()
 | 
			
		||||
        updateDriverList()
 | 
			
		||||
        _areDriversLoading.value = false
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun updateDriverList() {
 | 
			
		||||
        val selectedDriver = GpuDriverHelper.customDriverSettingData
 | 
			
		||||
        val newDriverList = mutableListOf(
 | 
			
		||||
            Driver(
 | 
			
		||||
                selectedDriver == GpuDriverMetadata(),
 | 
			
		||||
                YuzuApplication.appContext.getString(R.string.system_gpu_driver)
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
        driverData.forEach {
 | 
			
		||||
            newDriverList.add(it.second.toDriver(it.second == selectedDriver))
 | 
			
		||||
        }
 | 
			
		||||
        selectedDriver = value
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun setNewDriverInstalled(value: Boolean) {
 | 
			
		||||
        _newDriverInstalled.value = value
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun addDriver(driverData: Pair<String, GpuDriverMetadata>) {
 | 
			
		||||
        val driverIndex = _driverList.value.indexOfFirst { it == driverData }
 | 
			
		||||
        if (driverIndex == -1) {
 | 
			
		||||
            _driverList.value.add(driverData)
 | 
			
		||||
            setSelectedDriverIndex(_driverList.value.size - 1)
 | 
			
		||||
            _selectedDriverTitle.value = driverData.second.name
 | 
			
		||||
                ?: YuzuApplication.appContext.getString(R.string.system_gpu_driver)
 | 
			
		||||
        } else {
 | 
			
		||||
            setSelectedDriverIndex(driverIndex)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun removeDriver(driverData: Pair<String, GpuDriverMetadata>) {
 | 
			
		||||
        _driverList.value.remove(driverData)
 | 
			
		||||
        _driverList.value = newDriverList
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun onOpenDriverManager(game: Game?) {
 | 
			
		||||
        if (game != null) {
 | 
			
		||||
            SettingsFile.loadCustomConfig(game)
 | 
			
		||||
        }
 | 
			
		||||
        updateDriverList()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        val driverPath = StringSetting.DRIVER_PATH.getString()
 | 
			
		||||
        if (driverPath.isEmpty()) {
 | 
			
		||||
            setSelectedDriverIndex(0)
 | 
			
		||||
    fun onDriverSelected(position: Int) {
 | 
			
		||||
        if (position == 0) {
 | 
			
		||||
            StringSetting.DRIVER_PATH.setString("")
 | 
			
		||||
        } else {
 | 
			
		||||
            findSelectedDriver(GpuDriverHelper.getMetadataFromZip(File(driverPath)))
 | 
			
		||||
            StringSetting.DRIVER_PATH.setString(driverData[position - 1].first)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun onDriverRemoved(removedPosition: Int, selectedPosition: Int) {
 | 
			
		||||
        driversToDelete.add(driverData[removedPosition - 1].first)
 | 
			
		||||
        driverData.removeAt(removedPosition - 1)
 | 
			
		||||
        onDriverSelected(selectedPosition)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun onDriverAdded(driver: Pair<String, GpuDriverMetadata>) {
 | 
			
		||||
        if (driversToDelete.contains(driver.first)) {
 | 
			
		||||
            driversToDelete.remove(driver.first)
 | 
			
		||||
        }
 | 
			
		||||
        driverData.add(driver)
 | 
			
		||||
        onDriverSelected(driverData.size)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun onCloseDriverManager(game: Game?) {
 | 
			
		||||
        _isDeletingDrivers.value = true
 | 
			
		||||
        StringSetting.DRIVER_PATH.setString(driverList.value[selectedDriver].first)
 | 
			
		||||
        updateDriverNameForGame(game)
 | 
			
		||||
        if (game == null) {
 | 
			
		||||
            NativeConfig.saveGlobalConfig()
 | 
			
		||||
@@ -181,20 +157,6 @@ class DriverViewModel : ViewModel() {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun findSelectedDriver(currentDriverMetadata: GpuDriverMetadata) {
 | 
			
		||||
        if (driverList.value.size == 1) {
 | 
			
		||||
            setSelectedDriverIndex(0)
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        driverList.value.forEachIndexed { i: Int, driver: Pair<String, GpuDriverMetadata> ->
 | 
			
		||||
            if (driver.second == currentDriverMetadata) {
 | 
			
		||||
                setSelectedDriverIndex(i)
 | 
			
		||||
                return
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun updateDriverNameForGame(game: Game?) {
 | 
			
		||||
        if (!GpuDriverHelper.supportsCustomDriverLoading()) {
 | 
			
		||||
            return
 | 
			
		||||
@@ -217,7 +179,6 @@ class DriverViewModel : ViewModel() {
 | 
			
		||||
 | 
			
		||||
    private fun setDriverReady() {
 | 
			
		||||
        _isDriverReady.value = true
 | 
			
		||||
        _selectedDriverTitle.value = GpuDriverHelper.customDriverSettingData.name
 | 
			
		||||
            ?: YuzuApplication.appContext.getString(R.string.system_gpu_driver)
 | 
			
		||||
        updateName()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -62,9 +62,6 @@ object GpuDriverHelper {
 | 
			
		||||
                ?.sortedByDescending { it: Pair<String, GpuDriverMetadata> -> it.second.name }
 | 
			
		||||
                ?.distinct()
 | 
			
		||||
                ?.toMutableList() ?: mutableListOf()
 | 
			
		||||
 | 
			
		||||
        // TODO: Get system driver information
 | 
			
		||||
        drivers.add(0, Pair("", GpuDriverMetadata()))
 | 
			
		||||
        return drivers
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user