Browse Source

[android,ui] fix delete buttons available for external content

pull/3691/head
xbzk 3 weeks ago
parent
commit
f1463a8e41
  1. 18
      src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AddonAdapter.kt
  2. 16
      src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Patch.kt
  3. 2
      src/android/app/src/main/jni/native.cpp
  4. 2
      src/common/android/id_cache.cpp
  5. 97
      src/core/file_sys/patch_manager.cpp
  6. 1
      src/core/file_sys/patch_manager.h

18
src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AddonAdapter.kt

@ -40,11 +40,21 @@ class AddonAdapter(val addonViewModel: AddonViewModel) :
} }
} }
val deleteAction = {
addonViewModel.setAddonToDelete(model)
val canDelete = model.isRemovable
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
src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Patch.kt

@ -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
}

2
src/android/app/src/main/jni/native.cpp

@ -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;
} }

2
src/common/android/id_cache.cpp

@ -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;");

97
src/core/file_sys/patch_manager.cpp

@ -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());
std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match),
[this](const ContentProviderEntry& entry) {
const auto base_tid = GetBaseTitleID(entry.title_id);
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);
return false;
}
auto nca = content_provider.GetEntry(entry);
if (!nca) {
LOG_DEBUG(Loader, "Failed to get NCA for DLC {:016X}", entry.title_id);
return false;
}
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));
return false;
}
return true;
});
bool has_external_dlc = false;
bool has_nand_dlc = false;
bool has_sdmc_dlc = false;
bool has_other_dlc = false;
const auto dlc_entries_with_origin =
content_union->ListEntriesFilterOrigin(std::nullopt, TitleType::AOC, ContentRecordType::Data);
dlc_match.reserve(dlc_entries_with_origin.size());
for (const auto& [slot, entry] : dlc_entries_with_origin) {
const auto base_tid = GetBaseTitleID(entry.title_id);
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;
}
const auto* slot_provider = content_union->GetSlotProvider(slot);
if (slot_provider == nullptr) {
continue;
}
auto nca = slot_provider->GetEntry(entry);
if (!nca) {
LOG_DEBUG(Loader, "Failed to get NCA for DLC {:016X}", entry.title_id);
continue;
}
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;

1
src/core/file_sys/patch_manager.h

@ -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…
Cancel
Save