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 499ac6d74..f3ad4f290 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/LauncherActivity.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/LauncherActivity.java @@ -1,8 +1,7 @@ package net.kdt.pojavlaunch; -import static net.kdt.pojavlaunch.MainActivity.INTENT_MINECRAFT_VERSION; - -import android.content.Intent; +import android.app.NotificationManager; +import android.content.Context; import android.os.Bundle; import android.view.View; import android.widget.ImageButton; @@ -27,15 +26,17 @@ import net.kdt.pojavlaunch.extra.ExtraListener; import net.kdt.pojavlaunch.fragments.MainMenuFragment; import net.kdt.pojavlaunch.fragments.MicrosoftLoginFragment; import net.kdt.pojavlaunch.fragments.SelectAuthFragment; -import net.kdt.pojavlaunch.mirrors.DownloadMirror; import net.kdt.pojavlaunch.modloaders.modpacks.ModloaderInstallTracker; import net.kdt.pojavlaunch.modloaders.modpacks.imagecache.IconCacheJanitor; import net.kdt.pojavlaunch.prefs.LauncherPreferences; import net.kdt.pojavlaunch.prefs.screens.LauncherPreferenceFragment; import net.kdt.pojavlaunch.progresskeeper.ProgressKeeper; +import net.kdt.pojavlaunch.progresskeeper.TaskCountListener; import net.kdt.pojavlaunch.services.ProgressServiceKeeper; import net.kdt.pojavlaunch.tasks.AsyncMinecraftDownloader; import net.kdt.pojavlaunch.tasks.AsyncVersionList; +import net.kdt.pojavlaunch.tasks.ContextAwareDoneListener; +import net.kdt.pojavlaunch.utils.NotificationUtils; import net.kdt.pojavlaunch.value.launcherprofiles.LauncherProfiles; import net.kdt.pojavlaunch.value.launcherprofiles.MinecraftProfile; @@ -53,6 +54,7 @@ public class LauncherActivity extends BaseActivity { private ProgressLayout mProgressLayout; private ProgressServiceKeeper mProgressServiceKeeper; private ModloaderInstallTracker mInstallTracker; + private NotificationManager mNotificationManager; /* Allows to switch from one button "type" to another */ private final FragmentManager.FragmentLifecycleCallbacks mFragmentCallbackListener = new FragmentManager.FragmentLifecycleCallbacks() { @@ -123,32 +125,24 @@ public class LauncherActivity extends BaseActivity { } String normalizedVersionId = AsyncMinecraftDownloader.normalizeVersionId(prof.lastVersionId); JMinecraftVersionList.Version mcVersion = AsyncMinecraftDownloader.getListedVersion(normalizedVersionId); - new AsyncMinecraftDownloader(this, mcVersion, normalizedVersionId, new AsyncMinecraftDownloader.DoneListener() { - @Override - public void onDownloadDone() { - ProgressKeeper.waitUntilDone(()-> runOnUiThread(() -> { - try { - Intent mainIntent = new Intent(getBaseContext(), MainActivity.class); - mainIntent.putExtra(INTENT_MINECRAFT_VERSION, normalizedVersionId); - mainIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); - startActivity(mainIntent); - finish(); - android.os.Process.killProcess(android.os.Process.myPid()); //You should kill yourself, NOW! - } catch (Throwable e) { - Tools.showError(getBaseContext(), e); - } - })); - } - - @Override - public void onDownloadFailed(Throwable th) { - if(DownloadMirror.checkForTamperedException(LauncherActivity.this, th)) return; - if(th != null) Tools.showError(LauncherActivity.this, R.string.mc_download_failed, th); - } - }); + new AsyncMinecraftDownloader(this, + mcVersion, + normalizedVersionId, + new ContextAwareDoneListener(this, normalizedVersionId) + ); return false; }; + private final TaskCountListener mDoubleLaunchPreventionListener = (tc)->{ + // Hide the notification that starts the game if there are tasks executing. + // Prevents the user from trying to launch the game with tasks ongoing. + if(tc > 0) { + Tools.runOnUiThread(() -> + mNotificationManager.cancel(NotificationUtils.NOTIFICATION_ID_GAME_START) + ); + } + }; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -156,6 +150,8 @@ public class LauncherActivity extends BaseActivity { IconCacheJanitor.runJanitor(); getWindow().setBackgroundDrawable(null); bindViews(); + mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + ProgressKeeper.addTaskCountListener(mDoubleLaunchPreventionListener); ProgressKeeper.addTaskCountListener((mProgressServiceKeeper = new ProgressServiceKeeper(this))); mSettingsButton.setOnClickListener(mSettingButtonListener); diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/ShowErrorActivity.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/ShowErrorActivity.java index ec64ee7fb..1c78021e1 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/ShowErrorActivity.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/ShowErrorActivity.java @@ -12,7 +12,8 @@ import androidx.annotation.Nullable; import androidx.core.app.NotificationCompat; import net.kdt.pojavlaunch.contextexecutor.ContextExecutorTask; -import net.kdt.pojavlaunch.value.NotificationConstants; +import net.kdt.pojavlaunch.utils.NotificationUtils; +import net.kdt.pojavlaunch.utils.NotificationUtils; import java.io.Serializable; @@ -45,31 +46,23 @@ public class ShowErrorActivity extends Activity { this.mThrowable = mThrowable; this.mRolledMsg = mRolledMsg; } + @Override public void executeWithActivity(Activity activity) { - Tools.showError(activity, mRolledMsg, mThrowable); + Tools.showError(activity, mRolledMsg, mThrowable, true); } @Override public void executeWithApplication(Context context) { - sendNotification(context, this); + Intent showErrorIntent = new Intent(context, ShowErrorActivity.class); + showErrorIntent.putExtra(ERROR_ACTIVITY_REMOTE_TASK, this); + NotificationUtils.sendBasicNotification(context, + R.string.notif_error_occured, + R.string.notif_error_occured_desc, + showErrorIntent, + NotificationUtils.PENDINGINTENT_CODE_SHOW_ERROR, + NotificationUtils.NOTIFICATION_ID_SHOW_ERROR + ); } } - private static void sendNotification(Context context, RemoteErrorTask remoteErrorTask) { - - Intent showErrorIntent = new Intent(context, ShowErrorActivity.class); - showErrorIntent.putExtra(ERROR_ACTIVITY_REMOTE_TASK, remoteErrorTask); - - PendingIntent pendingIntent = PendingIntent.getActivity(context, NotificationConstants.PENDINGINTENT_CODE_SHOW_ERROR, showErrorIntent, - Build.VERSION.SDK_INT >=23 ? PendingIntent.FLAG_IMMUTABLE : 0); - - NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, context.getString(R.string.notif_channel_id)) - .setContentTitle(context.getString(R.string.notif_error_occured)) - .setContentText(context.getString(R.string.notif_error_occured_desc)) - .setSmallIcon(R.drawable.notif_icon) - .setContentIntent(pendingIntent); - notificationManager.notify(NotificationConstants.NOTIFICATION_ID_SHOW_ERROR, notificationBuilder.build()); - } - } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java index 3d3e09a3d..a96c4d9b8 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java @@ -548,7 +548,9 @@ public final class Tools { public static void showError(final Context ctx, final String rolledMessage, final Throwable e) { showError(ctx, R.string.global_error, rolledMessage, e, false, false); } - + public static void showError(final Context ctx, final String rolledMessage, final Throwable e, boolean exitIfOk) { + showError(ctx, R.string.global_error, rolledMessage, e, exitIfOk, false); + } public static void showError(final Context ctx, final int titleId, final Throwable e, final boolean exitIfOk) { showError(ctx, titleId, null, e, exitIfOk, false); } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/NotificationDownloadListener.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/NotificationDownloadListener.java index 84c41e961..6a3f9297f 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/NotificationDownloadListener.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/NotificationDownloadListener.java @@ -1,36 +1,24 @@ package net.kdt.pojavlaunch.modloaders.modpacks.api; -import android.app.NotificationManager; -import android.app.PendingIntent; import android.content.Context; import android.content.Intent; -import android.os.Build; - -import androidx.core.app.NotificationCompat; import net.kdt.pojavlaunch.LauncherActivity; import net.kdt.pojavlaunch.R; import net.kdt.pojavlaunch.Tools; import net.kdt.pojavlaunch.modloaders.ModloaderDownloadListener; import net.kdt.pojavlaunch.modloaders.modpacks.ModloaderInstallTracker; -import net.kdt.pojavlaunch.value.NotificationConstants; +import net.kdt.pojavlaunch.utils.NotificationUtils; import java.io.File; public class NotificationDownloadListener implements ModloaderDownloadListener { - - private final NotificationCompat.Builder mNotificationBuilder; - private final NotificationManager mNotificationManager; private final Context mContext; private final ModLoader mModLoader; public NotificationDownloadListener(Context context, ModLoader modLoader) { mModLoader = modLoader; mContext = context.getApplicationContext(); - mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - mNotificationBuilder = new NotificationCompat.Builder(context, "channel_id") - .setContentTitle(context.getString(R.string.modpack_install_notification_title)) - .setSmallIcon(R.drawable.notif_icon); } @Override @@ -38,32 +26,29 @@ public class NotificationDownloadListener implements ModloaderDownloadListener { if(mModLoader.requiresGuiInstallation()) { ModloaderInstallTracker.saveModLoader(mContext, mModLoader, downloadedFile); Intent mainActivityIntent = new Intent(mContext, LauncherActivity.class); - Tools.runOnUiThread(() -> sendIntentNotification(mainActivityIntent, R.string.modpack_install_notification_success)); + Tools.runOnUiThread(() -> NotificationUtils.sendBasicNotification(mContext, + R.string.modpack_install_notification_title, + R.string.modpack_install_notification_success, + mainActivityIntent, + NotificationUtils.PENDINGINTENT_CODE_DOWNLOAD_SERVICE, + NotificationUtils.NOTIFICATION_ID_DOWNLOAD_LISTENER + )); } } @Override public void onDataNotAvailable() { - Tools.runOnUiThread(()->sendEmptyNotification(R.string.modpack_install_notification_data_not_available)); + Tools.runOnUiThread(()->NotificationUtils.sendBasicNotification(mContext, + R.string.modpack_install_notification_title, + R.string.modpack_install_notification_success, + null, + NotificationUtils.PENDINGINTENT_CODE_DOWNLOAD_SERVICE, + NotificationUtils.NOTIFICATION_ID_DOWNLOAD_LISTENER + )); } @Override public void onDownloadError(Exception e) { Tools.showErrorRemote(mContext, R.string.modpack_install_modloader_download_failed, e); } - - private void sendIntentNotification(Intent intent, int contentText) { - PendingIntent pendingInstallIntent = - PendingIntent.getActivity(mContext, NotificationConstants.PENDINGINTENT_CODE_DOWNLOAD_SERVICE, - intent, Build.VERSION.SDK_INT >=23 ? PendingIntent.FLAG_IMMUTABLE : 0); - - mNotificationBuilder.setContentText(mContext.getText(contentText)); - mNotificationBuilder.setContentIntent(pendingInstallIntent); - mNotificationManager.notify(NotificationConstants.NOTIFICATION_ID_DOWNLOAD_LISTENER, mNotificationBuilder.build()); - } - - private void sendEmptyNotification(int contentText) { - mNotificationBuilder.setContentText(mContext.getText(contentText)); - mNotificationManager.notify(NotificationConstants.NOTIFICATION_ID_DOWNLOAD_LISTENER, mNotificationBuilder.build()); - } } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/services/GameService.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/services/GameService.java index a88416961..9329e05a5 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/services/GameService.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/services/GameService.java @@ -14,7 +14,7 @@ import androidx.core.content.ContextCompat; import net.kdt.pojavlaunch.R; import net.kdt.pojavlaunch.Tools; -import net.kdt.pojavlaunch.value.NotificationConstants; +import net.kdt.pojavlaunch.utils.NotificationUtils; import java.lang.ref.WeakReference; @@ -39,7 +39,7 @@ public class GameService extends Service { } Intent killIntent = new Intent(getApplicationContext(), GameService.class); killIntent.putExtra("kill", true); - PendingIntent pendingKillIntent = PendingIntent.getService(this, NotificationConstants.PENDINGINTENT_CODE_KILL_GAME_SERVICE + PendingIntent pendingKillIntent = PendingIntent.getService(this, NotificationUtils.PENDINGINTENT_CODE_KILL_GAME_SERVICE , killIntent, Build.VERSION.SDK_INT >=23 ? PendingIntent.FLAG_IMMUTABLE : 0); NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "channel_id") .setContentTitle(getString(R.string.lazy_service_default_title)) @@ -47,7 +47,7 @@ public class GameService extends Service { .addAction(android.R.drawable.ic_menu_close_clear_cancel, getString(R.string.notification_terminate), pendingKillIntent) .setSmallIcon(R.drawable.notif_icon) .setNotificationSilent(); - startForeground(NotificationConstants.NOTIFICATION_ID_GAME_SERVICE, notificationBuilder.build()); + startForeground(NotificationUtils.NOTIFICATION_ID_GAME_SERVICE, notificationBuilder.build()); return START_NOT_STICKY; // non-sticky so android wont try restarting the game after the user uses the "Quit" button } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/services/ProgressService.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/services/ProgressService.java index 2ffa71eb9..fa005f016 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/services/ProgressService.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/services/ProgressService.java @@ -19,7 +19,7 @@ import net.kdt.pojavlaunch.R; import net.kdt.pojavlaunch.Tools; import net.kdt.pojavlaunch.progresskeeper.ProgressKeeper; import net.kdt.pojavlaunch.progresskeeper.TaskCountListener; -import net.kdt.pojavlaunch.value.NotificationConstants; +import net.kdt.pojavlaunch.utils.NotificationUtils; /** * Lazy service which allows the process not to get killed. @@ -43,7 +43,7 @@ public class ProgressService extends Service implements TaskCountListener { notificationManagerCompat = NotificationManagerCompat.from(getApplicationContext()); Intent killIntent = new Intent(getApplicationContext(), ProgressService.class); killIntent.putExtra("kill", true); - PendingIntent pendingKillIntent = PendingIntent.getService(this, NotificationConstants.PENDINGINTENT_CODE_KILL_PROGRESS_SERVICE + PendingIntent pendingKillIntent = PendingIntent.getService(this, NotificationUtils.PENDINGINTENT_CODE_KILL_PROGRESS_SERVICE , killIntent, Build.VERSION.SDK_INT >=23 ? PendingIntent.FLAG_IMMUTABLE : 0); mNotificationBuilder = new NotificationCompat.Builder(this, "channel_id") .setContentTitle(getString(R.string.lazy_service_default_title)) @@ -64,7 +64,7 @@ public class ProgressService extends Service implements TaskCountListener { } Log.d("ProgressService", "Started!"); mNotificationBuilder.setContentText(getString(R.string.progresslayout_tasks_in_progress, ProgressKeeper.getTaskCount())); - startForeground(NotificationConstants.NOTIFICATION_ID_PROGRESS_SERVICE, mNotificationBuilder.build()); + startForeground(NotificationUtils.NOTIFICATION_ID_PROGRESS_SERVICE, mNotificationBuilder.build()); if(ProgressKeeper.getTaskCount() < 1) stopSelf(); else ProgressKeeper.addTaskCountListener(this, false); diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/ContextAwareDoneListener.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/ContextAwareDoneListener.java new file mode 100644 index 000000000..4d8c280d8 --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/ContextAwareDoneListener.java @@ -0,0 +1,73 @@ +package net.kdt.pojavlaunch.tasks; + +import static net.kdt.pojavlaunch.MainActivity.INTENT_MINECRAFT_VERSION; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; + +import net.kdt.pojavlaunch.MainActivity; +import net.kdt.pojavlaunch.R; +import net.kdt.pojavlaunch.Tools; +import net.kdt.pojavlaunch.contextexecutor.ContextExecutor; +import net.kdt.pojavlaunch.contextexecutor.ContextExecutorTask; +import net.kdt.pojavlaunch.progresskeeper.ProgressKeeper; +import net.kdt.pojavlaunch.utils.NotificationUtils; + +public class ContextAwareDoneListener implements AsyncMinecraftDownloader.DoneListener, ContextExecutorTask { + private final String mErrorString; + private final String mNormalizedVersionid; + + public ContextAwareDoneListener(Context baseContext, String versionId) { + this.mErrorString = baseContext.getString(R.string.mc_download_failed); + this.mNormalizedVersionid = versionId; + } + + private Intent createGameStartIntent(Context context) { + Intent mainIntent = new Intent(context, MainActivity.class); + mainIntent.putExtra(INTENT_MINECRAFT_VERSION, mNormalizedVersionid); + mainIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); + return mainIntent; + } + + @Override + public void onDownloadDone() { + ProgressKeeper.waitUntilDone(()->ContextExecutor.execute(this)); + } + + @Override + public void onDownloadFailed(Throwable throwable) { + if(throwable != null) + Tools.showErrorRemote(mErrorString, throwable); + } + + @Override + public void executeWithActivity(Activity activity) { + try { + Intent gameStartIntent = createGameStartIntent(activity); + activity.startActivity(gameStartIntent); + activity.finish(); + android.os.Process.killProcess(android.os.Process.myPid()); //You should kill yourself, NOW! + } catch (Throwable e) { + Tools.showError(activity.getBaseContext(), e); + } + } + + @Override + public void executeWithApplication(Context context) { + Intent gameStartIntent = createGameStartIntent(context); + // Since the game is a separate process anyway, it does not matter if it gets invoked + // from somewhere other than the launcher activity. + // The only problem may arise if the launcher starts doing something when the user starts the notification. + // So, the notification is automatically removed once there are tasks ongoing in the ProgressKeeper + NotificationUtils.sendBasicNotification(context, + R.string.notif_download_finished, + R.string.notif_download_finished_desc, + gameStartIntent, + NotificationUtils.PENDINGINTENT_CODE_GAME_START, + NotificationUtils.NOTIFICATION_ID_GAME_START + ); + // You should keep yourself safe, NOW! + // otherwise android does weird things... + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/NotificationUtils.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/NotificationUtils.java new file mode 100644 index 000000000..9fa2c8f8f --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/NotificationUtils.java @@ -0,0 +1,41 @@ +package net.kdt.pojavlaunch.utils; + +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.os.Build; + +import androidx.core.app.NotificationCompat; + +import net.kdt.pojavlaunch.R; + +public class NotificationUtils { + + public static final int NOTIFICATION_ID_PROGRESS_SERVICE = 1; + public static final int NOTIFICATION_ID_GAME_SERVICE = 2; + public static final int NOTIFICATION_ID_DOWNLOAD_LISTENER = 3; + public static final int NOTIFICATION_ID_SHOW_ERROR = 4; + public static final int NOTIFICATION_ID_GAME_START = 5; + public static final int PENDINGINTENT_CODE_KILL_PROGRESS_SERVICE = 1; + public static final int PENDINGINTENT_CODE_KILL_GAME_SERVICE = 2; + public static final int PENDINGINTENT_CODE_DOWNLOAD_SERVICE = 3; + public static final int PENDINGINTENT_CODE_SHOW_ERROR = 4; + public static final int PENDINGINTENT_CODE_GAME_START = 5; + + public static void sendBasicNotification(Context context, int contentTitle, int contentText, Intent actionIntent, + int pendingIntentCode, int notificationId) { + + PendingIntent pendingIntent = PendingIntent.getActivity(context, pendingIntentCode, actionIntent, + Build.VERSION.SDK_INT >=23 ? PendingIntent.FLAG_IMMUTABLE : 0); + + NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, context.getString(R.string.notif_channel_id)); + if(contentTitle != -1) notificationBuilder.setContentTitle(context.getString(contentTitle)); + if(contentText != -1) notificationBuilder.setContentText(context.getString(contentText)); + if(actionIntent != null) notificationBuilder.setContentIntent(pendingIntent); + notificationBuilder.setSmallIcon(R.drawable.notif_icon); + + notificationManager.notify(notificationId, notificationBuilder.build()); + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/value/NotificationConstants.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/value/NotificationConstants.java deleted file mode 100644 index 02c23596e..000000000 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/value/NotificationConstants.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.kdt.pojavlaunch.value; - -public class NotificationConstants { - public static final int NOTIFICATION_ID_PROGRESS_SERVICE = 1; - public static final int NOTIFICATION_ID_GAME_SERVICE = 2; - public static final int NOTIFICATION_ID_DOWNLOAD_LISTENER = 3; - public static final int NOTIFICATION_ID_SHOW_ERROR = 4; - public static final int PENDINGINTENT_CODE_KILL_PROGRESS_SERVICE = 1; - public static final int PENDINGINTENT_CODE_KILL_GAME_SERVICE = 2; - public static final int PENDINGINTENT_CODE_DOWNLOAD_SERVICE = 3; - public static final int PENDINGINTENT_CODE_SHOW_ERROR = 4; -} diff --git a/app_pojavlauncher/src/main/res/values/strings.xml b/app_pojavlauncher/src/main/res/values/strings.xml index 8e8c0bf31..dc6c30740 100644 --- a/app_pojavlauncher/src/main/res/values/strings.xml +++ b/app_pojavlauncher/src/main/res/values/strings.xml @@ -350,4 +350,6 @@ Select a download mirror instead of using the official download server Verify game version manifest When enabled, the launcher will check the game version manifest along with the libraries. + The game is ready to launch + Click here to start it!