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 202504
versionName "3.25.4"
versionCode 202505
versionName "3.25.5"
resourceConfigurations += ['en', 'ru']
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
Expand Down
78 changes: 39 additions & 39 deletions app/src/main/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -77,44 +77,44 @@ else()
set(CMAKE_POLICY_DEFAULT_CMP0063 NEW)
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
add_subdirectory("${CMAKE_BINARY_DIR}/oniguruma-src"
"${CMAKE_BINARY_DIR}/oniguruma-build"
"${CMAKE_BINARY_DIR}/oniguruma-build"
)
add_library(oniguruma::onig ALIAS onig)
endif()

configure_file(qsp_config.h.cmakein qsp_config.h @ONLY)

set(QSP_SOURCES
qsp/bindings/bindings_config.h
qsp/bindings/default/default_callbacks.c
qsp/bindings/default/default_control.c
qsp/bindings/default/qsp_default.h
qsp/bindings/java/java_callbacks.c
qsp/bindings/java/java_control.c
qsp/bindings/java/qsp_java.h
qsp/bindings/qsp.h
qsp/actions.c qsp/actions.h
qsp/callbacks.c qsp/callbacks.h
qsp/codetools.c qsp/codetools.h
qsp/coding.c qsp/coding.h
qsp/common.c qsp/common.h
qsp/errors.c qsp/errors.h
qsp/game.c qsp/game.h
qsp/locations.c qsp/locations.h
qsp/mathops.c qsp/mathops.h
qsp/memwatch.c qsp/memwatch.h
qsp/menu.c qsp/menu.h
qsp/objects.c qsp/objects.h
qsp/playlist.c qsp/playlist.h
qsp/regexp.c qsp/regexp.h
qsp/statements.c qsp/statements.h
qsp/text.c qsp/text.h
qsp/time.c qsp/time.h
qsp/towlower.c
qsp/towupper.c
qsp/tuples.c qsp/tuples.h
qsp/variables.c qsp/variables.h
qsp/variant.c qsp/variant.h
qsp/bindings/bindings_config.h
qsp/bindings/default/default_callbacks.c
qsp/bindings/default/default_control.c
qsp/bindings/default/qsp_default.h
qsp/bindings/java/java_callbacks.c
qsp/bindings/java/java_control.c
qsp/bindings/java/qsp_java.h
qsp/bindings/qsp.h
qsp/actions.c qsp/actions.h
qsp/callbacks.c qsp/callbacks.h
qsp/codetools.c qsp/codetools.h
qsp/coding.c qsp/coding.h
qsp/common.c qsp/common.h
qsp/errors.c qsp/errors.h
qsp/game.c qsp/game.h
qsp/locations.c qsp/locations.h
qsp/mathops.c qsp/mathops.h
qsp/memwatch.c qsp/memwatch.h
qsp/menu.c qsp/menu.h
qsp/objects.c qsp/objects.h
qsp/playlist.c qsp/playlist.h
qsp/regexp.c qsp/regexp.h
qsp/statements.c qsp/statements.h
qsp/text.c qsp/text.h
qsp/time.c qsp/time.h
qsp/towlower.c
qsp/towupper.c
qsp/tuples.c qsp/tuples.h
qsp/variables.c qsp/variables.h
qsp/variant.c qsp/variant.h
)
add_library(qsp SHARED ${QSP_SOURCES})
target_compile_definitions(qsp PUBLIC _UNICODE)
Expand All @@ -135,7 +135,7 @@ if (BUILD_JAVA)
endif()

target_include_directories(qsp
INTERFACE
INTERFACE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/qsp/bindings/default>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/qsp>"
Expand All @@ -145,33 +145,33 @@ target_include_directories(qsp
install(TARGETS qsp EXPORT QspTargets)

generate_export_header(qsp
BASE_NAME Qsp
EXPORT_MACRO_NAME QSP_EXTERN
BASE_NAME Qsp
EXPORT_MACRO_NAME QSP_EXTERN
)

write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/cmake/Qsp/QspConfigVersion.cmake COMPATIBILITY AnyNewerVersion)
configure_package_config_file(QspConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/Qsp/QspConfig.cmake
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Qsp"
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Qsp"
)

export(TARGETS qsp NAMESPACE Qsp:: FILE ${CMAKE_CURRENT_BINARY_DIR}/QspConfig.cmake)
install(EXPORT QspTargets NAMESPACE Qsp:: DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Qsp")

install(
DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/cmake
DESTINATION "${CMAKE_INSTALL_LIBDIR}"
DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/cmake
DESTINATION "${CMAKE_INSTALL_LIBDIR}"
)

install(FILES
qsp/bindings/qsp.h
qsp/bindings/bindings_config.h
"${CMAKE_CURRENT_BINARY_DIR}/qsp_export.h"
DESTINATION
DESTINATION
"${CMAKE_INSTALL_INCLUDEDIR}/qsp"
)

install(FILES
qsp/bindings/default/qsp_default.h
DESTINATION
DESTINATION
"${CMAKE_INSTALL_INCLUDEDIR}/qsp/default"
)
6 changes: 3 additions & 3 deletions app/src/main/cpp/qsp/game.c
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ INLINE QSP_BOOL qspCheckGameStatus(QSPString *strs, int strsCount, QSP_BOOL isUC
{
/* variables count */
if (!qspGetIntValueAndSkipLine(strs, strsCount, &ind, isUCS, &count)) return QSP_FALSE;
if (count < 0 || count > QSP_VARSMAXBUCKETSIZE) return QSP_FALSE;
if (count < 0 || count > QSP_VARSBUCKETSIZE) return QSP_FALSE;
/* variables */
for (j = 0; j < count; ++j)
{
Expand Down Expand Up @@ -586,11 +586,11 @@ QSP_BOOL qspOpenGameStatus(void *data, int dataSize)
for (i = 0; i < QSP_VARSBUCKETS; ++i)
{
varsCount = qspReadEncodedIntVal(strs[ind++], isUCS);
bucket->Capacity = bucket->VarsCount = varsCount;
bucket->VarsCount = varsCount;
bucket->Vars = 0;
if (varsCount)
{
var = bucket->Vars = (QSPVar *)malloc(varsCount * sizeof(QSPVar));
var = bucket->Vars = (QSPVar *)malloc(QSP_VARSBUCKETSIZE * sizeof(QSPVar));
for (j = 0; j < varsCount; ++j)
{
var->Name = qspDecodeString(strs[ind++], isUCS);
Expand Down
20 changes: 11 additions & 9 deletions app/src/main/cpp/qsp/variables.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,19 +127,21 @@ QSPVar *qspVarReference(QSPString name, QSP_BOOL toCreate)
}
if (toCreate)
{
if (varsCount >= QSP_VARSMAXBUCKETSIZE)
if (bucket->Vars)
{
qspSetError(QSP_ERR_TOOMANYVARS);
return 0;
if (varsCount >= QSP_VARSBUCKETSIZE)
{
qspSetError(QSP_ERR_TOOMANYVARS);
return 0;
}
var = bucket->Vars + varsCount;
}
if (varsCount >= bucket->Capacity)
else
{
bucket->Capacity = varsCount + 16;
bucket->Vars = (QSPVar *)realloc(bucket->Vars, bucket->Capacity * sizeof(QSPVar));
/* The fixed buffer without memory reallocation helps to cache specific variables */
var = bucket->Vars = (QSPVar *)malloc(QSP_VARSBUCKETSIZE * sizeof(QSPVar));
}

var = bucket->Vars + varsCount;

var->Name = qspCopyToNewText(name);
qspInitVarData(var);

Expand Down Expand Up @@ -167,7 +169,7 @@ void qspClearAllVars(QSP_BOOL toInit)
}
free(bucket->Vars);
}
bucket->Capacity = bucket->VarsCount = 0;
bucket->VarsCount = 0;
bucket->Vars = 0;
++bucket;
}
Expand Down
3 changes: 1 addition & 2 deletions app/src/main/cpp/qsp/variables.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
#define QSP_VARSDEFINES

#define QSP_VARSBUCKETS 1024
#define QSP_VARSMAXBUCKETSIZE 50
#define QSP_VARSBUCKETSIZE 32
#define QSP_VARGROUPSBATCHSIZE 256
#define QSP_VARARGS QSP_FMT("ARGS")
#define QSP_VARRES QSP_FMT("RESULT")
Expand All @@ -50,7 +50,6 @@
{
QSPVar *Vars;
int VarsCount;
int Capacity;
} QSPVarsBucket;

typedef struct
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,15 @@
import androidx.recyclerview.widget.RecyclerView;

public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {

private final OnItemClickListener mListener;
private final GestureDetector mGestureDetector;

public interface OnItemClickListener {
void onItemClick(View view , int position);

void onLongItemClick(View view , int position);
}

public RecyclerItemClickListener(Context context ,
final RecyclerView recyclerView ,
public RecyclerItemClickListener(Context context,
final RecyclerView recyclerView,
OnItemClickListener listener) {
mListener = listener;
mGestureDetector = new GestureDetector(context ,
mGestureDetector = new GestureDetector(context,
new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(@NonNull MotionEvent e) {
Expand All @@ -31,30 +26,36 @@ public boolean onSingleTapUp(@NonNull MotionEvent e) {

@Override
public void onLongPress(@NonNull MotionEvent e) {
var child = recyclerView.findChildViewUnder(e.getX() , e.getY());
var child = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (child != null && mListener != null) {
mListener.onLongItemClick(child , recyclerView.getChildAdapterPosition(child));
mListener.onLongItemClick(child, recyclerView.getChildAdapterPosition(child));
}
}
});
}

@Override
public boolean onInterceptTouchEvent(RecyclerView view , MotionEvent e) {
var childView = view.findChildViewUnder(e.getX() , e.getY());
public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
var childView = view.findChildViewUnder(e.getX(), e.getY());
if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
mListener.onItemClick(childView , view.getChildAdapterPosition(childView));
mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
return true;
}
return false;
}

@Override
public void onTouchEvent(@NonNull RecyclerView view ,
public void onTouchEvent(@NonNull RecyclerView view,
@NonNull MotionEvent motionEvent) {
}

@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}

public interface OnItemClickListener {
void onItemClick(View view, int position);

void onLongItemClick(View view, int position);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.qp.android.helpers.adapters;

import android.content.Context;
import android.util.AttributeSet;

import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

public class WrapContentLinearLayoutManager extends LinearLayoutManager {

public WrapContentLinearLayoutManager(Context context) {
super(context);
}

public WrapContentLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}

public WrapContentLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}

@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
try {
super.onLayoutChildren(recycler, state);
} catch (IndexOutOfBoundsException e) {
// do nothing
}
}
}
34 changes: 24 additions & 10 deletions app/src/main/java/org/qp/android/ui/game/GameMainFragment.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.qp.android.ui.game;

import static android.view.View.GONE;
import static android.view.View.VISIBLE;

import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
Expand All @@ -21,6 +24,7 @@
import org.qp.android.R;
import org.qp.android.databinding.FragmentGameMainBinding;
import org.qp.android.helpers.adapters.RecyclerItemClickListener;
import org.qp.android.helpers.adapters.WrapContentLinearLayoutManager;

public class GameMainFragment extends Fragment {

Expand All @@ -46,7 +50,6 @@ public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable Bundle savedInstanceState) {
var gameMainBinding = FragmentGameMainBinding.inflate(getLayoutInflater());
viewModel = new ViewModelProvider(requireActivity()).get(GameViewModel.class);
gameMainBinding.setGameViewModel(viewModel);

layoutTop = gameMainBinding.layoutTop;
layoutTop.setBackgroundColor(viewModel.getBackgroundColor());
Expand Down Expand Up @@ -88,23 +91,34 @@ public void onClickImage(String src) {
null));

// RecyclerView
var layoutManager = new WrapContentLinearLayoutManager(
requireContext(), LinearLayoutManager.VERTICAL, false
);
actionsView = gameMainBinding.actions;
var manager = (LinearLayoutManager) actionsView.getLayoutManager();
actionsView.setLayoutManager(layoutManager);
var dividerItemDecoration = new DividerItemDecoration(
actionsView.getContext(), manager.getOrientation());
actionsView.getContext(), layoutManager.getOrientation()
);
actionsView.addItemDecoration(dividerItemDecoration);
actionsView.setOverScrollMode(View.OVER_SCROLL_NEVER);
actionsView.setBackgroundColor(viewModel.getBackgroundColor());
actionsView.setAdapter(adapter);

viewModel.actsListLiveData.observe(getViewLifecycleOwner(), listItems -> {
actionsView.setBackgroundColor(viewModel.getBackgroundColor());
adapter.typeface = viewModel.getSettingsController().getTypeface();
adapter.textSize = viewModel.getFontSize();
adapter.textColor = viewModel.getTextColor();
adapter.linkTextColor = viewModel.getLinkColor();
adapter.backgroundColor = viewModel.getBackgroundColor();
adapter.submitList(listItems);
if (!viewModel.showActions || listItems.isEmpty()) {
actionsView.setVisibility(GONE);
separatorView.setVisibility(GONE);
} else {
actionsView.setVisibility(VISIBLE);
separatorView.setVisibility(VISIBLE);
actionsView.setBackgroundColor(viewModel.getBackgroundColor());
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 Down
Loading
Loading