Android: Show how long ago each savestate was created
This commit is contained in:
parent
a8b7c3b577
commit
21d3ea523c
|
@ -326,6 +326,11 @@ public final class NativeLibrary
|
||||||
*/
|
*/
|
||||||
public static native void LoadStateAs(String path);
|
public static native void LoadStateAs(String path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns when the savestate in the given slot was created, or 0 if the slot is empty.
|
||||||
|
*/
|
||||||
|
public static native long GetUnixTimeOfStateSlot(int slot);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the current working user directory
|
* Sets the current working user directory
|
||||||
* If not set, it auto-detects a location
|
* If not set, it auto-detects a location
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.dolphinemu.dolphinemu.fragments;
|
package org.dolphinemu.dolphinemu.fragments;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.text.format.DateUtils;
|
||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
@ -11,6 +12,7 @@ import android.widget.GridLayout;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
|
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||||
import org.dolphinemu.dolphinemu.R;
|
import org.dolphinemu.dolphinemu.R;
|
||||||
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
||||||
|
|
||||||
|
@ -22,40 +24,35 @@ public final class SaveLoadStateFragment extends Fragment implements View.OnClic
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String KEY_SAVEORLOAD = "saveorload";
|
private static final String KEY_SAVEORLOAD = "saveorload";
|
||||||
private static SparseIntArray saveButtonsActionsMap = new SparseIntArray();
|
|
||||||
|
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
|
static
|
||||||
{
|
{
|
||||||
saveButtonsActionsMap
|
buttonsMap.append(R.id.loadsave_state_button_1, 0);
|
||||||
.append(R.id.loadsave_state_button_1, EmulationActivity.MENU_ACTION_SAVE_SLOT1);
|
buttonsMap.append(R.id.loadsave_state_button_2, 1);
|
||||||
saveButtonsActionsMap
|
buttonsMap.append(R.id.loadsave_state_button_3, 2);
|
||||||
.append(R.id.loadsave_state_button_2, EmulationActivity.MENU_ACTION_SAVE_SLOT2);
|
buttonsMap.append(R.id.loadsave_state_button_4, 3);
|
||||||
saveButtonsActionsMap
|
buttonsMap.append(R.id.loadsave_state_button_5, 4);
|
||||||
.append(R.id.loadsave_state_button_3, EmulationActivity.MENU_ACTION_SAVE_SLOT3);
|
buttonsMap.append(R.id.loadsave_state_button_6, 5);
|
||||||
saveButtonsActionsMap
|
|
||||||
.append(R.id.loadsave_state_button_4, EmulationActivity.MENU_ACTION_SAVE_SLOT4);
|
|
||||||
saveButtonsActionsMap
|
|
||||||
.append(R.id.loadsave_state_button_5, EmulationActivity.MENU_ACTION_SAVE_SLOT5);
|
|
||||||
saveButtonsActionsMap
|
|
||||||
.append(R.id.loadsave_state_button_6, EmulationActivity.MENU_ACTION_SAVE_SLOT6);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static SparseIntArray loadButtonsActionsMap = new SparseIntArray();
|
|
||||||
|
|
||||||
static
|
|
||||||
{
|
|
||||||
loadButtonsActionsMap
|
|
||||||
.append(R.id.loadsave_state_button_1, EmulationActivity.MENU_ACTION_LOAD_SLOT1);
|
|
||||||
loadButtonsActionsMap
|
|
||||||
.append(R.id.loadsave_state_button_2, EmulationActivity.MENU_ACTION_LOAD_SLOT2);
|
|
||||||
loadButtonsActionsMap
|
|
||||||
.append(R.id.loadsave_state_button_3, EmulationActivity.MENU_ACTION_LOAD_SLOT3);
|
|
||||||
loadButtonsActionsMap
|
|
||||||
.append(R.id.loadsave_state_button_4, EmulationActivity.MENU_ACTION_LOAD_SLOT4);
|
|
||||||
loadButtonsActionsMap
|
|
||||||
.append(R.id.loadsave_state_button_5, EmulationActivity.MENU_ACTION_LOAD_SLOT5);
|
|
||||||
loadButtonsActionsMap
|
|
||||||
.append(R.id.loadsave_state_button_6, EmulationActivity.MENU_ACTION_LOAD_SLOT6);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private SaveOrLoad mSaveOrLoad;
|
private SaveOrLoad mSaveOrLoad;
|
||||||
|
@ -88,6 +85,7 @@ public final class SaveLoadStateFragment extends Fragment implements View.OnClic
|
||||||
for (int childIndex = 0; childIndex < grid.getChildCount(); childIndex++)
|
for (int childIndex = 0; childIndex < grid.getChildCount(); childIndex++)
|
||||||
{
|
{
|
||||||
Button button = (Button) grid.getChildAt(childIndex);
|
Button button = (Button) grid.getChildAt(childIndex);
|
||||||
|
setButtonText(button, childIndex);
|
||||||
button.setOnClickListener(this);
|
button.setOnClickListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,20 +97,31 @@ public final class SaveLoadStateFragment extends Fragment implements View.OnClic
|
||||||
|
|
||||||
@SuppressWarnings("WrongConstant")
|
@SuppressWarnings("WrongConstant")
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View button)
|
public void onClick(View view)
|
||||||
{
|
|
||||||
int action = 0;
|
|
||||||
switch (mSaveOrLoad)
|
|
||||||
{
|
|
||||||
case SAVE:
|
|
||||||
action = saveButtonsActionsMap.get(button.getId(), -1);
|
|
||||||
break;
|
|
||||||
case LOAD:
|
|
||||||
action = loadButtonsActionsMap.get(button.getId(), -1);
|
|
||||||
}
|
|
||||||
if (action >= 0)
|
|
||||||
{
|
{
|
||||||
|
int buttonIndex = buttonsMap.get(view.getId(), -1);
|
||||||
|
|
||||||
|
int action = (mSaveOrLoad == SaveOrLoad.SAVE ? saveActionsMap : loadActionsMap)[buttonIndex];
|
||||||
((EmulationActivity) getActivity()).handleMenuAction(action);
|
((EmulationActivity) getActivity()).handleMenuAction(action);
|
||||||
|
|
||||||
|
// The savestate most likely hasn't gotten saved 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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,42 +11,36 @@
|
||||||
android:id="@+id/loadsave_state_button_1"
|
android:id="@+id/loadsave_state_button_1"
|
||||||
android:layout_width="128dp"
|
android:layout_width="128dp"
|
||||||
android:layout_height="96dp"
|
android:layout_height="96dp"
|
||||||
android:text="@string/emulation_slot1"
|
|
||||||
style="@style/OverlayInGameMenuOption"/>
|
style="@style/OverlayInGameMenuOption"/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/loadsave_state_button_2"
|
android:id="@+id/loadsave_state_button_2"
|
||||||
android:layout_width="128dp"
|
android:layout_width="128dp"
|
||||||
android:layout_height="96dp"
|
android:layout_height="96dp"
|
||||||
android:text="@string/emulation_slot2"
|
|
||||||
style="@style/OverlayInGameMenuOption"/>
|
style="@style/OverlayInGameMenuOption"/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/loadsave_state_button_3"
|
android:id="@+id/loadsave_state_button_3"
|
||||||
android:layout_width="128dp"
|
android:layout_width="128dp"
|
||||||
android:layout_height="96dp"
|
android:layout_height="96dp"
|
||||||
android:text="@string/emulation_slot3"
|
|
||||||
style="@style/OverlayInGameMenuOption"/>
|
style="@style/OverlayInGameMenuOption"/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/loadsave_state_button_4"
|
android:id="@+id/loadsave_state_button_4"
|
||||||
android:layout_width="128dp"
|
android:layout_width="128dp"
|
||||||
android:layout_height="96dp"
|
android:layout_height="96dp"
|
||||||
android:text="@string/emulation_slot4"
|
|
||||||
style="@style/OverlayInGameMenuOption"/>
|
style="@style/OverlayInGameMenuOption"/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/loadsave_state_button_5"
|
android:id="@+id/loadsave_state_button_5"
|
||||||
android:layout_width="128dp"
|
android:layout_width="128dp"
|
||||||
android:layout_height="96dp"
|
android:layout_height="96dp"
|
||||||
android:text="@string/emulation_slot5"
|
|
||||||
style="@style/OverlayInGameMenuOption"/>
|
style="@style/OverlayInGameMenuOption"/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/loadsave_state_button_6"
|
android:id="@+id/loadsave_state_button_6"
|
||||||
android:layout_width="128dp"
|
android:layout_width="128dp"
|
||||||
android:layout_height="96dp"
|
android:layout_height="96dp"
|
||||||
android:text="@string/emulation_slot6"
|
|
||||||
style="@style/OverlayInGameMenuOption"/>
|
style="@style/OverlayInGameMenuOption"/>
|
||||||
|
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
|
|
|
@ -380,12 +380,8 @@ It can efficiently compress both junk data and encrypted Wii data.
|
||||||
<string name="emulation_savestate">Save State</string>
|
<string name="emulation_savestate">Save State</string>
|
||||||
<string name="emulation_loadstate">Load State</string>
|
<string name="emulation_loadstate">Load State</string>
|
||||||
<string name="emulation_exit">Exit Emulation</string>
|
<string name="emulation_exit">Exit Emulation</string>
|
||||||
<string name="emulation_slot1">Slot 1</string>
|
<string name="emulation_state_slot">Slot %1$d\n\n%2$s</string>
|
||||||
<string name="emulation_slot2">Slot 2</string>
|
<string name="emulation_state_slot_empty">Slot %1$d\n\nEmpty</string>
|
||||||
<string name="emulation_slot3">Slot 3</string>
|
|
||||||
<string name="emulation_slot4">Slot 4</string>
|
|
||||||
<string name="emulation_slot5">Slot 5</string>
|
|
||||||
<string name="emulation_slot6">Slot 6</string>
|
|
||||||
<string name="emulation_quicksave">Quick Save</string>
|
<string name="emulation_quicksave">Quick Save</string>
|
||||||
<string name="emulation_quickload">Quick Load</string>
|
<string name="emulation_quickload">Quick Load</string>
|
||||||
<string name="emulation_refresh_wiimotes">Refresh Wii Remotes</string>
|
<string name="emulation_refresh_wiimotes">Refresh Wii Remotes</string>
|
||||||
|
|
|
@ -78,6 +78,9 @@
|
||||||
|
|
||||||
<style name="OverlayInGameMenuOption" parent="InGameMenuOption">
|
<style name="OverlayInGameMenuOption" parent="InGameMenuOption">
|
||||||
<item name="android:textColor">@color/button_text_color</item>
|
<item name="android:textColor">@color/button_text_color</item>
|
||||||
|
<item name="android:padding">8dp</item>
|
||||||
|
<item name="android:gravity">center</item>
|
||||||
|
<item name="android:layout_gravity">center</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- Inherit from a base file picker theme that handles day/night -->
|
<!-- Inherit from a base file picker theme that handles day/night -->
|
||||||
|
|
|
@ -333,6 +333,12 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_LoadStateAs(
|
||||||
State::LoadAs(GetJString(env, path));
|
State::LoadAs(GetJString(env, path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jlong JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetUnixTimeOfStateSlot(
|
||||||
|
JNIEnv* env, jobject obj, jint slot)
|
||||||
|
{
|
||||||
|
return static_cast<jlong>(State::GetUnixTimeOfSlot(slot));
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_utils_DirectoryInitialization_SetSysDirectory(
|
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_utils_DirectoryInitialization_SetSysDirectory(
|
||||||
JNIEnv* env, jobject obj, jstring jPath)
|
JNIEnv* env, jobject obj, jstring jPath)
|
||||||
{
|
{
|
||||||
|
|
|
@ -482,6 +482,17 @@ std::string GetInfoStringOfSlot(int slot, bool translate)
|
||||||
return Common::Timer::GetDateTimeFormatted(header.time);
|
return Common::Timer::GetDateTimeFormatted(header.time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 GetUnixTimeOfSlot(int slot)
|
||||||
|
{
|
||||||
|
State::StateHeader header;
|
||||||
|
if (!ReadHeader(MakeStateFilename(slot), header))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
constexpr u64 MS_PER_SEC = 1000;
|
||||||
|
return static_cast<u64>(header.time * MS_PER_SEC) +
|
||||||
|
(Common::Timer::DOUBLE_TIME_OFFSET * MS_PER_SEC);
|
||||||
|
}
|
||||||
|
|
||||||
static void LoadFileStateData(const std::string& filename, std::vector<u8>& ret_data)
|
static void LoadFileStateData(const std::string& filename, std::vector<u8>& ret_data)
|
||||||
{
|
{
|
||||||
Flush();
|
Flush();
|
||||||
|
|
|
@ -36,6 +36,9 @@ bool ReadHeader(const std::string& filename, StateHeader& header);
|
||||||
// which can be presented to the user for identification purposes
|
// which can be presented to the user for identification purposes
|
||||||
std::string GetInfoStringOfSlot(int slot, bool translate = true);
|
std::string GetInfoStringOfSlot(int slot, bool translate = true);
|
||||||
|
|
||||||
|
// Returns when the savestate in the given slot was created, or 0 if the slot is empty.
|
||||||
|
u64 GetUnixTimeOfSlot(int slot);
|
||||||
|
|
||||||
// These don't happen instantly - they get scheduled as events.
|
// These don't happen instantly - they get scheduled as events.
|
||||||
// ...But only if we're not in the main CPU thread.
|
// ...But only if we're not in the main CPU thread.
|
||||||
// If we're in the main CPU thread then they run immediately instead
|
// If we're in the main CPU thread then they run immediately instead
|
||||||
|
|
Loading…
Reference in New Issue