mirror of
https://github.com/rafaelvcaetano/melonDS-android.git
synced 2024-11-30 09:00:49 +00:00
Add support for internal firmware
This commit is contained in:
parent
7c261c2424
commit
138213a8b0
1
app/proguard-rules.pro
vendored
1
app/proguard-rules.pro
vendored
@ -23,6 +23,7 @@
|
||||
-keepclassmembers enum * { *; }
|
||||
|
||||
-keep class me.magnum.melonds.domain.model.RendererConfiguration { *; }
|
||||
-keep class me.magnum.melonds.domain.model.FirmwareConfiguration { *; }
|
||||
-keep class me.magnum.melonds.domain.model.EmulatorConfiguration { *; }
|
||||
-keep class me.magnum.melonds.domain.model.ConsoleType { *; }
|
||||
-keep class me.magnum.melonds.domain.model.MicSource { *; }
|
||||
|
BIN
app/src/main/assets/bios/drastic_bios_arm7.bin
Normal file
BIN
app/src/main/assets/bios/drastic_bios_arm7.bin
Normal file
Binary file not shown.
BIN
app/src/main/assets/bios/drastic_bios_arm9.bin
Normal file
BIN
app/src/main/assets/bios/drastic_bios_arm9.bin
Normal file
Binary file not shown.
36
app/src/main/assets/bios/drastic_bios_readme.txt
Normal file
36
app/src/main/assets/bios/drastic_bios_readme.txt
Normal file
@ -0,0 +1,36 @@
|
||||
Custom NDS ARM7/ARM9 BIOS replacement
|
||||
Copyright (c) 2013, Gilead Kutnick
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1) Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2) Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
-- Info --
|
||||
|
||||
This archive contains source code and assembly for a custom BIOS replacement
|
||||
for the Nintendo DS system. This code is in no way affiliated with Nintendo
|
||||
and is not derived from Nintendo's BIOS implementation but has been implemented
|
||||
using publically available documentation.
|
||||
|
||||
It can be assembled using the included Makefile along with a proper ARM gcc
|
||||
toolchain. Change the first four lines to point to the proper toolchain of your
|
||||
choice.
|
||||
|
@ -12,6 +12,7 @@
|
||||
#define MAX_CHEAT_SIZE (2*64)
|
||||
|
||||
MelonDSAndroid::EmulatorConfiguration buildEmulatorConfiguration(JNIEnv* env, jobject emulatorConfiguration);
|
||||
MelonDSAndroid::FirmwareConfiguration buildFirmwareConfiguration(JNIEnv* env, jobject firmwareConfiguration);
|
||||
GPU::RenderSettings buildRenderSettings(JNIEnv* env, jobject renderSettings);
|
||||
void* emulate(void*);
|
||||
|
||||
@ -310,6 +311,7 @@ MelonDSAndroid::EmulatorConfiguration buildEmulatorConfiguration(JNIEnv* env, jo
|
||||
jclass consoleTypeEnumClass = env->FindClass("me/magnum/melonds/domain/model/ConsoleType");
|
||||
jclass micSourceEnumClass = env->FindClass("me/magnum/melonds/domain/model/MicSource");
|
||||
|
||||
jboolean useCustomBios = env->GetBooleanField(emulatorConfiguration, env->GetFieldID(emulatorConfigurationClass, "useCustomBios", "Z"));
|
||||
jstring dsConfigDir = (jstring) env->GetObjectField(emulatorConfiguration, env->GetFieldID(emulatorConfigurationClass, "dsConfigDirectory", "Ljava/lang/String;"));
|
||||
jstring dsiConfigDir = (jstring) env->GetObjectField(emulatorConfiguration, env->GetFieldID(emulatorConfigurationClass, "dsiConfigDirectory", "Ljava/lang/String;"));
|
||||
jfloat fastForwardMaxSpeed = env->GetFloatField(emulatorConfiguration, env->GetFieldID(emulatorConfigurationClass, "fastForwardSpeedMultiplier", "F"));
|
||||
@ -321,9 +323,11 @@ MelonDSAndroid::EmulatorConfiguration buildEmulatorConfiguration(JNIEnv* env, jo
|
||||
jint micSource = env->GetIntField(micSourceEnum, env->GetFieldID(micSourceEnumClass, "sourceValue", "I"));
|
||||
const char* dsDir = env->GetStringUTFChars(dsConfigDir, JNI_FALSE);
|
||||
const char* dsiDir = env->GetStringUTFChars(dsiConfigDir, JNI_FALSE);
|
||||
jobject firmwareConfigurationObject = env->GetObjectField(emulatorConfiguration, env->GetFieldID(emulatorConfigurationClass, "firmwareConfiguration", "Lme/magnum/melonds/domain/model/FirmwareConfiguration;"));
|
||||
jobject rendererConfigurationObject = env->GetObjectField(emulatorConfiguration, env->GetFieldID(emulatorConfigurationClass, "rendererConfiguration", "Lme/magnum/melonds/domain/model/RendererConfiguration;"));
|
||||
|
||||
MelonDSAndroid::EmulatorConfiguration finalEmulatorConfiguration;
|
||||
finalEmulatorConfiguration.userInternalFirmwareAndBios = !useCustomBios;
|
||||
finalEmulatorConfiguration.dsConfigDir = const_cast<char*>(dsDir);
|
||||
finalEmulatorConfiguration.dsiConfigDir = const_cast<char*>(dsiDir);
|
||||
finalEmulatorConfiguration.fastForwardSpeedMultiplier = fastForwardMaxSpeed;
|
||||
@ -331,10 +335,40 @@ MelonDSAndroid::EmulatorConfiguration buildEmulatorConfiguration(JNIEnv* env, jo
|
||||
finalEmulatorConfiguration.consoleType = consoleType;
|
||||
finalEmulatorConfiguration.soundEnabled = soundEnabled;
|
||||
finalEmulatorConfiguration.micSource = micSource;
|
||||
finalEmulatorConfiguration.firmwareConfiguration = buildFirmwareConfiguration(env, firmwareConfigurationObject);
|
||||
finalEmulatorConfiguration.renderSettings = buildRenderSettings(env, rendererConfigurationObject);
|
||||
return finalEmulatorConfiguration;
|
||||
}
|
||||
|
||||
MelonDSAndroid::FirmwareConfiguration buildFirmwareConfiguration(JNIEnv* env, jobject firmwareConfiguration) {
|
||||
jclass firmwareConfigurationClass = env->GetObjectClass(firmwareConfiguration);
|
||||
jstring nicknameString = (jstring) env->GetObjectField(firmwareConfiguration, env->GetFieldID(firmwareConfigurationClass, "nickname", "Ljava/lang/String;"));
|
||||
jstring messageString = (jstring) env->GetObjectField(firmwareConfiguration, env->GetFieldID(firmwareConfigurationClass, "message", "Ljava/lang/String;"));
|
||||
int language = env->GetIntField(firmwareConfiguration, env->GetFieldID(firmwareConfigurationClass, "language", "I"));
|
||||
int colour = env->GetIntField(firmwareConfiguration, env->GetFieldID(firmwareConfigurationClass, "favouriteColour", "I"));
|
||||
int birthdayDay = env->GetIntField(firmwareConfiguration, env->GetFieldID(firmwareConfigurationClass, "birthdayDay", "I"));
|
||||
int birthdayMonth = env->GetIntField(firmwareConfiguration, env->GetFieldID(firmwareConfigurationClass, "birthdayMonth", "I"));
|
||||
|
||||
jboolean isCopy = JNI_FALSE;
|
||||
const char* nickname = env->GetStringUTFChars(nicknameString, &isCopy);
|
||||
const char* message = env->GetStringUTFChars(messageString, &isCopy);
|
||||
|
||||
MelonDSAndroid::FirmwareConfiguration finalFirmwareConfiguration;
|
||||
strcpy(finalFirmwareConfiguration.username, nickname);
|
||||
strcpy(finalFirmwareConfiguration.message, message);
|
||||
finalFirmwareConfiguration.language = language;
|
||||
finalFirmwareConfiguration.favouriteColour = colour;
|
||||
finalFirmwareConfiguration.birthdayDay = birthdayDay;
|
||||
finalFirmwareConfiguration.birthdayMonth = birthdayMonth;
|
||||
|
||||
if (isCopy) {
|
||||
env->ReleaseStringUTFChars(nicknameString, nickname);
|
||||
env->ReleaseStringUTFChars(messageString, message);
|
||||
}
|
||||
|
||||
return finalFirmwareConfiguration;
|
||||
}
|
||||
|
||||
GPU::RenderSettings buildRenderSettings(JNIEnv* env, jobject renderSettings) {
|
||||
jclass renderSettingsClass = env->GetObjectClass(renderSettings);
|
||||
jboolean threadedRendering = env->GetBooleanField(renderSettings, env->GetFieldID(renderSettingsClass, "threadedRendering", "Z"));
|
||||
|
@ -1,6 +1,7 @@
|
||||
package me.magnum.melonds.domain.model
|
||||
|
||||
data class EmulatorConfiguration(
|
||||
val useCustomBios: Boolean,
|
||||
val dsConfigDirectory: String,
|
||||
val dsiConfigDirectory: String,
|
||||
val fastForwardSpeedMultiplier: Float,
|
||||
@ -8,5 +9,6 @@ data class EmulatorConfiguration(
|
||||
val consoleType: ConsoleType,
|
||||
val soundEnabled: Boolean,
|
||||
val micSource: MicSource,
|
||||
val firmwareConfiguration: FirmwareConfiguration,
|
||||
val rendererConfiguration: RendererConfiguration
|
||||
)
|
@ -0,0 +1,20 @@
|
||||
package me.magnum.melonds.domain.model
|
||||
|
||||
enum class FirmwareColour {
|
||||
GRAY,
|
||||
BROWN,
|
||||
RED,
|
||||
PINK,
|
||||
ORANGE,
|
||||
YELLOW,
|
||||
LIME,
|
||||
GREEN,
|
||||
DARK_GREEN,
|
||||
TURQUOISE,
|
||||
LIGHT_BLUE,
|
||||
BLUE,
|
||||
DARK_BLUE,
|
||||
PURPLE,
|
||||
VIOLET,
|
||||
FUCHSIA
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
package me.magnum.melonds.domain.model
|
||||
|
||||
data class FirmwareConfiguration(val nickname: String, val message: String, val language: Int, val favouriteColour: Int, val birthdayMonth: Int, val birthdayDay: Int)
|
@ -15,6 +15,8 @@ interface SettingsRepository {
|
||||
fun getRomIconFiltering(): RomIconFiltering
|
||||
|
||||
fun getDefaultConsoleType(): ConsoleType
|
||||
fun getFirmwareConfiguration(): FirmwareConfiguration
|
||||
fun useCustomBios(): Boolean
|
||||
fun getDsBiosDirectory(): Uri?
|
||||
fun getDsiBiosDirectory(): Uri?
|
||||
fun showBootScreen(): Boolean
|
||||
|
@ -43,11 +43,12 @@ class SharedPreferencesSettingsRepository(private val context: Context, private
|
||||
|
||||
override fun getEmulatorConfiguration(): EmulatorConfiguration {
|
||||
val consoleType = getDefaultConsoleType()
|
||||
val useCustomBios = useCustomBios()
|
||||
val dsBiosDirUri = getDsBiosDirectory()
|
||||
val dsiBiosDirUri = getDsiBiosDirectory()
|
||||
|
||||
// Ensure all BIOS dirs are set. DSi requires both dirs to be set
|
||||
if (dsBiosDirUri == null || (consoleType == ConsoleType.DSi && dsiBiosDirUri == null))
|
||||
if ((consoleType == ConsoleType.DS && useCustomBios && dsBiosDirUri == null) || (consoleType == ConsoleType.DSi && (dsBiosDirUri == null || dsiBiosDirUri == null)))
|
||||
throw IllegalStateException("BIOS directory not set")
|
||||
|
||||
val dsBiosDirPath = FileUtils.getAbsolutePathFromSAFUri(context, dsBiosDirUri)
|
||||
@ -56,6 +57,7 @@ class SharedPreferencesSettingsRepository(private val context: Context, private
|
||||
val dsiConfigDirectoryPath = "$dsiBiosDirPath/"
|
||||
|
||||
return EmulatorConfiguration(
|
||||
useCustomBios(),
|
||||
dsConfigDirectoryPath,
|
||||
dsiConfigDirectoryPath,
|
||||
getFastForwardSpeedMultiplier(),
|
||||
@ -63,6 +65,7 @@ class SharedPreferencesSettingsRepository(private val context: Context, private
|
||||
consoleType,
|
||||
isSoundEnabled(),
|
||||
getMicSource(),
|
||||
getFirmwareConfiguration(),
|
||||
RendererConfiguration(
|
||||
getVideoFiltering(),
|
||||
isThreadedRenderingEnabled()
|
||||
@ -95,6 +98,31 @@ class SharedPreferencesSettingsRepository(private val context: Context, private
|
||||
return enumValueOfIgnoreCase(consoleTypePreference)
|
||||
}
|
||||
|
||||
override fun getFirmwareConfiguration(): FirmwareConfiguration {
|
||||
val birthdayPreference = preferences.getString("firmware_settings_birthday", "01/01")!!
|
||||
val parts = birthdayPreference.split("/")
|
||||
val birthday = if (parts.size != 2) {
|
||||
Pair(1, 1)
|
||||
} else {
|
||||
val day = parts[0].toIntOrNull() ?: 1
|
||||
val month = parts[1].toIntOrNull() ?: 1
|
||||
Pair(day, month)
|
||||
}
|
||||
|
||||
return FirmwareConfiguration(
|
||||
preferences.getString("firmware_settings_nickname", "Player")!!,
|
||||
preferences.getString("firmware_settings_message", "Hello!")!!,
|
||||
preferences.getString("firmware_settings_language", "1")!!.toInt(),
|
||||
preferences.getInt("firmware_settings_colour", 0),
|
||||
birthday.first,
|
||||
birthday.second,
|
||||
)
|
||||
}
|
||||
|
||||
override fun useCustomBios(): Boolean {
|
||||
return preferences.getBoolean("use_custom_bios", false)
|
||||
}
|
||||
|
||||
override fun getDsBiosDirectory(): Uri? {
|
||||
val dirPreference = preferences.getStringSet("bios_dir", null)?.firstOrNull()
|
||||
return dirPreference?.let { Uri.parse(it) }
|
||||
|
@ -71,6 +71,7 @@ class EmulatorViewModel @ViewModelInject constructor(
|
||||
fun getEmulatorConfigurationForRom(rom: Rom): EmulatorConfiguration {
|
||||
val baseConfiguration = settingsRepository.getEmulatorConfiguration()
|
||||
return EmulatorConfiguration(
|
||||
baseConfiguration.useCustomBios,
|
||||
baseConfiguration.dsConfigDirectory,
|
||||
baseConfiguration.dsiConfigDirectory,
|
||||
baseConfiguration.fastForwardSpeedMultiplier,
|
||||
@ -78,6 +79,7 @@ class EmulatorViewModel @ViewModelInject constructor(
|
||||
getRomOptionOrDefault(rom.config.runtimeConsoleType, baseConfiguration.consoleType),
|
||||
baseConfiguration.soundEnabled,
|
||||
getRomOptionOrDefault(rom.config.runtimeMicSource, baseConfiguration.micSource),
|
||||
baseConfiguration.firmwareConfiguration,
|
||||
baseConfiguration.rendererConfiguration
|
||||
)
|
||||
}
|
||||
|
@ -74,11 +74,6 @@ class RomListActivity : AppCompatActivity() {
|
||||
})
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
checkConfigDirectorySetup()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
if (menu == null)
|
||||
return super.onCreateOptionsMenu(menu)
|
||||
|
@ -148,6 +148,10 @@ class RomListViewModel @ViewModelInject constructor(
|
||||
|
||||
fun getRomConfigurationDirStatus(rom: Rom): ConfigurationUtils.ConfigurationDirStatus {
|
||||
val romTargetConsoleType = getRomTargetConsoleType(rom)
|
||||
if (romTargetConsoleType == ConsoleType.DS && !settingsRepository.useCustomBios()) {
|
||||
return ConfigurationUtils.ConfigurationDirStatus.VALID
|
||||
}
|
||||
|
||||
return getConsoleConfigurationDirStatus(romTargetConsoleType)
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,73 @@
|
||||
package me.magnum.melonds.ui.settings
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import me.magnum.melonds.R
|
||||
import me.magnum.melonds.ui.settings.preferences.FirmwareBirthdayPreference
|
||||
import me.magnum.melonds.ui.settings.preferences.StoragePickerPreference
|
||||
import me.magnum.melonds.utils.FileUtils
|
||||
|
||||
abstract class BasePreferencesFragment : PreferenceFragmentCompat() {
|
||||
protected companion object {
|
||||
private val sBindPreferenceSummaryToValueListener = Preference.OnPreferenceChangeListener { preference, value ->
|
||||
when (preference) {
|
||||
is ListPreference -> {
|
||||
// For list preferences, look up the correct display value in
|
||||
// the preference's 'entries' list.
|
||||
val index = preference.findIndexOfValue(value.toString())
|
||||
|
||||
// Set the summary to reflect the new value.
|
||||
val summary = if (index >= 0)
|
||||
preference.entries[index]
|
||||
else
|
||||
preference.getContext().getString(R.string.not_set)
|
||||
preference.setSummary(summary)
|
||||
}
|
||||
is StoragePickerPreference -> {
|
||||
if (value == null || value !is Set<*> || value.isEmpty())
|
||||
preference.summary = preference.getContext().getString(R.string.not_set)
|
||||
else {
|
||||
val uris = value.mapNotNull { FileUtils.getAbsolutePathFromSAFUri(preference.context, Uri.parse(it as String)) }
|
||||
preference.summary = uris.joinToString("\n")
|
||||
}
|
||||
}
|
||||
is FirmwareBirthdayPreference -> {
|
||||
val birthdayString = (value as String?) ?: "01/01"
|
||||
preference.summary = birthdayString
|
||||
}
|
||||
else -> {
|
||||
// For all other preferences, set the summary to the value's
|
||||
// simple string representation.
|
||||
preference.summary = value.toString()
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fun bindPreferenceSummaryToValue(preference: Preference?) {
|
||||
if (preference == null)
|
||||
return
|
||||
|
||||
// Set the listener to watch for value changes.
|
||||
preference.onPreferenceChangeListener = sBindPreferenceSummaryToValueListener
|
||||
|
||||
// Trigger the listener immediately with the preference's
|
||||
// current value. Special handling for directory pickers since sets can't be converted
|
||||
// to string
|
||||
if (preference is StoragePickerPreference) {
|
||||
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
|
||||
PreferenceManager.getDefaultSharedPreferences(preference.context)
|
||||
.getStringSet(preference.key, null))
|
||||
} else {
|
||||
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
|
||||
PreferenceManager.getDefaultSharedPreferences(preference.context)
|
||||
.getString(preference.key, null))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun getTitle(): String
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package me.magnum.melonds.ui.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import me.magnum.melonds.R
|
||||
|
||||
class FirmwarePreferencesFragment : BasePreferencesFragment() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.pref_firmware_user_settings, rootKey)
|
||||
bindPreferenceSummaryToValue(findPreference("firmware_settings_birthday"))
|
||||
}
|
||||
|
||||
override fun getTitle(): String {
|
||||
return getString(R.string.firmware_user_settings)
|
||||
}
|
||||
}
|
@ -22,61 +22,7 @@ import java.math.RoundingMode
|
||||
import java.util.*
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainPreferencesFragment : PreferenceFragmentCompat() {
|
||||
private companion object {
|
||||
val sBindPreferenceSummaryToValueListener = Preference.OnPreferenceChangeListener { preference, value ->
|
||||
when (preference) {
|
||||
is ListPreference -> {
|
||||
// For list preferences, look up the correct display value in
|
||||
// the preference's 'entries' list.
|
||||
val index = preference.findIndexOfValue(value.toString())
|
||||
|
||||
// Set the summary to reflect the new value.
|
||||
val summary = if (index >= 0)
|
||||
preference.entries[index]
|
||||
else
|
||||
preference.getContext().getString(R.string.not_set)
|
||||
preference.setSummary(summary)
|
||||
}
|
||||
is StoragePickerPreference -> {
|
||||
if (value == null || value !is Set<*> || value.isEmpty())
|
||||
preference.summary = preference.getContext().getString(R.string.not_set)
|
||||
else {
|
||||
val uris = value.mapNotNull { FileUtils.getAbsolutePathFromSAFUri(preference.context, Uri.parse(it as String)) }
|
||||
preference.summary = uris.joinToString("\n")
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
// For all other preferences, set the summary to the value's
|
||||
// simple string representation.
|
||||
preference.summary = value.toString()
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fun bindPreferenceSummaryToValue(preference: Preference?) {
|
||||
if (preference == null)
|
||||
return
|
||||
|
||||
// Set the listener to watch for value changes.
|
||||
preference.onPreferenceChangeListener = sBindPreferenceSummaryToValueListener
|
||||
|
||||
// Trigger the listener immediately with the preference's
|
||||
// current value. Special handling for directory pickers since sets can't be converted
|
||||
// to string
|
||||
if (preference is StoragePickerPreference) {
|
||||
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
|
||||
PreferenceManager.getDefaultSharedPreferences(preference.context)
|
||||
.getStringSet(preference.key, null))
|
||||
} else {
|
||||
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
|
||||
PreferenceManager.getDefaultSharedPreferences(preference.context)
|
||||
.getString(preference.key, null))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MainPreferencesFragment : BasePreferencesFragment() {
|
||||
private val viewModel: SettingsViewModel by activityViewModels()
|
||||
|
||||
private lateinit var clearRomCachePreference: Preference
|
||||
@ -89,9 +35,13 @@ class MainPreferencesFragment : PreferenceFragmentCompat() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun getTitle(): String {
|
||||
return getString(R.string.settings)
|
||||
}
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.pref_main, rootKey)
|
||||
clearRomCachePreference = findPreference<Preference>("rom_cache_clear")!!
|
||||
clearRomCachePreference = findPreference("rom_cache_clear")!!
|
||||
val consoleTypePreference = findPreference<ListPreference>("console_type")!!
|
||||
val dsBiosDirPreference = findPreference<StoragePickerPreference>("bios_dir")!!
|
||||
val dsiBiosDirPreference = findPreference<StoragePickerPreference>("dsi_bios_dir")!!
|
||||
|
@ -10,6 +10,14 @@ class SettingsActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setupActionBar()
|
||||
|
||||
supportFragmentManager.addOnBackStackChangedListener {
|
||||
val fragment = supportFragmentManager.fragments.lastOrNull()
|
||||
if (fragment is BasePreferencesFragment) {
|
||||
supportActionBar?.title = fragment.getTitle()
|
||||
}
|
||||
}
|
||||
|
||||
supportFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(android.R.id.content, MainPreferencesFragment())
|
||||
@ -24,11 +32,19 @@ class SettingsActivity : AppCompatActivity() {
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
val id = item.itemId
|
||||
if (id == android.R.id.home) {
|
||||
if (!super.onOptionsItemSelected(item)) {
|
||||
if (!popBackStackIfNeeded()) {
|
||||
finish()
|
||||
}
|
||||
return true
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
private fun popBackStackIfNeeded(): Boolean {
|
||||
if (supportFragmentManager.backStackEntryCount > 0) {
|
||||
supportFragmentManager.popBackStack()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
@ -8,7 +8,9 @@ import android.view.View
|
||||
import android.widget.ImageView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.res.getIntOrThrow
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.widget.ImageViewCompat
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceViewHolder
|
||||
import me.magnum.melonds.R
|
||||
import me.magnum.melonds.domain.model.ConsoleType
|
||||
@ -21,8 +23,8 @@ class BiosDirectoryPickerPreference(context: Context?, attrs: AttributeSet?) : S
|
||||
selectionType = SelectionType.DIRECTORY
|
||||
}
|
||||
|
||||
lateinit var consoleType: ConsoleType
|
||||
lateinit var imageViewStatus: ImageView
|
||||
private var consoleType: ConsoleType? = null
|
||||
private var imageViewStatus: ImageView? = null
|
||||
|
||||
override fun onDirectoryPicked(uri: Uri?) {
|
||||
super.onDirectoryPicked(uri)
|
||||
@ -33,25 +35,37 @@ class BiosDirectoryPickerPreference(context: Context?, attrs: AttributeSet?) : S
|
||||
updateStatusIndicator(uri)
|
||||
}
|
||||
|
||||
override fun onDependencyChanged(dependency: Preference?, disableDependent: Boolean) {
|
||||
super.onDependencyChanged(dependency, disableDependent)
|
||||
imageViewStatus?.isGone = disableDependent
|
||||
}
|
||||
|
||||
private fun updateStatusIndicator(uri: Uri?) {
|
||||
val dirResult = ConfigurationUtils.checkConfigurationDirectory(context, uri, consoleType)
|
||||
if (!isEnabled) {
|
||||
imageViewStatus?.isGone = true
|
||||
return
|
||||
}
|
||||
|
||||
imageViewStatus?.isGone = false
|
||||
|
||||
val dirResult = ConfigurationUtils.checkConfigurationDirectory(context, uri, consoleType!!)
|
||||
when (dirResult.status) {
|
||||
ConfigurationUtils.ConfigurationDirStatus.VALID -> {
|
||||
(imageViewStatus.parent as View).visibility = View.GONE
|
||||
(imageViewStatus!!.parent as View).visibility = View.GONE
|
||||
}
|
||||
ConfigurationUtils.ConfigurationDirStatus.INVALID -> {
|
||||
(imageViewStatus.parent as View).visibility = View.VISIBLE
|
||||
imageViewStatus.setImageResource(R.drawable.ic_status_warn)
|
||||
ImageViewCompat.setImageTintList(imageViewStatus, ColorStateList.valueOf(ContextCompat.getColor(context, R.color.statusWarn)))
|
||||
(imageViewStatus!!.parent as View).visibility = View.VISIBLE
|
||||
imageViewStatus!!.setImageResource(R.drawable.ic_status_warn)
|
||||
ImageViewCompat.setImageTintList(imageViewStatus!!, ColorStateList.valueOf(ContextCompat.getColor(context, R.color.statusWarn)))
|
||||
}
|
||||
ConfigurationUtils.ConfigurationDirStatus.UNSET ->{
|
||||
(imageViewStatus.parent as View).visibility = View.VISIBLE
|
||||
imageViewStatus.setImageResource(R.drawable.ic_status_error)
|
||||
ImageViewCompat.setImageTintList(imageViewStatus, ColorStateList.valueOf(ContextCompat.getColor(context, R.color.statusError)))
|
||||
(imageViewStatus!!.parent as View).visibility = View.VISIBLE
|
||||
imageViewStatus!!.setImageResource(R.drawable.ic_status_error)
|
||||
ImageViewCompat.setImageTintList(imageViewStatus!!, ColorStateList.valueOf(ContextCompat.getColor(context, R.color.statusError)))
|
||||
}
|
||||
}
|
||||
imageViewStatus.setOnClickListener {
|
||||
FileStatusPopup(context, dirResult.fileResults).showAt(imageViewStatus)
|
||||
imageViewStatus!!.setOnClickListener {
|
||||
FileStatusPopup(context, dirResult.fileResults).showAt(imageViewStatus!!)
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,13 +74,8 @@ class BiosDirectoryPickerPreference(context: Context?, attrs: AttributeSet?) : S
|
||||
return
|
||||
|
||||
val attrArray = context.theme.obtainStyledAttributes(attrs, R.styleable.BiosDirectoryPickerPreference, 0, 0)
|
||||
val count = attrArray.indexCount
|
||||
for (i in 0..count) {
|
||||
val attr = attrArray.getIndex(i)
|
||||
when (attr) {
|
||||
R.styleable.BiosDirectoryPickerPreference_consoleType -> consoleType = ConsoleType.values()[attrArray.getIntOrThrow(attr)]
|
||||
}
|
||||
}
|
||||
consoleType = ConsoleType.values()[attrArray.getIntOrThrow(R.styleable.BiosDirectoryPickerPreference_consoleType)]
|
||||
|
||||
attrArray.recycle()
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,127 @@
|
||||
package me.magnum.melonds.ui.settings.preferences
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.preference.Preference
|
||||
import me.magnum.melonds.R
|
||||
import me.magnum.melonds.databinding.DialogFirmwareBirthdayBinding
|
||||
import java.text.NumberFormat
|
||||
|
||||
class FirmwareBirthdayPreference(context: Context?, attrs: AttributeSet?) : Preference(context, attrs) {
|
||||
companion object {
|
||||
private val daysInMonth = mapOf(
|
||||
1 to 31,
|
||||
2 to 29,
|
||||
3 to 31,
|
||||
4 to 30,
|
||||
5 to 31,
|
||||
6 to 30,
|
||||
7 to 31,
|
||||
8 to 31,
|
||||
9 to 30,
|
||||
10 to 31,
|
||||
11 to 30,
|
||||
12 to 31
|
||||
)
|
||||
|
||||
private val numberFormat = NumberFormat.getNumberInstance().apply {
|
||||
minimumIntegerDigits = 2
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick() {
|
||||
super.onClick()
|
||||
val binding = DialogFirmwareBirthdayBinding.inflate(LayoutInflater.from(context))
|
||||
|
||||
AlertDialog.Builder(context)
|
||||
.setTitle(title)
|
||||
.setView(binding.root)
|
||||
.setPositiveButton(R.string.ok) { dialog, _ ->
|
||||
val day = binding.textBirthdayDay.text.toString().toInt()
|
||||
val month = binding.textBirthdayMonth.text.toString().toInt()
|
||||
val birthday = "${numberFormat.format(day)}/${numberFormat.format(month)}"
|
||||
if (callChangeListener(birthday)) {
|
||||
persistString(birthday)
|
||||
}
|
||||
dialog.dismiss()
|
||||
}
|
||||
.setNegativeButton(R.string.cancel) { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
}
|
||||
.show()
|
||||
|
||||
val currentBirthday = getPersistedString("01/01")
|
||||
val parts = currentBirthday.split("/")
|
||||
if (parts.size != 2) {
|
||||
setNumberFormatted(binding.textBirthdayDay, 1)
|
||||
setNumberFormatted(binding.textBirthdayMonth, 1)
|
||||
} else {
|
||||
setNumberFormatted(binding.textBirthdayDay, parts[0].toIntOrNull() ?: 1)
|
||||
setNumberFormatted(binding.textBirthdayMonth, parts[1].toIntOrNull() ?: 1)
|
||||
}
|
||||
|
||||
binding.buttonBirthdayDayIncrease.setOnClickListener {
|
||||
val day = binding.textBirthdayDay.text.toString().toIntOrNull() ?: 0
|
||||
val month = binding.textBirthdayMonth.text.toString().toIntOrNull() ?: 1
|
||||
val newDay = coerceDayForMonth(day + 1, month, true)
|
||||
setNumberFormatted(binding.textBirthdayDay, newDay)
|
||||
}
|
||||
binding.buttonBirthdayDayDecrease.setOnClickListener {
|
||||
val day = binding.textBirthdayDay.text.toString().toIntOrNull() ?: 2
|
||||
val month = binding.textBirthdayMonth.text.toString().toIntOrNull() ?: 1
|
||||
val newDay = coerceDayForMonth(day - 1, month, true)
|
||||
setNumberFormatted(binding.textBirthdayDay, newDay)
|
||||
}
|
||||
binding.buttonBirthdayMonthIncrease.setOnClickListener {
|
||||
val day = binding.textBirthdayDay.text.toString().toIntOrNull() ?: 1
|
||||
val month = binding.textBirthdayMonth.text.toString().toIntOrNull() ?: 0
|
||||
val newMonth = coerceMonth(month + 1)
|
||||
val newDay = coerceDayForMonth(day, newMonth, false)
|
||||
|
||||
setNumberFormatted(binding.textBirthdayMonth, newMonth)
|
||||
if (newDay != day) {
|
||||
setNumberFormatted(binding.textBirthdayDay, newDay)
|
||||
}
|
||||
}
|
||||
binding.buttonBirthdayMonthDecrease.setOnClickListener {
|
||||
val day = binding.textBirthdayDay.text.toString().toIntOrNull() ?: 1
|
||||
val month = binding.textBirthdayMonth.text.toString().toIntOrNull() ?: 2
|
||||
val newMonth = coerceMonth(month - 1)
|
||||
val newDay = coerceDayForMonth(day, newMonth, false)
|
||||
|
||||
setNumberFormatted(binding.textBirthdayMonth, newMonth)
|
||||
if (newDay != day) {
|
||||
setNumberFormatted(binding.textBirthdayDay, newDay)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun coerceDayForMonth(day: Int, month: Int, loop: Boolean): Int {
|
||||
val daysInMonth = daysInMonth[month] ?: 1
|
||||
return if (loop) {
|
||||
when {
|
||||
day > daysInMonth -> 1
|
||||
day < 1 -> daysInMonth
|
||||
else -> day
|
||||
}
|
||||
} else {
|
||||
day.coerceIn(1, daysInMonth)
|
||||
}
|
||||
}
|
||||
|
||||
private fun coerceMonth(month: Int): Int {
|
||||
return when {
|
||||
month < 1 -> 12
|
||||
month > 12 -> 1
|
||||
else -> month
|
||||
}
|
||||
}
|
||||
|
||||
private fun setNumberFormatted(view: TextView, value: Int) {
|
||||
val formattedValue = numberFormat.format(value)
|
||||
view.text = formattedValue.toString()
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package me.magnum.melonds.ui.settings.preferences
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.children
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceViewHolder
|
||||
import me.magnum.melonds.R
|
||||
import me.magnum.melonds.databinding.DialogFirmwareColourPickerBinding
|
||||
import me.magnum.melonds.domain.model.FirmwareColour
|
||||
|
||||
class FirmwareColourPickerPreference(context: Context?, attrs: AttributeSet?) : Preference(context, attrs) {
|
||||
companion object {
|
||||
private val colorMapper = mapOf(
|
||||
FirmwareColour.GRAY to 0x61829A,
|
||||
FirmwareColour.BROWN to 0xBA4900,
|
||||
FirmwareColour.RED to 0xFB0018,
|
||||
FirmwareColour.PINK to 0xFB8AFB,
|
||||
FirmwareColour.ORANGE to 0xFB9200,
|
||||
FirmwareColour.YELLOW to 0xF3E300,
|
||||
FirmwareColour.LIME to 0xAAFB00,
|
||||
FirmwareColour.GREEN to 0x00FB00,
|
||||
FirmwareColour.DARK_GREEN to 0x00A238,
|
||||
FirmwareColour.TURQUOISE to 0x49DB8A,
|
||||
FirmwareColour.LIGHT_BLUE to 0x30BAF3,
|
||||
FirmwareColour.BLUE to 0x0059F3,
|
||||
FirmwareColour.DARK_BLUE to 0x000092,
|
||||
FirmwareColour.PURPLE to 0x8A00D3,
|
||||
FirmwareColour.VIOLET to 0xD300EB,
|
||||
FirmwareColour.FUCHSIA to 0xFB0092
|
||||
)
|
||||
}
|
||||
|
||||
private lateinit var viewSelectedColour: View
|
||||
|
||||
init {
|
||||
widgetLayoutResource = R.layout.preference_firmware_colour_picker_colour
|
||||
}
|
||||
|
||||
override fun onClick() {
|
||||
super.onClick()
|
||||
|
||||
val binding = DialogFirmwareColourPickerBinding.inflate(LayoutInflater.from(context))
|
||||
|
||||
val alertDialog = AlertDialog.Builder(context)
|
||||
.setTitle(title)
|
||||
.setView(binding.root)
|
||||
.setNegativeButton(R.string.cancel) { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
}
|
||||
.show()
|
||||
|
||||
binding.layoutGridColours.children.flatMap { (it as ViewGroup).children }.forEach {
|
||||
it.setOnClickListener { view ->
|
||||
val selectedColour = (view.tag as String).toInt()
|
||||
updateSelectedColour(selectedColour)
|
||||
if (callChangeListener(selectedColour)) {
|
||||
persistInt(selectedColour)
|
||||
}
|
||||
alertDialog.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSelectedColour(selectedColour: Int) {
|
||||
val firmwareColour = FirmwareColour.values()[selectedColour]
|
||||
colorMapper[firmwareColour]?.let {
|
||||
val colourWithAlpha = (0xFF000000 or it.toLong())
|
||||
viewSelectedColour.setBackgroundColor(colourWithAlpha.toInt())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: PreferenceViewHolder?) {
|
||||
super.onBindViewHolder(holder)
|
||||
if (holder != null) {
|
||||
viewSelectedColour = holder.findViewById(R.id.viewSelectedColour)
|
||||
updateSelectedColour(getPersistedInt(0))
|
||||
}
|
||||
}
|
||||
}
|
98
app/src/main/res/layout/dialog_firmware_birthday.xml
Normal file
98
app/src/main/res/layout/dialog_firmware_birthday.xml
Normal file
@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingStart="?attr/dialogPreferredPadding"
|
||||
android:paddingEnd="?attr/dialogPreferredPadding">
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonBirthdayDayIncrease"
|
||||
android:layout_width="50sp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/symbol_increase"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/buttonBirthdayMonthIncrease"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textBirthdayDay"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:gravity="center_horizontal"
|
||||
app:layout_constraintEnd_toEndOf="@+id/buttonBirthdayDayIncrease"
|
||||
app:layout_constraintStart_toStartOf="@+id/buttonBirthdayDayIncrease"
|
||||
app:layout_constraintTop_toBottomOf="@+id/buttonBirthdayDayIncrease"
|
||||
tools:text="31" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonBirthdayDayDecrease"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/symbol_decrease"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="@+id/textBirthdayDay"
|
||||
app:layout_constraintStart_toStartOf="@+id/textBirthdayDay"
|
||||
app:layout_constraintTop_toBottomOf="@+id/textBirthdayDay" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/day"
|
||||
app:layout_constraintEnd_toEndOf="@id/buttonBirthdayDayDecrease"
|
||||
app:layout_constraintStart_toStartOf="@+id/buttonBirthdayDayDecrease"
|
||||
app:layout_constraintTop_toBottomOf="@+id/buttonBirthdayDayDecrease" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonBirthdayMonthIncrease"
|
||||
android:layout_width="50sp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/symbol_increase"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/buttonBirthdayDayIncrease"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textBirthdayMonth"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:gravity="center_horizontal"
|
||||
app:layout_constraintEnd_toEndOf="@+id/buttonBirthdayMonthIncrease"
|
||||
app:layout_constraintStart_toStartOf="@+id/buttonBirthdayMonthIncrease"
|
||||
app:layout_constraintTop_toBottomOf="@+id/buttonBirthdayMonthIncrease"
|
||||
tools:text="12" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonBirthdayMonthDecrease"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/symbol_decrease"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="@+id/textBirthdayMonth"
|
||||
app:layout_constraintStart_toStartOf="@+id/textBirthdayMonth"
|
||||
app:layout_constraintTop_toBottomOf="@+id/textBirthdayMonth" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/month"
|
||||
app:layout_constraintEnd_toEndOf="@id/buttonBirthdayMonthDecrease"
|
||||
app:layout_constraintStart_toStartOf="@+id/buttonBirthdayMonthDecrease"
|
||||
app:layout_constraintTop_toBottomOf="@+id/buttonBirthdayMonthDecrease" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
163
app/src/main/res/layout/dialog_firmware_colour_picker.xml
Normal file
163
app/src/main/res/layout/dialog_firmware_colour_picker.xml
Normal file
@ -0,0 +1,163 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingStart="?attr/dialogPreferredPadding"
|
||||
android:paddingEnd="?attr/dialogPreferredPadding"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/layoutGridColours"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layoutColourRow0"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toTopOf="@+id/layoutColourRow1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<View
|
||||
android:id="@+id/viewColour00"
|
||||
style="@style/ColourTile"
|
||||
android:background="#61829A"
|
||||
android:tag="0" />
|
||||
|
||||
<View
|
||||
android:id="@+id/viewColour01"
|
||||
style="@style/ColourTile"
|
||||
android:background="#BA4900"
|
||||
android:tag="1" />
|
||||
|
||||
<View
|
||||
android:id="@+id/viewColour02"
|
||||
style="@style/ColourTile"
|
||||
android:background="#FB0018"
|
||||
android:tag="2" />
|
||||
|
||||
<View
|
||||
android:id="@+id/viewColour03"
|
||||
style="@style/ColourTile"
|
||||
android:background="#FB8AFB"
|
||||
android:tag="3" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layoutColourRow1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/layoutColourRow2"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/layoutColourRow0">
|
||||
|
||||
<View
|
||||
android:id="@+id/viewColour10"
|
||||
style="@style/ColourTile"
|
||||
android:background="#FB9200"
|
||||
android:tag="4" />
|
||||
|
||||
<View
|
||||
android:id="@+id/viewColour11"
|
||||
style="@style/ColourTile"
|
||||
android:background="#F3E300"
|
||||
android:tag="5" />
|
||||
|
||||
<View
|
||||
android:id="@+id/viewColour12"
|
||||
style="@style/ColourTile"
|
||||
android:background="#AAFB00"
|
||||
android:tag="6" />
|
||||
|
||||
<View
|
||||
android:id="@+id/viewColour13"
|
||||
style="@style/ColourTile"
|
||||
android:background="#00FB00"
|
||||
android:tag="7" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layoutColourRow2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/layoutColourRow3"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/layoutColourRow1">
|
||||
|
||||
<View
|
||||
android:id="@+id/viewColour20"
|
||||
style="@style/ColourTile"
|
||||
android:background="#00A238"
|
||||
android:tag="8"
|
||||
app:layout_constraintBottom_toTopOf="@+id/viewColour30"
|
||||
app:layout_constraintEnd_toStartOf="@+id/viewColour21" />
|
||||
|
||||
<View
|
||||
android:id="@+id/viewColour21"
|
||||
style="@style/ColourTile"
|
||||
android:background="#49DB8A"
|
||||
android:tag="9" />
|
||||
|
||||
<View
|
||||
android:id="@+id/viewColour22"
|
||||
style="@style/ColourTile"
|
||||
android:background="#30BAF3"
|
||||
android:tag="10" />
|
||||
|
||||
<View
|
||||
android:id="@+id/viewColour23"
|
||||
style="@style/ColourTile"
|
||||
android:background="#0059F3"
|
||||
android:tag="11" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layoutColourRow3"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/layoutColourRow2">
|
||||
|
||||
<View
|
||||
android:id="@+id/viewColour30"
|
||||
style="@style/ColourTile"
|
||||
android:background="#000092"
|
||||
android:tag="12" />
|
||||
|
||||
<View
|
||||
android:id="@+id/viewColour31"
|
||||
style="@style/ColourTile"
|
||||
android:background="#8A00D3"
|
||||
android:tag="13" />
|
||||
|
||||
<View
|
||||
android:id="@+id/viewColour32"
|
||||
style="@style/ColourTile"
|
||||
android:background="#D300EB"
|
||||
android:tag="14" />
|
||||
|
||||
<View
|
||||
android:id="@+id/viewColour33"
|
||||
style="@style/ColourTile"
|
||||
android:background="#FB0092"
|
||||
android:tag="15" />
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<View
|
||||
android:id="@+id/viewSelectedColour"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_gravity="center"
|
||||
tools:background="#FB9200"/>
|
||||
</LinearLayout>
|
@ -10,6 +10,15 @@
|
||||
<item>dsi</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="firmware_settings_language_values">
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
<item>5</item>
|
||||
<item>0</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="video_filtering_values">
|
||||
<item>none</item>
|
||||
<item>linear</item>
|
||||
|
@ -67,6 +67,10 @@
|
||||
<string name="cache_size_calculating">Cache size: calculating…</string>
|
||||
<string name="rom_search_directories">Search directories</string>
|
||||
<string name="console_type">Default system</string>
|
||||
<string name="firmware_user_settings">Firmware user settings</string>
|
||||
<string name="firmware_user_settings_summary">Adjust the user settings of the internal firmware</string>
|
||||
<string name="use_custom_bios_firmware">Use custom BIOS and firmware</string>
|
||||
<string name="use_custom_bios_firmware_summary">Using a custom BIOS and firmware allows you to enter the DS\'s boot screen, just like in a real system.</string>
|
||||
<string name="bios_directory">DS BIOS directory</string>
|
||||
<string name="dsi_bios_directory">DSi BIOS directory</string>
|
||||
<string name="show_boot_screen">Show boot screen</string>
|
||||
@ -95,11 +99,21 @@
|
||||
<string name="import_cheats_summary">Import cheats from database files to make them available. Only XML databases are supported for now. Any previously imported cheat will be deleted.</string>
|
||||
<string name="rom_shortcut">ROM shortcut</string>
|
||||
|
||||
<string name="firmware_nickname">Nickname</string>
|
||||
<string name="firmware_message">Message</string>
|
||||
<string name="firmware_language">Language</string>
|
||||
<string name="firmware_favourite_colour">Favourite colour</string>
|
||||
<string name="firmware_birthday">Birthday</string>
|
||||
|
||||
<string name="error_clear_rom_cache">Failed to clear ROM cache</string>
|
||||
<string name="importing_cheats">Importing cheats…</string>
|
||||
<string name="starting">Starting…</string>
|
||||
<string name="failed_save_cheat_changes">Could not save cheat changes</string>
|
||||
<string name="no_cheats_found">Could not find cheats for the current ROM. Try importing a different cheat database.</string>
|
||||
<string name="day">Day</string>
|
||||
<string name="month">Month</string>
|
||||
<string name="symbol_increase">+</string>
|
||||
<string name="symbol_decrease">-</string>
|
||||
|
||||
<string name="rom_settings">Rom settings</string> <!-- Accessibility string. Should not use acronyms -->
|
||||
<string name="label_rom_config_console">Boot system</string>
|
||||
@ -155,6 +169,15 @@
|
||||
<item>@string/console_dsi</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="firmware_settings_language_options">
|
||||
<item>English</item>
|
||||
<item>French</item>
|
||||
<item>German</item>
|
||||
<item>Italian</item>
|
||||
<item>Spanish</item>
|
||||
<item>Japanese</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="game_runtime_mic_source_options">
|
||||
<item>Default</item>
|
||||
<item>None</item>
|
||||
|
@ -75,4 +75,14 @@
|
||||
<item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
|
||||
<item name="android:textColor">?android:attr/textColorSecondary</item>
|
||||
</style>
|
||||
|
||||
<style name="ColourTile">
|
||||
<item name="android:layout_width">0dp</item>
|
||||
<item name="android:layout_height">match_parent</item>
|
||||
<item name="android:layout_margin">16dp</item>
|
||||
<item name="android:layout_weight">1</item>
|
||||
<item name="android:gravity">center</item>
|
||||
<item name="android:clickable">true</item>
|
||||
<item name="android:focusable">true</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
36
app/src/main/res/xml/pref_firmware_user_settings.xml
Normal file
36
app/src/main/res/xml/pref_firmware_user_settings.xml
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<EditTextPreference
|
||||
android:key="firmware_settings_nickname"
|
||||
android:title="@string/firmware_nickname"
|
||||
android:summary="%s"
|
||||
app:useSimpleSummaryProvider="true"
|
||||
android:defaultValue="Player" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="firmware_settings_message"
|
||||
android:title="@string/firmware_message"
|
||||
android:summary="%s"
|
||||
app:useSimpleSummaryProvider="true"
|
||||
android:defaultValue="Hello!" />
|
||||
|
||||
<ListPreference
|
||||
android:key="firmware_settings_language"
|
||||
android:title="@string/firmware_language"
|
||||
android:summary="%s"
|
||||
android:entries="@array/firmware_settings_language_options"
|
||||
android:entryValues="@array/firmware_settings_language_values"
|
||||
android:defaultValue="1" />
|
||||
|
||||
<me.magnum.melonds.ui.settings.preferences.FirmwareColourPickerPreference
|
||||
android:key="firmware_settings_colour"
|
||||
android:title="@string/firmware_favourite_colour" />
|
||||
|
||||
<me.magnum.melonds.ui.settings.preferences.FirmwareBirthdayPreference
|
||||
android:key="firmware_settings_birthday"
|
||||
android:title="@string/firmware_birthday"
|
||||
android:defaultValue="01/01" />
|
||||
</PreferenceScreen>
|
@ -57,9 +57,28 @@
|
||||
android:entryValues="@array/console_type_values"
|
||||
android:defaultValue="ds" />
|
||||
|
||||
<Preference
|
||||
android:key="firmware_user_settings"
|
||||
android:title="@string/firmware_user_settings"
|
||||
android:summary="@string/firmware_user_settings_summary"
|
||||
android:fragment="me.magnum.melonds.ui.settings.FirmwarePreferencesFragment" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="use_custom_bios"
|
||||
android:title="@string/use_custom_bios_firmware"
|
||||
android:summary="@string/use_custom_bios_firmware_summary"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="show_bios"
|
||||
android:title="@string/show_boot_screen"
|
||||
android:dependency="use_custom_bios"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<me.magnum.melonds.ui.settings.preferences.BiosDirectoryPickerPreference
|
||||
android:key="bios_dir"
|
||||
android:title="@string/bios_directory"
|
||||
android:dependency="use_custom_bios"
|
||||
app:consoleType="ds" />
|
||||
|
||||
<me.magnum.melonds.ui.settings.preferences.BiosDirectoryPickerPreference
|
||||
@ -67,11 +86,6 @@
|
||||
android:title="@string/dsi_bios_directory"
|
||||
app:consoleType="dsi" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="show_bios"
|
||||
android:title="@string/show_boot_screen"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="enable_jit"
|
||||
android:title="@string/enable_jit"
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit f29e1920bd8f58031ec1521750db9b44d0355148
|
||||
Subproject commit 149a551669d81d6c350fb23df6ebb0c647d138b0
|
Loading…
Reference in New Issue
Block a user