mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-08 21:53:31 +01:00
Merge pull request #11921 from t895/kotlin-fragments
Android: Convert "fragments" package to Kotlin
This commit is contained in:
commit
bcd6e2e6dc
@ -1,90 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
package org.dolphinemu.dolphinemu.fragments;
|
|
||||||
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.core.content.FileProvider;
|
|
||||||
|
|
||||||
import com.nononsenseapps.filepicker.FilePickerFragment;
|
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.R;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.HashSet;
|
|
||||||
|
|
||||||
public class CustomFilePickerFragment extends FilePickerFragment
|
|
||||||
{
|
|
||||||
public static final String KEY_EXTENSIONS = "KEY_EXTENSIONS";
|
|
||||||
|
|
||||||
private HashSet<String> mExtensions;
|
|
||||||
|
|
||||||
public void setExtensions(HashSet<String> extensions)
|
|
||||||
{
|
|
||||||
Bundle b = getArguments();
|
|
||||||
if (b == null)
|
|
||||||
b = new Bundle();
|
|
||||||
|
|
||||||
b.putSerializable(KEY_EXTENSIONS, extensions);
|
|
||||||
setArguments(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Uri toUri(@NonNull final File file)
|
|
||||||
{
|
|
||||||
return FileProvider
|
|
||||||
.getUriForFile(getContext(),
|
|
||||||
getContext().getApplicationContext().getPackageName() + ".filesprovider",
|
|
||||||
file);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void onActivityCreated(Bundle savedInstanceState)
|
|
||||||
{
|
|
||||||
super.onActivityCreated(savedInstanceState);
|
|
||||||
|
|
||||||
mExtensions = (HashSet<String>) getArguments().getSerializable(KEY_EXTENSIONS);
|
|
||||||
|
|
||||||
if (mode == MODE_DIR)
|
|
||||||
{
|
|
||||||
TextView ok = getActivity().findViewById(R.id.nnf_button_ok);
|
|
||||||
ok.setText(R.string.select_dir);
|
|
||||||
|
|
||||||
TextView cancel = getActivity().findViewById(R.id.nnf_button_cancel);
|
|
||||||
cancel.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean isItemVisible(@NonNull final File file)
|
|
||||||
{
|
|
||||||
// Some users jump to the conclusion that Dolphin isn't able to detect their
|
|
||||||
// files if the files don't show up in the file picker when mode == MODE_DIR.
|
|
||||||
// To avoid this, show files even when the user needs to select a directory.
|
|
||||||
|
|
||||||
return (showHiddenItems || !file.isHidden()) &&
|
|
||||||
(file.isDirectory() ||
|
|
||||||
mExtensions.contains(fileExtension(file.getName()).toLowerCase()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCheckable(@NonNull final File file)
|
|
||||||
{
|
|
||||||
// We need to make a small correction to the isCheckable logic due to
|
|
||||||
// overriding isItemVisible to show files when mode == MODE_DIR.
|
|
||||||
// AbstractFilePickerFragment always treats files as checkable when
|
|
||||||
// allowExistingFile == true, but we don't want files to be checkable when mode == MODE_DIR.
|
|
||||||
|
|
||||||
return super.isCheckable(file) && !(mode == MODE_DIR && file.isFile());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String fileExtension(@NonNull String filename)
|
|
||||||
{
|
|
||||||
int i = filename.lastIndexOf('.');
|
|
||||||
return i < 0 ? "" : filename.substring(i + 1);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,73 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
package org.dolphinemu.dolphinemu.fragments
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.core.content.FileProvider
|
||||||
|
import com.nononsenseapps.filepicker.FilePickerFragment
|
||||||
|
import org.dolphinemu.dolphinemu.R
|
||||||
|
import org.dolphinemu.dolphinemu.utils.SerializableHelper.serializable
|
||||||
|
import java.io.File
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
class CustomFilePickerFragment : FilePickerFragment() {
|
||||||
|
private var extensions: HashSet<String>? = null
|
||||||
|
|
||||||
|
fun setExtensions(extensions: HashSet<String>?) {
|
||||||
|
var b = arguments
|
||||||
|
if (b == null)
|
||||||
|
b = Bundle()
|
||||||
|
b.putSerializable(KEY_EXTENSIONS, extensions)
|
||||||
|
arguments = b
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toUri(file: File): Uri {
|
||||||
|
return FileProvider.getUriForFile(
|
||||||
|
requireContext(),
|
||||||
|
"${requireContext().applicationContext.packageName}.filesprovider",
|
||||||
|
file
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
extensions = requireArguments().serializable(KEY_EXTENSIONS) as HashSet<String>?
|
||||||
|
|
||||||
|
if (mode == MODE_DIR) {
|
||||||
|
val ok = requireActivity().findViewById<TextView>(R.id.nnf_button_ok)
|
||||||
|
ok.setText(R.string.select_dir)
|
||||||
|
|
||||||
|
val cancel = requireActivity().findViewById<TextView>(R.id.nnf_button_cancel)
|
||||||
|
cancel.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isItemVisible(file: File): Boolean {
|
||||||
|
// Some users jump to the conclusion that Dolphin isn't able to detect their
|
||||||
|
// files if the files don't show up in the file picker when mode == MODE_DIR.
|
||||||
|
// To avoid this, show files even when the user needs to select a directory.
|
||||||
|
return (showHiddenItems || !file.isHidden) &&
|
||||||
|
(file.isDirectory || extensions!!.contains(fileExtension(file.name).lowercase(Locale.getDefault())))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isCheckable(file: File): Boolean {
|
||||||
|
// We need to make a small correction to the isCheckable logic due to
|
||||||
|
// overriding isItemVisible to show files when mode == MODE_DIR.
|
||||||
|
// AbstractFilePickerFragment always treats files as checkable when
|
||||||
|
// allowExistingFile == true, but we don't want files to be checkable when mode == MODE_DIR.
|
||||||
|
return super.isCheckable(file) && !(mode == MODE_DIR && file.isFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val KEY_EXTENSIONS = "KEY_EXTENSIONS"
|
||||||
|
|
||||||
|
private fun fileExtension(filename: String): String {
|
||||||
|
val i = filename.lastIndexOf('.')
|
||||||
|
return if (i < 0) "" else filename.substring(i + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,355 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
package org.dolphinemu.dolphinemu.fragments;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.SurfaceHolder;
|
|
||||||
import android.view.SurfaceView;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.Button;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
|
||||||
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
|
||||||
import org.dolphinemu.dolphinemu.databinding.FragmentEmulationBinding;
|
|
||||||
import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting;
|
|
||||||
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
|
|
||||||
import org.dolphinemu.dolphinemu.overlay.InputOverlay;
|
|
||||||
import org.dolphinemu.dolphinemu.utils.Log;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback
|
|
||||||
{
|
|
||||||
private static final String KEY_GAMEPATHS = "gamepaths";
|
|
||||||
private static final String KEY_RIIVOLUTION = "riivolution";
|
|
||||||
private static final String KEY_SYSTEM_MENU = "systemMenu";
|
|
||||||
|
|
||||||
private InputOverlay mInputOverlay;
|
|
||||||
|
|
||||||
private String[] mGamePaths;
|
|
||||||
private boolean mRiivolution;
|
|
||||||
private boolean mRunWhenSurfaceIsValid;
|
|
||||||
private boolean mLoadPreviousTemporaryState;
|
|
||||||
private boolean mLaunchSystemMenu;
|
|
||||||
|
|
||||||
private EmulationActivity activity;
|
|
||||||
|
|
||||||
private FragmentEmulationBinding mBinding;
|
|
||||||
|
|
||||||
public static EmulationFragment newInstance(String[] gamePaths, boolean riivolution,
|
|
||||||
boolean systemMenu)
|
|
||||||
{
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putStringArray(KEY_GAMEPATHS, gamePaths);
|
|
||||||
args.putBoolean(KEY_RIIVOLUTION, riivolution);
|
|
||||||
args.putBoolean(KEY_SYSTEM_MENU, systemMenu);
|
|
||||||
|
|
||||||
EmulationFragment fragment = new EmulationFragment();
|
|
||||||
fragment.setArguments(args);
|
|
||||||
return fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAttach(@NonNull Context context)
|
|
||||||
{
|
|
||||||
super.onAttach(context);
|
|
||||||
|
|
||||||
if (context instanceof EmulationActivity)
|
|
||||||
{
|
|
||||||
activity = (EmulationActivity) context;
|
|
||||||
NativeLibrary.setEmulationActivity((EmulationActivity) context);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new IllegalStateException("EmulationFragment must have EmulationActivity parent");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize anything that doesn't depend on the layout / views in here.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState)
|
|
||||||
{
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
mGamePaths = getArguments().getStringArray(KEY_GAMEPATHS);
|
|
||||||
mRiivolution = getArguments().getBoolean(KEY_RIIVOLUTION);
|
|
||||||
mLaunchSystemMenu = getArguments().getBoolean(KEY_SYSTEM_MENU);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
|
||||||
Bundle savedInstanceState)
|
|
||||||
{
|
|
||||||
mBinding = FragmentEmulationBinding.inflate(inflater, container, false);
|
|
||||||
return mBinding.getRoot();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
|
|
||||||
{
|
|
||||||
// The new Surface created here will get passed to the native code via onSurfaceChanged.
|
|
||||||
SurfaceView surfaceView = mBinding.surfaceEmulation;
|
|
||||||
surfaceView.getHolder().addCallback(this);
|
|
||||||
|
|
||||||
mInputOverlay = mBinding.surfaceInputOverlay;
|
|
||||||
|
|
||||||
Button doneButton = mBinding.doneControlConfig;
|
|
||||||
if (doneButton != null)
|
|
||||||
{
|
|
||||||
doneButton.setOnClickListener(v -> stopConfiguringControls());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mInputOverlay != null)
|
|
||||||
{
|
|
||||||
view.post(() ->
|
|
||||||
{
|
|
||||||
int overlayX = mInputOverlay.getLeft();
|
|
||||||
int overlayY = mInputOverlay.getTop();
|
|
||||||
mInputOverlay.setSurfacePosition(new Rect(
|
|
||||||
surfaceView.getLeft() - overlayX, surfaceView.getTop() - overlayY,
|
|
||||||
surfaceView.getRight() - overlayX, surfaceView.getBottom() - overlayY));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroyView()
|
|
||||||
{
|
|
||||||
super.onDestroyView();
|
|
||||||
mBinding = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume()
|
|
||||||
{
|
|
||||||
super.onResume();
|
|
||||||
|
|
||||||
if (mInputOverlay != null && NativeLibrary.IsGameMetadataValid())
|
|
||||||
mInputOverlay.refreshControls();
|
|
||||||
|
|
||||||
run(activity.isActivityRecreated());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPause()
|
|
||||||
{
|
|
||||||
if (NativeLibrary.IsRunningAndUnpaused() && !NativeLibrary.IsShowingAlertMessage())
|
|
||||||
{
|
|
||||||
Log.debug("[EmulationFragment] Pausing emulation.");
|
|
||||||
NativeLibrary.PauseEmulation();
|
|
||||||
}
|
|
||||||
|
|
||||||
super.onPause();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy()
|
|
||||||
{
|
|
||||||
if (mInputOverlay != null)
|
|
||||||
mInputOverlay.onDestroy();
|
|
||||||
|
|
||||||
super.onDestroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDetach()
|
|
||||||
{
|
|
||||||
NativeLibrary.clearEmulationActivity();
|
|
||||||
super.onDetach();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void toggleInputOverlayVisibility(Settings settings)
|
|
||||||
{
|
|
||||||
BooleanSetting.MAIN_SHOW_INPUT_OVERLAY
|
|
||||||
.setBoolean(settings, !BooleanSetting.MAIN_SHOW_INPUT_OVERLAY.getBoolean());
|
|
||||||
|
|
||||||
if (mInputOverlay != null)
|
|
||||||
mInputOverlay.refreshControls();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void initInputPointer()
|
|
||||||
{
|
|
||||||
if (mInputOverlay != null)
|
|
||||||
mInputOverlay.initTouchPointer();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void refreshInputOverlay()
|
|
||||||
{
|
|
||||||
if (mInputOverlay != null)
|
|
||||||
mInputOverlay.refreshControls();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void refreshOverlayPointer()
|
|
||||||
{
|
|
||||||
if (mInputOverlay != null)
|
|
||||||
mInputOverlay.refreshOverlayPointer();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void resetInputOverlay()
|
|
||||||
{
|
|
||||||
if (mInputOverlay != null)
|
|
||||||
mInputOverlay.resetButtonPlacement();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void surfaceCreated(@NonNull SurfaceHolder holder)
|
|
||||||
{
|
|
||||||
// We purposely don't do anything here.
|
|
||||||
// All work is done in surfaceChanged, which we are guaranteed to get even for surface creation.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
|
|
||||||
{
|
|
||||||
Log.debug("[EmulationFragment] Surface changed. Resolution: " + width + "x" + height);
|
|
||||||
NativeLibrary.SurfaceChanged(holder.getSurface());
|
|
||||||
if (mRunWhenSurfaceIsValid)
|
|
||||||
{
|
|
||||||
runWithValidSurface();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void surfaceDestroyed(@NonNull SurfaceHolder holder)
|
|
||||||
{
|
|
||||||
Log.debug("[EmulationFragment] Surface destroyed.");
|
|
||||||
NativeLibrary.SurfaceDestroyed();
|
|
||||||
mRunWhenSurfaceIsValid = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stopEmulation()
|
|
||||||
{
|
|
||||||
Log.debug("[EmulationFragment] Stopping emulation.");
|
|
||||||
NativeLibrary.StopEmulation();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startConfiguringControls()
|
|
||||||
{
|
|
||||||
if (mInputOverlay != null)
|
|
||||||
{
|
|
||||||
mBinding.doneControlConfig.setVisibility(View.VISIBLE);
|
|
||||||
mInputOverlay.setEditMode(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stopConfiguringControls()
|
|
||||||
{
|
|
||||||
if (mInputOverlay != null)
|
|
||||||
{
|
|
||||||
mBinding.doneControlConfig.setVisibility(View.GONE);
|
|
||||||
mInputOverlay.setEditMode(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isConfiguringControls()
|
|
||||||
{
|
|
||||||
return mInputOverlay != null && mInputOverlay.isInEditMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void run(boolean isActivityRecreated)
|
|
||||||
{
|
|
||||||
if (isActivityRecreated)
|
|
||||||
{
|
|
||||||
if (NativeLibrary.IsRunning())
|
|
||||||
{
|
|
||||||
mLoadPreviousTemporaryState = false;
|
|
||||||
deleteFile(getTemporaryStateFilePath());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mLoadPreviousTemporaryState = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log.debug("[EmulationFragment] activity resumed or fresh start");
|
|
||||||
mLoadPreviousTemporaryState = false;
|
|
||||||
// activity resumed without being killed or this is the first run
|
|
||||||
deleteFile(getTemporaryStateFilePath());
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the surface is set, run now. Otherwise, wait for it to get set.
|
|
||||||
if (NativeLibrary.HasSurface())
|
|
||||||
{
|
|
||||||
runWithValidSurface();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mRunWhenSurfaceIsValid = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void runWithValidSurface()
|
|
||||||
{
|
|
||||||
mRunWhenSurfaceIsValid = false;
|
|
||||||
if (!NativeLibrary.IsRunning())
|
|
||||||
{
|
|
||||||
NativeLibrary.SetIsBooting();
|
|
||||||
|
|
||||||
Thread emulationThread = new Thread(() ->
|
|
||||||
{
|
|
||||||
if (mLoadPreviousTemporaryState)
|
|
||||||
{
|
|
||||||
Log.debug("[EmulationFragment] Starting emulation thread from previous state.");
|
|
||||||
NativeLibrary.Run(mGamePaths, mRiivolution, getTemporaryStateFilePath(), true);
|
|
||||||
}
|
|
||||||
if (mLaunchSystemMenu)
|
|
||||||
{
|
|
||||||
Log.debug("[EmulationFragment] Starting emulation thread for the Wii Menu.");
|
|
||||||
NativeLibrary.RunSystemMenu();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log.debug("[EmulationFragment] Starting emulation thread.");
|
|
||||||
NativeLibrary.Run(mGamePaths, mRiivolution);
|
|
||||||
}
|
|
||||||
EmulationActivity.stopIgnoringLaunchRequests();
|
|
||||||
}, "NativeEmulation");
|
|
||||||
emulationThread.start();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!EmulationActivity.Companion.getHasUserPausedEmulation() &&
|
|
||||||
!NativeLibrary.IsShowingAlertMessage())
|
|
||||||
{
|
|
||||||
Log.debug("[EmulationFragment] Resuming emulation.");
|
|
||||||
NativeLibrary.UnPauseEmulation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void saveTemporaryState()
|
|
||||||
{
|
|
||||||
NativeLibrary.SaveStateAs(getTemporaryStateFilePath(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getTemporaryStateFilePath()
|
|
||||||
{
|
|
||||||
return getContext().getFilesDir() + File.separator + "temp.sav";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void deleteFile(String path)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
File file = new File(path);
|
|
||||||
if (!file.delete())
|
|
||||||
{
|
|
||||||
Log.error("[EmulationFragment] Failed to delete " + file.getAbsolutePath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ignored)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,264 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
package org.dolphinemu.dolphinemu.fragments
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Rect
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.SurfaceHolder
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import org.dolphinemu.dolphinemu.NativeLibrary
|
||||||
|
import org.dolphinemu.dolphinemu.activities.EmulationActivity
|
||||||
|
import org.dolphinemu.dolphinemu.databinding.FragmentEmulationBinding
|
||||||
|
import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting
|
||||||
|
import org.dolphinemu.dolphinemu.features.settings.model.Settings
|
||||||
|
import org.dolphinemu.dolphinemu.overlay.InputOverlay
|
||||||
|
import org.dolphinemu.dolphinemu.utils.Log
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
|
private var inputOverlay: InputOverlay? = null
|
||||||
|
|
||||||
|
private var gamePaths: Array<String>? = null
|
||||||
|
private var riivolution = false
|
||||||
|
private var runWhenSurfaceIsValid = false
|
||||||
|
private var loadPreviousTemporaryState = false
|
||||||
|
private var launchSystemMenu = false
|
||||||
|
|
||||||
|
private var emulationActivity: EmulationActivity? = null
|
||||||
|
|
||||||
|
private var _binding: FragmentEmulationBinding? = null
|
||||||
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
override fun onAttach(context: Context) {
|
||||||
|
super.onAttach(context)
|
||||||
|
if (context is EmulationActivity) {
|
||||||
|
emulationActivity = context
|
||||||
|
NativeLibrary.setEmulationActivity(context)
|
||||||
|
} else {
|
||||||
|
throw IllegalStateException("EmulationFragment must have EmulationActivity parent")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize anything that doesn't depend on the layout / views in here.
|
||||||
|
*/
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
requireArguments().apply {
|
||||||
|
gamePaths = getStringArray(KEY_GAMEPATHS)
|
||||||
|
riivolution = getBoolean(KEY_RIIVOLUTION)
|
||||||
|
launchSystemMenu = getBoolean(KEY_SYSTEM_MENU)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
_binding = FragmentEmulationBinding.inflate(inflater, container, false)
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
// The new Surface created here will get passed to the native code via onSurfaceChanged.
|
||||||
|
val surfaceView = binding.surfaceEmulation
|
||||||
|
surfaceView.holder.addCallback(this)
|
||||||
|
|
||||||
|
inputOverlay = binding.surfaceInputOverlay
|
||||||
|
|
||||||
|
val doneButton = binding.doneControlConfig
|
||||||
|
doneButton?.setOnClickListener { stopConfiguringControls() }
|
||||||
|
|
||||||
|
if (inputOverlay != null) {
|
||||||
|
view.post {
|
||||||
|
val overlayX = inputOverlay!!.left
|
||||||
|
val overlayY = inputOverlay!!.top
|
||||||
|
inputOverlay?.setSurfacePosition(
|
||||||
|
Rect(
|
||||||
|
surfaceView.left - overlayX,
|
||||||
|
surfaceView.top - overlayY,
|
||||||
|
surfaceView.right - overlayX,
|
||||||
|
surfaceView.bottom - overlayY
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
super.onDestroyView()
|
||||||
|
_binding = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
if (NativeLibrary.IsGameMetadataValid())
|
||||||
|
inputOverlay?.refreshControls()
|
||||||
|
|
||||||
|
run(emulationActivity!!.isActivityRecreated)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
if (NativeLibrary.IsRunningAndUnpaused() && !NativeLibrary.IsShowingAlertMessage()) {
|
||||||
|
Log.debug("[EmulationFragment] Pausing emulation.")
|
||||||
|
NativeLibrary.PauseEmulation()
|
||||||
|
}
|
||||||
|
super.onPause()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
inputOverlay?.onDestroy()
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDetach() {
|
||||||
|
NativeLibrary.clearEmulationActivity()
|
||||||
|
super.onDetach()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toggleInputOverlayVisibility(settings: Settings?) {
|
||||||
|
BooleanSetting.MAIN_SHOW_INPUT_OVERLAY.setBoolean(
|
||||||
|
settings!!,
|
||||||
|
!BooleanSetting.MAIN_SHOW_INPUT_OVERLAY.boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
inputOverlay?.refreshControls()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun initInputPointer() = inputOverlay?.initTouchPointer()
|
||||||
|
|
||||||
|
fun refreshInputOverlay() = inputOverlay?.refreshControls()
|
||||||
|
|
||||||
|
fun refreshOverlayPointer() = inputOverlay?.refreshOverlayPointer()
|
||||||
|
|
||||||
|
fun resetInputOverlay() = inputOverlay?.resetButtonPlacement()
|
||||||
|
|
||||||
|
override fun surfaceCreated(holder: SurfaceHolder) {
|
||||||
|
// We purposely don't do anything here.
|
||||||
|
// All work is done in surfaceChanged, which we are guaranteed to get even for surface creation.
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
|
||||||
|
Log.debug("[EmulationFragment] Surface changed. Resolution: $width x $height")
|
||||||
|
NativeLibrary.SurfaceChanged(holder.surface)
|
||||||
|
if (runWhenSurfaceIsValid) {
|
||||||
|
runWithValidSurface()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun surfaceDestroyed(holder: SurfaceHolder) {
|
||||||
|
Log.debug("[EmulationFragment] Surface destroyed.")
|
||||||
|
NativeLibrary.SurfaceDestroyed()
|
||||||
|
runWhenSurfaceIsValid = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stopEmulation() {
|
||||||
|
Log.debug("[EmulationFragment] Stopping emulation.")
|
||||||
|
NativeLibrary.StopEmulation()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startConfiguringControls() {
|
||||||
|
binding.doneControlConfig?.visibility = View.VISIBLE
|
||||||
|
inputOverlay?.editMode = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stopConfiguringControls() {
|
||||||
|
binding.doneControlConfig?.visibility = View.GONE
|
||||||
|
inputOverlay?.editMode = false
|
||||||
|
}
|
||||||
|
|
||||||
|
val isConfiguringControls: Boolean
|
||||||
|
get() = inputOverlay != null && inputOverlay!!.isInEditMode
|
||||||
|
|
||||||
|
private fun run(isActivityRecreated: Boolean) {
|
||||||
|
if (isActivityRecreated) {
|
||||||
|
if (NativeLibrary.IsRunning()) {
|
||||||
|
loadPreviousTemporaryState = false
|
||||||
|
deleteFile(temporaryStateFilePath)
|
||||||
|
} else {
|
||||||
|
loadPreviousTemporaryState = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.debug("[EmulationFragment] activity resumed or fresh start")
|
||||||
|
loadPreviousTemporaryState = false
|
||||||
|
// activity resumed without being killed or this is the first run
|
||||||
|
deleteFile(temporaryStateFilePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the surface is set, run now. Otherwise, wait for it to get set.
|
||||||
|
if (NativeLibrary.HasSurface()) {
|
||||||
|
runWithValidSurface()
|
||||||
|
} else {
|
||||||
|
runWhenSurfaceIsValid = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun runWithValidSurface() {
|
||||||
|
runWhenSurfaceIsValid = false
|
||||||
|
if (!NativeLibrary.IsRunning()) {
|
||||||
|
NativeLibrary.SetIsBooting()
|
||||||
|
val emulationThread = Thread({
|
||||||
|
if (loadPreviousTemporaryState) {
|
||||||
|
Log.debug("[EmulationFragment] Starting emulation thread from previous state.")
|
||||||
|
NativeLibrary.Run(gamePaths, riivolution, temporaryStateFilePath, true)
|
||||||
|
}
|
||||||
|
if (launchSystemMenu) {
|
||||||
|
Log.debug("[EmulationFragment] Starting emulation thread for the Wii Menu.")
|
||||||
|
NativeLibrary.RunSystemMenu()
|
||||||
|
} else {
|
||||||
|
Log.debug("[EmulationFragment] Starting emulation thread.")
|
||||||
|
NativeLibrary.Run(gamePaths, riivolution)
|
||||||
|
}
|
||||||
|
EmulationActivity.stopIgnoringLaunchRequests()
|
||||||
|
}, "NativeEmulation")
|
||||||
|
emulationThread.start()
|
||||||
|
} else {
|
||||||
|
if (!EmulationActivity.hasUserPausedEmulation && !NativeLibrary.IsShowingAlertMessage()) {
|
||||||
|
Log.debug("[EmulationFragment] Resuming emulation.")
|
||||||
|
NativeLibrary.UnPauseEmulation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveTemporaryState() = NativeLibrary.SaveStateAs(temporaryStateFilePath, true)
|
||||||
|
|
||||||
|
private val temporaryStateFilePath: String
|
||||||
|
get() = "${requireContext().filesDir}${File.separator}temp.sav"
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val KEY_GAMEPATHS = "gamepaths"
|
||||||
|
private const val KEY_RIIVOLUTION = "riivolution"
|
||||||
|
private const val KEY_SYSTEM_MENU = "systemMenu"
|
||||||
|
|
||||||
|
fun newInstance(
|
||||||
|
gamePaths: Array<String>?,
|
||||||
|
riivolution: Boolean,
|
||||||
|
systemMenu: Boolean
|
||||||
|
): EmulationFragment {
|
||||||
|
val args = Bundle()
|
||||||
|
args.apply {
|
||||||
|
putStringArray(KEY_GAMEPATHS, gamePaths)
|
||||||
|
putBoolean(KEY_RIIVOLUTION, riivolution)
|
||||||
|
putBoolean(KEY_SYSTEM_MENU, systemMenu)
|
||||||
|
}
|
||||||
|
val fragment = EmulationFragment()
|
||||||
|
fragment.arguments = args
|
||||||
|
return fragment
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deleteFile(path: String) {
|
||||||
|
try {
|
||||||
|
val file = File(path)
|
||||||
|
if (!file.delete()) {
|
||||||
|
Log.error("[EmulationFragment] Failed to delete ${file.absolutePath}")
|
||||||
|
}
|
||||||
|
} catch (ignored: Exception) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,228 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
package org.dolphinemu.dolphinemu.fragments;
|
|
||||||
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.util.SparseIntArray;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
|
|
||||||
import androidx.annotation.ColorInt;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.core.graphics.Insets;
|
|
||||||
import androidx.core.view.ViewCompat;
|
|
||||||
import androidx.core.view.WindowInsetsCompat;
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
|
|
||||||
import com.google.android.material.color.MaterialColors;
|
|
||||||
import com.google.android.material.elevation.ElevationOverlayProvider;
|
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
|
||||||
import org.dolphinemu.dolphinemu.R;
|
|
||||||
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
|
||||||
import org.dolphinemu.dolphinemu.databinding.FragmentIngameMenuBinding;
|
|
||||||
import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting;
|
|
||||||
import org.dolphinemu.dolphinemu.features.settings.model.IntSetting;
|
|
||||||
import org.dolphinemu.dolphinemu.utils.InsetsHelper;
|
|
||||||
import org.dolphinemu.dolphinemu.utils.ThemeHelper;
|
|
||||||
|
|
||||||
public final class MenuFragment extends Fragment implements View.OnClickListener
|
|
||||||
{
|
|
||||||
private static final String KEY_TITLE = "title";
|
|
||||||
private static final String KEY_WII = "wii";
|
|
||||||
private static SparseIntArray buttonsActionsMap = new SparseIntArray();
|
|
||||||
|
|
||||||
private int mCutInset = 0;
|
|
||||||
|
|
||||||
static
|
|
||||||
{
|
|
||||||
buttonsActionsMap
|
|
||||||
.append(R.id.menu_pause_emulation, EmulationActivity.MENU_ACTION_PAUSE_EMULATION);
|
|
||||||
buttonsActionsMap
|
|
||||||
.append(R.id.menu_unpause_emulation, EmulationActivity.MENU_ACTION_UNPAUSE_EMULATION);
|
|
||||||
buttonsActionsMap
|
|
||||||
.append(R.id.menu_take_screenshot, EmulationActivity.MENU_ACTION_TAKE_SCREENSHOT);
|
|
||||||
buttonsActionsMap.append(R.id.menu_quicksave, EmulationActivity.MENU_ACTION_QUICK_SAVE);
|
|
||||||
buttonsActionsMap.append(R.id.menu_quickload, EmulationActivity.MENU_ACTION_QUICK_LOAD);
|
|
||||||
buttonsActionsMap
|
|
||||||
.append(R.id.menu_emulation_save_root, EmulationActivity.MENU_ACTION_SAVE_ROOT);
|
|
||||||
buttonsActionsMap
|
|
||||||
.append(R.id.menu_emulation_load_root, EmulationActivity.MENU_ACTION_LOAD_ROOT);
|
|
||||||
buttonsActionsMap
|
|
||||||
.append(R.id.menu_overlay_controls, EmulationActivity.MENU_ACTION_OVERLAY_CONTROLS);
|
|
||||||
buttonsActionsMap
|
|
||||||
.append(R.id.menu_refresh_wiimotes, EmulationActivity.MENU_ACTION_REFRESH_WIIMOTES);
|
|
||||||
buttonsActionsMap.append(R.id.menu_change_disc, EmulationActivity.MENU_ACTION_CHANGE_DISC);
|
|
||||||
buttonsActionsMap.append(R.id.menu_exit, EmulationActivity.MENU_ACTION_EXIT);
|
|
||||||
buttonsActionsMap.append(R.id.menu_settings, EmulationActivity.MENU_ACTION_SETTINGS);
|
|
||||||
buttonsActionsMap.append(R.id.menu_skylanders, EmulationActivity.MENU_ACTION_SKYLANDERS);
|
|
||||||
buttonsActionsMap.append(R.id.menu_infinitybase, EmulationActivity.MENU_ACTION_INFINITY_BASE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private FragmentIngameMenuBinding mBinding;
|
|
||||||
|
|
||||||
public static MenuFragment newInstance()
|
|
||||||
{
|
|
||||||
MenuFragment fragment = new MenuFragment();
|
|
||||||
|
|
||||||
Bundle arguments = new Bundle();
|
|
||||||
if (NativeLibrary.IsGameMetadataValid())
|
|
||||||
{
|
|
||||||
arguments.putString(KEY_TITLE, NativeLibrary.GetCurrentTitleDescription());
|
|
||||||
arguments.putBoolean(KEY_WII, NativeLibrary.IsEmulatingWii());
|
|
||||||
}
|
|
||||||
fragment.setArguments(arguments);
|
|
||||||
|
|
||||||
return fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
|
||||||
Bundle savedInstanceState)
|
|
||||||
{
|
|
||||||
mBinding = FragmentIngameMenuBinding.inflate(inflater, container, false);
|
|
||||||
return mBinding.getRoot();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
|
|
||||||
{
|
|
||||||
if (IntSetting.MAIN_INTERFACE_THEME.getInt() != ThemeHelper.DEFAULT)
|
|
||||||
{
|
|
||||||
@ColorInt int color = new ElevationOverlayProvider(view.getContext()).compositeOverlay(
|
|
||||||
MaterialColors.getColor(view, R.attr.colorSurface),
|
|
||||||
view.getElevation());
|
|
||||||
view.setBackgroundColor(color);
|
|
||||||
}
|
|
||||||
|
|
||||||
setInsets();
|
|
||||||
updatePauseUnpauseVisibility();
|
|
||||||
|
|
||||||
if (!requireActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN))
|
|
||||||
{
|
|
||||||
mBinding.menuOverlayControls.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!getArguments().getBoolean(KEY_WII, true))
|
|
||||||
{
|
|
||||||
mBinding.menuRefreshWiimotes.setVisibility(View.GONE);
|
|
||||||
mBinding.menuSkylanders.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!BooleanSetting.MAIN_EMULATE_SKYLANDER_PORTAL.getBoolean())
|
|
||||||
{
|
|
||||||
mBinding.menuSkylanders.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
LinearLayout options = mBinding.layoutOptions;
|
|
||||||
for (int childIndex = 0; childIndex < options.getChildCount(); childIndex++)
|
|
||||||
{
|
|
||||||
Button button = (Button) options.getChildAt(childIndex);
|
|
||||||
|
|
||||||
button.setOnClickListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
mBinding.menuExit.setOnClickListener(this);
|
|
||||||
|
|
||||||
String title = getArguments().getString(KEY_TITLE, null);
|
|
||||||
if (title != null)
|
|
||||||
{
|
|
||||||
mBinding.textGameTitle.setText(title);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setInsets()
|
|
||||||
{
|
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(mBinding.getRoot(), (v, windowInsets) ->
|
|
||||||
{
|
|
||||||
Insets cutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout());
|
|
||||||
mCutInset = cutInsets.left;
|
|
||||||
|
|
||||||
int left = 0;
|
|
||||||
int right = 0;
|
|
||||||
if (ViewCompat.getLayoutDirection(v) == ViewCompat.LAYOUT_DIRECTION_LTR)
|
|
||||||
{
|
|
||||||
left = cutInsets.left;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
right = cutInsets.right;
|
|
||||||
}
|
|
||||||
|
|
||||||
v.post(() -> NativeLibrary.SetObscuredPixelsLeft(v.getWidth()));
|
|
||||||
|
|
||||||
// Don't use padding if the navigation bar isn't in the way
|
|
||||||
if (InsetsHelper.getBottomPaddingRequired(requireActivity()) > 0)
|
|
||||||
{
|
|
||||||
v.setPadding(left, cutInsets.top, right,
|
|
||||||
cutInsets.bottom + InsetsHelper.getNavigationBarHeight(requireContext()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
v.setPadding(left, cutInsets.top, right,
|
|
||||||
cutInsets.bottom + getResources().getDimensionPixelSize(R.dimen.spacing_large));
|
|
||||||
}
|
|
||||||
return windowInsets;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume()
|
|
||||||
{
|
|
||||||
super.onResume();
|
|
||||||
|
|
||||||
boolean savestatesEnabled = BooleanSetting.MAIN_ENABLE_SAVESTATES.getBoolean();
|
|
||||||
int savestateVisibility = savestatesEnabled ? View.VISIBLE : View.GONE;
|
|
||||||
mBinding.menuQuicksave.setVisibility(savestateVisibility);
|
|
||||||
mBinding.menuQuickload.setVisibility(savestateVisibility);
|
|
||||||
mBinding.menuEmulationSaveRoot.setVisibility(savestateVisibility);
|
|
||||||
mBinding.menuEmulationLoadRoot.setVisibility(savestateVisibility);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroyView()
|
|
||||||
{
|
|
||||||
super.onDestroyView();
|
|
||||||
|
|
||||||
NativeLibrary.SetObscuredPixelsLeft(mCutInset);
|
|
||||||
mBinding = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updatePauseUnpauseVisibility()
|
|
||||||
{
|
|
||||||
boolean paused = EmulationActivity.Companion.getHasUserPausedEmulation();
|
|
||||||
|
|
||||||
mBinding.menuUnpauseEmulation.setVisibility(paused ? View.VISIBLE : View.GONE);
|
|
||||||
mBinding.menuPauseEmulation.setVisibility(paused ? View.GONE : View.VISIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick(View button)
|
|
||||||
{
|
|
||||||
int action = buttonsActionsMap.get(button.getId());
|
|
||||||
EmulationActivity activity = (EmulationActivity) requireActivity();
|
|
||||||
|
|
||||||
if (action == EmulationActivity.MENU_ACTION_OVERLAY_CONTROLS)
|
|
||||||
{
|
|
||||||
// We could use the button parameter as the anchor here, but this often results in a tiny menu
|
|
||||||
// (because the button often is in the middle of the screen), so let's use mTitleText instead
|
|
||||||
activity.showOverlayControlsMenu(mBinding.textGameTitle);
|
|
||||||
}
|
|
||||||
else if (action >= 0)
|
|
||||||
{
|
|
||||||
activity.handleMenuAction(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action == EmulationActivity.MENU_ACTION_PAUSE_EMULATION ||
|
|
||||||
action == EmulationActivity.MENU_ACTION_UNPAUSE_EMULATION)
|
|
||||||
{
|
|
||||||
updatePauseUnpauseVisibility();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,210 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
package org.dolphinemu.dolphinemu.fragments
|
||||||
|
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.SparseIntArray
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.Button
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import com.google.android.material.color.MaterialColors
|
||||||
|
import com.google.android.material.elevation.ElevationOverlayProvider
|
||||||
|
import org.dolphinemu.dolphinemu.NativeLibrary
|
||||||
|
import org.dolphinemu.dolphinemu.R
|
||||||
|
import org.dolphinemu.dolphinemu.activities.EmulationActivity
|
||||||
|
import org.dolphinemu.dolphinemu.databinding.FragmentIngameMenuBinding
|
||||||
|
import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting
|
||||||
|
import org.dolphinemu.dolphinemu.features.settings.model.IntSetting
|
||||||
|
import org.dolphinemu.dolphinemu.utils.InsetsHelper
|
||||||
|
import org.dolphinemu.dolphinemu.utils.ThemeHelper
|
||||||
|
|
||||||
|
class MenuFragment : Fragment(), View.OnClickListener {
|
||||||
|
private var cutInset = 0
|
||||||
|
|
||||||
|
private var _binding: FragmentIngameMenuBinding? = null
|
||||||
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
_binding = FragmentIngameMenuBinding.inflate(inflater, container, false)
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
if (IntSetting.MAIN_INTERFACE_THEME.int != ThemeHelper.DEFAULT) {
|
||||||
|
@ColorInt val color = ElevationOverlayProvider(view.context).compositeOverlay(
|
||||||
|
MaterialColors.getColor(view, R.attr.colorSurface),
|
||||||
|
view.elevation
|
||||||
|
)
|
||||||
|
view.setBackgroundColor(color)
|
||||||
|
}
|
||||||
|
|
||||||
|
setInsets()
|
||||||
|
updatePauseUnpauseVisibility()
|
||||||
|
|
||||||
|
if (!requireActivity().packageManager.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) {
|
||||||
|
binding.menuOverlayControls.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!requireArguments().getBoolean(KEY_WII, true)) {
|
||||||
|
binding.menuRefreshWiimotes.visibility = View.GONE
|
||||||
|
binding.menuSkylanders.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!BooleanSetting.MAIN_EMULATE_SKYLANDER_PORTAL.boolean) {
|
||||||
|
binding.menuSkylanders.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
val options = binding.layoutOptions
|
||||||
|
for (childIndex in 0 until options.childCount) {
|
||||||
|
val button = options.getChildAt(childIndex) as Button
|
||||||
|
button.setOnClickListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.menuExit.setOnClickListener(this)
|
||||||
|
|
||||||
|
val title = requireArguments().getString(KEY_TITLE, null)
|
||||||
|
if (title != null) {
|
||||||
|
binding.textGameTitle.text = title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setInsets() =
|
||||||
|
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v: View, windowInsets: WindowInsetsCompat ->
|
||||||
|
val cutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
|
||||||
|
cutInset = cutInsets.left
|
||||||
|
var left = 0
|
||||||
|
var right = 0
|
||||||
|
if (ViewCompat.getLayoutDirection(v) == ViewCompat.LAYOUT_DIRECTION_LTR) {
|
||||||
|
left = cutInsets.left
|
||||||
|
} else {
|
||||||
|
right = cutInsets.right
|
||||||
|
}
|
||||||
|
v.post { NativeLibrary.SetObscuredPixelsLeft(v.width) }
|
||||||
|
|
||||||
|
// Don't use padding if the navigation bar isn't in the way
|
||||||
|
if (InsetsHelper.getBottomPaddingRequired(requireActivity()) > 0) {
|
||||||
|
v.setPadding(
|
||||||
|
left, cutInsets.top, right,
|
||||||
|
cutInsets.bottom + InsetsHelper.getNavigationBarHeight(requireContext())
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
v.setPadding(
|
||||||
|
left, cutInsets.top, right,
|
||||||
|
cutInsets.bottom + resources.getDimensionPixelSize(R.dimen.spacing_large)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
windowInsets
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
val savestatesEnabled = BooleanSetting.MAIN_ENABLE_SAVESTATES.boolean
|
||||||
|
val savestateVisibility = if (savestatesEnabled) View.VISIBLE else View.GONE
|
||||||
|
binding.menuQuicksave.visibility = savestateVisibility
|
||||||
|
binding.menuQuickload.visibility = savestateVisibility
|
||||||
|
binding.menuEmulationSaveRoot.visibility = savestateVisibility
|
||||||
|
binding.menuEmulationLoadRoot.visibility = savestateVisibility
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
super.onDestroyView()
|
||||||
|
NativeLibrary.SetObscuredPixelsLeft(cutInset)
|
||||||
|
_binding = null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updatePauseUnpauseVisibility() {
|
||||||
|
val paused = EmulationActivity.hasUserPausedEmulation
|
||||||
|
binding.menuUnpauseEmulation.visibility = if (paused) View.VISIBLE else View.GONE
|
||||||
|
binding.menuPauseEmulation.visibility = if (paused) View.GONE else View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(button: View) {
|
||||||
|
val action = buttonsActionsMap[button.id]
|
||||||
|
val activity = requireActivity() as EmulationActivity
|
||||||
|
|
||||||
|
if (action == EmulationActivity.MENU_ACTION_OVERLAY_CONTROLS) {
|
||||||
|
// We could use the button parameter as the anchor here, but this often results in a tiny menu
|
||||||
|
// (because the button often is in the middle of the screen), so let's use mTitleText instead
|
||||||
|
activity.showOverlayControlsMenu(binding.textGameTitle)
|
||||||
|
} else if (action >= 0) {
|
||||||
|
activity.handleMenuAction(action)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == EmulationActivity.MENU_ACTION_PAUSE_EMULATION ||
|
||||||
|
action == EmulationActivity.MENU_ACTION_UNPAUSE_EMULATION
|
||||||
|
) {
|
||||||
|
updatePauseUnpauseVisibility()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val KEY_TITLE = "title"
|
||||||
|
private const val KEY_WII = "wii"
|
||||||
|
private val buttonsActionsMap = SparseIntArray()
|
||||||
|
|
||||||
|
init {
|
||||||
|
buttonsActionsMap.append(
|
||||||
|
R.id.menu_pause_emulation,
|
||||||
|
EmulationActivity.MENU_ACTION_PAUSE_EMULATION
|
||||||
|
)
|
||||||
|
buttonsActionsMap.append(
|
||||||
|
R.id.menu_unpause_emulation,
|
||||||
|
EmulationActivity.MENU_ACTION_UNPAUSE_EMULATION
|
||||||
|
)
|
||||||
|
buttonsActionsMap.append(
|
||||||
|
R.id.menu_take_screenshot,
|
||||||
|
EmulationActivity.MENU_ACTION_TAKE_SCREENSHOT
|
||||||
|
)
|
||||||
|
buttonsActionsMap.append(R.id.menu_quicksave, EmulationActivity.MENU_ACTION_QUICK_SAVE)
|
||||||
|
buttonsActionsMap.append(R.id.menu_quickload, EmulationActivity.MENU_ACTION_QUICK_LOAD)
|
||||||
|
buttonsActionsMap.append(
|
||||||
|
R.id.menu_emulation_save_root,
|
||||||
|
EmulationActivity.MENU_ACTION_SAVE_ROOT
|
||||||
|
)
|
||||||
|
buttonsActionsMap.append(
|
||||||
|
R.id.menu_emulation_load_root,
|
||||||
|
EmulationActivity.MENU_ACTION_LOAD_ROOT
|
||||||
|
)
|
||||||
|
buttonsActionsMap.append(
|
||||||
|
R.id.menu_overlay_controls,
|
||||||
|
EmulationActivity.MENU_ACTION_OVERLAY_CONTROLS
|
||||||
|
)
|
||||||
|
buttonsActionsMap.append(
|
||||||
|
R.id.menu_refresh_wiimotes,
|
||||||
|
EmulationActivity.MENU_ACTION_REFRESH_WIIMOTES
|
||||||
|
)
|
||||||
|
buttonsActionsMap.append(
|
||||||
|
R.id.menu_change_disc,
|
||||||
|
EmulationActivity.MENU_ACTION_CHANGE_DISC
|
||||||
|
)
|
||||||
|
buttonsActionsMap.append(R.id.menu_exit, EmulationActivity.MENU_ACTION_EXIT)
|
||||||
|
buttonsActionsMap.append(R.id.menu_settings, EmulationActivity.MENU_ACTION_SETTINGS)
|
||||||
|
buttonsActionsMap.append(R.id.menu_skylanders, EmulationActivity.MENU_ACTION_SKYLANDERS)
|
||||||
|
buttonsActionsMap.append(
|
||||||
|
R.id.menu_infinitybase,
|
||||||
|
EmulationActivity.MENU_ACTION_INFINITY_BASE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun newInstance(): MenuFragment {
|
||||||
|
val fragment = MenuFragment()
|
||||||
|
val arguments = Bundle()
|
||||||
|
if (NativeLibrary.IsGameMetadataValid()) {
|
||||||
|
arguments.putString(KEY_TITLE, NativeLibrary.GetCurrentTitleDescription())
|
||||||
|
arguments.putBoolean(KEY_WII, NativeLibrary.IsEmulatingWii())
|
||||||
|
}
|
||||||
|
fragment.arguments = arguments
|
||||||
|
return fragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,149 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
package org.dolphinemu.dolphinemu.fragments;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.text.format.DateUtils;
|
|
||||||
import android.util.SparseIntArray;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.GridLayout;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
|
||||||
import org.dolphinemu.dolphinemu.R;
|
|
||||||
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
|
||||||
import org.dolphinemu.dolphinemu.databinding.FragmentSaveloadStateBinding;
|
|
||||||
|
|
||||||
public final class SaveLoadStateFragment extends Fragment implements View.OnClickListener
|
|
||||||
{
|
|
||||||
public enum SaveOrLoad
|
|
||||||
{
|
|
||||||
SAVE, LOAD
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String KEY_SAVEORLOAD = "saveorload";
|
|
||||||
|
|
||||||
private static int[] saveActionsMap = new int[]{
|
|
||||||
EmulationActivity.MENU_ACTION_SAVE_SLOT1,
|
|
||||||
EmulationActivity.MENU_ACTION_SAVE_SLOT2,
|
|
||||||
EmulationActivity.MENU_ACTION_SAVE_SLOT3,
|
|
||||||
EmulationActivity.MENU_ACTION_SAVE_SLOT4,
|
|
||||||
EmulationActivity.MENU_ACTION_SAVE_SLOT5,
|
|
||||||
EmulationActivity.MENU_ACTION_SAVE_SLOT6,
|
|
||||||
};
|
|
||||||
|
|
||||||
private static int[] loadActionsMap = new int[]{
|
|
||||||
EmulationActivity.MENU_ACTION_LOAD_SLOT1,
|
|
||||||
EmulationActivity.MENU_ACTION_LOAD_SLOT2,
|
|
||||||
EmulationActivity.MENU_ACTION_LOAD_SLOT3,
|
|
||||||
EmulationActivity.MENU_ACTION_LOAD_SLOT4,
|
|
||||||
EmulationActivity.MENU_ACTION_LOAD_SLOT5,
|
|
||||||
EmulationActivity.MENU_ACTION_LOAD_SLOT6,
|
|
||||||
};
|
|
||||||
|
|
||||||
private static SparseIntArray buttonsMap = new SparseIntArray();
|
|
||||||
|
|
||||||
static
|
|
||||||
{
|
|
||||||
buttonsMap.append(R.id.loadsave_state_button_1, 0);
|
|
||||||
buttonsMap.append(R.id.loadsave_state_button_2, 1);
|
|
||||||
buttonsMap.append(R.id.loadsave_state_button_3, 2);
|
|
||||||
buttonsMap.append(R.id.loadsave_state_button_4, 3);
|
|
||||||
buttonsMap.append(R.id.loadsave_state_button_5, 4);
|
|
||||||
buttonsMap.append(R.id.loadsave_state_button_6, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
private SaveOrLoad mSaveOrLoad;
|
|
||||||
|
|
||||||
private FragmentSaveloadStateBinding mBinding;
|
|
||||||
|
|
||||||
public static SaveLoadStateFragment newInstance(SaveOrLoad saveOrLoad)
|
|
||||||
{
|
|
||||||
SaveLoadStateFragment fragment = new SaveLoadStateFragment();
|
|
||||||
|
|
||||||
Bundle arguments = new Bundle();
|
|
||||||
arguments.putSerializable(KEY_SAVEORLOAD, saveOrLoad);
|
|
||||||
fragment.setArguments(arguments);
|
|
||||||
|
|
||||||
return fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState)
|
|
||||||
{
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
mSaveOrLoad = (SaveOrLoad) getArguments().getSerializable(KEY_SAVEORLOAD);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
|
||||||
Bundle savedInstanceState)
|
|
||||||
{
|
|
||||||
mBinding = FragmentSaveloadStateBinding.inflate(inflater, container, false);
|
|
||||||
return mBinding.getRoot();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
|
|
||||||
{
|
|
||||||
GridLayout grid = mBinding.gridStateSlots;
|
|
||||||
for (int childIndex = 0; childIndex < grid.getChildCount(); childIndex++)
|
|
||||||
{
|
|
||||||
Button button = (Button) grid.getChildAt(childIndex);
|
|
||||||
setButtonText(button, childIndex);
|
|
||||||
button.setOnClickListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// So that item clicked to start this Fragment is no longer the focused item.
|
|
||||||
grid.requestFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroyView()
|
|
||||||
{
|
|
||||||
super.onDestroyView();
|
|
||||||
mBinding = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick(View view)
|
|
||||||
{
|
|
||||||
int buttonIndex = buttonsMap.get(view.getId(), -1);
|
|
||||||
|
|
||||||
int action = (mSaveOrLoad == SaveOrLoad.SAVE ? saveActionsMap : loadActionsMap)[buttonIndex];
|
|
||||||
((EmulationActivity) getActivity()).handleMenuAction(action);
|
|
||||||
|
|
||||||
if (mSaveOrLoad == SaveOrLoad.SAVE)
|
|
||||||
{
|
|
||||||
// Update the "last modified" time.
|
|
||||||
// The savestate most likely hasn't gotten saved to disk yet (it happens asynchronously),
|
|
||||||
// so we unfortunately can't rely on setButtonText/GetUnixTimeOfStateSlot here.
|
|
||||||
|
|
||||||
Button button = (Button) view;
|
|
||||||
CharSequence time = DateUtils.getRelativeTimeSpanString(0, 0, DateUtils.MINUTE_IN_MILLIS);
|
|
||||||
button.setText(getString(R.string.emulation_state_slot, buttonIndex + 1, time));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setButtonText(Button button, int index)
|
|
||||||
{
|
|
||||||
long creationTime = NativeLibrary.GetUnixTimeOfStateSlot(index);
|
|
||||||
if (creationTime != 0)
|
|
||||||
{
|
|
||||||
CharSequence relativeTime = DateUtils.getRelativeTimeSpanString(creationTime);
|
|
||||||
button.setText(getString(R.string.emulation_state_slot, index + 1, relativeTime));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
button.setText(getString(R.string.emulation_state_slot_empty, index + 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,121 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
package org.dolphinemu.dolphinemu.fragments
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.text.format.DateUtils
|
||||||
|
import android.util.SparseIntArray
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.Button
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import org.dolphinemu.dolphinemu.NativeLibrary
|
||||||
|
import org.dolphinemu.dolphinemu.R
|
||||||
|
import org.dolphinemu.dolphinemu.activities.EmulationActivity
|
||||||
|
import org.dolphinemu.dolphinemu.databinding.FragmentSaveloadStateBinding
|
||||||
|
import org.dolphinemu.dolphinemu.utils.SerializableHelper.serializable
|
||||||
|
|
||||||
|
class SaveLoadStateFragment : Fragment(), View.OnClickListener {
|
||||||
|
enum class SaveOrLoad { SAVE, LOAD }
|
||||||
|
|
||||||
|
private var saveOrLoad: SaveOrLoad? = null
|
||||||
|
|
||||||
|
private var _binding: FragmentSaveloadStateBinding? = null
|
||||||
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
saveOrLoad = requireArguments().serializable(KEY_SAVEORLOAD) as SaveOrLoad?
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
|
_binding = FragmentSaveloadStateBinding.inflate(inflater, container, false)
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
val grid = binding.gridStateSlots
|
||||||
|
for (childIndex in 0 until grid.childCount) {
|
||||||
|
val button = grid.getChildAt(childIndex) as Button
|
||||||
|
setButtonText(button, childIndex)
|
||||||
|
button.setOnClickListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
// So that item clicked to start this Fragment is no longer the focused item.
|
||||||
|
grid.requestFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
super.onDestroyView()
|
||||||
|
_binding = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(view: View) {
|
||||||
|
val buttonIndex = buttonsMap[view.id, -1]
|
||||||
|
|
||||||
|
val action =
|
||||||
|
(if (saveOrLoad == SaveOrLoad.SAVE) saveActionsMap else loadActionsMap)[buttonIndex]
|
||||||
|
(requireActivity() as EmulationActivity?)?.handleMenuAction(action)
|
||||||
|
|
||||||
|
if (saveOrLoad == SaveOrLoad.SAVE) {
|
||||||
|
// Update the "last modified" time.
|
||||||
|
// The savestate most likely hasn't gotten saved to disk yet (it happens asynchronously),
|
||||||
|
// so we unfortunately can't rely on setButtonText/GetUnixTimeOfStateSlot here.
|
||||||
|
val button = view as Button
|
||||||
|
val time = DateUtils.getRelativeTimeSpanString(0, 0, DateUtils.MINUTE_IN_MILLIS)
|
||||||
|
button.text = getString(R.string.emulation_state_slot, buttonIndex + 1, time)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setButtonText(button: Button, index: Int) {
|
||||||
|
val creationTime = NativeLibrary.GetUnixTimeOfStateSlot(index)
|
||||||
|
button.text = if (creationTime != 0L) {
|
||||||
|
val relativeTime = DateUtils.getRelativeTimeSpanString(creationTime)
|
||||||
|
getString(R.string.emulation_state_slot, index + 1, relativeTime)
|
||||||
|
} else {
|
||||||
|
getString(R.string.emulation_state_slot_empty, index + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val KEY_SAVEORLOAD = "saveorload"
|
||||||
|
|
||||||
|
private val saveActionsMap = intArrayOf(
|
||||||
|
EmulationActivity.MENU_ACTION_SAVE_SLOT1,
|
||||||
|
EmulationActivity.MENU_ACTION_SAVE_SLOT2,
|
||||||
|
EmulationActivity.MENU_ACTION_SAVE_SLOT3,
|
||||||
|
EmulationActivity.MENU_ACTION_SAVE_SLOT4,
|
||||||
|
EmulationActivity.MENU_ACTION_SAVE_SLOT5,
|
||||||
|
EmulationActivity.MENU_ACTION_SAVE_SLOT6
|
||||||
|
)
|
||||||
|
|
||||||
|
private val loadActionsMap = intArrayOf(
|
||||||
|
EmulationActivity.MENU_ACTION_LOAD_SLOT1,
|
||||||
|
EmulationActivity.MENU_ACTION_LOAD_SLOT2,
|
||||||
|
EmulationActivity.MENU_ACTION_LOAD_SLOT3,
|
||||||
|
EmulationActivity.MENU_ACTION_LOAD_SLOT4,
|
||||||
|
EmulationActivity.MENU_ACTION_LOAD_SLOT5,
|
||||||
|
EmulationActivity.MENU_ACTION_LOAD_SLOT6
|
||||||
|
)
|
||||||
|
|
||||||
|
private val buttonsMap = SparseIntArray()
|
||||||
|
|
||||||
|
init {
|
||||||
|
buttonsMap.append(R.id.loadsave_state_button_1, 0)
|
||||||
|
buttonsMap.append(R.id.loadsave_state_button_2, 1)
|
||||||
|
buttonsMap.append(R.id.loadsave_state_button_3, 2)
|
||||||
|
buttonsMap.append(R.id.loadsave_state_button_4, 3)
|
||||||
|
buttonsMap.append(R.id.loadsave_state_button_5, 4)
|
||||||
|
buttonsMap.append(R.id.loadsave_state_button_6, 5)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun newInstance(saveOrLoad: SaveOrLoad): SaveLoadStateFragment {
|
||||||
|
val fragment = SaveLoadStateFragment()
|
||||||
|
val arguments = Bundle()
|
||||||
|
arguments.putSerializable(KEY_SAVEORLOAD, saveOrLoad)
|
||||||
|
fragment.arguments = arguments
|
||||||
|
return fragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user