Skip to content
This repository was archived by the owner on Mar 12, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Expand Down
15 changes: 15 additions & 0 deletions app/src/main/java/org/qp/android/model/repository/LocalGame.java
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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,
Expand Down
69 changes: 19 additions & 50 deletions app/src/main/java/org/qp/android/model/service/HtmlProcessor.java
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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;
Expand Down Expand Up @@ -176,64 +174,35 @@ private String lineBreaksInHTML(@NonNull String s) {

private void handleImagesInHtml(@NonNull Context context,
@NonNull Element documentBody) {
var dynBlackList = new ArrayList<String>();
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<String>();
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<Boolean> 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<Boolean> 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%;");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import java.util.List;
import java.util.Objects;

public class GameItemRecycler extends RecyclerView.Adapter<GameItemRecycler.ViewHolder> {
public class GameItemAdapter extends RecyclerView.Adapter<GameItemAdapter.ViewHolder> {

private static final DiffUtil.ItemCallback<QSPLib.ListItem> DIFF_CALLBACK =
new DiffUtil.ItemCallback<>() {
Expand Down Expand Up @@ -62,15 +62,15 @@ public void submitList(List<QSPLib.ListItem> 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;
Expand Down
19 changes: 14 additions & 5 deletions app/src/main/java/org/qp/android/ui/game/GameMainFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

public class GameMainFragment extends Fragment {

private final GameItemAdapter adapter = new GameItemAdapter();
private GameViewModel viewModel;
private ConstraintLayout layoutTop;
private WebView mainDescView;
Expand Down Expand Up @@ -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(
Expand All @@ -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
Expand All @@ -118,6 +126,7 @@ public void onClickImage(String src) {
actionsView.setBackgroundColor(viewModel.getBackgroundColor());
gameMainBinding.getRoot().refreshDrawableState();
});

return gameMainBinding.getRoot();
}

Expand Down
14 changes: 12 additions & 2 deletions app/src/main/java/org/qp/android/ui/game/GameObjectFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

public class GameObjectFragment extends Fragment {

private final GameItemAdapter adapter = new GameItemAdapter();
private FragmentRecyclerBinding recyclerBinding;
private GameViewModel viewModel;
private RecyclerView objectView;
Expand All @@ -38,16 +39,25 @@ 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
viewModel.getControllerObserver().observe(getViewLifecycleOwner(), settingsController -> {
objectView.setBackgroundColor(viewModel.getBackgroundColor());
recyclerBinding.getRoot().refreshDrawableState();
});

return recyclerBinding.getRoot();
}

Expand Down
Loading
Loading