From 2e0a9c6e2eab91108ffd8c3e11d8bb74f47e1b2a Mon Sep 17 00:00:00 2001
From: WhoYouAndM3 <83360444+l3ger0j@users.noreply.github.com>
Date: Sat, 8 Mar 2025 03:58:22 +0300
Subject: [PATCH 1/6] Fix the error no permissions on Bluetooth
---
app/src/main/AndroidManifest.xml | 1 +
1 file changed, 1 insertion(+)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 5612caaa..9b73f13e 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -3,6 +3,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
+
From 9f2ae9503b987f4fad3d9602c6f03d365afb9f1c Mon Sep 17 00:00:00 2001
From: WhoYouAndM3 <83360444+l3ger0j@users.noreply.github.com>
Date: Sat, 8 Mar 2025 04:11:12 +0300
Subject: [PATCH 2/6] Fix the resizing of the picture
---
.../android/model/service/HtmlProcessor.java | 69 +++++--------------
1 file changed, 19 insertions(+), 50 deletions(-)
diff --git a/app/src/main/java/org/qp/android/model/service/HtmlProcessor.java b/app/src/main/java/org/qp/android/model/service/HtmlProcessor.java
index 989f02eb..56b891f0 100644
--- a/app/src/main/java/org/qp/android/model/service/HtmlProcessor.java
+++ b/app/src/main/java/org/qp/android/model/service/HtmlProcessor.java
@@ -1,7 +1,6 @@
package org.qp.android.model.service;
import static org.qp.android.helpers.utils.Base64Util.encodeBase64;
-import static org.qp.android.helpers.utils.FileUtil.fromRelPath;
import static org.qp.android.helpers.utils.StringUtil.isNotEmpty;
import static org.qp.android.helpers.utils.StringUtil.isNullOrEmpty;
@@ -17,7 +16,6 @@
import org.qp.android.ui.settings.SettingsController;
import java.util.ArrayList;
-import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Pattern;
@@ -176,64 +174,35 @@ private String lineBreaksInHTML(@NonNull String s) {
private void handleImagesInHtml(@NonNull Context context,
@NonNull Element documentBody) {
- var dynBlackList = new ArrayList();
- documentBody.select("a").forEach(element -> {
- if (element.attr("href").contains("exec:")) {
- dynBlackList.add(element.select("img").attr("src"));
- }
- });
+ if (controller.isUseFullscreenImages) {
+ var dynBlackList = new ArrayList();
+ documentBody.select("a").forEach(element -> {
+ if (element.attr("href").contains("exec:")) {
+ dynBlackList.add(element.select("img").attr("src"));
+ }
+ });
- documentBody.select("img").forEach(img -> {
- if (controller.isUseFullscreenImages) {
+ documentBody.select("img").forEach(img -> {
if (!dynBlackList.contains(img.attr("src"))) {
- img.attr("onclick" , "img.onClickImage(this.src);");
+ img.attr("onclick", "img.onClickImage(this.src);");
}
- }
+ });
+ }
+
+ documentBody.select("img").forEach(img -> {
if (controller.isUseAutoWidth && controller.isUseAutoHeight) {
img.attr("style", "display: inline; height: auto; max-width: 100%;");
- }
- if (!controller.isUseAutoWidth) {
- shouldChangeWidth(context, img).thenAccept(aBoolean -> {
- if (!aBoolean) return;
+ } else {
+ if (!controller.isUseAutoWidth) {
img.attr("style" , "max-width:" + controller.customWidthImage+";");
- });
- } else if (!controller.isUseAutoHeight) {
- shouldChangeHeight(context, img).thenAccept(aBoolean -> {
- if (!aBoolean) return;
- img.attr("style" , "max-height:" + controller.customHeightImage+";");
- });
+ }
+ if (!controller.isUseAutoHeight) {
+ img.attr("style" , "max-height:" + controller.customHeightImage+";");
+ }
}
});
}
- private CompletableFuture shouldChangeWidth(Context context,
- Element img) {
- var relPath = img.attr("src");
- return CompletableFuture
- .supplyAsync(() -> fromRelPath(context , relPath , curGameDir), executors)
- .thenApply(imageFile -> {
- if (imageFile == null) return false;
- var drawable = imageProvider.getDrawableFromPath(context , imageFile.getUri());
- if (drawable == null) return false;
- var widthPix = context.getResources().getDisplayMetrics().widthPixels;
- return drawable.getIntrinsicWidth() < widthPix;
- });
- }
-
- private CompletableFuture shouldChangeHeight(Context context,
- Element img) {
- var relPath = img.attr("src");
- return CompletableFuture
- .supplyAsync(() -> fromRelPath(context , relPath , curGameDir), executors)
- .thenApply(imageFile -> {
- if (imageFile == null) return false;
- var drawable = imageProvider.getDrawableFromPath(context , imageFile.getUri());
- if (drawable == null) return false;
- var heightPix = context.getResources().getDisplayMetrics().heightPixels;
- return drawable.getIntrinsicHeight() < heightPix;
- });
- }
-
private void handleVideosInHtml(Element documentBody) {
var videoElement = documentBody.select("video");
videoElement.attr("style", "max-width:100%;");
From bd0a1de694ebf8ccbc2ce0581c62c844016beba0 Mon Sep 17 00:00:00 2001
From: WhoYouAndM3 <83360444+l3ger0j@users.noreply.github.com>
Date: Sat, 8 Mar 2025 04:13:47 +0300
Subject: [PATCH 3/6] Improve the rendering of RecyclerView and rename
GameItemRecycler
---
...ItemRecycler.java => GameItemAdapter.java} | 10 +-
.../qp/android/ui/game/GameMainFragment.java | 19 ++-
.../android/ui/game/GameObjectFragment.java | 14 +-
.../org/qp/android/ui/game/GameViewModel.java | 140 ++++--------------
4 files changed, 63 insertions(+), 120 deletions(-)
rename app/src/main/java/org/qp/android/ui/game/{GameItemRecycler.java => GameItemAdapter.java} (89%)
diff --git a/app/src/main/java/org/qp/android/ui/game/GameItemRecycler.java b/app/src/main/java/org/qp/android/ui/game/GameItemAdapter.java
similarity index 89%
rename from app/src/main/java/org/qp/android/ui/game/GameItemRecycler.java
rename to app/src/main/java/org/qp/android/ui/game/GameItemAdapter.java
index cae0d4eb..dbb653bb 100644
--- a/app/src/main/java/org/qp/android/ui/game/GameItemRecycler.java
+++ b/app/src/main/java/org/qp/android/ui/game/GameItemAdapter.java
@@ -21,7 +21,7 @@
import java.util.List;
import java.util.Objects;
-public class GameItemRecycler extends RecyclerView.Adapter {
+public class GameItemAdapter extends RecyclerView.Adapter {
private static final DiffUtil.ItemCallback DIFF_CALLBACK =
new DiffUtil.ItemCallback<>() {
@@ -62,15 +62,15 @@ public void submitList(List gameData) {
@NonNull
@Override
- public GameItemRecycler.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
- int viewType) {
+ public GameItemAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+ int viewType) {
var inflater = LayoutInflater.from(parent.getContext());
var listGameItemBinding = ListGameItemBinding.inflate(inflater, parent, false);
- return new GameItemRecycler.ViewHolder(listGameItemBinding);
+ return new GameItemAdapter.ViewHolder(listGameItemBinding);
}
@Override
- public void onBindViewHolder(@NonNull GameItemRecycler.ViewHolder holder, int position) {
+ public void onBindViewHolder(@NonNull GameItemAdapter.ViewHolder holder, int position) {
var qpListItem = getItem(position);
final var itemImage = holder.listGameItemBinding.itemIcon;
diff --git a/app/src/main/java/org/qp/android/ui/game/GameMainFragment.java b/app/src/main/java/org/qp/android/ui/game/GameMainFragment.java
index af6ff2f8..1e301c9e 100644
--- a/app/src/main/java/org/qp/android/ui/game/GameMainFragment.java
+++ b/app/src/main/java/org/qp/android/ui/game/GameMainFragment.java
@@ -24,6 +24,7 @@
public class GameMainFragment extends Fragment {
+ private final GameItemAdapter adapter = new GameItemAdapter();
private GameViewModel viewModel;
private ConstraintLayout layoutTop;
private WebView mainDescView;
@@ -76,7 +77,7 @@ public void onClickImage(String src) {
}
}, "img");
if (viewModel.getSettingsController().isUseAutoscroll) {
- mainDescView.postDelayed(onScroll, 300);
+ mainDescView.post(onScroll);
}
viewModel.getMainDescObserver().observe(getViewLifecycleOwner(), desc ->
mainDescView.loadDataWithBaseURL(
@@ -90,13 +91,20 @@ public void onClickImage(String src) {
actionsView = gameMainBinding.actions;
var manager = (LinearLayoutManager) actionsView.getLayoutManager();
var dividerItemDecoration = new DividerItemDecoration(
- actionsView.getContext(),
- manager.getOrientation());
+ actionsView.getContext(), manager.getOrientation());
actionsView.addItemDecoration(dividerItemDecoration);
actionsView.setOverScrollMode(View.OVER_SCROLL_NEVER);
- viewModel.getActionObserver().observe(getViewLifecycleOwner(), actions -> {
+ actionsView.setBackgroundColor(viewModel.getBackgroundColor());
+ actionsView.setAdapter(adapter);
+
+ viewModel.actsListLiveData.observe(getViewLifecycleOwner(), listItems -> {
actionsView.setBackgroundColor(viewModel.getBackgroundColor());
- actionsView.setAdapter(actions);
+ adapter.typeface = viewModel.getSettingsController().getTypeface();
+ adapter.textSize = viewModel.getFontSize();
+ adapter.textColor = viewModel.getTextColor();
+ adapter.linkTextColor = viewModel.getLinkColor();
+ adapter.backgroundColor = viewModel.getBackgroundColor();
+ adapter.submitList(listItems);
});
// Settings
@@ -118,6 +126,7 @@ public void onClickImage(String src) {
actionsView.setBackgroundColor(viewModel.getBackgroundColor());
gameMainBinding.getRoot().refreshDrawableState();
});
+
return gameMainBinding.getRoot();
}
diff --git a/app/src/main/java/org/qp/android/ui/game/GameObjectFragment.java b/app/src/main/java/org/qp/android/ui/game/GameObjectFragment.java
index c46157fc..25f0e1b6 100644
--- a/app/src/main/java/org/qp/android/ui/game/GameObjectFragment.java
+++ b/app/src/main/java/org/qp/android/ui/game/GameObjectFragment.java
@@ -18,6 +18,7 @@
public class GameObjectFragment extends Fragment {
+ private final GameItemAdapter adapter = new GameItemAdapter();
private FragmentRecyclerBinding recyclerBinding;
private GameViewModel viewModel;
private RecyclerView objectView;
@@ -38,9 +39,17 @@ public View onCreateView(@NonNull LayoutInflater inflater,
manager.getOrientation());
objectView.addItemDecoration(dividerItemDecoration);
objectView.setOverScrollMode(View.OVER_SCROLL_NEVER);
- viewModel.getObjectsObserver().observe(getViewLifecycleOwner(), gameItemRecycler -> {
+ objectView.setBackgroundColor(viewModel.getBackgroundColor());
+ objectView.setAdapter(adapter);
+
+ viewModel.objsListLiveData.observe(getViewLifecycleOwner(), listItems -> {
objectView.setBackgroundColor(viewModel.getBackgroundColor());
- recyclerBinding.shareRecyclerView.setAdapter(gameItemRecycler);
+ adapter.typeface = viewModel.getSettingsController().getTypeface();
+ adapter.textSize = viewModel.getFontSize();
+ adapter.textColor = viewModel.getTextColor();
+ adapter.linkTextColor = viewModel.getLinkColor();
+ adapter.backgroundColor = viewModel.getBackgroundColor();
+ adapter.submitList(listItems);
});
// Settings
@@ -48,6 +57,7 @@ public View onCreateView(@NonNull LayoutInflater inflater,
objectView.setBackgroundColor(viewModel.getBackgroundColor());
recyclerBinding.getRoot().refreshDrawableState();
});
+
return recyclerBinding.getRoot();
}
diff --git a/app/src/main/java/org/qp/android/ui/game/GameViewModel.java b/app/src/main/java/org/qp/android/ui/game/GameViewModel.java
index 06b0bf38..99370a13 100644
--- a/app/src/main/java/org/qp/android/ui/game/GameViewModel.java
+++ b/app/src/main/java/org/qp/android/ui/game/GameViewModel.java
@@ -6,9 +6,7 @@
import static org.qp.android.helpers.utils.ColorUtil.getHexColor;
import static org.qp.android.helpers.utils.FileUtil.findOrCreateFolder;
import static org.qp.android.helpers.utils.FileUtil.fromRelPath;
-import static org.qp.android.helpers.utils.FileUtil.isWritableDir;
import static org.qp.android.helpers.utils.PathUtil.getExtension;
-import static org.qp.android.helpers.utils.StringUtil.isNotEmptyOrBlank;
import static org.qp.android.helpers.utils.ThreadUtil.assertNonUiThread;
import static org.qp.android.helpers.utils.ViewUtil.getFontStyle;
import static org.qp.android.ui.game.GameActivity.LOAD;
@@ -61,11 +59,7 @@
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.stream.Collectors;
public class GameViewModel extends AndroidViewModel implements GameInterface {
@@ -89,12 +83,11 @@ public class GameViewModel extends AndroidViewModel implements GameInterface {
""";
private static final String PAGE_BODY_TEMPLATE = "REPLACETEXT";
private final QuestopiaApplication questopiaApplication;
- private final ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
private final MutableLiveData controllerObserver = new MutableLiveData<>();
private final MutableLiveData mainDescLiveData = new MutableLiveData<>();
private final MutableLiveData varsDescLiveData = new MutableLiveData<>();
- private final MutableLiveData actionsListLiveData = new MutableLiveData<>();
- private final MutableLiveData objectsListLiveData = new MutableLiveData<>();
+ public final MutableLiveData> actsListLiveData = new MutableLiveData<>();
+ public final MutableLiveData> objsListLiveData = new MutableLiveData<>();
private final Handler counterHandler = new Handler();
public ObservableBoolean isActionVisible = new ObservableBoolean();
public MutableLiveData outputTextObserver = new MutableLiveData<>();
@@ -236,20 +229,6 @@ public LiveData getVarsDescObserver() {
return varsDescLiveData;
}
- public LiveData getObjectsObserver() {
- if (objectsListLiveData.getValue() == null) {
- refreshObjectsRecycler();
- }
- return objectsListLiveData;
- }
-
- public LiveData getActionObserver() {
- if (actionsListLiveData.getValue() == null) {
- refreshActionsRecycler();
- }
- return actionsListLiveData;
- }
-
public Optional getCurGameDir() {
if (gameDirUri == null) return Optional.empty();
return Optional.ofNullable(DocumentFileCompat.fromUri(getApplication(), gameDirUri));
@@ -375,39 +354,33 @@ public void updatePageTemplate() {
}
private void refreshMainDesc() {
- CompletableFuture
- .supplyAsync(() -> getHtml(getLibGameState().mainDesc), service)
- .thenAcceptAsync(libMainDesc -> {
- var dirtyHTML = pageTemplate.replace("REPLACETEXT", libMainDesc);
- var cleanHTML = "";
- if (getSettingsController().isImageDisabled) {
- cleanHTML = getHtmlProcessor().getCleanHtmlRemMedia(dirtyHTML);
- } else {
- cleanHTML = getHtmlProcessor().getCleanHtmlAndMedia(getApplication(), dirtyHTML);
- }
- if (!cleanHTML.isBlank()) {
- getGameActivity().warnUser(GameActivity.TAB_MAIN_DESC_AND_ACTIONS);
- }
- mainDescLiveData.postValue(cleanHTML);
- }, service);
+ var libMainDesc = getHtml(getLibGameState().mainDesc);
+ var dirtyHTML = pageTemplate.replace("REPLACETEXT", libMainDesc);
+ var cleanHTML = "";
+ if (getSettingsController().isImageDisabled) {
+ cleanHTML = getHtmlProcessor().getCleanHtmlRemMedia(dirtyHTML);
+ } else {
+ cleanHTML = getHtmlProcessor().getCleanHtmlAndMedia(getApplication(), dirtyHTML);
+ }
+ if (!cleanHTML.isBlank()) {
+ getGameActivity().warnUser(GameActivity.TAB_MAIN_DESC_AND_ACTIONS);
+ }
+ mainDescLiveData.postValue(cleanHTML);
}
private void refreshVarsDesc() {
- CompletableFuture
- .supplyAsync(() -> getHtml(getLibGameState().varsDesc), service)
- .thenAcceptAsync(libVarsDesc -> {
- var dirtyHTML = pageTemplate.replace("REPLACETEXT", libVarsDesc);
- var cleanHTML = "";
- if (getSettingsController().isImageDisabled) {
- cleanHTML = getHtmlProcessor().getCleanHtmlRemMedia(dirtyHTML);
- } else {
- cleanHTML = getHtmlProcessor().getCleanHtmlAndMedia(getApplication(), dirtyHTML);
- }
- if (!cleanHTML.isBlank()) {
- getGameActivity().warnUser(GameActivity.TAB_VARS_DESC);
- }
- varsDescLiveData.postValue(cleanHTML);
- }, service);
+ final var libVarsDesc = getHtml(getLibGameState().varsDesc);
+ final var dirtyHTML = pageTemplate.replace("REPLACETEXT", libVarsDesc);
+ var cleanHTML = "";
+ if (getSettingsController().isImageDisabled) {
+ cleanHTML = getHtmlProcessor().getCleanHtmlRemMedia(dirtyHTML);
+ } else {
+ cleanHTML = getHtmlProcessor().getCleanHtmlAndMedia(getApplication(), dirtyHTML);
+ }
+ if (!cleanHTML.isBlank()) {
+ getGameActivity().warnUser(GameActivity.TAB_VARS_DESC);
+ }
+ varsDescLiveData.postValue(cleanHTML);
}
public void onActionClicked(int index) {
@@ -415,35 +388,10 @@ public void onActionClicked(int index) {
}
private void refreshActionsRecycler() {
- CompletableFuture
- .supplyAsync(() -> {
- var list = new ArrayList<>(getLibGameState().actionsList);
- var dir = DocumentFileCompat.fromUri(getApplication(), gameDirUri);
- if (!isWritableDir(getApplication(), dir)) return null;
- list.stream()
- .parallel()
- .map(item -> isNotEmptyOrBlank(item.image())
- ? String.valueOf(fromRelPath(getApplication(), item.image(), dir))
- : ""
- )
- .collect(Collectors.toUnmodifiableList());
- return list;
- }, service)
- .thenApplyAsync(list -> {
- var actionsRecycler = new GameItemRecycler();
- actionsRecycler.typeface = getSettingsController().getTypeface();
- actionsRecycler.textSize = getFontSize();
- actionsRecycler.textColor = getTextColor();
- actionsRecycler.linkTextColor = getLinkColor();
- actionsRecycler.backgroundColor = getBackgroundColor();
- actionsRecycler.submitList(list);
- return actionsRecycler;
- })
- .thenAcceptAsync(actionsRecycler -> {
- actionsListLiveData.postValue(actionsRecycler);
- int count = actionsRecycler.getItemCount();
- isActionVisible.set(showActions && count > 0);
- }, service);
+ var listItems = getLibGameState().actionsList;
+ var listSize = listItems.size();
+ isActionVisible.set(showActions && listSize > 0);
+ actsListLiveData.postValue(listItems);
}
public void onObjectClicked(int index) {
@@ -451,32 +399,8 @@ public void onObjectClicked(int index) {
}
private void refreshObjectsRecycler() {
- CompletableFuture
- .supplyAsync(() -> {
- var list = new ArrayList<>(getLibGameState().objectsList);
- var dir = DocumentFileCompat.fromUri(getApplication(), gameDirUri);
- if (!isWritableDir(getApplication(), dir)) return null;
- list.stream()
- .parallel()
- .map(item -> isNotEmptyOrBlank(item.image())
- ? String.valueOf(fromRelPath(getApplication(), item.image(), dir))
- : ""
- )
- .collect(Collectors.toUnmodifiableList());
- return list;
- }, service)
- .thenApplyAsync(list -> {
- getGameActivity().warnUser(GameActivity.TAB_OBJECTS);
- var objectsRecycler = new GameItemRecycler();
- objectsRecycler.typeface = getSettingsController().getTypeface();
- objectsRecycler.textSize = getFontSize();
- objectsRecycler.textColor = getTextColor();
- objectsRecycler.linkTextColor = getLinkColor();
- objectsRecycler.backgroundColor = getBackgroundColor();
- objectsRecycler.submitList(list);
- return objectsRecycler;
- })
- .thenAcceptAsync(objectsListLiveData::postValue, service);
+ getGameActivity().warnUser(GameActivity.TAB_OBJECTS);
+ objsListLiveData.postValue(getLibGameState().objectsList);
}
public void setCallback() {
From 3c9c11679e4805a046a65be3cf3e6624afc9dd6e Mon Sep 17 00:00:00 2001
From: WhoYouAndM3 <83360444+l3ger0j@users.noreply.github.com>
Date: Tue, 11 Mar 2025 00:55:05 +0300
Subject: [PATCH 4/6] Add a search for game files in the mods folder
---
.../qp/android/model/repository/LocalGame.java | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/app/src/main/java/org/qp/android/model/repository/LocalGame.java b/app/src/main/java/org/qp/android/model/repository/LocalGame.java
index d0693534..f3ad4cec 100644
--- a/app/src/main/java/org/qp/android/model/repository/LocalGame.java
+++ b/app/src/main/java/org/qp/android/model/repository/LocalGame.java
@@ -1,5 +1,6 @@
package org.qp.android.model.repository;
+import static org.qp.android.helpers.utils.DirUtil.MOD_DIR_NAME;
import static org.qp.android.helpers.utils.FileUtil.documentWrap;
import static org.qp.android.helpers.utils.FileUtil.findOrCreateFile;
import static org.qp.android.helpers.utils.FileUtil.forceCreateFile;
@@ -149,6 +150,20 @@ public boolean searchAndWriteFileInfo(DocumentFile rootDir, GameData data) {
}
});
+ var modDir = fromRelPath(context, MOD_DIR_NAME, rootDir);
+ if (isWritableDir(context, modDir)) {
+ var modFiles = modDir.listFiles();
+ if (modFiles != null || modFiles.length != 0) {
+ Arrays.stream(modFiles).forEach(d -> {
+ var dirExtension = documentWrap(d).getExtension();
+ var lcName = dirExtension.toLowerCase(Locale.ROOT);
+ if (lcName.endsWith("qsp") || lcName.endsWith("gam")) {
+ gameFiles.add(d.getUri());
+ }
+ });
+ }
+ }
+
if (gameFiles.isEmpty()) {
var allFiles = DocumentFileUtils.search(
rootDir,
From 410f3d16e7696062be0c10604e1e5bedd83ef05d Mon Sep 17 00:00:00 2001
From: WhoYouAndM3 <83360444+l3ger0j@users.noreply.github.com>
Date: Mon, 17 Mar 2025 00:50:54 +0300
Subject: [PATCH 5/6] Fix loading of case-sensitive images
---
.../org/qp/android/ui/game/GameViewModel.java | 23 +++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/app/src/main/java/org/qp/android/ui/game/GameViewModel.java b/app/src/main/java/org/qp/android/ui/game/GameViewModel.java
index 99370a13..a6d9d7ce 100644
--- a/app/src/main/java/org/qp/android/ui/game/GameViewModel.java
+++ b/app/src/main/java/org/qp/android/ui/game/GameViewModel.java
@@ -6,7 +6,9 @@
import static org.qp.android.helpers.utils.ColorUtil.getHexColor;
import static org.qp.android.helpers.utils.FileUtil.findOrCreateFolder;
import static org.qp.android.helpers.utils.FileUtil.fromRelPath;
+import static org.qp.android.helpers.utils.FileUtil.isWritableFile;
import static org.qp.android.helpers.utils.PathUtil.getExtension;
+import static org.qp.android.helpers.utils.StringUtil.isNotEmptyOrBlank;
import static org.qp.android.helpers.utils.ThreadUtil.assertNonUiThread;
import static org.qp.android.helpers.utils.ViewUtil.getFontStyle;
import static org.qp.android.ui.game.GameActivity.LOAD;
@@ -653,6 +655,27 @@ public WebResourceResponse shouldInterceptRequest(WebView view,
try {
if (uri.getPath() == null) throw new NullPointerException();
var imageFile = fromRelPath(getGameActivity(), uri.getPath(), rootDir);
+ if (!isWritableFile(getApplication(), imageFile)) {
+ var pathElement = uri.getPath().split("/");
+ var corrPath = new StringBuilder("/");
+ var files = rootDir.listFiles();
+ for (var path : pathElement) {
+ for (var file : files) {
+ var name = file.getName();
+ if (!isNotEmptyOrBlank(name)) continue;
+ if (name.equalsIgnoreCase(path)) {
+ if (getExtension(name) != null) {
+ corrPath.append("/").append(name);
+ } else {
+ corrPath.append("/").append(name).append("/");
+ }
+ files = file.listFiles();
+ }
+ }
+ }
+ var corrFilePath = corrPath.toString().replace("//", "/");
+ imageFile = fromRelPath(getApplication(), corrFilePath, rootDir);
+ }
var extension = MimeTypeMap.getSingleton().getMimeTypeFromExtension(getExtension(imageFile));
var in = getApplication().getContentResolver().openInputStream(imageFile.getUri());
return new WebResourceResponse(extension, null, in);
From 93e347d08c246cb34e2e067f86cddf7635f96006 Mon Sep 17 00:00:00 2001
From: WhoYouAndM3 <83360444+l3ger0j@users.noreply.github.com>
Date: Mon, 17 Mar 2025 23:38:25 +0300
Subject: [PATCH 6/6] Bump to 3.25.4
---
app/build.gradle | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index f9a12a36..a6ae4339 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -10,8 +10,8 @@ android {
applicationId "org.qp.android"
minSdk 26
targetSdk 34
- versionCode 202503
- versionName "3.25.3"
+ versionCode 202504
+ versionName "3.25.4"
resourceConfigurations += ['en', 'ru']
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {