+ * Non-letter characters return U+0000.
+ *
+ * @param lwjglGlfwKeycode A GLFW key code macro (e.g., {@link LwjglGlfwKeycode#GLFW_KEY_W}).
+ */
+ public static char getLwjglChar(int lwjglGlfwKeycode){
+ int androidKeycode = sAndroidKeycodes[sLwjglKeycodesReversed[lwjglGlfwKeycode]];
+ KeyEvent key = new KeyEvent(KeyEvent.ACTION_UP, androidKeycode);
+ char charToSend;
+ charToSend = ((char) key.getUnicodeChar());
+ int currentMods = CallbackBridge.getCurrentMods();
+ if (Character.isLetter(charToSend) && (
+ ((currentMods & LwjglGlfwKeycode.GLFW_MOD_SHIFT) != 0) ^
+ ((currentMods & LwjglGlfwKeycode.GLFW_MOD_CAPS_LOCK) != 0))
+ ){
+ charToSend = Character.toUpperCase(charToSend);
+ }
+ return charToSend;
+ }
+
public static short getValueByIndex(int index) {
return sLwjglKeycodes[index];
}
@@ -218,6 +241,7 @@ public class EfficientAndroidLWJGLKeycode {
private static void add(int androidKeycode, short LWJGLKeycode){
sAndroidKeycodes[mTmpCount] = androidKeycode;
sLwjglKeycodes[mTmpCount] = LWJGLKeycode;
+ sLwjglKeycodesReversed[LWJGLKeycode] = mTmpCount;
mTmpCount ++;
}
}
diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/LauncherActivity.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/LauncherActivity.java
index 9b8834d17..8498e93fb 100644
--- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/LauncherActivity.java
+++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/LauncherActivity.java
@@ -1,6 +1,8 @@
package net.kdt.pojavlaunch;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static net.kdt.pojavlaunch.Tools.hasNoOnlineProfileDialog;
+
import android.Manifest;
import android.app.NotificationManager;
import android.content.Context;
@@ -139,7 +141,7 @@ public class LauncherActivity extends BaseActivity {
}
if (isOlderThan13) {
- Toast.makeText(this, R.string.toast_not_available_demo, Toast.LENGTH_LONG).show();
+ hasNoOnlineProfileDialog(this, getString(R.string.global_error), getString(R.string.demo_versions_supported));
return false;
}
}
@@ -164,7 +166,9 @@ public class LauncherActivity extends BaseActivity {
};
private ActivityResultLauncher
+ * This is of course, very jank, it does not work for anything below 1.7.5 but why is anyone
+ * on that version anyway? Legacy4J has LTS for like all the versions.
+ */
+ private static void startOldLegacy4JMitigation(Activity activity, File gamedir) {
+ boolean hasLegacy4J = false;
+ File modsDir = new File(gamedir, "mods");
+ File[] mods = modsDir.listFiles(file -> file.isFile() && file.getName().endsWith(".jar"));
+ if(mods != null) {
+ for (File file : mods) {
+ String name = file.getName();
+ if (name.contains("Legacy4J")) {
+ hasLegacy4J = true;
+ break;
+ }
+ }
+ }
+ if (hasLegacy4J) {
+ String TAG = "OldLegacy4JMitigation";
+ Log.i(TAG, "Legacy4J detected!");
+ oldL4JMitigationLogListener = loggedLine -> {
+ if (LauncherPreferences.PREF_GAMEPAD_SDL_PASSTHRU && loggedLine.contains("literal{SDL3 (isXander's libsdl4j)} isn't supported in this system. GLFW will be used instead.")) {
+ Log.i(TAG, "Old version of Legacy4J detected! Force enabling SDL");
+ Tools.SDL.initializeControllerSubsystems();
+ Tools.runOnUiThread(() -> {
+ Tools.dialog(activity, activity.getString(R.string.global_warning), activity.getString(R.string.oldL4JFound));
+ });
+ Logger.removeLogListener(oldL4JMitigationLogListener);
+ } else if (LauncherPreferences.PREF_GAMEPAD_SDL_PASSTHRU && loggedLine.contains("Added SDL Controller Mappings")) {
+ Log.i(TAG, "Fixed version of Legacy4J detected! Have fun!");
+ Logger.removeLogListener(oldL4JMitigationLogListener);
+ }
+ };
+ Logger.addLogListener(oldL4JMitigationLogListener);
+ }
+ }
public static File getGameDirPath(@NonNull MinecraftProfile minecraftProfile){
if(minecraftProfile.gameDir != null){
@@ -798,6 +935,9 @@ public final class Tools {
public static void dialogOnUiThread(final Activity activity, final CharSequence title, final CharSequence message) {
activity.runOnUiThread(()->dialog(activity, title, message));
}
+ public static void dialogOnUiThread(final Activity activity, final int title, final int message) {
+ dialogOnUiThread(activity, activity.getString(title), activity.getString(message));
+ }
public static void dialog(final Context context, final CharSequence title, final CharSequence message) {
new AlertDialog.Builder(context)
@@ -899,7 +1039,7 @@ public final class Tools {
insertSafety(inheritsVer, customVer,
"assetIndex", "assets", "id",
"mainClass", "minecraftArguments",
- "releaseTime", "time", "type"
+ "releaseTime", "time", "type", "inheritsFrom"
);
// Go through the libraries, remove the ones overridden by the custom version
@@ -1429,6 +1569,18 @@ public final class Tools {
OBSOLETE_RESOURCES_PATH = DIR_GAME_NEW + "/resources";
}
+ private static NetworkInfo getActiveNetworkInfo(Context ctx) {
+ ConnectivityManager connMgr = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
+ return networkInfo; // This can return null when there is no wifi or data connected
+ }
+
+ public static boolean isOnline(Context ctx) {
+ NetworkInfo info = getActiveNetworkInfo(ctx);
+ if(info == null) return false;
+ return (info.isConnected());
+ }
+
public static boolean isDemoProfile(Context ctx){
MinecraftAccount currentProfile = PojavProfile.getCurrentProfileContent(ctx, null);
return currentProfile != null && currentProfile.isDemo();
@@ -1438,4 +1590,117 @@ public final class Tools {
MinecraftAccount currentProfile = PojavProfile.getCurrentProfileContent(ctx, null);
return currentProfile == null || currentProfile.isLocal();
}
+ public static boolean hasOnlineProfile(){
+ for (MinecraftAccount accountToCheck : getAllProfiles()) {
+ if (!accountToCheck.isLocal() && !accountToCheck.isDemo()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static void hasNoOnlineProfileDialog(Activity activity, @Nullable Runnable run, @Nullable String customTitle, @Nullable String customMessage){
+ if (hasOnlineProfile() && !Tools.isDemoProfile(activity)){
+ if (run != null) { // Demo profile handling should be using customTitle and customMessage
+ run.run();
+ }
+ } else { // If there is no online profile, show a dialog
+ customTitle = customTitle == null ? activity.getString(R.string.no_minecraft_account_found) : customTitle;
+ customMessage = customMessage == null ? activity.getString(R.string.feature_requires_java_account) : customMessage;
+ dialogOnUiThread(activity, customTitle, customMessage);
+ }
+ }
+
+ // Some boilerplate to reduce boilerplate elsewhere
+ public static void hasNoOnlineProfileDialog(Activity activity){
+ hasNoOnlineProfileDialog(activity, null, null, null);
+ }
+ public static void hasNoOnlineProfileDialog(Activity activity, Runnable run){
+ hasNoOnlineProfileDialog(activity, run, null, null);
+ }
+ public static void hasNoOnlineProfileDialog(Activity activity, String customTitle, String customMessage){
+ hasNoOnlineProfileDialog(activity, null, customTitle, customMessage);
+ }
+
+ public static String getSelectedVanillaMcVer(){
+ String selectedProfile = LauncherPreferences.DEFAULT_PREF.getString(LauncherPreferences.PREF_KEY_CURRENT_PROFILE, "");
+ MinecraftProfile selected = LauncherProfiles.mainProfileJson.profiles.get(selectedProfile);
+ if (selected == null) { // This should NEVER happen.
+ throw new RuntimeException("No profile selected, how did you reach this? Go ask in the discord or github");
+ }
+ String currentMCVersion = selected.lastVersionId;
+ String vanillaVersion = currentMCVersion;
+ File providedJsonFile = new File(Tools.DIR_HOME_VERSION + "/" + currentMCVersion + "/" + currentMCVersion + ".json");
+ JMinecraftVersionList.Version providedJsonVersion = null;
+ try {
+ providedJsonVersion = Tools.GLOBAL_GSON.fromJson(Tools.read(providedJsonFile.getAbsolutePath()), JMinecraftVersionList.Version.class);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ try {
+ vanillaVersion = providedJsonVersion.inheritsFrom != null ? providedJsonVersion.inheritsFrom : vanillaVersion;
+ } catch (NullPointerException e) {
+ throw new RuntimeException(e);
+ }
+ return vanillaVersion;
+ }
+
+ public static Integer mcVersiontoInt(String mcVersion){
+ String[] sVersionArray = mcVersion.split("\\.");
+ String[] iVersionArray = new String[3];
+ // Make sure this is actually a version string
+ for (int i = 0; i < iVersionArray.length; i++) {
+ try {
+ // Ensure there's padding
+ sVersionArray[i] = String.format("%3s", sVersionArray[i]).replace(' ', '0');
+ // Grab only the last 3, MCJE 999.999.999 isnt coming soon anyway
+ sVersionArray[i] = sVersionArray[i].substring(sVersionArray[i].length() - 3);
+ } catch (ArrayIndexOutOfBoundsException ignored){
+ // If we don't get 3 a third array, pad with 0s because it's probably 1.21 or something
+ iVersionArray[i] = "000";
+ continue;
+ }
+ try {
+ // Verify its a real deal, legit number
+ Integer.parseInt(sVersionArray[i]);
+ iVersionArray[i] = sVersionArray[i];
+ } catch (NumberFormatException e) {
+ throw new RuntimeException("Tools(mcVersiontoInt): Invalid version string");
+ }
+ }
+ return Integer.parseInt(iVersionArray[0] + iVersionArray[1] + iVersionArray[2]);
+ }
+
+ public static boolean isPointerDeviceConnected() {
+ int[] deviceIds = InputDevice.getDeviceIds();
+ for (int id : deviceIds) {
+ InputDevice device = InputDevice.getDevice(id);
+ if (device == null) continue;
+ int sources = device.getSources();
+ if ((sources & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE
+ || (sources & InputDevice.SOURCE_TOUCHPAD) == InputDevice.SOURCE_TOUCHPAD
+ || (sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static Object runMethodbyReflection(String className, String methodName) throws ReflectiveOperationException{
+ Class> clazz = Class.forName(className);
+ Method method = clazz.getDeclaredMethod(methodName);
+ method.setAccessible(true);
+ Object motionListener = method.invoke(null);
+ assert motionListener != null;
+ return motionListener;
+ }
+
+ static class SDL {
+ /**
+ * Initializes gamepad, joystick, and event subsystems.
+ * This triggers {@link SDLControllerManager#pollInputDevices()} and subsequently disables
+ * the emulated gamepad implementation.
+ */
+ public static native void initializeControllerSubsystems();
+ }
}
diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlButton.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlButton.java
index 5fb9d687b..efa07b234 100644
--- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlButton.java
+++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlButton.java
@@ -15,6 +15,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
+import net.kdt.pojavlaunch.EfficientAndroidLWJGLKeycode;
import net.kdt.pojavlaunch.LwjglGlfwKeycode;
import net.kdt.pojavlaunch.MainActivity;
import net.kdt.pojavlaunch.R;
@@ -191,7 +192,7 @@ public class ControlButton extends TextView implements ControlInterface {
setActivated(isDown);
for(int keycode : mProperties.keycodes){
if(keycode >= GLFW_KEY_UNKNOWN){
- sendKeyPress(keycode, CallbackBridge.getCurrentMods(), isDown);
+ sendKeyPress(keycode, EfficientAndroidLWJGLKeycode.getLwjglChar(keycode), CallbackBridge.getCurrentMods(), isDown);
CallbackBridge.setModifiers(keycode, isDown);
}else{
Log.i("punjabilauncher", "sendSpecialKey("+keycode+","+isDown+")");
diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/Gamepad.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/Gamepad.java
index fe97ec601..e810273e7 100644
--- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/Gamepad.java
+++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/Gamepad.java
@@ -90,6 +90,7 @@ public class Gamepad implements GrabListener, GamepadHandler {
private boolean mRemoved = false;
public Gamepad(View contextView, InputDevice inputDevice, GamepadDataProvider mapProvider, boolean showCursor){
+
Settings.setDeadzoneScale(PREF_DEADZONE_SCALE);
mScreenChoreographer = Choreographer.getInstance();
diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/mouse/AndroidPointerCapture.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/mouse/AndroidPointerCapture.java
index 38f6dd4ca..418c46bb2 100644
--- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/mouse/AndroidPointerCapture.java
+++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/mouse/AndroidPointerCapture.java
@@ -1,13 +1,20 @@
package net.kdt.pojavlaunch.customcontrols.mouse;
+import static net.kdt.pojavlaunch.prefs.LauncherPreferences.DEFAULT_PREF;
+import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_MOUSE_GRAB_FORCE;
+
+import android.content.SharedPreferences;
import android.os.Build;
+import android.util.Log;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
+import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
+import net.kdt.pojavlaunch.GrabListener;
import net.kdt.pojavlaunch.MinecraftGLSurface;
import net.kdt.pojavlaunch.Tools;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
@@ -15,7 +22,7 @@ import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import org.lwjgl.glfw.CallbackBridge;
@RequiresApi(api = Build.VERSION_CODES.O)
-public class AndroidPointerCapture implements ViewTreeObserver.OnWindowFocusChangeListener, View.OnCapturedPointerListener {
+public class AndroidPointerCapture implements ViewTreeObserver.OnWindowFocusChangeListener, View.OnCapturedPointerListener, GrabListener, SharedPreferences.OnSharedPreferenceChangeListener {
private static final float TOUCHPAD_SCROLL_THRESHOLD = 1;
private final AbstractTouchpad mTouchpad;
private final View mHostView;
@@ -32,14 +39,43 @@ public class AndroidPointerCapture implements ViewTreeObserver.OnWindowFocusChan
this.mHostView = hostView;
hostView.setOnCapturedPointerListener(this);
hostView.getViewTreeObserver().addOnWindowFocusChangeListener(this);
+ DEFAULT_PREF.registerOnSharedPreferenceChangeListener(this);
+ CallbackBridge.addGrabListener(this);
}
+ /**
+ * Checks whether or not the touchpad is already enabled and if user prefers virtual cursor
+ * if they don't, the touchpad is not enabled
+ */
private void enableTouchpadIfNecessary() {
- if(!mTouchpad.getDisplayState()) mTouchpad.enable(true);
+ if(!mTouchpad.getDisplayState() && PREF_MOUSE_GRAB_FORCE) mTouchpad.enable(true);
+ }
+
+ // Needed so it releases the cursor when inside game menu
+ @Override
+ public void onGrabState(boolean isGrabbing) {
+ handleAutomaticCapture();
+ }
+ // It's only here so the side-dialog changes it live
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, @Nullable String key) {
+ if (sharedPreferences.getBoolean("always_grab_mouse", true)){
+ enableTouchpadIfNecessary();
+ } else mTouchpad.disable();
+ handleAutomaticCapture();
}
public void handleAutomaticCapture() {
- if(!mHostView.hasWindowFocus()) {
+ // isGrabbing checks for whether we are in menu
+ if (!CallbackBridge.isGrabbing()
+ && !PREF_MOUSE_GRAB_FORCE) {
+ mHostView.releasePointerCapture();
+ return;
+ }
+ if (mHostView.hasPointerCapture()) {
+ enableTouchpadIfNecessary();
+ }
+ if (!mHostView.hasWindowFocus()) {
mHostView.requestFocus();
} else {
mHostView.requestPointerCapture();
@@ -128,7 +164,11 @@ public class AndroidPointerCapture implements ViewTreeObserver.OnWindowFocusChan
@Override
public void onWindowFocusChanged(boolean hasFocus) {
- if(hasFocus && Tools.isAndroid8OrHigher()) mHostView.requestPointerCapture();
+ if (!CallbackBridge.isGrabbing() // Only capture if not in menu and user said so
+ && !PREF_MOUSE_GRAB_FORCE) {
+ return;
+ }
+ if (hasFocus && Tools.isAndroid8OrHigher()) mHostView.requestPointerCapture();
}
public void detach() {
diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/mouse/Touchpad.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/mouse/Touchpad.java
index 7a1f71d86..78ca9e710 100644
--- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/mouse/Touchpad.java
+++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/mouse/Touchpad.java
@@ -132,7 +132,7 @@ public class Touchpad extends View implements GrabListener, AbstractTouchpad {
public void enable(boolean supposed) {
if(mDisplayState) return;
mDisplayState = true;
- if(supposed && CallbackBridge.isGrabbing()) return;
+ if(supposed && CallbackBridge.isGrabbing() && LauncherPreferences.PREF_MOUSE_GRAB_FORCE) return;
_enable();
}
diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/LocalLoginFragment.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/LocalLoginFragment.java
index 86a00e375..e4e2e5d4f 100644
--- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/LocalLoginFragment.java
+++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/LocalLoginFragment.java
@@ -1,5 +1,7 @@
package net.kdt.pojavlaunch.fragments;
+import static net.kdt.pojavlaunch.Tools.hasOnlineProfile;
+
import android.content.Context;
import android.os.Bundle;
import android.view.View;
@@ -31,6 +33,10 @@ public class LocalLoginFragment extends Fragment {
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ // This is overkill but meh
+ if (!hasOnlineProfile()){
+ Tools.swapFragment(requireActivity(), MainMenuFragment.class, MainMenuFragment.TAG, null);
+ }
mUsernameEditText = view.findViewById(R.id.login_edit_email);
view.findViewById(R.id.login_button).setOnClickListener(v -> {
if(!checkEditText()) {
diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/MainMenuFragment.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/MainMenuFragment.java
index 364c3d0b1..ee59d87e4 100644
--- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/MainMenuFragment.java
+++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/MainMenuFragment.java
@@ -1,5 +1,7 @@
package net.kdt.pojavlaunch.fragments;
+import static net.kdt.pojavlaunch.Tools.hasNoOnlineProfileDialog;
+import static net.kdt.pojavlaunch.Tools.hasOnlineProfile;
import static net.kdt.pojavlaunch.Tools.openPath;
import static net.kdt.pojavlaunch.Tools.shareLog;
@@ -53,11 +55,13 @@ public class MainMenuFragment extends Fragment {
mNewsButton.setOnClickListener(v -> Tools.openURL(requireActivity(), Tools.URL_HOME));
mDiscordButton.setOnClickListener(v -> Tools.openURL(requireActivity(), getString(R.string.discord_invite)));
mCustomControlButton.setOnClickListener(v -> startActivity(new Intent(requireContext(), CustomControlsActivity.class)));
- mInstallJarButton.setOnClickListener(v -> runInstallerWithConfirmation(false));
- mInstallJarButton.setOnLongClickListener(v->{
- runInstallerWithConfirmation(true);
- return true;
- });
+ if (hasOnlineProfile()) {
+ mInstallJarButton.setOnClickListener(v -> runInstallerWithConfirmation(false));
+ mInstallJarButton.setOnLongClickListener(v -> {
+ runInstallerWithConfirmation(true);
+ return true;
+ });
+ } else mInstallJarButton.setOnClickListener(v -> hasNoOnlineProfileDialog(requireActivity()));
mEditProfileButton.setOnClickListener(v -> mVersionSpinner.openProfileEditor(requireActivity()));
mPlayButton.setOnClickListener(v -> ExtraCore.setValue(ExtraConstants.LAUNCH_GAME, true));
@@ -65,13 +69,12 @@ public class MainMenuFragment extends Fragment {
mShareLogsButton.setOnClickListener((v) -> shareLog(requireContext()));
mOpenDirectoryButton.setOnClickListener((v)-> {
- Tools.switchDemo(Tools.isDemoProfile(v.getContext())); // avoid switching accounts being able to access
- if(Tools.isDemoProfile(v.getContext())){
- Toast.makeText(v.getContext(), R.string.toast_not_available_demo, Toast.LENGTH_LONG).show();
- return;
- }
+ if (Tools.isDemoProfile(v.getContext())){ // Say a different message when on demo profile since they might see the hidden demo folder
+ hasNoOnlineProfileDialog(getActivity(), getString(R.string.demo_unsupported), getString(R.string.change_account));
+ } else if (!hasOnlineProfile()) { // Otherwise display the generic pop-up to log in
+ hasNoOnlineProfileDialog(requireActivity());
+ } else openPath(v.getContext(), getCurrentProfileDirectory(), false);
- openPath(v.getContext(), getCurrentProfileDirectory(), false);
});
@@ -97,12 +100,6 @@ public class MainMenuFragment extends Fragment {
}
private void runInstallerWithConfirmation(boolean isCustomArgs) {
- // avoid using custom installers to install a version
- if(Tools.isLocalProfile(requireContext()) || Tools.isDemoProfile(requireContext())){
- Toast.makeText(requireContext(), R.string.toast_not_available_demo, Toast.LENGTH_LONG).show();
- return;
- }
-
if (ProgressKeeper.getTaskCount() == 0)
Tools.installMod(requireActivity(), isCustomArgs);
else
diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ModVersionListFragment.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ModVersionListFragment.java
index 1260cdde6..7b2952d3b 100644
--- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ModVersionListFragment.java
+++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ModVersionListFragment.java
@@ -17,7 +17,6 @@ import androidx.fragment.app.Fragment;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.Tools;
import net.kdt.pojavlaunch.extra.ExtraCore;
-import net.kdt.pojavlaunch.mirrors.DownloadMirror;
import net.kdt.pojavlaunch.modloaders.ModloaderDownloadListener;
import net.kdt.pojavlaunch.modloaders.ModloaderListenerProxy;
import net.kdt.pojavlaunch.progresskeeper.ProgressKeeper;
@@ -106,7 +105,7 @@ public abstract class ModVersionListFragment> {
+ public static final String TAG = "NeoForgeInstallFragment";
+ public NeoForgeInstallFragment() {
+ super(TAG);
+ }
+
+ private static final String NEOFORGE_METADATA_URL = "https://meta.prismlauncher.org/v1/net.neoforged/index.json";
+
+
+ @Override
+ public void onAttach(@NonNull Context context) {
+ super.onAttach(context);
+ }
+
+ @Override
+ public int getTitleText() {
+ return R.string.neoforge_dl_select_version;
+ }
+
+ @Override
+ public int getNoDataMsg() {
+ return R.string.neoforge_dl_no_installer;
+ }
+
+ @Override
+ public List