diff --git a/Source/Android/app/build.gradle b/Source/Android/app/build.gradle index 11349147e8..e265f56068 100644 --- a/Source/Android/app/build.gradle +++ b/Source/Android/app/build.gradle @@ -144,8 +144,10 @@ dependencies { implementation 'androidx.preference:preference:1.2.0' implementation 'androidx.profileinstaller:profileinstaller:1.2.2' - // Force dependency version to solve build conflict with androidx preferences - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1" + // Kotlin extensions for lifecycle components + implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1' + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1' + implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1' // Android TV UI libraries. implementation 'androidx.leanback:leanback:1.0.0' diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/OnlineUpdateRegionSelectDialogFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/OnlineUpdateRegionSelectDialogFragment.java deleted file mode 100644 index ea1c535ca4..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/OnlineUpdateRegionSelectDialogFragment.java +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -package org.dolphinemu.dolphinemu.features.sysupdate.ui; - -import android.app.Dialog; -import android.os.Bundle; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.DialogFragment; -import androidx.lifecycle.ViewModelProvider; - -import com.google.android.material.dialog.MaterialAlertDialogBuilder; - -import org.dolphinemu.dolphinemu.R; - -public class OnlineUpdateRegionSelectDialogFragment extends DialogFragment -{ - @NonNull - @Override - public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) - { - String[] items = - {getString(R.string.country_europe), getString(R.string.country_japan), getString( - R.string.country_korea), getString(R.string.country_usa)}; - int checkedItem = -1; - - return new MaterialAlertDialogBuilder(requireContext()) - .setTitle(R.string.region_select_title) - .setSingleChoiceItems(items, checkedItem, (dialog, which) -> - { - SystemUpdateViewModel viewModel = - new ViewModelProvider(requireActivity()).get(SystemUpdateViewModel.class); - viewModel.setRegion(which); - - SystemUpdateProgressBarDialogFragment progressBarFragment = - new SystemUpdateProgressBarDialogFragment(); - progressBarFragment - .show(getParentFragmentManager(), "OnlineUpdateProgressBarDialogFragment"); - dismiss(); - }) - .create(); - } -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/OnlineUpdateRegionSelectDialogFragment.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/OnlineUpdateRegionSelectDialogFragment.kt new file mode 100644 index 0000000000..ef41c2a034 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/OnlineUpdateRegionSelectDialogFragment.kt @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.sysupdate.ui + +import android.app.Dialog +import android.content.DialogInterface +import android.os.Bundle +import androidx.fragment.app.DialogFragment +import androidx.lifecycle.ViewModelProvider +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import org.dolphinemu.dolphinemu.R + +class OnlineUpdateRegionSelectDialogFragment : DialogFragment() { + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val items = arrayOf( + getString(R.string.country_europe), + getString(R.string.country_japan), + getString(R.string.country_korea), + getString(R.string.country_usa) + ) + val checkedItem = -1 + return MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.region_select_title) + .setSingleChoiceItems(items, checkedItem) { _: DialogInterface?, which: Int -> + val viewModel = + ViewModelProvider(requireActivity())[SystemUpdateViewModel::class.java] + viewModel.region = which + SystemUpdateProgressBarDialogFragment().show( + parentFragmentManager, + SystemUpdateProgressBarDialogFragment.TAG + ) + dismiss() + } + .create() + } + + companion object { + const val TAG = "OnlineUpdateRegionSelectDialogFragment" + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemMenuNotInstalledDialogFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemMenuNotInstalledDialogFragment.java deleted file mode 100644 index 671750e1d6..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemMenuNotInstalledDialogFragment.java +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -package org.dolphinemu.dolphinemu.features.sysupdate.ui; - -import android.app.Dialog; -import android.os.Bundle; - -import androidx.fragment.app.DialogFragment; -import androidx.fragment.app.FragmentManager; - -import com.google.android.material.dialog.MaterialAlertDialogBuilder; - -import org.dolphinemu.dolphinemu.R; - -public class SystemMenuNotInstalledDialogFragment extends DialogFragment -{ - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) - { - return new MaterialAlertDialogBuilder(requireContext()) - .setTitle(R.string.system_menu_not_installed_title) - .setMessage(R.string.system_menu_not_installed_message) - .setPositiveButton(R.string.yes, (dialog, which) -> - { - FragmentManager fragmentManager = getParentFragmentManager(); - OnlineUpdateRegionSelectDialogFragment dialogFragment = - new OnlineUpdateRegionSelectDialogFragment(); - dialogFragment.show(fragmentManager, "OnlineUpdateRegionSelectDialogFragment"); - dismiss(); - }) - .setNegativeButton(R.string.no, (dialog, which) -> dismiss()) - .create(); - } -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemMenuNotInstalledDialogFragment.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemMenuNotInstalledDialogFragment.kt new file mode 100644 index 0000000000..9dfb328738 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemMenuNotInstalledDialogFragment.kt @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.sysupdate.ui + +import android.app.Dialog +import android.content.DialogInterface +import android.os.Bundle +import androidx.fragment.app.DialogFragment +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import org.dolphinemu.dolphinemu.R + +class SystemMenuNotInstalledDialogFragment : DialogFragment() { + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.system_menu_not_installed_title) + .setMessage(R.string.system_menu_not_installed_message) + .setPositiveButton(R.string.yes) { _: DialogInterface?, _: Int -> + OnlineUpdateRegionSelectDialogFragment().show( + parentFragmentManager, + OnlineUpdateRegionSelectDialogFragment.TAG + ) + dismiss() + } + .setNegativeButton(R.string.no) { _: DialogInterface?, _: Int -> dismiss() } + .create() + } + + companion object { + const val TAG = "SystemMenuNotInstalledDialogFragment" + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemUpdateProgressBarDialogFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemUpdateProgressBarDialogFragment.java deleted file mode 100644 index 96dda28903..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemUpdateProgressBarDialogFragment.java +++ /dev/null @@ -1,133 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -package org.dolphinemu.dolphinemu.features.sysupdate.ui; - -import android.app.Dialog; -import android.content.pm.ActivityInfo; -import android.os.Bundle; -import android.widget.Button; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.app.AppCompatActivity; -import androidx.fragment.app.DialogFragment; -import androidx.lifecycle.ViewModelProvider; - -import com.google.android.material.dialog.MaterialAlertDialogBuilder; - -import org.dolphinemu.dolphinemu.R; -import org.dolphinemu.dolphinemu.databinding.DialogProgressBinding; -import org.dolphinemu.dolphinemu.databinding.DialogProgressTvBinding; - -public class SystemUpdateProgressBarDialogFragment extends DialogFragment -{ - @NonNull - @Override - public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) - { - // Store the current orientation to be restored later - final int orientation = getActivity().getRequestedOrientation(); - // Rotating the device while the update is running can result in a title failing to import. - getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED); - - SystemUpdateViewModel viewModel = - new ViewModelProvider(requireActivity()).get(SystemUpdateViewModel.class); - - DialogProgressBinding dialogProgressBinding; - DialogProgressTvBinding dialogProgressTvBinding; - - // We need to set the message to something here, otherwise the text will not appear when we set it later. - MaterialAlertDialogBuilder progressDialogBuilder = - new MaterialAlertDialogBuilder(requireContext()) - .setTitle(getString(R.string.updating)) - .setMessage("") - .setNegativeButton(getString(R.string.cancel), null) - .setCancelable(false); - - // TODO: Remove dialog_progress_tv if we switch to an AppCompatActivity for leanback - if (getActivity() instanceof AppCompatActivity) - { - dialogProgressBinding = DialogProgressBinding.inflate(getLayoutInflater()); - progressDialogBuilder.setView(dialogProgressBinding.getRoot()); - - viewModel.getProgressData().observe(this, - (@Nullable Integer progress) -> dialogProgressBinding.updateProgress.setProgress( - progress)); - - viewModel.getTotalData().observe(this, (@Nullable Integer total) -> - { - if (total == 0) - { - return; - } - - dialogProgressBinding.updateProgress.setMax(total); - }); - } - else - { - dialogProgressTvBinding = DialogProgressTvBinding.inflate(getLayoutInflater()); - progressDialogBuilder.setView(dialogProgressTvBinding.getRoot()); - - viewModel.getProgressData().observe(this, - (@Nullable Integer progress) -> dialogProgressTvBinding.updateProgress.setProgress( - progress)); - - viewModel.getTotalData().observe(this, (@Nullable Integer total) -> - { - if (total == 0) - { - return; - } - - dialogProgressTvBinding.updateProgress.setMax(total); - }); - } - - AlertDialog progressDialog = progressDialogBuilder.create(); - - viewModel.getTitleIdData().observe(this, (@Nullable Long titleId) -> progressDialog.setMessage( - getString(R.string.updating_message, titleId))); - - viewModel.getResultData().observe(this, (@Nullable Integer result) -> - { - if (result == -1) - { - // This is the default value, ignore - return; - } - - SystemUpdateResultFragment progressBarFragment = new SystemUpdateResultFragment(); - progressBarFragment.show(getParentFragmentManager(), "OnlineUpdateResultFragment"); - - getActivity().setRequestedOrientation(orientation); - - dismiss(); - }); - - if (savedInstanceState == null) - { - viewModel.startUpdate(); - } - return progressDialog; - } - - // By default, the ProgressDialog will immediately dismiss itself upon a button being pressed. - // Setting the OnClickListener again after the dialog is shown overrides this behavior. - @Override - public void onResume() - { - super.onResume(); - AlertDialog alertDialog = (AlertDialog) getDialog(); - SystemUpdateViewModel viewModel = - new ViewModelProvider(requireActivity()).get(SystemUpdateViewModel.class); - Button negativeButton = alertDialog.getButton(Dialog.BUTTON_NEGATIVE); - negativeButton.setOnClickListener(v -> - { - alertDialog.setTitle(getString(R.string.cancelling)); - alertDialog.setMessage(getString(R.string.update_cancelling)); - viewModel.setCanceled(); - }); - } -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemUpdateProgressBarDialogFragment.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemUpdateProgressBarDialogFragment.kt new file mode 100644 index 0000000000..a02e210a9c --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemUpdateProgressBarDialogFragment.kt @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.sysupdate.ui + +import android.app.Dialog +import android.os.Bundle +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.DialogFragment +import androidx.lifecycle.ViewModelProvider +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import org.dolphinemu.dolphinemu.R +import org.dolphinemu.dolphinemu.databinding.DialogProgressBinding +import org.dolphinemu.dolphinemu.databinding.DialogProgressTvBinding + +class SystemUpdateProgressBarDialogFragment : DialogFragment() { + private lateinit var viewModel: SystemUpdateViewModel + + private lateinit var binding: DialogProgressBinding + private lateinit var bindingTv: DialogProgressTvBinding + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + viewModel = ViewModelProvider(requireActivity())[SystemUpdateViewModel::class.java] + + // We need to set the message to something here, otherwise the text will not appear when we set it later. + val progressDialogBuilder = MaterialAlertDialogBuilder(requireContext()) + .setTitle(getString(R.string.updating)) + .setMessage("") + .setNegativeButton(getString(R.string.cancel), null) + .setCancelable(false) + + // TODO: Remove dialog_progress_tv if we switch to an AppCompatActivity for leanback + if (activity is AppCompatActivity) { + binding = DialogProgressBinding.inflate(layoutInflater) + progressDialogBuilder.setView(binding.root) + + viewModel.progressData.observe( + this + ) { progress: Int -> + binding.updateProgress.progress = progress + } + + viewModel.totalData.observe(this) { total: Int -> + if (total == 0) { + return@observe + } + binding.updateProgress.max = total + } + } else { + bindingTv = DialogProgressTvBinding.inflate(layoutInflater) + progressDialogBuilder.setView(bindingTv.root) + + viewModel.progressData.observe( + this + ) { progress: Int -> + bindingTv.updateProgress.progress = progress + } + + viewModel.totalData.observe(this) { total: Int -> + if (total == 0) { + return@observe + } + bindingTv.updateProgress.max = total + } + } + + val progressDialog = progressDialogBuilder.create() + + viewModel.titleIdData.observe(this) { titleId: Long -> + progressDialog.setMessage(getString(R.string.updating_message, titleId)) + } + + viewModel.resultData.observe(this) { result: Int -> + if (result == -1) { + // This is the default value, ignore + return@observe + } + + val progressBarFragment = SystemUpdateResultFragment() + progressBarFragment.show(parentFragmentManager, SystemUpdateResultFragment.TAG) + + dismiss() + } + + if (savedInstanceState == null) { + viewModel.startUpdate() + } + return progressDialog + } + + // By default, the ProgressDialog will immediately dismiss itself upon a button being pressed. + // Setting the OnClickListener again after the dialog is shown overrides this behavior. + override fun onResume() { + super.onResume() + val alertDialog = dialog as AlertDialog + val negativeButton = alertDialog.getButton(Dialog.BUTTON_NEGATIVE) + negativeButton.setOnClickListener { + alertDialog.setTitle(getString(R.string.cancelling)) + alertDialog.setMessage(getString(R.string.update_cancelling)) + viewModel.setCanceled() + + if (activity is AppCompatActivity) + binding.updateProgress.isIndeterminate = true + else + bindingTv.updateProgress.isIndeterminate = true + } + } + + companion object { + const val TAG = "SystemUpdateProgressBarDialogFragment" + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemUpdateResultFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemUpdateResultFragment.java deleted file mode 100644 index a8e638ad90..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemUpdateResultFragment.java +++ /dev/null @@ -1,105 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -package org.dolphinemu.dolphinemu.features.sysupdate.ui; - -import android.app.Dialog; -import android.os.Bundle; - -import androidx.annotation.NonNull; -import androidx.fragment.app.DialogFragment; -import androidx.lifecycle.ViewModelProvider; - -import com.google.android.material.dialog.MaterialAlertDialogBuilder; - -import org.dolphinemu.dolphinemu.R; -import org.dolphinemu.dolphinemu.utils.WiiUtils; - -public class SystemUpdateResultFragment extends DialogFragment -{ - private int mResult; - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) - { - SystemUpdateViewModel viewModel = - new ViewModelProvider(requireActivity()).get(SystemUpdateViewModel.class); - if (savedInstanceState == null) - { - mResult = viewModel.getResultData().getValue().intValue(); - viewModel.clear(); - } - else - { - mResult = savedInstanceState.getInt("result"); - } - - String message; - switch (mResult) - { - case WiiUtils.UPDATE_RESULT_SUCCESS: - message = getString(R.string.update_success); - break; - case WiiUtils.UPDATE_RESULT_ALREADY_UP_TO_DATE: - message = getString(R.string.already_up_to_date); - break; - case WiiUtils.UPDATE_RESULT_REGION_MISMATCH: - message = getString(R.string.region_mismatch); - break; - case WiiUtils.UPDATE_RESULT_MISSING_UPDATE_PARTITION: - message = getString(R.string.missing_update_partition); - break; - case WiiUtils.UPDATE_RESULT_DISC_READ_FAILED: - message = getString(R.string.disc_read_failed); - break; - case WiiUtils.UPDATE_RESULT_SERVER_FAILED: - message = getString(R.string.server_failed); - break; - case WiiUtils.UPDATE_RESULT_DOWNLOAD_FAILED: - message = getString(R.string.download_failed); - break; - case WiiUtils.UPDATE_RESULT_IMPORT_FAILED: - message = getString(R.string.import_failed); - break; - case WiiUtils.UPDATE_RESULT_CANCELLED: - message = getString(R.string.update_cancelled); - break; - default: - throw new IllegalStateException("Unexpected value: " + mResult); - } - - String title; - switch (mResult) - { - case WiiUtils.UPDATE_RESULT_SUCCESS: - case WiiUtils.UPDATE_RESULT_ALREADY_UP_TO_DATE: - title = getString(R.string.update_success_title); - break; - case WiiUtils.UPDATE_RESULT_REGION_MISMATCH: - case WiiUtils.UPDATE_RESULT_MISSING_UPDATE_PARTITION: - case WiiUtils.UPDATE_RESULT_DISC_READ_FAILED: - case WiiUtils.UPDATE_RESULT_SERVER_FAILED: - case WiiUtils.UPDATE_RESULT_DOWNLOAD_FAILED: - case WiiUtils.UPDATE_RESULT_IMPORT_FAILED: - title = getString(R.string.update_failed_title); - break; - case WiiUtils.UPDATE_RESULT_CANCELLED: - title = getString(R.string.update_cancelled_title); - break; - default: - throw new IllegalStateException("Unexpected value: " + mResult); - } - - return new MaterialAlertDialogBuilder(requireContext()) - .setTitle(title) - .setMessage(message) - .setPositiveButton(R.string.ok, (dialog, which) -> dismiss()) - .create(); - } - - @Override - public void onSaveInstanceState(@NonNull Bundle outState) - { - super.onSaveInstanceState(outState); - outState.putInt("result", mResult); - } -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemUpdateResultFragment.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemUpdateResultFragment.kt new file mode 100644 index 0000000000..a6af39e6b4 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemUpdateResultFragment.kt @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.sysupdate.ui + +import android.app.Dialog +import android.content.DialogInterface +import android.os.Bundle +import androidx.fragment.app.DialogFragment +import androidx.lifecycle.ViewModelProvider +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import org.dolphinemu.dolphinemu.R +import org.dolphinemu.dolphinemu.utils.WiiUtils + +class SystemUpdateResultFragment : DialogFragment() { + private val resultKey = "result" + + private var mResult = 0 + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val viewModel = ViewModelProvider(requireActivity())[SystemUpdateViewModel::class.java] + if (savedInstanceState == null) { + mResult = viewModel.resultData.value!!.toInt() + viewModel.clear() + } else { + mResult = savedInstanceState.getInt(resultKey) + } + val message: String = when (mResult) { + WiiUtils.UPDATE_RESULT_SUCCESS -> getString(R.string.update_success) + WiiUtils.UPDATE_RESULT_ALREADY_UP_TO_DATE -> getString(R.string.already_up_to_date) + WiiUtils.UPDATE_RESULT_REGION_MISMATCH -> getString(R.string.region_mismatch) + WiiUtils.UPDATE_RESULT_MISSING_UPDATE_PARTITION -> getString(R.string.missing_update_partition) + WiiUtils.UPDATE_RESULT_DISC_READ_FAILED -> getString(R.string.disc_read_failed) + WiiUtils.UPDATE_RESULT_SERVER_FAILED -> getString(R.string.server_failed) + WiiUtils.UPDATE_RESULT_DOWNLOAD_FAILED -> getString(R.string.download_failed) + WiiUtils.UPDATE_RESULT_IMPORT_FAILED -> getString(R.string.import_failed) + WiiUtils.UPDATE_RESULT_CANCELLED -> getString(R.string.update_cancelled) + else -> throw IllegalStateException("Unexpected value: $mResult") + } + val title: String = when (mResult) { + WiiUtils.UPDATE_RESULT_SUCCESS, + WiiUtils.UPDATE_RESULT_ALREADY_UP_TO_DATE -> getString(R.string.update_success_title) + WiiUtils.UPDATE_RESULT_REGION_MISMATCH, + WiiUtils.UPDATE_RESULT_MISSING_UPDATE_PARTITION, + WiiUtils.UPDATE_RESULT_DISC_READ_FAILED, + WiiUtils.UPDATE_RESULT_SERVER_FAILED, + WiiUtils.UPDATE_RESULT_DOWNLOAD_FAILED, + WiiUtils.UPDATE_RESULT_IMPORT_FAILED -> getString(R.string.update_failed_title) + WiiUtils.UPDATE_RESULT_CANCELLED -> getString(R.string.update_cancelled_title) + else -> throw IllegalStateException("Unexpected value: $mResult") + } + + return MaterialAlertDialogBuilder(requireContext()) + .setTitle(title) + .setMessage(message) + .setPositiveButton(R.string.ok) { _: DialogInterface?, _: Int -> dismiss() } + .create() + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + outState.putInt(resultKey, mResult) + } + + companion object { + const val TAG = "SystemUpdateResultFragment" + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemUpdateViewModel.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemUpdateViewModel.java deleted file mode 100644 index a249b01ee7..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemUpdateViewModel.java +++ /dev/null @@ -1,152 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -package org.dolphinemu.dolphinemu.features.sysupdate.ui; - -import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.ViewModel; - -import org.dolphinemu.dolphinemu.utils.WiiUpdateCallback; -import org.dolphinemu.dolphinemu.utils.WiiUtils; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -public class SystemUpdateViewModel extends ViewModel -{ - private static final ExecutorService executor = Executors.newFixedThreadPool(1); - - private final MutableLiveData mProgressData = new MutableLiveData<>(); - private final MutableLiveData mTotalData = new MutableLiveData<>(); - private final MutableLiveData mTitleIdData = new MutableLiveData<>(); - private final MutableLiveData mResultData = new MutableLiveData<>(); - - private boolean mCanceled = false; - private int mRegion; - private String mDiscPath; - - public SystemUpdateViewModel() - { - clear(); - } - - public void setRegion(int region) - { - mRegion = region; - } - - public int getRegion() - { - return mRegion; - } - - public void setDiscPath(String discPath) - { - mDiscPath = discPath; - } - - public String getDiscPath() - { - return mDiscPath; - } - - public MutableLiveData getProgressData() - { - return mProgressData; - } - - public MutableLiveData getTotalData() - { - return mTotalData; - } - - public MutableLiveData getTitleIdData() - { - return mTitleIdData; - } - - public MutableLiveData getResultData() - { - return mResultData; - } - - public void setCanceled() - { - mCanceled = true; - } - - public void startUpdate() - { - if (!mDiscPath.isEmpty()) - { - startDiscUpdate(mDiscPath); - } - else - { - final String region; - switch (mRegion) - { - case 0: - region = "EUR"; - break; - case 1: - region = "JPN"; - break; - case 2: - region = "KOR"; - break; - case 3: - region = "USA"; - break; - default: - region = ""; - break; - } - startOnlineUpdate(region); - } - } - - public void startOnlineUpdate(String region) - { - mCanceled = false; - - executor.execute(() -> - { - int result = WiiUtils.doOnlineUpdate(region, constructCallback()); - mResultData.postValue(result); - }); - } - - public void startDiscUpdate(String path) - { - mCanceled = false; - - executor.execute(() -> - { - int result = WiiUtils.doDiscUpdate(path, constructCallback()); - mResultData.postValue(result); - }); - } - - public void clear() - { - mProgressData.setValue(0); - mTotalData.setValue(0); - mTitleIdData.setValue(0l); - mResultData.setValue(-1); - mCanceled = false; - mRegion = -1; - mDiscPath = ""; - } - - private WiiUpdateCallback constructCallback() - { - return (processed, total, titleId) -> - { - mProgressData.postValue(processed); - mTotalData.postValue(total); - mTitleIdData.postValue(titleId); - - return !mCanceled; - }; - } -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemUpdateViewModel.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemUpdateViewModel.kt new file mode 100644 index 0000000000..7dc53d83bd --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/sysupdate/ui/SystemUpdateViewModel.kt @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.sysupdate.ui + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.dolphinemu.dolphinemu.utils.WiiUpdateCallback +import org.dolphinemu.dolphinemu.utils.WiiUtils + +class SystemUpdateViewModel : ViewModel() { + val progressData = MutableLiveData() + val totalData = MutableLiveData() + val titleIdData = MutableLiveData() + val resultData = MutableLiveData() + + private var isRunning = false + private var canceled = false + var region = -1 + var discPath: String = "" + + init { + clear() + } + + fun setCanceled() { + canceled = true + } + + fun startUpdate() { + if (isRunning) return + isRunning = true + + viewModelScope.launch { + withContext(Dispatchers.IO) { + if (discPath.isNotEmpty()) { + startDiscUpdate(discPath) + } else { + val region: String = when (region) { + 0 -> "EUR" + 1 -> "JPN" + 2 -> "KOR" + 3 -> "USA" + else -> "" + } + startOnlineUpdate(region) + } + isRunning = false + } + } + } + + private fun startOnlineUpdate(region: String) { + canceled = false + val result = WiiUtils.doOnlineUpdate(region, constructCallback()) + resultData.postValue(result) + } + + private fun startDiscUpdate(path: String) { + canceled = false + val result = WiiUtils.doDiscUpdate(path, constructCallback()) + resultData.postValue(result) + } + + fun clear() { + progressData.value = 0 + totalData.value = 0 + titleIdData.value = 0L + resultData.value = -1 + } + + private fun constructCallback(): WiiUpdateCallback { + return WiiUpdateCallback { processed: Int, total: Int, titleId: Long -> + progressData.postValue(processed) + totalData.postValue(total) + titleIdData.postValue(titleId) + !canceled + } + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java index 2e5d9c617f..b36a9ced2b 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java @@ -319,7 +319,7 @@ public final class MainPresenter SystemUpdateProgressBarDialogFragment progressBarFragment = new SystemUpdateProgressBarDialogFragment(); progressBarFragment - .show(activity.getSupportFragmentManager(), "SystemUpdateProgressBarDialogFragment"); + .show(activity.getSupportFragmentManager(), SystemUpdateProgressBarDialogFragment.TAG); progressBarFragment.setCancelable(false); } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/WiiUtils.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/WiiUtils.java deleted file mode 100644 index 61dfedf5cd..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/WiiUtils.java +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -package org.dolphinemu.dolphinemu.utils; - -public final class WiiUtils -{ - public static final int RESULT_SUCCESS = 0; - public static final int RESULT_ERROR = 1; - public static final int RESULT_CANCELLED = 2; - public static final int RESULT_CORRUPTED_SOURCE = 3; - public static final int RESULT_TITLE_MISSING = 4; - - public static final int UPDATE_RESULT_SUCCESS = 0; - public static final int UPDATE_RESULT_ALREADY_UP_TO_DATE = 1; - public static final int UPDATE_RESULT_REGION_MISMATCH = 2; - public static final int UPDATE_RESULT_MISSING_UPDATE_PARTITION = 3; - public static final int UPDATE_RESULT_DISC_READ_FAILED = 4; - public static final int UPDATE_RESULT_SERVER_FAILED = 5; - public static final int UPDATE_RESULT_DOWNLOAD_FAILED = 6; - public static final int UPDATE_RESULT_IMPORT_FAILED = 7; - public static final int UPDATE_RESULT_CANCELLED = 8; - - public static native boolean installWAD(String file); - - public static native int importWiiSave(String file, BooleanSupplier canOverwrite); - - public static native void importNANDBin(String file); - - public static native int doOnlineUpdate(String region, WiiUpdateCallback callback); - - public static native int doDiscUpdate(String path, WiiUpdateCallback callback); - - public static native boolean isSystemMenuInstalled(); - - public static native boolean isSystemMenuvWii(); - - public static native String getSystemMenuVersion(); - - public static native boolean syncSdFolderToSdImage(); - - public static native boolean syncSdImageToSdFolder(); -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/WiiUtils.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/WiiUtils.kt new file mode 100644 index 0000000000..b41ab24816 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/WiiUtils.kt @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.utils + +object WiiUtils { + const val RESULT_SUCCESS = 0 + const val RESULT_ERROR = 1 + const val RESULT_CANCELLED = 2 + const val RESULT_CORRUPTED_SOURCE = 3 + const val RESULT_TITLE_MISSING = 4 + const val UPDATE_RESULT_SUCCESS = 0 + const val UPDATE_RESULT_ALREADY_UP_TO_DATE = 1 + const val UPDATE_RESULT_REGION_MISMATCH = 2 + const val UPDATE_RESULT_MISSING_UPDATE_PARTITION = 3 + const val UPDATE_RESULT_DISC_READ_FAILED = 4 + const val UPDATE_RESULT_SERVER_FAILED = 5 + const val UPDATE_RESULT_DOWNLOAD_FAILED = 6 + const val UPDATE_RESULT_IMPORT_FAILED = 7 + const val UPDATE_RESULT_CANCELLED = 8 + + @JvmStatic + external fun installWAD(file: String): Boolean + + @JvmStatic + external fun importWiiSave(file: String, canOverwrite: BooleanSupplier): Int + + @JvmStatic + external fun importNANDBin(file: String) + external fun doOnlineUpdate(region: String, callback: WiiUpdateCallback): Int + external fun doDiscUpdate(path: String, callback: WiiUpdateCallback): Int + + @JvmStatic + external fun isSystemMenuInstalled(): Boolean + + @JvmStatic + external fun isSystemMenuvWii(): Boolean + + @JvmStatic + external fun getSystemMenuVersion(): String + + @JvmStatic + external fun syncSdFolderToSdImage(): Boolean + + @JvmStatic + external fun syncSdImageToSdFolder(): Boolean +}