Expand Up @@ -25,6 +25,7 @@
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.model.StringSetting;
import org.dolphinemu.dolphinemu.features.settings.model.WiimoteProfileStringSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.DateTimeChoiceSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.SwitchSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.FilePicker;
import org.dolphinemu.dolphinemu.features.settings.model.view.HeaderSetting;
Expand Down Expand Up @@ -564,8 +565,13 @@ private void addPathsSettings(ArrayList<SettingsItem> sl)

private void addGameCubeSettings(ArrayList<SettingsItem> sl)
{
sl.add(new HeaderSetting(mContext, R.string.ipl_settings, 0));
sl.add(new SwitchSetting(mContext, BooleanSetting.MAIN_SKIP_IPL, R.string.skip_main_menu,
R.string.skip_main_menu_description));
sl.add(new SingleChoiceSetting(mContext, IntSetting.MAIN_GC_LANGUAGE, R.string.system_language,
0, R.array.gameCubeSystemLanguageEntries, R.array.gameCubeSystemLanguageValues));

sl.add(new HeaderSetting(mContext, R.string.device_settings, 0));
sl.add(new SingleChoiceSetting(mContext, IntSetting.MAIN_SLOT_A, R.string.slot_a_device, 0,
R.array.slotDeviceEntries, R.array.slotDeviceValues));
sl.add(new SingleChoiceSetting(mContext, IntSetting.MAIN_SLOT_B, R.string.slot_b_device, 0,
Expand Down Expand Up @@ -715,17 +721,103 @@ else if (defaultCpuCore == 4) // AArch64
emuCoresEntries = R.array.emuCoresEntriesGeneric;
emuCoresValues = R.array.emuCoresValuesGeneric;
}
sl.add(new HeaderSetting(mContext, R.string.cpu_options, 0));
sl.add(new SingleChoiceSetting(mContext, IntSetting.MAIN_CPU_CORE, R.string.cpu_core, 0,
emuCoresEntries, emuCoresValues));
sl.add(new SwitchSetting(mContext, BooleanSetting.MAIN_MMU, R.string.mmu_enable,
R.string.mmu_enable_description));
sl.add(new SwitchSetting(mContext, BooleanSetting.MAIN_PAUSE_ON_PANIC, R.string.pause_on_panic,
R.string.pause_on_panic_description));
sl.add(new SwitchSetting(mContext, BooleanSetting.MAIN_ACCURATE_CPU_CACHE,
R.string.enable_cpu_cache, R.string.enable_cpu_cache_description));

sl.add(new HeaderSetting(mContext, R.string.clock_override, 0));
sl.add(new SwitchSetting(mContext, BooleanSetting.MAIN_OVERCLOCK_ENABLE,
R.string.overclock_enable, R.string.overclock_enable_description));
sl.add(new PercentSliderSetting(mContext, FloatSetting.MAIN_OVERCLOCK, R.string.overclock_title,
R.string.overclock_title_description, 0, 400, "%"));

AbstractIntSetting mem1Setting = new AbstractIntSetting()
{
@Override
public int getInt(Settings settings)
{
return IntSetting.MAIN_MEM1_SIZE.getInt(settings) / 1024 / 1024;
}

@Override
public void setInt(Settings settings, int newValue)
{
IntSetting.MAIN_MEM1_SIZE.setInt(settings, newValue * 1024 * 1024);
}

@Override
public boolean isOverridden(Settings settings)
{
return IntSetting.MAIN_MEM1_SIZE.isOverridden(settings);
}

@Override
public boolean isRuntimeEditable()
{
return IntSetting.MAIN_MEM1_SIZE.isRuntimeEditable();
}

@Override
public boolean delete(Settings settings)
{
return IntSetting.MAIN_MEM1_SIZE.delete(settings);
}
};
AbstractIntSetting mem2Setting = new AbstractIntSetting()
{
@Override
public int getInt(Settings settings)
{
return IntSetting.MAIN_MEM2_SIZE.getInt(settings) / 1024 / 1024;
}

@Override
public void setInt(Settings settings, int newValue)
{
IntSetting.MAIN_MEM2_SIZE.setInt(settings, newValue * 1024 * 1024);
}

@Override
public boolean isOverridden(Settings settings)
{
return IntSetting.MAIN_MEM2_SIZE.isOverridden(settings);
}

@Override
public boolean isRuntimeEditable()
{
return IntSetting.MAIN_MEM2_SIZE.isRuntimeEditable();
}

@Override
public boolean delete(Settings settings)
{
return IntSetting.MAIN_MEM2_SIZE.delete(settings);
}
};
sl.add(new HeaderSetting(mContext, R.string.memory_override, 0));
sl.add(new SwitchSetting(mContext, BooleanSetting.MAIN_RAM_OVERRIDE_ENABLE,
R.string.enable_memory_size_override,
R.string.enable_memory_size_override_description));
sl.add(new IntSliderSetting(mContext, mem1Setting, R.string.main_mem1_size, 0, 24, 64, "MB"));
sl.add(new IntSliderSetting(mContext, mem2Setting, R.string.main_mem2_size, 0, 64, 128, "MB"));

sl.add(new HeaderSetting(mContext, R.string.gpu_options, 0));
sl.add(new SingleChoiceSetting(mContext, synchronizeGpuThread, R.string.synchronize_gpu_thread,
R.string.synchronize_gpu_thread_description, R.array.synchronizeGpuThreadEntries,
R.array.synchronizeGpuThreadValues));

sl.add(new HeaderSetting(mContext, R.string.custom_rtc_options, 0));
sl.add(new SwitchSetting(mContext, BooleanSetting.MAIN_CUSTOM_RTC_ENABLE,
R.string.custom_rtc_enable, R.string.custom_rtc_description));
sl.add(new DateTimeChoiceSetting(mContext, StringSetting.MAIN_CUSTOM_RTC_VALUE,
R.string.set_custom_rtc, 0));
}

private void addSerialPortSubSettings(ArrayList<SettingsItem> sl, int serialPort1Type)
Expand Down Expand Up @@ -800,6 +892,37 @@ private void addEnhanceSettings(ArrayList<SettingsItem> sl)
sl.add(new SingleChoiceSetting(mContext, IntSetting.GFX_ENHANCE_MAX_ANISOTROPY,
R.string.anisotropic_filtering, R.string.anisotropic_filtering_description,
R.array.anisotropicFilteringEntries, R.array.anisotropicFilteringValues));
AbstractIntSetting filteringSetting = new AbstractIntSetting()
{
@Override public int getInt(Settings settings)
{
return IntSetting.GFX_ENHANCE_FORCE_TEXTURE_FILTERING.getInt(settings);
}

@Override public void setInt(Settings settings, int newValue)
{
BooleanSetting.GFX_ENHANCE_FORCE_FILTERING.setBoolean(settings, (newValue > 0));
IntSetting.GFX_ENHANCE_FORCE_TEXTURE_FILTERING.setInt(settings, newValue);
}

@Override public boolean isOverridden(Settings settings)
{
return IntSetting.GFX_ENHANCE_FORCE_TEXTURE_FILTERING.isOverridden(settings);
}

@Override public boolean isRuntimeEditable()
{
return IntSetting.GFX_ENHANCE_FORCE_TEXTURE_FILTERING.isRuntimeEditable();
}

@Override public boolean delete(Settings settings)
{
return IntSetting.GFX_ENHANCE_FORCE_TEXTURE_FILTERING.delete(settings);
}
};
sl.add(new SingleChoiceSetting(mContext, filteringSetting, R.string.texture_filtering,
R.string.texture_filtering_description, R.array.textureFilteringEntries,
R.array.textureFilteringValues));

int stereoModeValue = IntSetting.GFX_STEREO_MODE.getInt(mSettings);
final int anaglyphMode = 3;
Expand All @@ -821,8 +944,6 @@ private void addEnhanceSettings(ArrayList<SettingsItem> sl)
R.string.scaled_efb_copy, R.string.scaled_efb_copy_description));
sl.add(new SwitchSetting(mContext, BooleanSetting.GFX_ENABLE_PIXEL_LIGHTING,
R.string.per_pixel_lighting, R.string.per_pixel_lighting_description));
sl.add(new SwitchSetting(mContext, BooleanSetting.GFX_ENHANCE_FORCE_FILTERING,
R.string.force_texture_filtering, R.string.force_texture_filtering_description));
sl.add(new SwitchSetting(mContext, BooleanSetting.GFX_ENHANCE_FORCE_TRUE_COLOR,
R.string.force_24bit_color, R.string.force_24bit_color_description));
sl.add(new SwitchSetting(mContext, BooleanSetting.GFX_DISABLE_FOG, R.string.disable_fog,
Expand Down Expand Up @@ -944,8 +1065,12 @@ private void addAdvancedGraphicsSettings(ArrayList<SettingsItem> sl)
R.string.defer_efb_invalidation, R.string.defer_efb_invalidation_description));
sl.add(new InvertedSwitchSetting(mContext, BooleanSetting.GFX_HACK_FAST_TEXTURE_SAMPLING,
R.string.manual_texture_sampling, R.string.manual_texture_sampling_description));

sl.add(new HeaderSetting(mContext, R.string.frame_dumping, 0));
sl.add(new SwitchSetting(mContext, BooleanSetting.GFX_INTERNAL_RESOLUTION_FRAME_DUMPS,
R.string.internal_resolution_dumps, R.string.internal_resolution_dumps_description));
sl.add(new IntSliderSetting(mContext, IntSetting.GFX_PNG_COMPRESSION_LEVEL,
R.string.png_compression_level, 0, 0, 9, ""));

sl.add(new HeaderSetting(mContext, R.string.debugging, 0));
sl.add(new SwitchSetting(mContext, BooleanSetting.GFX_ENABLE_WIREFRAME,
Expand Down
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: GPL-2.0-or-later

package org.dolphinemu.dolphinemu.features.settings.ui.viewholder

import android.text.TextUtils
import android.view.View
import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding
import org.dolphinemu.dolphinemu.features.settings.model.view.DateTimeChoiceSetting
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter
import java.time.Instant
import java.time.ZoneId
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle

class DateTimeSettingViewHolder(
private val binding: ListItemSettingBinding,
adapter: SettingsAdapter
) : SettingViewHolder(binding.root, adapter) {
private var mItem: DateTimeChoiceSetting? = null

override fun bind(item: SettingsItem) {
mItem = item as DateTimeChoiceSetting
val inputTime = mItem!!.getSelectedValue(adapter.settings)
binding.textSettingName.text = item.getName()

if (!TextUtils.isEmpty(inputTime)) {
val epochTime = inputTime.substring(2).toLong(16)
val instant = Instant.ofEpochMilli(epochTime * 1000)
val zonedTime = ZonedDateTime.ofInstant(instant, ZoneId.of("UTC"))
val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
binding.textSettingDescription.text = dateFormatter.format(zonedTime)
} else {
binding.textSettingDescription.text = item.getDescription()
}
setStyle(binding.textSettingName, mItem)
}

override fun onClick(clicked: View) {
if (!mItem!!.isEditable) {
showNotRuntimeEditableError()
return
}
adapter.onDateTimeClick(mItem, bindingAdapterPosition)
setStyle(binding.textSettingName, mItem)
}

override fun getItem(): SettingsItem? {
return mItem
}
}
Expand Up @@ -54,6 +54,12 @@ protected static void showNotRuntimeEditableError()
Toast.LENGTH_SHORT).show();
}

protected static void showIplNotAvailableError()
{
Toast.makeText(DolphinApplication.getAppContext(), R.string.ipl_not_found, Toast.LENGTH_SHORT)
.show();
}

/**
* Called by the adapter to set this ViewHolder's child views to display the list item
* it must now represent.
Expand Down
Expand Up @@ -7,13 +7,20 @@
import androidx.annotation.Nullable;

import org.dolphinemu.dolphinemu.databinding.ListItemSettingSwitchBinding;
import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.SwitchSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;

public final class SwitchSettingViewHolder extends SettingViewHolder
{
private SwitchSetting mItem;
private boolean iplExists = false;

private final ListItemSettingSwitchBinding mBinding;

Expand All @@ -32,11 +39,43 @@ public void bind(SettingsItem item)
mBinding.textSettingDescription.setText(item.getDescription());

mBinding.settingSwitch.setChecked(mItem.isChecked(getAdapter().getSettings()));
mBinding.settingSwitch.setEnabled(true);

mBinding.settingSwitch.setEnabled(mItem.isEditable());
// Check for IPL to make sure user can skip.
if (mItem.getSetting() == BooleanSetting.MAIN_SKIP_IPL)
{
ArrayList<String> iplDirs = new ArrayList<>(Arrays.asList("USA", "JAP", "EUR"));
for (String dir : iplDirs)
{
File iplFile = new File(DirectoryInitialization.getUserDirectory(),
File.separator + "GC" + File.separator + dir + File.separator + "IPL.bin");
if (iplFile.exists())
{
iplExists = true;
break;
}
}

if (mItem.isChecked(getAdapter().getSettings()))
{
mBinding.settingSwitch.setEnabled(iplExists);
}
else
{
mBinding.settingSwitch.setEnabled(true);
}
}

mBinding.settingSwitch.setOnCheckedChangeListener((buttonView, isChecked) ->
{
// If a user has skip IPL disabled previously and deleted their IPL file, we need to allow
// them to skip it or else their game will appear broken. However, once this is enabled, we
// need to disable the option again to prevent the same issue from occurring.
if (mItem.getSetting() == BooleanSetting.MAIN_SKIP_IPL && !iplExists && isChecked)
{
mBinding.settingSwitch.setEnabled(false);
}

getAdapter().onBooleanClick(mItem, mBinding.settingSwitch.isChecked());

setStyle(mBinding.textSettingName, mItem);
Expand All @@ -54,6 +93,15 @@ public void onClick(View clicked)
return;
}

if (mItem.getSetting() == BooleanSetting.MAIN_SKIP_IPL && !iplExists)
{
if (mItem.isChecked(getAdapter().getSettings()))
{
showIplNotAvailableError();
return;
}
}

mBinding.settingSwitch.toggle();
}

Expand Down
14 changes: 13 additions & 1 deletion Source/Android/app/src/main/res/values/arrays.xml
Expand Up @@ -293,7 +293,7 @@

<!-- Anisotropic Filtering Preference -->
<string-array name="anisotropicFilteringEntries">
<item>@string/multiple_one</item>
<item>@string/filtering_default</item>
<item>@string/multiple_two</item>
<item>@string/multiple_four</item>
<item>@string/multiple_eight</item>
Expand All @@ -307,6 +307,18 @@
<item>4</item>
</integer-array>

<!-- Texture Filtering Preference -->
<string-array name="textureFilteringEntries">
<item>@string/filtering_default</item>
<item>@string/filtering_nearest</item>
<item>@string/filtering_linear</item>
</string-array>
<integer-array name="textureFilteringValues">
<item>0</item>
<item>1</item>
<item>2</item>
</integer-array>

<!-- Stereoscopy Preference -->
<string-array name="stereoscopyEntries">
<item>@string/stereoscopy_off</item>
Expand Down
32 changes: 32 additions & 0 deletions Source/Android/app/src/main/res/values/strings.xml
Expand Up @@ -128,6 +128,10 @@
<string name="speed_limit">Speed Limit (0% = Unlimited)</string>
<string name="overclock_warning">WARNING: Changing this from the default (100%) WILL break games and cause glitches. Please do not report bugs that occur with a non-default clock.</string>
<string name="gamecube_submenu">GameCube</string>
<string name="ipl_settings">IPL Settings</string>
<string name="skip_main_menu">Skip Main Menu</string>
<string name="skip_main_menu_description">Put IPL ROMs in User/GC/&lt;region&gt;</string>
<string name="device_settings">Device Settings</string>
<string name="system_language">System Language</string>
<string name="slot_a_device">GameCube Slot A Device</string>
<string name="slot_b_device">GameCube Slot B Device</string>
Expand Down Expand Up @@ -250,6 +254,8 @@
<string name="FSAA_description">Reduces the amount of aliasing caused by rasterizing 3D graphics. This makes the rendered picture look less blocky. Heavily decreases emulation speed and sometimes causes issues.</string>
<string name="anisotropic_filtering">Anisotropic Filtering</string>
<string name="anisotropic_filtering_description">Enhances visual quality of textures that are at oblique viewing angles. Might cause issues in a small number of games.</string>
<string name="texture_filtering">Texture Filtering</string>
<string name="texture_filtering_description">Overrides the texture scaling filter selected by the game. Any option except \'Default\' will alter the look of the game\'s textures and might cause issues in a small number of games.</string>
<string name="post_processing_shader">Post-Processing Effect</string>
<string name="post_processing_shader_description">Apply a post-processing effect after finishing a frame</string>
<string name="postprocessing_shader">Post Processing Shader</string>
Expand Down Expand Up @@ -368,7 +374,9 @@
<string name="manual_texture_sampling">Manual Texture Sampling</string>
<string name="manual_texture_sampling_description">Use a manual implementation of texture sampling instead of the graphics backend\'s built-in functionality.</string>
<string name="internal_resolution_dumps">Dump Frames at Internal Resolution</string>
<string name="frame_dumping">Frame Dumping</string>
<string name="internal_resolution_dumps_description">Creates frame dumps and screenshots at the internal resolution of the renderer, rather than the size of the window it is displayed within. If the aspect ratio is widescreen, the output image will be scaled horizontally to preserve the vertical resolution.</string>
<string name="png_compression_level">PNG Compression Level</string>
<string name="debugging">Debugging</string>
<string name="wireframe">Enable Wireframe</string>
<string name="show_stats">Show Statistics</string>
Expand All @@ -381,15 +389,33 @@

<!-- Advanced Settings -->
<string name="advanced_submenu">Advanced</string>
<string name="cpu_options">CPU Options</string>
<string name="cpu_core">CPU Core</string>
<string name="mmu_enable">Enable MMU</string>
<string name="mmu_enable_description">Enables the Memory Management Unit. Needed for some games, but may reduce performance.</string>
<string name="pause_on_panic">Pause on Panic</string>
<string name="pause_on_panic_description">Pauses the emulation if a Read/Write or Unknown Instruction panic occurs. The performance impact is the same as having Enable MMU on.</string>
<string name="enable_cpu_cache">Enable Write-Back Cache (slow)</string>
<string name="enable_cpu_cache_description">Enables emulation of the CPU write-back cache. Enabling will have a significant impact on performance. This should be left disabled unless absolutely needed.</string>
<string name="clock_override">Clock Override</string>
<string name="overclock_enable">Override Emulated CPU Clock Speed</string>
<string name="overclock_enable_description">Higher values can make variable-framerate games run at a higher framerate, requiring a powerful device. Lower values make games run at a lower framerate, increasing emulation speed, but reducing the emulated console\'s performance.</string>
<string name="overclock_title">Emulated CPU Clock Speed</string>
<string name="overclock_title_description">Adjusts the emulated CPU\'s clock rate if \"Override Emulated CPU Clock Speed\" is enabled.</string>
<string name="memory_override">Memory Override</string>
<string name="enable_memory_size_override">Enable Emulated Memory Size Override</string>
<string name="enable_memory_size_override_description">Adjusts the amount of RAM in the emulated console.\n\nWARNING: Enabling this will completely break many games. Only a small number of games can benefit from this.</string>
<string name="main_mem1_size">MEM1 Size</string>
<string name="main_mem2_size">MEM2 Size</string>
<string name="gpu_options">GPU Options</string>
<string name="synchronize_gpu_thread">Synchronize GPU Thread</string>
<string name="synchronize_gpu_thread_description">Synchronizing the GPU thread reduces the risk of games crashing or becoming unstable with dual core enabled, but can also reduce the performance gain of dual core. If unsure, select \"On Idle Skipping\". Selecting \"Never\" is risky and not recommended!</string>
<string name="custom_rtc_options">Custom RTC Options</string>
<string name="custom_rtc_enable">Enable Custom RTC</string>
<string name="custom_rtc_description">This settings allows you to set a custom real time clock (RTC) separate from your current system time.</string>
<string name="set_custom_rtc">Set Custom RTC</string>
<string name="select_rtc_date">Select RTC Date</string>
<string name="select_rtc_time">Select RTC Time</string>

<!-- Log Configuration -->
<string name="log_submenu">Log</string>
Expand Down Expand Up @@ -623,6 +649,7 @@ It can efficiently compress both junk data and encrypted Wii data.
<string name="path_not_changeable_scoped_storage">Due to the Scoped Storage policy in Android 11 and newer, you can\'t change this path.</string>
<string name="load_settings">Loading Settings…</string>
<string name="setting_not_runtime_editable">This setting can\'t be changed while a game is running.</string>
<string name="ipl_not_found">IPL not found</string>
<string name="setting_clear_info">Long press a setting to clear it.</string>
<string name="setting_clear_confirm">Do you want to restore this setting to its default value?</string>
<string name="setting_cleared">Setting cleared</string>
Expand Down Expand Up @@ -752,6 +779,11 @@ It can efficiently compress both junk data and encrypted Wii data.
<string name="multiple_eight">8x</string>
<string name="multiple_sixteen">16x</string>

<!-- Texture Filtering Preference -->
<string name="filtering_default">Default</string>
<string name="filtering_nearest">Force Nearest</string>
<string name="filtering_linear">Force Linear</string>

<!-- Stereoscopy Preference -->
<string name="stereoscopy_off">Off</string>
<string name="stereoscopy_side_by_side">Side-by-Side</string>
Expand Down