mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-04-10 03:18:55 +02:00
[android,ui] fix delete buttons available for external content
This commit is contained in:
parent
9423a33fc2
commit
f1463a8e41
6 changed files with 92 additions and 36 deletions
|
|
@ -40,11 +40,21 @@ class AddonAdapter(val addonViewModel: AddonViewModel) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val deleteAction = {
|
val canDelete = model.isRemovable
|
||||||
addonViewModel.setAddonToDelete(model)
|
binding.deleteCard.isEnabled = canDelete
|
||||||
|
binding.buttonDelete.isEnabled = canDelete
|
||||||
|
binding.deleteCard.alpha = if (canDelete) 1f else 0.38f
|
||||||
|
|
||||||
|
if (canDelete) {
|
||||||
|
val deleteAction = {
|
||||||
|
addonViewModel.setAddonToDelete(model)
|
||||||
|
}
|
||||||
|
binding.deleteCard.setOnClickListener { deleteAction() }
|
||||||
|
binding.buttonDelete.setOnClickListener { deleteAction() }
|
||||||
|
} else {
|
||||||
|
binding.deleteCard.setOnClickListener(null)
|
||||||
|
binding.buttonDelete.setOnClickListener(null)
|
||||||
}
|
}
|
||||||
binding.deleteCard.setOnClickListener { deleteAction() }
|
|
||||||
binding.buttonDelete.setOnClickListener { deleteAction() }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,5 +16,17 @@ data class Patch(
|
||||||
val type: Int,
|
val type: Int,
|
||||||
val programId: String,
|
val programId: String,
|
||||||
val titleId: String,
|
val titleId: String,
|
||||||
val numericVersion: Long = 0
|
val numericVersion: Long = 0,
|
||||||
)
|
val source: Int = 0
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
const val SOURCE_UNKNOWN = 0
|
||||||
|
const val SOURCE_NAND = 1
|
||||||
|
const val SOURCE_SDMC = 2
|
||||||
|
const val SOURCE_EXTERNAL = 3
|
||||||
|
const val SOURCE_PACKED = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
val isRemovable: Boolean
|
||||||
|
get() = source != SOURCE_EXTERNAL && source != SOURCE_PACKED
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1407,7 +1407,7 @@ jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPatchesForFile(JNIEnv* env
|
||||||
Common::Android::ToJString(env, patch.version), static_cast<jint>(patch.type),
|
Common::Android::ToJString(env, patch.version), static_cast<jint>(patch.type),
|
||||||
Common::Android::ToJString(env, std::to_string(patch.program_id)),
|
Common::Android::ToJString(env, std::to_string(patch.program_id)),
|
||||||
Common::Android::ToJString(env, std::to_string(patch.title_id)),
|
Common::Android::ToJString(env, std::to_string(patch.title_id)),
|
||||||
static_cast<jlong>(patch.numeric_version));
|
static_cast<jlong>(patch.numeric_version), static_cast<jint>(patch.source));
|
||||||
env->SetObjectArrayElement(jpatchArray, i, jpatch);
|
env->SetObjectArrayElement(jpatchArray, i, jpatch);
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -516,7 +516,7 @@ namespace Common::Android {
|
||||||
s_patch_class = reinterpret_cast<jclass>(env->NewGlobalRef(patch_class));
|
s_patch_class = reinterpret_cast<jclass>(env->NewGlobalRef(patch_class));
|
||||||
s_patch_constructor = env->GetMethodID(
|
s_patch_constructor = env->GetMethodID(
|
||||||
patch_class, "<init>",
|
patch_class, "<init>",
|
||||||
"(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;J)V");
|
"(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JI)V");
|
||||||
s_patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z");
|
s_patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z");
|
||||||
s_patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;");
|
s_patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;");
|
||||||
s_patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;");
|
s_patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;");
|
||||||
|
|
|
||||||
|
|
@ -771,6 +771,7 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
|
||||||
std::nullopt, std::nullopt, ContentRecordType::Program, update_tid);
|
std::nullopt, std::nullopt, ContentRecordType::Program, update_tid);
|
||||||
|
|
||||||
for (const auto& [slot, entry] : all_updates) {
|
for (const auto& [slot, entry] : all_updates) {
|
||||||
|
(void)entry;
|
||||||
if (slot == ContentProviderUnionSlot::External ||
|
if (slot == ContentProviderUnionSlot::External ||
|
||||||
slot == ContentProviderUnionSlot::FrontendManual) {
|
slot == ContentProviderUnionSlot::FrontendManual) {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -786,7 +787,7 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
|
||||||
source_suffix = " (NAND)";
|
source_suffix = " (NAND)";
|
||||||
break;
|
break;
|
||||||
case ContentProviderUnionSlot::SDMC:
|
case ContentProviderUnionSlot::SDMC:
|
||||||
source_type = PatchSource::NAND;
|
source_type = PatchSource::SDMC;
|
||||||
source_suffix = " (SDMC)";
|
source_suffix = " (SDMC)";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -956,37 +957,60 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DLC
|
// DLC
|
||||||
const auto dlc_entries =
|
|
||||||
content_provider.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);
|
|
||||||
|
|
||||||
std::vector<ContentProviderEntry> dlc_match;
|
std::vector<ContentProviderEntry> dlc_match;
|
||||||
dlc_match.reserve(dlc_entries.size());
|
bool has_external_dlc = false;
|
||||||
std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match),
|
bool has_nand_dlc = false;
|
||||||
[this](const ContentProviderEntry& entry) {
|
bool has_sdmc_dlc = false;
|
||||||
const auto base_tid = GetBaseTitleID(entry.title_id);
|
bool has_other_dlc = false;
|
||||||
const bool matches_base = base_tid == title_id;
|
const auto dlc_entries_with_origin =
|
||||||
|
content_union->ListEntriesFilterOrigin(std::nullopt, TitleType::AOC, ContentRecordType::Data);
|
||||||
|
|
||||||
if (!matches_base) {
|
dlc_match.reserve(dlc_entries_with_origin.size());
|
||||||
LOG_DEBUG(Loader, "DLC {:016X} base {:016X} doesn't match title {:016X}",
|
for (const auto& [slot, entry] : dlc_entries_with_origin) {
|
||||||
entry.title_id, base_tid, title_id);
|
const auto base_tid = GetBaseTitleID(entry.title_id);
|
||||||
return false;
|
const bool matches_base = base_tid == title_id;
|
||||||
}
|
if (!matches_base) {
|
||||||
|
LOG_DEBUG(Loader, "DLC {:016X} base {:016X} doesn't match title {:016X}",
|
||||||
|
entry.title_id, base_tid, title_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
auto nca = content_provider.GetEntry(entry);
|
const auto* slot_provider = content_union->GetSlotProvider(slot);
|
||||||
if (!nca) {
|
if (slot_provider == nullptr) {
|
||||||
LOG_DEBUG(Loader, "Failed to get NCA for DLC {:016X}", entry.title_id);
|
continue;
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const auto status = nca->GetStatus();
|
auto nca = slot_provider->GetEntry(entry);
|
||||||
if (status != Loader::ResultStatus::Success) {
|
if (!nca) {
|
||||||
LOG_DEBUG(Loader, "DLC {:016X} NCA has status {}",
|
LOG_DEBUG(Loader, "Failed to get NCA for DLC {:016X}", entry.title_id);
|
||||||
entry.title_id, static_cast<int>(status));
|
continue;
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
const auto status = nca->GetStatus();
|
||||||
});
|
if (status != Loader::ResultStatus::Success) {
|
||||||
|
LOG_DEBUG(Loader, "DLC {:016X} NCA has status {}", entry.title_id,
|
||||||
|
static_cast<int>(status));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (slot) {
|
||||||
|
case ContentProviderUnionSlot::External:
|
||||||
|
case ContentProviderUnionSlot::FrontendManual:
|
||||||
|
has_external_dlc = true;
|
||||||
|
break;
|
||||||
|
case ContentProviderUnionSlot::UserNAND:
|
||||||
|
case ContentProviderUnionSlot::SysNAND:
|
||||||
|
has_nand_dlc = true;
|
||||||
|
break;
|
||||||
|
case ContentProviderUnionSlot::SDMC:
|
||||||
|
has_sdmc_dlc = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
has_other_dlc = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dlc_match.push_back(entry);
|
||||||
|
}
|
||||||
|
|
||||||
if (!dlc_match.empty()) {
|
if (!dlc_match.empty()) {
|
||||||
// Ensure sorted so DLC IDs show in order.
|
// Ensure sorted so DLC IDs show in order.
|
||||||
|
|
@ -1000,13 +1024,22 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
|
||||||
|
|
||||||
const auto dlc_disabled =
|
const auto dlc_disabled =
|
||||||
std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end();
|
std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end();
|
||||||
|
PatchSource dlc_source = PatchSource::Unknown;
|
||||||
|
if (has_external_dlc && !has_nand_dlc && !has_sdmc_dlc && !has_other_dlc) {
|
||||||
|
dlc_source = PatchSource::External;
|
||||||
|
} else if (has_nand_dlc && !has_external_dlc && !has_sdmc_dlc && !has_other_dlc) {
|
||||||
|
dlc_source = PatchSource::NAND;
|
||||||
|
} else if (has_sdmc_dlc && !has_external_dlc && !has_nand_dlc && !has_other_dlc) {
|
||||||
|
dlc_source = PatchSource::SDMC;
|
||||||
|
}
|
||||||
|
|
||||||
out.push_back({.enabled = !dlc_disabled,
|
out.push_back({.enabled = !dlc_disabled,
|
||||||
.name = "DLC",
|
.name = "DLC",
|
||||||
.version = std::move(list),
|
.version = std::move(list),
|
||||||
.type = PatchType::DLC,
|
.type = PatchType::DLC,
|
||||||
.program_id = title_id,
|
.program_id = title_id,
|
||||||
.title_id = dlc_match.back().title_id,
|
.title_id = dlc_match.back().title_id,
|
||||||
.source = PatchSource::Unknown});
|
.source = dlc_source});
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ enum class PatchType { Update, DLC, Mod };
|
||||||
enum class PatchSource {
|
enum class PatchSource {
|
||||||
Unknown,
|
Unknown,
|
||||||
NAND,
|
NAND,
|
||||||
|
SDMC,
|
||||||
External,
|
External,
|
||||||
Packed,
|
Packed,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue