diff --git a/FCL/build.gradle b/FCL/build.gradle index a045f6f5..f5776d1e 100644 --- a/FCL/build.gradle +++ b/FCL/build.gradle @@ -1,5 +1,6 @@ plugins { id 'com.android.application' + id 'org.jetbrains.kotlin.android' version '1.9.20' id "org.hidetake.ssh" version "2.11.2" } @@ -102,6 +103,15 @@ android { } pickFirst '**/libbytehook.so' } + kotlinOptions { + jvmTarget = "1.8" + } + dataBinding { + enabled true + } + buildFeatures { + buildConfig true + } splits { def arch = System.getProperty("arch", "all") if (arch != 'all') { @@ -178,6 +188,7 @@ dependencies { implementation 'com.google.android.material:material:1.11.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'com.github.Mathias-Boulay:android_gamepad_remapper:06184ddbce' + implementation 'com.github.bumptech.glide:glide:4.16.0' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' diff --git a/FCL/src/main/assets/app_runtime/jna/jna-arm64.zip b/FCL/src/main/assets/app_runtime/jna/jna-arm64.zip new file mode 100644 index 00000000..606a4d52 Binary files /dev/null and b/FCL/src/main/assets/app_runtime/jna/jna-arm64.zip differ diff --git a/FCL/src/main/assets/app_runtime/jna/version b/FCL/src/main/assets/app_runtime/jna/version new file mode 100644 index 00000000..56a6051c --- /dev/null +++ b/FCL/src/main/assets/app_runtime/jna/version @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/FCL/src/main/java/com/mio/util/AnimUtil.kt b/FCL/src/main/java/com/mio/util/AnimUtil.kt new file mode 100644 index 00000000..776467d9 --- /dev/null +++ b/FCL/src/main/java/com/mio/util/AnimUtil.kt @@ -0,0 +1,99 @@ +package com.mio.util + +import android.animation.ObjectAnimator +import android.animation.TimeInterpolator +import android.view.View + +class AnimUtil { + + companion object { + @JvmStatic + fun playTranslationY( + view: View, + duration: Long, + vararg values: Float + ): ObjectAnimator { + return ObjectAnimator.ofFloat(view, "translationY", *values).apply { + this.duration = duration + } + } + + @JvmStatic + fun playTranslationX( + view: View, + duration: Long, + vararg values: Float + ): ObjectAnimator { + return ObjectAnimator.ofFloat(view, "translationX", *values).apply { + this.duration = duration + } + } + + @JvmStatic + fun playTranslationZ( + view: View, + duration: Long, + vararg values: Float + ): ObjectAnimator { + return ObjectAnimator.ofFloat(view, "translationZ", *values).apply { + this.duration = duration + } + } + + @JvmStatic + fun playRotation( + view: View, + duration: Long, + vararg values: Float + ): ObjectAnimator { + return ObjectAnimator.ofFloat(view, "rotation", *values).apply { + this.duration = duration + } + } + + @JvmStatic + fun playScaleX( + view: View, + duration: Long, + vararg values: Float + ): ObjectAnimator { + return ObjectAnimator.ofFloat(view, "scaleX", *values).apply { + this.duration = duration + } + } + + @JvmStatic + fun playScaleY( + view: View, + duration: Long, + vararg values: Float + ): ObjectAnimator { + return ObjectAnimator.ofFloat(view, "scaleY", *values).apply { + this.duration = duration + } + } + + @JvmStatic + fun playAlpha( + view: View, + duration: Long, + vararg values: Float + ): ObjectAnimator { + return ObjectAnimator.ofFloat(view, "alpha", *values).apply { + this.duration = duration + } + } + + @JvmStatic + fun ObjectAnimator.delay(delayTime: Long): ObjectAnimator { + this.startDelay = delayTime + return this + } + + @JvmStatic + fun ObjectAnimator.interpolator(interpolator: TimeInterpolator): ObjectAnimator { + this.interpolator = interpolator + return this + } + } +} \ No newline at end of file diff --git a/FCL/src/main/java/com/tungsten/fcl/activity/MainActivity.java b/FCL/src/main/java/com/tungsten/fcl/activity/MainActivity.java deleted file mode 100644 index 1e5a5ac0..00000000 --- a/FCL/src/main/java/com/tungsten/fcl/activity/MainActivity.java +++ /dev/null @@ -1,421 +0,0 @@ -package com.tungsten.fcl.activity; - -import static com.tungsten.fcl.setting.Accounts.getAccountFactory; -import static com.tungsten.fclcore.download.LibraryAnalyzer.LibraryType.MINECRAFT; -import static com.tungsten.fclcore.fakefx.beans.binding.Bindings.createStringBinding; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.Intent; -import android.graphics.drawable.BitmapDrawable; -import android.os.Bundle; -import android.view.View; -import android.view.ViewGroup; -import android.widget.RelativeLayout; -import android.widget.ScrollView; - -import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.widget.LinearLayoutCompat; -import androidx.constraintlayout.widget.ConstraintLayout; - -import com.tungsten.fcl.R; -import com.tungsten.fcl.game.JarExecutorHelper; -import com.tungsten.fcl.game.TexturesLoader; -import com.tungsten.fcl.setting.Accounts; -import com.tungsten.fcl.setting.ConfigHolder; -import com.tungsten.fcl.setting.Profile; -import com.tungsten.fcl.setting.Profiles; -import com.tungsten.fcl.ui.UIManager; -import com.tungsten.fcl.ui.version.Versions; -import com.tungsten.fcl.upgrade.UpdateChecker; -import com.tungsten.fcl.util.AndroidUtils; -import com.tungsten.fcl.util.FXUtils; -import com.tungsten.fcl.util.WeakListenerHolder; -import com.tungsten.fclcore.auth.Account; -import com.tungsten.fclcore.auth.authlibinjector.AuthlibInjectorAccount; -import com.tungsten.fclcore.auth.authlibinjector.AuthlibInjectorServer; -import com.tungsten.fclcore.auth.offline.Skin; -import com.tungsten.fclcore.auth.yggdrasil.TextureModel; -import com.tungsten.fclcore.download.LibraryAnalyzer; -import com.tungsten.fclcore.event.Event; -import com.tungsten.fclcore.fakefx.beans.property.ObjectProperty; -import com.tungsten.fclcore.fakefx.beans.property.SimpleObjectProperty; -import com.tungsten.fclcore.fakefx.beans.value.ObservableValue; -import com.tungsten.fclcore.mod.RemoteMod; -import com.tungsten.fclcore.mod.RemoteModRepository; -import com.tungsten.fclcore.task.Schedulers; -import com.tungsten.fclcore.util.Logging; -import com.tungsten.fclcore.util.fakefx.BindingMapping; -import com.tungsten.fcllibrary.component.FCLActivity; -import com.tungsten.fcllibrary.component.theme.ThemeEngine; -import com.tungsten.fcllibrary.component.view.FCLButton; -import com.tungsten.fcllibrary.component.view.FCLDynamicIsland; -import com.tungsten.fcllibrary.component.view.FCLEditText; -import com.tungsten.fcllibrary.component.view.FCLImageView; -import com.tungsten.fcllibrary.component.view.FCLMenuView; -import com.tungsten.fcllibrary.component.view.FCLTextView; -import com.tungsten.fcllibrary.component.view.FCLUILayout; -import com.tungsten.fcllibrary.util.ConvertUtils; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.function.Consumer; -import java.util.logging.Level; -import java.util.stream.Stream; - -public class MainActivity extends FCLActivity implements FCLMenuView.OnSelectListener, View.OnClickListener { - - private static MainActivity instance; - - public ConstraintLayout background; - public FCLDynamicIsland titleView; - - private UIManager uiManager; - public FCLUILayout uiLayout; - - private ScrollView leftMenu; - public FCLMenuView home; - public FCLMenuView manage; - public FCLMenuView download; - public FCLMenuView controller; - public FCLMenuView multiplayer; - public FCLMenuView setting; - public FCLMenuView back; - - private LinearLayoutCompat account; - private FCLImageView avatar; - private FCLTextView accountName; - private FCLTextView accountHint; - private LinearLayoutCompat version; - private FCLImageView icon; - private FCLTextView versionName; - private FCLTextView versionHint; - private FCLButton executeJar; - private FCLButton launch; - - private ObjectProperty currentAccount; - private final WeakListenerHolder holder = new WeakListenerHolder(); - private Profile profile; - private Consumer onVersionIconChangedListener; - - public static MainActivity getInstance() { - return instance; - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - instance = this; - - background = findViewById(R.id.background); - background.setBackground(ThemeEngine.getInstance().getTheme().getBackground(this)); - - titleView = findViewById(R.id.title); - - Skin.registerDefaultSkinLoader((type) -> { - switch (type) { - case ALEX: - return Skin.class.getResourceAsStream("/assets/img/alex.png"); - case ARI: - return Skin.class.getResourceAsStream("/assets/img/ari.png"); - case EFE: - return Skin.class.getResourceAsStream("/assets/img/efe.png"); - case KAI: - return Skin.class.getResourceAsStream("/assets/img/kai.png"); - case MAKENA: - return Skin.class.getResourceAsStream("/assets/img/makena.png"); - case NOOR: - return Skin.class.getResourceAsStream("/assets/img/noor.png"); - case STEVE: - return Skin.class.getResourceAsStream("/assets/img/steve.png"); - case SUNNY: - return Skin.class.getResourceAsStream("/assets/img/sunny.png"); - case ZURI: - return Skin.class.getResourceAsStream("/assets/img/zuri.png"); - default: - return null; - } - }); - - RemoteMod.registerEmptyRemoteMod(new RemoteMod("", "", getString(R.string.mods_broken_dependency_title), getString(R.string.mods_broken_dependency_desc), new ArrayList<>(), "", "", new RemoteMod.IMod() { - @Override - public List loadDependencies(RemoteModRepository modRepository) throws IOException { - throw new IOException(); - } - - @Override - public Stream loadVersions(RemoteModRepository modRepository) throws IOException { - throw new IOException(); - } - })); - - try { - ConfigHolder.init(); - } catch (IOException e) { - Logging.LOG.log(Level.WARNING, e.getMessage()); - } - - uiLayout = findViewById(R.id.ui_layout); - uiLayout.post(() -> { - leftMenu = findViewById(R.id.left_scroll); - ThemeEngine.getInstance().registerEvent(leftMenu, () -> leftMenu.setBackgroundColor(ThemeEngine.getInstance().getTheme().getColor())); - - account = findViewById(R.id.account); - avatar = findViewById(R.id.avatar); - accountName = findViewById(R.id.account_name); - accountHint = findViewById(R.id.account_hint); - version = findViewById(R.id.version); - icon = findViewById(R.id.icon); - versionName = findViewById(R.id.version_name); - versionHint = findViewById(R.id.version_hint); - executeJar = findViewById(R.id.execute_jar); - launch = findViewById(R.id.launch); - account.setOnClickListener(this); - version.setOnClickListener(this); - executeJar.setOnClickListener(this); - executeJar.setOnLongClickListener(V -> { - int padding = ConvertUtils.dip2px(MainActivity.this, 15); - FCLEditText editText = new FCLEditText(MainActivity.this); - RelativeLayout layout = new RelativeLayout(MainActivity.this); - editText.setHint("-jar xxx"); - editText.setLines(1); - editText.setMaxLines(1); - layout.setPadding(padding, padding, padding, padding); - layout.addView(editText); - AlertDialog dialog = new AlertDialog.Builder(MainActivity.this) - .setTitle(R.string.jar_execute_custom_args) - .setView(layout) - .setPositiveButton(com.tungsten.fcllibrary.R.string.dialog_positive, (dialog1, which) -> JarExecutorHelper.exec(MainActivity.this, null, 8, editText.getText().toString())) - .setNegativeButton(com.tungsten.fcllibrary.R.string.dialog_negative, null) - .create(); - layout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - editText.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - ThemeEngine.getInstance().applyFullscreen(dialog.getWindow(), ThemeEngine.getInstance().getTheme().isFullscreen()); - dialog.show(); - return true; - }); - launch.setOnClickListener(this); - launch.setOnLongClickListener(view -> { - startActivity(new Intent(MainActivity.this, ShellActivity.class)); - return true; - }); - - uiManager = new UIManager(this, uiLayout); - uiManager.registerDefaultBackEvent(backToMainUI); - uiManager.init(() -> { - home = findViewById(R.id.home); - manage = findViewById(R.id.manage); - download = findViewById(R.id.download); - controller = findViewById(R.id.controller); - multiplayer = findViewById(R.id.multiplayer); - setting = findViewById(R.id.setting); - back = findViewById(R.id.back); - home.setOnSelectListener(this); - manage.setOnSelectListener(this); - download.setOnSelectListener(this); - controller.setOnSelectListener(this); - multiplayer.setOnSelectListener(this); - setting.setOnSelectListener(this); - back.setOnClickListener(this); - home.setSelected(true); - - setupAccountDisplay(); - setupVersionDisplay(); - - UpdateChecker.getInstance().checkAuto(this).start(); - }); - }); - } - - public Runnable backToMainUI = () -> { - if (uiManager.getCurrentUI() == uiManager.getMainUI()) { - Intent i = new Intent(Intent.ACTION_MAIN); - i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - i.addCategory(Intent.CATEGORY_HOME); - startActivity(i); - } else { - home.setSelected(true); - } - }; - - @Override - public void onBackPressed() { - if (uiManager != null) { - uiManager.onBackPressed(); - } - } - - @Override - protected void onPause() { - super.onPause(); - if (uiManager != null) { - uiManager.onPause(); - } - } - - @Override - protected void onResume() { - super.onResume(); - if (uiManager != null) { - uiManager.onResume(); - } - } - - @Override - public void onSelect(FCLMenuView view) { - refreshMenuView(view); - if (view == home) { - titleView.setTextWithAnim(getString(R.string.app_name)); - uiManager.switchUI(uiManager.getMainUI()); - } - if (view == manage) { - String version = Profiles.getSelectedVersion(); - if (version == null) { - refreshMenuView(null); - titleView.setTextWithAnim(getString(R.string.version)); - uiManager.switchUI(uiManager.getVersionUI()); - } else { - titleView.setTextWithAnim(getString(R.string.manage)); - uiManager.getManageUI().setVersion(version, Profiles.getSelectedProfile()); - uiManager.switchUI(uiManager.getManageUI()); - } - } - if (view == download) { - titleView.setTextWithAnim(getString(R.string.download)); - uiManager.switchUI(uiManager.getDownloadUI()); - } - if (view == controller) { - titleView.setTextWithAnim(getString(R.string.controller)); - uiManager.switchUI(uiManager.getControllerUI()); - } - if (view == multiplayer) { - titleView.setTextWithAnim(getString(R.string.multiplayer)); - uiManager.switchUI(uiManager.getMultiplayerUI()); - } - if (view == setting) { - titleView.setTextWithAnim(getString(R.string.setting)); - uiManager.switchUI(uiManager.getSettingUI()); - } - } - - public void refreshMenuView(FCLMenuView view) { - FCLMenuView[] views = { - home, - manage, - download, - controller, - multiplayer, - setting - }; - for (FCLMenuView v : views) { - if (v != view) { - v.setSelected(false); - } - } - } - - @Override - public void onClick(View view) { - if (view == account && uiManager.getCurrentUI() != uiManager.getAccountUI()) { - refreshMenuView(null); - titleView.setTextWithAnim(getString(R.string.account)); - uiManager.switchUI(uiManager.getAccountUI()); - } - if (view == version && uiManager.getCurrentUI() != uiManager.getVersionUI()) { - refreshMenuView(null); - titleView.setTextWithAnim(getString(R.string.version)); - uiManager.switchUI(uiManager.getVersionUI()); - } - if (view == back) { - if (uiManager != null) { - uiManager.onBackPressed(); - } - } - if (view == executeJar) { - JarExecutorHelper.start(this, this); - } - if (view == launch) { - Versions.launch(this, Profiles.getSelectedProfile()); - } - } - - private static ObservableValue accountSubtitle(Context context, Account account) { - if (account instanceof AuthlibInjectorAccount) { - return BindingMapping.of(((AuthlibInjectorAccount) account).getServer(), AuthlibInjectorServer::getName); - } else { - return createStringBinding(() -> Accounts.getLocalizedLoginTypeName(context, getAccountFactory(account))); - } - } - - private void setupAccountDisplay() { - currentAccount = new SimpleObjectProperty() { - - @Override - protected void invalidated() { - Account account = get(); - if (account == null) { - accountName.stringProperty().unbind(); - accountHint.stringProperty().unbind(); - avatar.imageProperty().unbind(); - accountName.setText(getString(R.string.account_state_no_account)); - accountHint.setText(getString(R.string.account_state_add)); - avatar.setBackgroundDrawable(new BitmapDrawable(TexturesLoader.toAvatar(TexturesLoader.getDefaultSkin(TextureModel.ALEX).getImage(), ConvertUtils.dip2px(MainActivity.this, 30)))); - } else { - accountName.stringProperty().bind(BindingMapping.of(account, Account::getCharacter)); - accountHint.stringProperty().bind(accountSubtitle(MainActivity.this, account)); - avatar.imageProperty().unbind(); - avatar.imageProperty().bind(TexturesLoader.avatarBinding(account, ConvertUtils.dip2px(MainActivity.this, 30))); - } - } - }; - currentAccount.bind(Accounts.selectedAccountProperty()); - } - - public void refreshAvatar(Account account) { - Schedulers.androidUIThread().execute(() -> { - if (currentAccount.get() == account) { - avatar.imageProperty().unbind(); - avatar.imageProperty().bind(TexturesLoader.avatarBinding(currentAccount.get(), ConvertUtils.dip2px(MainActivity.this, 30))); - } - }); - } - - @SuppressLint("UseCompatLoadingForDrawables") - private void loadVersion(String version) { - if (Profiles.getSelectedProfile() != profile) { - profile = Profiles.getSelectedProfile(); - if (profile != null) { - onVersionIconChangedListener = profile.getRepository().onVersionIconChanged.registerWeak(event -> this.loadVersion(Profiles.getSelectedVersion())); - } - } - if (version != null && Profiles.getSelectedProfile() != null && Profiles.getSelectedProfile().getRepository().hasVersion(version)) { - String game = Profiles.getSelectedProfile().getRepository().getGameVersion(version).orElse(getString(R.string.message_unknown)); - StringBuilder libraries = new StringBuilder(game); - LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(Profiles.getSelectedProfile().getRepository().getResolvedPreservingPatchesVersion(version)); - for (LibraryAnalyzer.LibraryMark mark : analyzer) { - String libraryId = mark.getLibraryId(); - String libraryVersion = mark.getLibraryVersion(); - if (libraryId.equals(MINECRAFT.getPatchId())) continue; - if (AndroidUtils.hasStringId(this, "install_installer_" + libraryId.replace("-", "_"))) { - libraries.append(", ").append(AndroidUtils.getLocalizedText(this, "install_installer_" + libraryId.replace("-", "_"))); - if (libraryVersion != null) - libraries.append(": ").append(libraryVersion.replaceAll("(?i)" + libraryId, "")); - } - } - versionName.setText(version); - versionHint.setText(libraries.toString()); - icon.setBackgroundDrawable(Profiles.getSelectedProfile().getRepository().getVersionIconImage(version)); - } else { - versionName.setText(getString(R.string.version_no_version)); - versionHint.setText(getString(R.string.version_manage)); - icon.setBackgroundDrawable(getDrawable(R.drawable.img_grass)); - } - } - - private void setupVersionDisplay() { - holder.add(FXUtils.onWeakChangeAndOperate(Profiles.selectedVersionProperty(), s -> Schedulers.androidUIThread().execute(() -> loadVersion(s)))); - } -} \ No newline at end of file diff --git a/FCL/src/main/java/com/tungsten/fcl/activity/MainActivity.kt b/FCL/src/main/java/com/tungsten/fcl/activity/MainActivity.kt new file mode 100644 index 00000000..240caeea --- /dev/null +++ b/FCL/src/main/java/com/tungsten/fcl/activity/MainActivity.kt @@ -0,0 +1,455 @@ +package com.tungsten.fcl.activity + +import android.annotation.SuppressLint +import android.content.Context +import android.content.DialogInterface +import android.content.Intent +import android.graphics.drawable.BitmapDrawable +import android.os.Bundle +import android.view.KeyEvent +import android.view.View +import android.view.ViewGroup +import android.widget.RelativeLayout +import androidx.appcompat.app.AlertDialog +import androidx.core.view.forEach +import androidx.databinding.DataBindingUtil +import com.tungsten.fcl.R +import com.tungsten.fcl.databinding.ActivityMainBinding +import com.tungsten.fcl.game.JarExecutorHelper +import com.tungsten.fcl.game.TexturesLoader +import com.tungsten.fcl.setting.Accounts +import com.tungsten.fcl.setting.ConfigHolder +import com.tungsten.fcl.setting.Profile +import com.tungsten.fcl.setting.Profiles +import com.tungsten.fcl.ui.UIManager +import com.tungsten.fcl.ui.version.Versions +import com.tungsten.fcl.upgrade.UpdateChecker +import com.tungsten.fcl.util.AndroidUtils +import com.tungsten.fcl.util.FXUtils +import com.tungsten.fcl.util.WeakListenerHolder +import com.tungsten.fclcore.auth.Account +import com.tungsten.fclcore.auth.authlibinjector.AuthlibInjectorAccount +import com.tungsten.fclcore.auth.authlibinjector.AuthlibInjectorServer +import com.tungsten.fclcore.auth.offline.Skin +import com.tungsten.fclcore.auth.yggdrasil.TextureModel +import com.tungsten.fclcore.download.LibraryAnalyzer +import com.tungsten.fclcore.download.LibraryAnalyzer.LibraryType +import com.tungsten.fclcore.event.Event +import com.tungsten.fclcore.fakefx.beans.binding.Bindings +import com.tungsten.fclcore.fakefx.beans.property.ObjectProperty +import com.tungsten.fclcore.fakefx.beans.property.SimpleObjectProperty +import com.tungsten.fclcore.fakefx.beans.value.ObservableValue +import com.tungsten.fclcore.mod.RemoteMod +import com.tungsten.fclcore.mod.RemoteMod.IMod +import com.tungsten.fclcore.mod.RemoteModRepository +import com.tungsten.fclcore.task.Schedulers +import com.tungsten.fclcore.util.Logging +import com.tungsten.fclcore.util.fakefx.BindingMapping +import com.tungsten.fcllibrary.component.FCLActivity +import com.tungsten.fcllibrary.component.theme.ThemeEngine +import com.tungsten.fcllibrary.component.view.FCLEditText +import com.tungsten.fcllibrary.component.view.FCLMenuView +import com.tungsten.fcllibrary.component.view.FCLMenuView.OnSelectListener +import com.tungsten.fcllibrary.util.ConvertUtils +import java.io.IOException +import java.util.function.Consumer +import java.util.logging.Level +import java.util.stream.Stream + +class MainActivity : FCLActivity(), OnSelectListener, View.OnClickListener { + companion object { + @SuppressLint("StaticFieldLeak") + @JvmStatic + lateinit var instance: MainActivity + } + + lateinit var bind: ActivityMainBinding + private var _uiManager: UIManager? = null + private lateinit var uiManager: UIManager + private lateinit var currentAccount: ObjectProperty + private val holder = WeakListenerHolder() + private var profile: Profile? = null + private var onVersionIconChangedListener: Consumer? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + instance = this + bind = DataBindingUtil.setContentView(this, R.layout.activity_main) + + bind.background.background = ThemeEngine.getInstance().getTheme().getBackground(this) + + Skin.registerDefaultSkinLoader { + when (it) { + Skin.Type.ALEX -> return@registerDefaultSkinLoader Skin::class.java.getResourceAsStream( + "/assets/img/alex.png" + ) + + Skin.Type.ARI -> return@registerDefaultSkinLoader Skin::class.java.getResourceAsStream( + "/assets/img/ari.png" + ) + + Skin.Type.EFE -> return@registerDefaultSkinLoader Skin::class.java.getResourceAsStream( + "/assets/img/efe.png" + ) + + Skin.Type.KAI -> return@registerDefaultSkinLoader Skin::class.java.getResourceAsStream( + "/assets/img/kai.png" + ) + + Skin.Type.MAKENA -> return@registerDefaultSkinLoader Skin::class.java.getResourceAsStream( + "/assets/img/makena.png" + ) + + Skin.Type.NOOR -> return@registerDefaultSkinLoader Skin::class.java.getResourceAsStream( + "/assets/img/noor.png" + ) + + Skin.Type.STEVE -> return@registerDefaultSkinLoader Skin::class.java.getResourceAsStream( + "/assets/img/steve.png" + ) + + Skin.Type.SUNNY -> return@registerDefaultSkinLoader Skin::class.java.getResourceAsStream( + "/assets/img/sunny.png" + ) + + Skin.Type.ZURI -> return@registerDefaultSkinLoader Skin::class.java.getResourceAsStream( + "/assets/img/zuri.png" + ) + + else -> return@registerDefaultSkinLoader null + } + } + + RemoteMod.registerEmptyRemoteMod( + RemoteMod( + "", + "", + getString(R.string.mods_broken_dependency_title), + getString(R.string.mods_broken_dependency_desc), + ArrayList(), + "", + "", + object : IMod { + @Throws(IOException::class) + override fun loadDependencies(modRepository: RemoteModRepository): List { + throw IOException() + } + + @Throws(IOException::class) + override fun loadVersions(modRepository: RemoteModRepository): Stream { + throw IOException() + } + }) + ) + + try { + ConfigHolder.init() + } catch (e: IOException) { + Logging.LOG.log(Level.WARNING, e.message) + } + + bind.apply { + uiLayout.post { + ThemeEngine.getInstance().registerEvent(leftMenu) { + leftMenu.setBackgroundColor( + ThemeEngine.getInstance().getTheme().color + ) + } + + account.setOnClickListener(this@MainActivity) + version.setOnClickListener(this@MainActivity) + executeJar.setOnClickListener(this@MainActivity) + executeJar.setOnLongClickListener { + val padding = ConvertUtils.dip2px(this@MainActivity, 15f) + val editText = FCLEditText(this@MainActivity) + val layout = RelativeLayout(this@MainActivity) + editText.hint = "-jar xxx" + editText.setLines(1) + editText.maxLines = 1 + layout.setPadding(padding, padding, padding, padding) + layout.addView(editText) + val dialog = AlertDialog.Builder(this@MainActivity) + .setTitle(R.string.jar_execute_custom_args) + .setView(layout) + .setPositiveButton(com.tungsten.fcllibrary.R.string.dialog_positive) { _: DialogInterface?, _: Int -> + JarExecutorHelper.exec( + this@MainActivity, null, 8, editText.text.toString() + ) + } + .setNegativeButton(com.tungsten.fcllibrary.R.string.dialog_negative, null) + .create() + layout.layoutParams = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + editText.layoutParams = RelativeLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + ThemeEngine.getInstance().applyFullscreen( + dialog.window, + ThemeEngine.getInstance().getTheme().isFullscreen + ) + dialog.show() + true + } + launch.setOnClickListener(this@MainActivity) + launch.setOnLongClickListener { + startActivity(Intent(this@MainActivity, ShellActivity::class.java)) + true + } + + uiManager = UIManager(this@MainActivity, uiLayout) + _uiManager = uiManager + uiManager.registerDefaultBackEvent() { + if (uiManager.currentUI === uiManager.mainUI) { + val i = Intent(Intent.ACTION_MAIN) + i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + i.addCategory(Intent.CATEGORY_HOME) + startActivity(i) + } else { + home.isSelected = true + } + } + uiManager.init { + home.setOnSelectListener(this@MainActivity) + manage.setOnSelectListener(this@MainActivity) + download.setOnSelectListener(this@MainActivity) + controller.setOnSelectListener(this@MainActivity) + multiplayer.setOnSelectListener(this@MainActivity) + setting.setOnSelectListener(this@MainActivity) + back.setOnClickListener(this@MainActivity) + home.setSelected(true) + + setupAccountDisplay() + setupVersionDisplay() + UpdateChecker.getInstance().checkAuto(this@MainActivity).start() + } + } + } + } + + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { + _uiManager?.onBackPressed() + return true + } + + override fun onPause() { + super.onPause() + _uiManager?.onPause() + } + + override fun onResume() { + super.onResume() + _uiManager?.onResume() + } + + override fun onSelect(view: FCLMenuView) { + refreshMenuView(view) + bind.apply { + when (view) { + home -> { + title.setTextWithAnim(getString(R.string.app_name)) + uiManager.switchUI(uiManager.mainUI) + } + + manage -> { + val version = Profiles.getSelectedVersion() + if (version == null) { + refreshMenuView(null) + title.setTextWithAnim(getString(R.string.version)) + uiManager.switchUI(uiManager.versionUI) + } else { + title.setTextWithAnim(getString(R.string.manage)) + uiManager.manageUI.setVersion(version, Profiles.getSelectedProfile()) + uiManager.switchUI(uiManager.manageUI) + } + } + + download -> { + title.setTextWithAnim(getString(R.string.download)) + uiManager.switchUI(uiManager.downloadUI) + } + + controller -> { + title.setTextWithAnim(getString(R.string.controller)) + uiManager.switchUI(uiManager.controllerUI) + } + + multiplayer -> { + title.setTextWithAnim(getString(R.string.multiplayer)) + uiManager.switchUI(uiManager.multiplayerUI) + } + + setting -> { + title.setTextWithAnim(getString(R.string.setting)) + uiManager.switchUI(uiManager.settingUI) + } + } + } + } + + fun refreshMenuView(view: FCLMenuView?) { + bind.menu.forEach { + if (it is FCLMenuView && it != view) { + it.isSelected = false + } + } + } + + override fun onClick(view: View) { + bind.apply { + if (view === account && uiManager.currentUI !== uiManager.accountUI) { + refreshMenuView(null) + title.setTextWithAnim(getString(R.string.account)) + uiManager.switchUI(uiManager.accountUI) + } + if (view === version && uiManager.currentUI !== uiManager.versionUI) { + refreshMenuView(null) + title.setTextWithAnim(getString(R.string.version)) + uiManager.switchUI(uiManager.versionUI) + } + if (view === back) { + uiManager.onBackPressed() + } + if (view === executeJar) { + JarExecutorHelper.start(this@MainActivity, this@MainActivity) + } + if (view === launch) { + Versions.launch(this@MainActivity, Profiles.getSelectedProfile()) + } + } + } + + private fun setupAccountDisplay() { + bind.apply { + currentAccount = object : SimpleObjectProperty() { + override fun invalidated() { + val account = get() + if (account == null) { + accountName.stringProperty().unbind() + accountHint.stringProperty().unbind() + avatar.imageProperty().unbind() + accountName.text = getString(R.string.account_state_no_account) + accountHint.text = getString(R.string.account_state_add) + avatar.setBackgroundDrawable( + BitmapDrawable( + TexturesLoader.toAvatar( + TexturesLoader.getDefaultSkin(TextureModel.ALEX).image, + ConvertUtils.dip2px( + this@MainActivity, 30f + ) + ) + ) + ) + } else { + accountName.stringProperty() + .bind(BindingMapping.of(account) { obj: Account -> obj.character }) + accountHint.stringProperty() + .bind(accountSubtitle(this@MainActivity, account)) + avatar.imageProperty().unbind() + avatar.imageProperty().bind( + TexturesLoader.avatarBinding( + account, ConvertUtils.dip2px( + this@MainActivity, 30f + ) + ) + ) + } + } + } + (currentAccount as SimpleObjectProperty).bind(Accounts.selectedAccountProperty()) + } + } + + fun refreshAvatar(account: Account) { + Schedulers.androidUIThread().execute { + if (currentAccount.get() === account) { + bind.avatar.imageProperty().unbind() + bind.avatar.imageProperty().bind( + TexturesLoader.avatarBinding( + currentAccount.get(), ConvertUtils.dip2px( + this@MainActivity, 30f + ) + ) + ) + } + } + } + + @SuppressLint("UseCompatLoadingForDrawables") + private fun loadVersion(version: String?) { + if (Profiles.getSelectedProfile() != profile) { + profile = Profiles.getSelectedProfile() + if (profile != null) { + onVersionIconChangedListener = + profile!!.repository.onVersionIconChanged.registerWeak { + this.loadVersion(Profiles.getSelectedVersion()) + } + } + } + if (version != null && Profiles.getSelectedProfile() != null && Profiles.getSelectedProfile().repository.hasVersion( + version + ) + ) { + val game = Profiles.getSelectedProfile().repository.getGameVersion(version) + .orElse(getString(R.string.message_unknown)) + val libraries = StringBuilder(game) + val analyzer = LibraryAnalyzer.analyze( + Profiles.getSelectedProfile().repository.getResolvedPreservingPatchesVersion(version) + ) + for (mark in analyzer) { + val libraryId = mark.libraryId + val libraryVersion = mark.libraryVersion + if (libraryId == LibraryType.MINECRAFT.patchId) continue + if (AndroidUtils.hasStringId( + this, + "install_installer_" + libraryId.replace("-", "_") + ) + ) { + libraries.append(", ").append( + AndroidUtils.getLocalizedText( + this, + "install_installer_" + libraryId.replace("-", "_") + ) + ) + if (libraryVersion != null) libraries.append(": ").append( + libraryVersion.replace( + "(?i)$libraryId".toRegex(), "" + ) + ) + } + } + bind.versionName.text = version + bind.versionHint.text = libraries.toString() + bind.icon.setBackgroundDrawable( + Profiles.getSelectedProfile().repository.getVersionIconImage( + version + ) + ) + } else { + bind.versionName.text = getString(R.string.version_no_version) + bind.versionHint.text = getString(R.string.version_manage) + bind.icon.setBackgroundDrawable(getDrawable(R.drawable.img_grass)) + } + } + + private fun setupVersionDisplay() { + holder.add(FXUtils.onWeakChangeAndOperate(Profiles.selectedVersionProperty()) { s: String? -> + Schedulers.androidUIThread().execute { loadVersion(s) } + }) + } + + private fun accountSubtitle(context: Context, account: Account): ObservableValue { + return if (account is AuthlibInjectorAccount) { + BindingMapping.of(account.server) { obj: AuthlibInjectorServer -> obj.name } + } else { + Bindings.createStringBinding({ + Accounts.getLocalizedLoginTypeName( + context, + Accounts.getAccountFactory(account) + ) + }) + } + } +} \ No newline at end of file diff --git a/FCL/src/main/java/com/tungsten/fcl/fragment/RuntimeFragment.java b/FCL/src/main/java/com/tungsten/fcl/fragment/RuntimeFragment.java deleted file mode 100644 index 2d7af933..00000000 --- a/FCL/src/main/java/com/tungsten/fcl/fragment/RuntimeFragment.java +++ /dev/null @@ -1,331 +0,0 @@ -package com.tungsten.fcl.fragment; - -import android.annotation.SuppressLint; -import android.graphics.Color; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.tungsten.fcl.R; -import com.tungsten.fcl.activity.SplashActivity; -import com.tungsten.fcl.util.RuntimeUtils; -import com.tungsten.fclauncher.utils.FCLPath; -import com.tungsten.fclcore.util.io.FileUtils; -import com.tungsten.fcllibrary.component.FCLFragment; -import com.tungsten.fcllibrary.component.view.FCLProgressBar; -import com.tungsten.fcllibrary.util.LocaleUtils; -import com.tungsten.fcllibrary.component.view.FCLButton; -import com.tungsten.fcllibrary.component.view.FCLImageView; - -import java.io.File; -import java.io.IOException; -import java.util.Locale; - -public class RuntimeFragment extends FCLFragment implements View.OnClickListener { - - boolean lwjgl = false; - boolean cacio = false; - boolean cacio11 = false; - boolean cacio17 = false; - boolean java8 = false; - boolean java11 = false; - boolean java17 = false; - boolean java21 = false; - - private FCLProgressBar lwjglProgress; - private FCLProgressBar cacioProgress; - private FCLProgressBar cacio11Progress; - private FCLProgressBar cacio17Progress; - private FCLProgressBar java8Progress; - private FCLProgressBar java11Progress; - private FCLProgressBar java17Progress; - private FCLProgressBar java21Progress; - - private FCLImageView lwjglState; - private FCLImageView cacioState; - private FCLImageView cacio11State; - private FCLImageView cacio17State; - private FCLImageView java8State; - private FCLImageView java11State; - private FCLImageView java17State; - private FCLImageView java21State; - - private FCLButton install; - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_runtime, container, false); - - lwjglProgress = findViewById(view, R.id.lwjgl_progress); - cacioProgress = findViewById(view, R.id.cacio_progress); - cacio11Progress = findViewById(view, R.id.cacio11_progress); - cacio17Progress = findViewById(view, R.id.cacio17_progress); - java8Progress = findViewById(view, R.id.java8_progress); - java11Progress = findViewById(view, R.id.java11_progress); - java17Progress = findViewById(view, R.id.java17_progress); - java21Progress = findViewById(view, R.id.java21_progress); - - lwjglState = findViewById(view, R.id.lwjgl_state); - cacioState = findViewById(view, R.id.cacio_state); - cacio11State = findViewById(view, R.id.cacio11_state); - cacio17State = findViewById(view, R.id.cacio17_state); - java8State = findViewById(view, R.id.java8_state); - java11State = findViewById(view, R.id.java11_state); - java17State = findViewById(view, R.id.java17_state); - java21State = findViewById(view, R.id.java21_state); - - initState(); - - refreshDrawables(); - - check(); - - install = findViewById(view, R.id.install); - install.setOnClickListener(this); - - return view; - } - - private void initState() { - try { - lwjgl = RuntimeUtils.isLatest(FCLPath.LWJGL_DIR, "/assets/app_runtime/lwjgl"); - cacio = RuntimeUtils.isLatest(FCLPath.CACIOCAVALLO_8_DIR, "/assets/app_runtime/caciocavallo"); - cacio11 = RuntimeUtils.isLatest(FCLPath.CACIOCAVALLO_11_DIR, "/assets/app_runtime/caciocavallo11"); - cacio17 = RuntimeUtils.isLatest(FCLPath.CACIOCAVALLO_17_DIR, "/assets/app_runtime/caciocavallo17"); - java8 = RuntimeUtils.isLatest(FCLPath.JAVA_8_PATH, "/assets/app_runtime/java/jre8"); - java11 = RuntimeUtils.isLatest(FCLPath.JAVA_11_PATH, "/assets/app_runtime/java/jre11"); - java17 = RuntimeUtils.isLatest(FCLPath.JAVA_17_PATH, "/assets/app_runtime/java/jre17"); - java21 = RuntimeUtils.isLatest(FCLPath.JAVA_21_PATH, "/assets/app_runtime/java/jre21"); - } catch (IOException e) { - e.printStackTrace(); - } - } - - private void refreshDrawables() { - if (getContext() != null) { - @SuppressLint("UseCompatLoadingForDrawables") Drawable stateUpdate = getContext().getDrawable(R.drawable.ic_baseline_update_24); - @SuppressLint("UseCompatLoadingForDrawables") Drawable stateDone = getContext().getDrawable(R.drawable.ic_baseline_done_24); - - stateUpdate.setTint(Color.GRAY); - stateDone.setTint(Color.GRAY); - - lwjglState.setBackgroundDrawable(lwjgl ? stateDone : stateUpdate); - cacioState.setBackgroundDrawable(cacio ? stateDone : stateUpdate); - cacio11State.setBackgroundDrawable(cacio11 ? stateDone : stateUpdate); - cacio17State.setBackgroundDrawable(cacio17 ? stateDone : stateUpdate); - java8State.setBackgroundDrawable(java8 ? stateDone : stateUpdate); - java11State.setBackgroundDrawable(java11 ? stateDone : stateUpdate); - java17State.setBackgroundDrawable(java17 ? stateDone : stateUpdate); - java21State.setBackgroundDrawable(java21 ? stateDone : stateUpdate); - } - } - - private boolean isLatest() { - return lwjgl && cacio && cacio11 && cacio17 && java8 && java11 && java17 && java21; - } - - private void check() { - if (isLatest()) { - if (getActivity() != null) { - ((SplashActivity) getActivity()).enterLauncher(); - } - } - } - - private boolean installing = false; - - private void install() { - if (installing) - return; - - installing = true; - if (!lwjgl) { - lwjglState.setVisibility(View.GONE); - lwjglProgress.setVisibility(View.VISIBLE); - new Thread(() -> { - try { - RuntimeUtils.install(getContext(), FCLPath.LWJGL_DIR, "app_runtime/lwjgl"); - lwjgl = true; - } catch (IOException e) { - e.printStackTrace(); - } - if (getActivity() != null) { - getActivity().runOnUiThread(() -> { - lwjglState.setVisibility(View.VISIBLE); - lwjglProgress.setVisibility(View.GONE); - refreshDrawables(); - check(); - }); - } - }).start(); - } - if (!cacio) { - cacioState.setVisibility(View.GONE); - cacioProgress.setVisibility(View.VISIBLE); - new Thread(() -> { - try { - RuntimeUtils.install(getContext(), FCLPath.CACIOCAVALLO_8_DIR, "app_runtime/caciocavallo"); - cacio = true; - } catch (IOException e) { - e.printStackTrace(); - } - if (getActivity() != null) { - getActivity().runOnUiThread(() -> { - cacioState.setVisibility(View.VISIBLE); - cacioProgress.setVisibility(View.GONE); - refreshDrawables(); - check(); - }); - } - }).start(); - } - if (!cacio11) { - cacio11State.setVisibility(View.GONE); - cacio11Progress.setVisibility(View.VISIBLE); - new Thread(() -> { - try { - RuntimeUtils.install(getContext(), FCLPath.CACIOCAVALLO_11_DIR, "app_runtime/caciocavallo11"); - cacio11 = true; - } catch (IOException e) { - e.printStackTrace(); - } - if (getActivity() != null) { - getActivity().runOnUiThread(() -> { - cacio11State.setVisibility(View.VISIBLE); - cacio11Progress.setVisibility(View.GONE); - refreshDrawables(); - check(); - }); - } - }).start(); - } - if (!cacio17) { - cacio17State.setVisibility(View.GONE); - cacio17Progress.setVisibility(View.VISIBLE); - new Thread(() -> { - try { - RuntimeUtils.install(getContext(), FCLPath.CACIOCAVALLO_17_DIR, "app_runtime/caciocavallo17"); - cacio17 = true; - } catch (IOException e) { - e.printStackTrace(); - } - if (getActivity() != null) { - getActivity().runOnUiThread(() -> { - cacio17State.setVisibility(View.VISIBLE); - cacio17Progress.setVisibility(View.GONE); - refreshDrawables(); - check(); - }); - } - }).start(); - } - if (!java8) { - java8State.setVisibility(View.GONE); - java8Progress.setVisibility(View.VISIBLE); - new Thread(() -> { - try { - RuntimeUtils.installJava(getContext(), FCLPath.JAVA_8_PATH, "app_runtime/java/jre8"); - java8 = true; - } catch (IOException e) { - e.printStackTrace(); - } - if (getActivity() != null) { - getActivity().runOnUiThread(() -> { - java8State.setVisibility(View.VISIBLE); - java8Progress.setVisibility(View.GONE); - refreshDrawables(); - check(); - }); - } - }).start(); - } - if (!java11) { - java11State.setVisibility(View.GONE); - java11Progress.setVisibility(View.VISIBLE); - new Thread(() -> { - try { - RuntimeUtils.installJava(getContext(), FCLPath.JAVA_11_PATH, "app_runtime/java/jre11"); - if (!LocaleUtils.getSystemLocale().getDisplayName().equals(Locale.CHINA.getDisplayName())) { - FileUtils.writeText(new File(FCLPath.JAVA_11_PATH + "/resolv.conf"), "nameserver 1.1.1.1\n" + "nameserver 1.0.0.1"); - } else { - FileUtils.writeText(new File(FCLPath.JAVA_11_PATH + "/resolv.conf"), "nameserver 8.8.8.8\n" + "nameserver 8.8.4.4"); - } - java11 = true; - } catch (IOException e) { - e.printStackTrace(); - } - if (getActivity() != null) { - getActivity().runOnUiThread(() -> { - java11State.setVisibility(View.VISIBLE); - java11Progress.setVisibility(View.GONE); - refreshDrawables(); - check(); - }); - } - }).start(); - } - if (!java17) { - java17State.setVisibility(View.GONE); - java17Progress.setVisibility(View.VISIBLE); - new Thread(() -> { - try { - RuntimeUtils.installJava(getContext(), FCLPath.JAVA_17_PATH, "app_runtime/java/jre17"); - if (!LocaleUtils.getSystemLocale().getDisplayName().equals(Locale.CHINA.getDisplayName())) { - FileUtils.writeText(new File(FCLPath.JAVA_17_PATH + "/resolv.conf"), "nameserver 1.1.1.1\n" + "nameserver 1.0.0.1"); - } else { - FileUtils.writeText(new File(FCLPath.JAVA_17_PATH + "/resolv.conf"), "nameserver 8.8.8.8\n" + "nameserver 8.8.4.4"); - } - java17 = true; - } catch (IOException e) { - e.printStackTrace(); - } - if (getActivity() != null) { - getActivity().runOnUiThread(() -> { - java17State.setVisibility(View.VISIBLE); - java17Progress.setVisibility(View.GONE); - refreshDrawables(); - check(); - }); - } - }).start(); - } - if (!java21) { - java21State.setVisibility(View.GONE); - java21Progress.setVisibility(View.VISIBLE); - new Thread(() -> { - try { - RuntimeUtils.installJava(getContext(), FCLPath.JAVA_21_PATH, "app_runtime/java/jre21"); - if (!LocaleUtils.getSystemLocale().getDisplayName().equals(Locale.CHINA.getDisplayName())) { - FileUtils.writeText(new File(FCLPath.JAVA_21_PATH + "/resolv.conf"), "nameserver 1.1.1.1\n" + "nameserver 1.0.0.1"); - } else { - FileUtils.writeText(new File(FCLPath.JAVA_21_PATH + "/resolv.conf"), "nameserver 8.8.8.8\n" + "nameserver 8.8.4.4"); - } - java21 = true; - } catch (IOException e) { - e.printStackTrace(); - } - if (getActivity() != null) { - getActivity().runOnUiThread(() -> { - java21State.setVisibility(View.VISIBLE); - java21Progress.setVisibility(View.GONE); - refreshDrawables(); - check(); - }); - } - }).start(); - } - } - - @Override - public void onClick(View view) { - if (view == install) { - install(); - } - } -} diff --git a/FCL/src/main/java/com/tungsten/fcl/fragment/RuntimeFragment.kt b/FCL/src/main/java/com/tungsten/fcl/fragment/RuntimeFragment.kt new file mode 100644 index 00000000..672931b8 --- /dev/null +++ b/FCL/src/main/java/com/tungsten/fcl/fragment/RuntimeFragment.kt @@ -0,0 +1,363 @@ +package com.tungsten.fcl.fragment + +import android.annotation.SuppressLint +import android.graphics.Color +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.content.res.AppCompatResources +import com.tungsten.fcl.R +import com.tungsten.fcl.activity.SplashActivity +import com.tungsten.fcl.databinding.FragmentRuntimeBinding +import com.tungsten.fcl.util.RuntimeUtils +import com.tungsten.fclauncher.utils.FCLPath +import com.tungsten.fclcore.util.io.FileUtils +import com.tungsten.fcllibrary.component.FCLFragment +import com.tungsten.fcllibrary.component.view.FCLButton +import com.tungsten.fcllibrary.component.view.FCLImageView +import com.tungsten.fcllibrary.component.view.FCLProgressBar +import com.tungsten.fcllibrary.util.LocaleUtils +import java.io.File +import java.io.IOException +import java.util.Locale + +class RuntimeFragment : FCLFragment(), View.OnClickListener { + private lateinit var bind: FragmentRuntimeBinding + var lwjgl: Boolean = false + var cacio: Boolean = false + var cacio11: Boolean = false + var cacio17: Boolean = false + var java8: Boolean = false + var java11: Boolean = false + var java17: Boolean = false + var java21: Boolean = false + var jna: Boolean = false + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = inflater.inflate(R.layout.fragment_runtime, container, false) + bind = FragmentRuntimeBinding.bind(view) + initState() + refreshDrawables() + check() + bind.install.setOnClickListener(this) + return view + } + + private fun initState() { + try { + lwjgl = RuntimeUtils.isLatest(FCLPath.LWJGL_DIR, "/assets/app_runtime/lwjgl") + cacio = RuntimeUtils.isLatest( + FCLPath.CACIOCAVALLO_8_DIR, + "/assets/app_runtime/caciocavallo" + ) + cacio11 = RuntimeUtils.isLatest( + FCLPath.CACIOCAVALLO_11_DIR, + "/assets/app_runtime/caciocavallo11" + ) + cacio17 = RuntimeUtils.isLatest( + FCLPath.CACIOCAVALLO_17_DIR, + "/assets/app_runtime/caciocavallo17" + ) + java8 = RuntimeUtils.isLatest(FCLPath.JAVA_8_PATH, "/assets/app_runtime/java/jre8") + java11 = RuntimeUtils.isLatest(FCLPath.JAVA_11_PATH, "/assets/app_runtime/java/jre11") + java17 = RuntimeUtils.isLatest(FCLPath.JAVA_17_PATH, "/assets/app_runtime/java/jre17") + java21 = RuntimeUtils.isLatest(FCLPath.JAVA_21_PATH, "/assets/app_runtime/java/jre21") + jna = RuntimeUtils.isLatest(FCLPath.JNA_PATH, "/assets/app_runtime/jna") + } catch (e: IOException) { + e.printStackTrace() + } + } + + private fun refreshDrawables() { + if (context != null) { + val stateUpdate = + AppCompatResources.getDrawable(requireContext(), R.drawable.ic_baseline_update_24) + val stateDone = + AppCompatResources.getDrawable(requireContext(), R.drawable.ic_baseline_done_24) + + stateUpdate?.setTint(Color.GRAY) + stateDone?.setTint(Color.GRAY) + + bind.apply { + lwjglState.setBackgroundDrawable(if (lwjgl) stateDone else stateUpdate) + cacioState.setBackgroundDrawable(if (cacio) stateDone else stateUpdate) + cacio11State.setBackgroundDrawable(if (cacio11) stateDone else stateUpdate) + cacio17State.setBackgroundDrawable(if (cacio17) stateDone else stateUpdate) + java8State.setBackgroundDrawable(if (java8) stateDone else stateUpdate) + java11State.setBackgroundDrawable(if (java11) stateDone else stateUpdate) + java17State.setBackgroundDrawable(if (java17) stateDone else stateUpdate) + java21State.setBackgroundDrawable(if (java21) stateDone else stateUpdate) + jnaState.setBackgroundDrawable(if (jna) stateDone else stateUpdate) + } + } + } + + private val isLatest: Boolean + get() = lwjgl && cacio && cacio11 && cacio17 && java8 && java11 && java17 && java21 && jna + + private fun check() { + if (isLatest) { + (activity as SplashActivity).enterLauncher() + } + } + + private var installing = false + + private fun install() { + if (installing) return + + bind.apply { + installing = true + if (!lwjgl) { + lwjglState.visibility = View.GONE + lwjglProgress.visibility = View.VISIBLE + Thread { + try { + RuntimeUtils.install(context, FCLPath.LWJGL_DIR, "app_runtime/lwjgl") + lwjgl = true + } catch (e: IOException) { + e.printStackTrace() + } + activity?.runOnUiThread { + lwjglState.visibility = View.VISIBLE + lwjglProgress.visibility = View.GONE + refreshDrawables() + check() + } + }.start() + } + if (!cacio) { + cacioState.visibility = View.GONE + cacioProgress.visibility = View.VISIBLE + Thread { + try { + RuntimeUtils.install( + context, + FCLPath.CACIOCAVALLO_8_DIR, + "app_runtime/caciocavallo" + ) + cacio = true + } catch (e: IOException) { + e.printStackTrace() + } + activity?.runOnUiThread { + cacioState.visibility = View.VISIBLE + cacioProgress.visibility = View.GONE + refreshDrawables() + check() + } + }.start() + } + if (!cacio11) { + cacio11State.visibility = View.GONE + cacio11Progress.visibility = View.VISIBLE + Thread { + try { + RuntimeUtils.install( + context, + FCLPath.CACIOCAVALLO_11_DIR, + "app_runtime/caciocavallo11" + ) + cacio11 = true + } catch (e: IOException) { + e.printStackTrace() + } + activity?.runOnUiThread { + cacio11State.visibility = View.VISIBLE + cacio11Progress.visibility = View.GONE + refreshDrawables() + check() + } + }.start() + } + if (!cacio17) { + cacio17State.visibility = View.GONE + cacio17Progress.visibility = View.VISIBLE + Thread { + try { + RuntimeUtils.install( + context, + FCLPath.CACIOCAVALLO_17_DIR, + "app_runtime/caciocavallo17" + ) + cacio17 = true + } catch (e: IOException) { + e.printStackTrace() + } + activity?.runOnUiThread { + cacio17State.visibility = View.VISIBLE + cacio17Progress.visibility = View.GONE + refreshDrawables() + check() + } + }.start() + } + if (!java8) { + java8State.visibility = View.GONE + java8Progress.visibility = View.VISIBLE + Thread { + try { + RuntimeUtils.installJava( + context, + FCLPath.JAVA_8_PATH, + "app_runtime/java/jre8" + ) + java8 = true + } catch (e: IOException) { + e.printStackTrace() + } + activity?.runOnUiThread { + java8State.visibility = View.VISIBLE + java8Progress.visibility = View.GONE + refreshDrawables() + check() + } + }.start() + } + if (!java11) { + java11State.visibility = View.GONE + java11Progress.visibility = View.VISIBLE + Thread { + try { + RuntimeUtils.installJava( + context, + FCLPath.JAVA_11_PATH, + "app_runtime/java/jre11" + ) + if (LocaleUtils.getSystemLocale().displayName != Locale.CHINA.displayName) { + FileUtils.writeText( + File(FCLPath.JAVA_11_PATH + "/resolv.conf"), """ + nameserver 1.1.1.1 + nameserver 1.0.0.1 + """.trimIndent() + ) + } else { + FileUtils.writeText( + File(FCLPath.JAVA_11_PATH + "/resolv.conf"), """ + nameserver 8.8.8.8 + nameserver 8.8.4.4 + """.trimIndent() + ) + } + java11 = true + } catch (e: IOException) { + e.printStackTrace() + } + activity?.runOnUiThread { + java11State.visibility = View.VISIBLE + java11Progress.visibility = View.GONE + refreshDrawables() + check() + } + }.start() + } + if (!java17) { + java17State.visibility = View.GONE + java17Progress.visibility = View.VISIBLE + Thread { + try { + RuntimeUtils.installJava( + context, + FCLPath.JAVA_17_PATH, + "app_runtime/java/jre17" + ) + if (LocaleUtils.getSystemLocale().displayName != Locale.CHINA.displayName) { + FileUtils.writeText( + File(FCLPath.JAVA_17_PATH + "/resolv.conf"), """ + nameserver 1.1.1.1 + nameserver 1.0.0.1 + """.trimIndent() + ) + } else { + FileUtils.writeText( + File(FCLPath.JAVA_17_PATH + "/resolv.conf"), """ + nameserver 8.8.8.8 + nameserver 8.8.4.4 + """.trimIndent() + ) + } + java17 = true + } catch (e: IOException) { + e.printStackTrace() + } + activity?.runOnUiThread { + java17State.visibility = View.VISIBLE + java17Progress.visibility = View.GONE + refreshDrawables() + check() + } + }.start() + } + if (!java21) { + java21State.visibility = View.GONE + java21Progress.visibility = View.VISIBLE + Thread { + try { + RuntimeUtils.installJava( + context, + FCLPath.JAVA_21_PATH, + "app_runtime/java/jre21" + ) + if (LocaleUtils.getSystemLocale().displayName != Locale.CHINA.displayName) { + FileUtils.writeText( + File(FCLPath.JAVA_21_PATH + "/resolv.conf"), """ + nameserver 1.1.1.1 + nameserver 1.0.0.1 + """.trimIndent() + ) + } else { + FileUtils.writeText( + File(FCLPath.JAVA_21_PATH + "/resolv.conf"), """ + nameserver 8.8.8.8 + nameserver 8.8.4.4 + """.trimIndent() + ) + } + java21 = true + } catch (e: IOException) { + e.printStackTrace() + } + activity?.runOnUiThread { + java21State.visibility = View.VISIBLE + java21Progress.visibility = View.GONE + refreshDrawables() + check() + } + }.start() + } + if (!jna) { + jnaState.visibility = View.GONE + jnaProgress.visibility = View.VISIBLE + Thread { + try { + RuntimeUtils.installJna( + context, + FCLPath.JNA_PATH, + "app_runtime/jna" + ) + jna = true + } catch (e: IOException) { + e.printStackTrace() + } + activity?.runOnUiThread { + jnaState.visibility = View.VISIBLE + jnaProgress.visibility = View.GONE + refreshDrawables() + check() + } + }.start() + } + } + } + + override fun onClick(view: View) { + if (view === bind.install) { + install() + } + } +} diff --git a/FCL/src/main/java/com/tungsten/fcl/game/LauncherHelper.java b/FCL/src/main/java/com/tungsten/fcl/game/LauncherHelper.java index f7553090..241b6e68 100644 --- a/FCL/src/main/java/com/tungsten/fcl/game/LauncherHelper.java +++ b/FCL/src/main/java/com/tungsten/fcl/game/LauncherHelper.java @@ -161,13 +161,19 @@ public final class LauncherHelper { .thenComposeAsync(() -> logIn(context, account).withStage("launch.state.logging_in")) .thenComposeAsync(authInfo -> Task.supplyAsync(() -> { LaunchOptions launchOptions = repository.getLaunchOptions(selectedVersion, javaVersionRef.get(), profile.getGameDir(), javaAgents); - return new FCLGameLauncher( + FCLGameLauncher launcher = new FCLGameLauncher( context, repository, version.get(), authInfo, launchOptions ); + version.get().getLibraries().forEach(library -> { + if (library.getName().startsWith("net.java.dev.jna:jna:")) { + launcher.setJnaVersion(library.getVersion()); + } + }); + return launcher; }).thenComposeAsync(launcher -> { // launcher is prev task's result return Task.supplyAsync(launcher::launch); }).thenAcceptAsync(fclBridge -> Schedulers.androidUIThread().execute(() -> { diff --git a/FCL/src/main/java/com/tungsten/fcl/ui/download/RemoteModInfoPage.java b/FCL/src/main/java/com/tungsten/fcl/ui/download/RemoteModInfoPage.java index 679f8d03..e4901812 100644 --- a/FCL/src/main/java/com/tungsten/fcl/ui/download/RemoteModInfoPage.java +++ b/FCL/src/main/java/com/tungsten/fcl/ui/download/RemoteModInfoPage.java @@ -7,6 +7,7 @@ import android.graphics.BitmapFactory; import android.view.View; import android.widget.ListView; +import com.bumptech.glide.Glide; import com.tungsten.fcl.R; import com.tungsten.fcl.setting.Profile; import com.tungsten.fcl.ui.PageManager; @@ -100,19 +101,7 @@ public class RemoteModInfoPage extends FCLTempPage implements View.OnClickListen super.onStart(); icon.setImageDrawable(null); - new Thread(() -> { - try { - URL url = new URL(addon.getIconUrl()); - HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); - httpURLConnection.setDoInput(true); - httpURLConnection.connect(); - InputStream inputStream = httpURLConnection.getInputStream(); - Bitmap icon = BitmapFactory.decodeStream(inputStream); - Schedulers.androidUIThread().execute(() -> RemoteModInfoPage.this.icon.setImageBitmap(icon)); - } catch (IOException e) { - e.printStackTrace(); - } - }).start(); + Glide.with(getContext()).load(addon.getIconUrl()).into(icon); ModTranslations.Mod mod = translations.getModByCurseForgeId(addon.getSlug()); name.setText(mod != null && LocaleUtils.isChinese(getContext()) ? mod.getDisplayName() : addon.getTitle()); description.setText(addon.getDescription()); diff --git a/FCL/src/main/java/com/tungsten/fcl/ui/download/RemoteModListAdapter.java b/FCL/src/main/java/com/tungsten/fcl/ui/download/RemoteModListAdapter.java index 64217533..cf75cbe3 100644 --- a/FCL/src/main/java/com/tungsten/fcl/ui/download/RemoteModListAdapter.java +++ b/FCL/src/main/java/com/tungsten/fcl/ui/download/RemoteModListAdapter.java @@ -7,12 +7,15 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import com.bumptech.glide.Glide; +import com.mio.util.AnimUtil; import com.tungsten.fcl.R; import com.tungsten.fcl.util.ModTranslations; import com.tungsten.fclcore.mod.RemoteMod; import com.tungsten.fclcore.task.Schedulers; import com.tungsten.fclcore.util.StringUtils; import com.tungsten.fcllibrary.component.FCLAdapter; +import com.tungsten.fcllibrary.component.theme.ThemeEngine; import com.tungsten.fcllibrary.util.LocaleUtils; import com.tungsten.fcllibrary.component.view.FCLImageView; import com.tungsten.fcllibrary.component.view.FCLLinearLayout; @@ -76,21 +79,7 @@ public class RemoteModListAdapter extends FCLAdapter { viewHolder.parent.setOnClickListener(v -> callback.onItemSelect(remoteMod)); viewHolder.icon.setImageDrawable(null); viewHolder.icon.setTag(i); - new Thread(() -> { - try { - URL url = new URL(remoteMod.getIconUrl()); - HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); - httpURLConnection.setDoInput(true); - httpURLConnection.connect(); - InputStream inputStream = httpURLConnection.getInputStream(); - Bitmap icon = BitmapFactory.decodeStream(inputStream); - if (viewHolder.icon.getTag().equals(i)) { - Schedulers.androidUIThread().execute(() -> viewHolder.icon.setImageBitmap(icon)); - } - } catch (IOException e) { - e.printStackTrace(); - } - }).start(); + Glide.with(getContext()).load(remoteMod.getIconUrl()).into(viewHolder.icon); ModTranslations.Mod mod = ModTranslations.getTranslationsByRepositoryType(downloadPage.repository.getType()).getModByCurseForgeId(remoteMod.getSlug()); viewHolder.name.setText(mod != null && LocaleUtils.isChinese(getContext()) ? mod.getDisplayName() : remoteMod.getTitle()); List categories = remoteMod.getCategories().stream().map(downloadPage::getLocalizedCategory).collect(Collectors.toList()); @@ -99,6 +88,7 @@ public class RemoteModListAdapter extends FCLAdapter { String tag = StringUtils.removeSuffix(stringBuilder.toString(), " "); viewHolder.tag.setText(tag); viewHolder.description.setText(remoteMod.getDescription()); + AnimUtil.playTranslationX(view, ThemeEngine.getInstance().getTheme().getAnimationSpeed() * 30L, -100f, 0f).start(); return view; } diff --git a/FCL/src/main/java/com/tungsten/fcl/ui/download/RemoteVersionListAdapter.java b/FCL/src/main/java/com/tungsten/fcl/ui/download/RemoteVersionListAdapter.java index 635d2403..37a776e6 100644 --- a/FCL/src/main/java/com/tungsten/fcl/ui/download/RemoteVersionListAdapter.java +++ b/FCL/src/main/java/com/tungsten/fcl/ui/download/RemoteVersionListAdapter.java @@ -10,6 +10,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import com.mio.util.AnimUtil; import com.tungsten.fcl.R; import com.tungsten.fclcore.download.RemoteVersion; import com.tungsten.fclcore.download.fabric.FabricAPIRemoteVersion; @@ -84,6 +85,7 @@ public class RemoteVersionListAdapter extends FCLAdapter { viewHolder.tag.setText(getTag(remoteVersion)); viewHolder.date.setVisibility(remoteVersion.getReleaseDate() == null ? View.GONE : View.VISIBLE); viewHolder.date.setText(remoteVersion.getReleaseDate() == null ? "" : formatDateTime(getContext(), remoteVersion.getReleaseDate())); + AnimUtil.playTranslationX(view, ThemeEngine.getInstance().getTheme().getAnimationSpeed() * 30L, -100f, 0f).start(); return view; } diff --git a/FCL/src/main/java/com/tungsten/fcl/ui/manage/ManageUI.java b/FCL/src/main/java/com/tungsten/fcl/ui/manage/ManageUI.java index f88e38c1..94f7b20f 100644 --- a/FCL/src/main/java/com/tungsten/fcl/ui/manage/ManageUI.java +++ b/FCL/src/main/java/com/tungsten/fcl/ui/manage/ManageUI.java @@ -62,7 +62,7 @@ public class ManageUI extends FCLMultiPageUI implements TabLayout.OnTabSelectedL Schedulers.androidUIThread().execute(() -> { if (isShowing()) { MainActivity.getInstance().refreshMenuView(null); - MainActivity.getInstance().home.setSelected(true); + MainActivity.getInstance().bind.home.setSelected(true); } }); return; @@ -158,7 +158,7 @@ public class ManageUI extends FCLMultiPageUI implements TabLayout.OnTabSelectedL loadVersion(preferredVersionName, this.version.get().getProfile()); } else if (isShowing()) { MainActivity.getInstance().refreshMenuView(null); - MainActivity.getInstance().home.setSelected(true); + MainActivity.getInstance().bind.home.setSelected(true); } } }); @@ -176,7 +176,7 @@ public class ManageUI extends FCLMultiPageUI implements TabLayout.OnTabSelectedL Schedulers.androidUIThread().execute(() -> { if (isShowing()) { MainActivity.getInstance().refreshMenuView(null); - MainActivity.getInstance().home.setSelected(true); + MainActivity.getInstance().bind.home.setSelected(true); } }); return; diff --git a/FCL/src/main/java/com/tungsten/fcl/ui/manage/ModListPage.java b/FCL/src/main/java/com/tungsten/fcl/ui/manage/ModListPage.java index 23a7444a..fd544dae 100644 --- a/FCL/src/main/java/com/tungsten/fcl/ui/manage/ModListPage.java +++ b/FCL/src/main/java/com/tungsten/fcl/ui/manage/ModListPage.java @@ -406,7 +406,7 @@ public class ModListPage extends FCLCommonPage implements ManageUI.VersionLoadab public void download() { MainActivity.getInstance().refreshMenuView(null); - MainActivity.getInstance().download.setSelected(true); + MainActivity.getInstance().bind.download.setSelected(true); DownloadPageManager.getInstance().switchPage(DownloadPageManager.PAGE_ID_DOWNLOAD_MOD); } diff --git a/FCL/src/main/java/com/tungsten/fcl/ui/setting/LauncherSettingPage.java b/FCL/src/main/java/com/tungsten/fcl/ui/setting/LauncherSettingPage.java index 50db9757..78e7446c 100644 --- a/FCL/src/main/java/com/tungsten/fcl/ui/setting/LauncherSettingPage.java +++ b/FCL/src/main/java/com/tungsten/fcl/ui/setting/LauncherSettingPage.java @@ -289,7 +289,7 @@ public class LauncherSettingPage extends FCLCommonPage implements View.OnClickLi if (AndroidUtils.isDocUri(uri)) { path = AndroidUtils.copyFileToDir(getActivity(), uri, new File(FCLPath.CACHE_DIR)); } - ThemeEngine.getInstance().applyAndSave(getContext(), ((MainActivity) getActivity()).background, path, null); + ThemeEngine.getInstance().applyAndSave(getContext(), ((MainActivity) getActivity()).bind.background, path, null); } })); } @@ -307,7 +307,7 @@ public class LauncherSettingPage extends FCLCommonPage implements View.OnClickLi if (AndroidUtils.isDocUri(uri)) { path = AndroidUtils.copyFileToDir(getActivity(), uri, new File(FCLPath.CACHE_DIR)); } - ThemeEngine.getInstance().applyAndSave(getContext(), ((MainActivity) getActivity()).background, null, path); + ThemeEngine.getInstance().applyAndSave(getContext(), ((MainActivity) getActivity()).bind.background, null, path); } })); } @@ -319,7 +319,7 @@ public class LauncherSettingPage extends FCLCommonPage implements View.OnClickLi if (!new File(FCLPath.LT_BACKGROUND_PATH).delete() && new File(FCLPath.LT_BACKGROUND_PATH).exists()) Schedulers.androidUIThread().execute(() -> Toast.makeText(getContext(), getContext().getString(R.string.message_failed), Toast.LENGTH_SHORT).show()); - Schedulers.androidUIThread().execute(() -> ThemeEngine.getInstance().applyAndSave(getContext(), ((MainActivity) getActivity()).background, null, null)); + Schedulers.androidUIThread().execute(() -> ThemeEngine.getInstance().applyAndSave(getContext(), ((MainActivity) getActivity()).bind.background, null, null)); }).start(); } if (v == resetDkBackground) { @@ -327,7 +327,7 @@ public class LauncherSettingPage extends FCLCommonPage implements View.OnClickLi if (!new File(FCLPath.DK_BACKGROUND_PATH).delete() && new File(FCLPath.DK_BACKGROUND_PATH).exists()) Schedulers.androidUIThread().execute(() -> Toast.makeText(getContext(), getContext().getString(R.string.message_failed), Toast.LENGTH_SHORT).show()); - Schedulers.androidUIThread().execute(() -> ThemeEngine.getInstance().applyAndSave(getContext(), ((MainActivity) getActivity()).background, null, null)); + Schedulers.androidUIThread().execute(() -> ThemeEngine.getInstance().applyAndSave(getContext(), ((MainActivity) getActivity()).bind.background, null, null)); }).start(); } } diff --git a/FCL/src/main/java/com/tungsten/fcl/ui/version/Versions.java b/FCL/src/main/java/com/tungsten/fcl/ui/version/Versions.java index 56e054af..aefc808a 100644 --- a/FCL/src/main/java/com/tungsten/fcl/ui/version/Versions.java +++ b/FCL/src/main/java/com/tungsten/fcl/ui/version/Versions.java @@ -219,7 +219,7 @@ public class Versions { builder.setMessage(context.getString(R.string.version_empty_launch)); builder.setNegativeButton(context.getString(com.tungsten.fcllibrary.R.string.dialog_positive), () -> { MainActivity.getInstance().refreshMenuView(null); - MainActivity.getInstance().download.setSelected(true); + MainActivity.getInstance().bind.download.setSelected(true); }); builder.create().show(); return false; diff --git a/FCL/src/main/java/com/tungsten/fcl/util/RuntimeUtils.java b/FCL/src/main/java/com/tungsten/fcl/util/RuntimeUtils.java index d1d40714..048d0049 100644 --- a/FCL/src/main/java/com/tungsten/fcl/util/RuntimeUtils.java +++ b/FCL/src/main/java/com/tungsten/fcl/util/RuntimeUtils.java @@ -5,10 +5,12 @@ import android.system.Os; import com.tungsten.fclauncher.FCLauncher; import com.tungsten.fclauncher.utils.Architecture; +import com.tungsten.fclauncher.utils.FCLPath; import com.tungsten.fclcore.util.Logging; import com.tungsten.fclcore.util.Pack200Utils; import com.tungsten.fclcore.util.io.FileUtils; import com.tungsten.fclcore.util.io.IOUtils; +import com.tungsten.fclcore.util.io.Unzipper; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; @@ -37,6 +39,15 @@ public class RuntimeUtils { copyAssets(context, srcDir, targetDir); } + public static void installJna(Context context, String targetDir, String srcDir) throws IOException { + FileUtils.deleteDirectory(new File(targetDir)); + new File(targetDir).mkdirs(); + copyAssets(context, srcDir, targetDir); + File file = new File(FCLPath.JNA_PATH, "jna-arm64.zip"); + new Unzipper(file, new File(FCLPath.RUNTIME_DIR)).unzip(); + file.delete(); + } + @SuppressWarnings("ResultOfMethodCallIgnored") public static void installJava(Context context, String targetDir, String srcDir) throws IOException { FileUtils.deleteDirectory(new File(targetDir)); diff --git a/FCL/src/main/res/layout/activity_main.xml b/FCL/src/main/res/layout/activity_main.xml index 9b44251d..565e270c 100644 --- a/FCL/src/main/res/layout/activity_main.xml +++ b/FCL/src/main/res/layout/activity_main.xml @@ -1,292 +1,304 @@ - - - + + android:id="@+id/background" + tools:context=".activity.MainActivity"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:clipChildren="false" + android:clipToPadding="false"> - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/FCL/src/main/res/layout/fragment_runtime.xml b/FCL/src/main/res/layout/fragment_runtime.xml index b8fd4563..ed83d3a0 100644 --- a/FCL/src/main/res/layout/fragment_runtime.xml +++ b/FCL/src/main/res/layout/fragment_runtime.xml @@ -1,381 +1,425 @@ - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + android:layout_marginStart="10dp" + android:layout_marginEnd="10dp" + android:text="@string/splash_runtime_title" + app:layout_constraintStart_toEndOf="@id/split" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent"/> - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + \ No newline at end of file diff --git a/FCL/src/main/res/layout/item_remote_version.xml b/FCL/src/main/res/layout/item_remote_version.xml index 46196955..aaa835e5 100644 --- a/FCL/src/main/res/layout/item_remote_version.xml +++ b/FCL/src/main/res/layout/item_remote_version.xml @@ -15,7 +15,8 @@ android:background="@drawable/bg_container_white_clickable" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="horizontal"> + android:orientation="horizontal" + android:stateListAnimator="@xml/anim_scale"> + android:layout_height="match_parent" + android:background="@color/ui_bg_color" + android:paddingStart="10dp" + android:paddingTop="10dp" + android:paddingEnd="10dp"> + android:layout_weight="1" + android:background="@drawable/bg_container_white"> + android:orientation="vertical" + android:padding="10dp"> + app:auto_text_tint="true" /> + app:auto_edit_tint="true" /> + app:auto_text_tint="true" /> + android:layout_marginTop="10dp" /> + app:auto_text_tint="true" /> + android:layout_marginTop="10dp" /> + app:auto_text_tint="true" /> + android:layout_marginTop="10dp" /> + app:auto_text_tint="true" /> + android:layout_marginTop="10dp" /> + android:layout_marginTop="10dp" + android:text="@string/install_modpack" + android:visibility="gone" + app:ripple="true" /> + android:layout_marginTop="10dp" + android:text="@string/search" + app:ripple="true" /> - + android:orientation="horizontal" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@+id/left"> - + - - - - - - - - - - - - - - - - - - - + android:layout_gravity="center" + android:layout_marginStart="10dp" + android:padding="10dp" + android:text="@string/search_previous_page" + app:auto_padding="false" + app:ripple="true" /> - + android:layout_gravity="center" + android:layout_marginStart="10dp" + android:padding="10dp" + android:text="@string/search_next_page" + app:auto_padding="false" + app:ripple="true" /> - + + + + + + + + + + + \ No newline at end of file diff --git a/FCL/src/main/res/values/strings.xml b/FCL/src/main/res/values/strings.xml index b1b989a2..7b0ede99 100644 --- a/FCL/src/main/res/values/strings.xml +++ b/FCL/src/main/res/values/strings.xml @@ -22,6 +22,7 @@ JRE 11 JRE 17 JRE 21 + JNA Install / Update Account diff --git a/FCLCore/src/main/java/com/tungsten/fclcore/launch/DefaultLauncher.java b/FCLCore/src/main/java/com/tungsten/fclcore/launch/DefaultLauncher.java index 10294c3f..b51e22bd 100644 --- a/FCLCore/src/main/java/com/tungsten/fclcore/launch/DefaultLauncher.java +++ b/FCLCore/src/main/java/com/tungsten/fclcore/launch/DefaultLauncher.java @@ -54,6 +54,7 @@ import java.util.logging.Level; import java.util.stream.Collectors; public class DefaultLauncher extends Launcher { + private String jnaVersion; public DefaultLauncher(Context context, GameRepository repository, Version version, AuthInfo authInfo, LaunchOptions options) { super(context, repository, version, authInfo, options); @@ -152,6 +153,9 @@ public class DefaultLauncher extends Launcher { res.addDefault("-Duser.timezone=", TimeZone.getDefault().getID()); res.addDefault("-Dorg.lwjgl.vulkan.libname=", "libvulkan.so"); File libJna = new File(FCLPath.RUNTIME_DIR, "jna"); + if (jnaVersion != null && !jnaVersion.isEmpty()) { + libJna = new File(libJna, jnaVersion); + } res.addDefault("-Djna.boot.library.path=", libJna.exists() ? libJna.getAbsolutePath() : context.getApplicationInfo().nativeLibraryDir); if (getInjectorArg() != null && options.isBeGesture()) { @@ -436,4 +440,8 @@ public class DefaultLauncher extends Launcher { config.setUseVKDriverSystem(options.isVKDriverSystem()); return FCLauncher.launchMinecraft(config); } + + public void setJnaVersion(String jnaVersion) { + this.jnaVersion = jnaVersion; + } } diff --git a/FCLLibrary/src/main/java/com/tungsten/fcllibrary/component/view/FCLButton.java b/FCLLibrary/src/main/java/com/tungsten/fcllibrary/component/view/FCLButton.java index 0bc29707..de211323 100644 --- a/FCLLibrary/src/main/java/com/tungsten/fcllibrary/component/view/FCLButton.java +++ b/FCLLibrary/src/main/java/com/tungsten/fcllibrary/component/view/FCLButton.java @@ -1,5 +1,6 @@ package com.tungsten.fcllibrary.component.view; +import android.animation.AnimatorInflater; import android.annotation.SuppressLint; import android.content.Context; import android.content.res.ColorStateList; @@ -95,6 +96,7 @@ public class FCLButton extends AppCompatButton { drawablePress.setCornerRadius(ConvertUtils.dip2px(getContext(), 8)); drawablePress.setStroke(ConvertUtils.dip2px(getContext(), 1.5f), Color.GRAY); drawablePress.setColor(ThemeEngine.getInstance().getTheme().getLtColor()); + setStateListAnimator(AnimatorInflater.loadStateListAnimator(getContext(), R.xml.anim_scale)); } public FCLButton(@NonNull Context context) { diff --git a/FCLLibrary/src/main/java/com/tungsten/fcllibrary/component/view/FCLMenuView.java b/FCLLibrary/src/main/java/com/tungsten/fcllibrary/component/view/FCLMenuView.java index 7deea291..eecbd208 100644 --- a/FCLLibrary/src/main/java/com/tungsten/fcllibrary/component/view/FCLMenuView.java +++ b/FCLLibrary/src/main/java/com/tungsten/fcllibrary/component/view/FCLMenuView.java @@ -1,5 +1,6 @@ package com.tungsten.fcllibrary.component.view; +import android.animation.AnimatorInflater; import android.content.Context; import android.content.res.ColorStateList; import android.graphics.drawable.RippleDrawable; @@ -11,6 +12,7 @@ import androidx.appcompat.widget.AppCompatImageButton; import com.tungsten.fclcore.fakefx.beans.property.IntegerProperty; import com.tungsten.fclcore.fakefx.beans.property.IntegerPropertyBase; +import com.tungsten.fcllibrary.R; import com.tungsten.fcllibrary.component.theme.ThemeEngine; import com.tungsten.fcllibrary.util.ConvertUtils; @@ -68,6 +70,7 @@ public class FCLMenuView extends AppCompatImageButton { setSelected(true); } }); + setStateListAnimator(AnimatorInflater.loadStateListAnimator(getContext(), R.xml.anim_scale_large)); } public void setSelected(boolean selected) { diff --git a/FCLLibrary/src/main/res/xml/anim_scale.xml b/FCLLibrary/src/main/res/xml/anim_scale.xml new file mode 100644 index 00000000..f3d53a0b --- /dev/null +++ b/FCLLibrary/src/main/res/xml/anim_scale.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FCLLibrary/src/main/res/xml/anim_scale_large.xml b/FCLLibrary/src/main/res/xml/anim_scale_large.xml new file mode 100644 index 00000000..d20d4f9e --- /dev/null +++ b/FCLLibrary/src/main/res/xml/anim_scale_large.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FCLauncher/src/main/java/com/tungsten/fclauncher/utils/FCLPath.java b/FCLauncher/src/main/java/com/tungsten/fclauncher/utils/FCLPath.java index b34dc468..d08037cd 100644 --- a/FCLauncher/src/main/java/com/tungsten/fclauncher/utils/FCLPath.java +++ b/FCLauncher/src/main/java/com/tungsten/fclauncher/utils/FCLPath.java @@ -19,6 +19,7 @@ public class FCLPath { public static String JAVA_11_PATH; public static String JAVA_17_PATH; public static String JAVA_21_PATH; + public static String JNA_PATH; public static String LWJGL_DIR; public static String CACIOCAVALLO_8_DIR; public static String CACIOCAVALLO_11_DIR; @@ -51,6 +52,7 @@ public class FCLPath { JAVA_11_PATH = RUNTIME_DIR + "/java/jre11"; JAVA_17_PATH = RUNTIME_DIR + "/java/jre17"; JAVA_21_PATH = RUNTIME_DIR + "/java/jre21"; + JNA_PATH = RUNTIME_DIR + "/jna"; LWJGL_DIR = RUNTIME_DIR + "/lwjgl"; CACIOCAVALLO_8_DIR = RUNTIME_DIR + "/caciocavallo"; CACIOCAVALLO_11_DIR = RUNTIME_DIR + "/caciocavallo11";