install/update modpacks

This commit is contained in:
Tungstend 2023-07-08 02:02:11 +08:00
parent bea005f0a8
commit eb57b64add
25 changed files with 1188 additions and 57 deletions

View File

@ -167,7 +167,7 @@ public class DownloadPage extends FCLCommonPage implements ManageUI.VersionLoada
switch (id) {
case PAGE_ID_DOWNLOAD_MODPACK:
this.callback = ((profile, version1, file) -> Versions.downloadModpackImpl(context, profile, version1, file));
this.callback = ((profile, version, file) -> Versions.downloadModpackImpl(context, parent, profile, file));
break;
case PAGE_ID_DOWNLOAD_MOD:
this.callback = (profile, version, file) -> download(context, profile, version, file, "mods");

View File

@ -8,8 +8,6 @@ import com.google.android.material.tabs.TabLayout;
import com.tungsten.fcl.R;
import com.tungsten.fcl.setting.Profile;
import com.tungsten.fcl.setting.Profiles;
import com.tungsten.fcl.util.FXUtils;
import com.tungsten.fcl.util.WeakListenerHolder;
import com.tungsten.fclcore.task.Task;
import com.tungsten.fcllibrary.component.ui.FCLBasePage;
import com.tungsten.fcllibrary.component.ui.FCLMultiPageUI;
@ -27,8 +25,6 @@ public class DownloadUI extends FCLMultiPageUI implements TabLayout.OnTabSelecte
private FCLTabLayout tabLayout;
private FCLUILayout container;
private WeakListenerHolder listenerHolder;
public DownloadUI(Context context, FCLUILayout parent, int id) {
super(context, parent, id);
}
@ -96,11 +92,9 @@ public class DownloadUI extends FCLMultiPageUI implements TabLayout.OnTabSelecte
}
private void loadVersions(Profile profile) {
listenerHolder = new WeakListenerHolder();
if (profile == Profiles.getSelectedProfile()) {
listenerHolder.add(FXUtils.onWeakChangeAndOperate(profile.selectedVersionProperty(), version -> {
pageManager.loadVersion(profile, null);
}));
profile.selectedVersionProperty().addListener(observable -> pageManager.loadVersion(profile, null));
}
}

View File

@ -0,0 +1,166 @@
package com.tungsten.fcl.ui.download;
import static com.tungsten.fclcore.util.Logging.LOG;
import android.content.Context;
import android.view.View;
import android.widget.Toast;
import com.tungsten.fcl.R;
import com.tungsten.fcl.game.FCLGameRepository;
import com.tungsten.fcl.game.ManuallyCreatedModpackException;
import com.tungsten.fcl.game.ModpackHelper;
import com.tungsten.fcl.setting.Profile;
import com.tungsten.fcl.setting.Profiles;
import com.tungsten.fcl.ui.manage.ManagePageManager;
import com.tungsten.fclcore.fakefx.beans.property.BooleanProperty;
import com.tungsten.fclcore.fakefx.beans.property.SimpleBooleanProperty;
import com.tungsten.fclcore.mod.Modpack;
import com.tungsten.fclcore.task.Schedulers;
import com.tungsten.fclcore.task.Task;
import com.tungsten.fclcore.util.StringUtils;
import com.tungsten.fclcore.util.io.CompressingUtils;
import com.tungsten.fclcore.util.io.FileUtils;
import com.tungsten.fcllibrary.component.dialog.FCLAlertDialog;
import com.tungsten.fcllibrary.component.view.FCLUILayout;
import java.io.File;
import java.nio.charset.Charset;
import java.util.logging.Level;
public class LocalModpackPage extends ModpackPage implements View.OnClickListener {
private final String updateVersion;
private final File modpackFile;
private final BooleanProperty installAsVersion = new SimpleBooleanProperty(true);
private boolean isManuallyCreated = false;
private Modpack manifest = null;
private Charset charset;
public LocalModpackPage(Context context, int id, FCLUILayout parent, int resId, Profile profile, String updateVersion, File modpackFile) {
super(context, id, parent, resId, profile);
this.updateVersion = updateVersion;
this.modpackFile = modpackFile;
}
@Override
public void onStart() {
super.onStart();
if (updateVersion != null) {
editText.setText(updateVersion);
editText.setEnabled(false);
}
progressBar.setVisibility(View.VISIBLE);
layout.setVisibility(View.GONE);
Task.supplyAsync(() -> CompressingUtils.findSuitableEncoding(modpackFile.toPath()))
.thenApplyAsync(encoding -> {
charset = encoding;
manifest = ModpackHelper.readModpackManifest(modpackFile.toPath(), encoding);
return manifest;
})
.whenComplete(Schedulers.androidUIThread(), (manifest, exception) -> {
if (exception instanceof ManuallyCreatedModpackException) {
progressBar.setVisibility(View.GONE);
layout.setVisibility(View.VISIBLE);
name.setText(modpackFile.getName());
installAsVersion.set(false);
if (updateVersion == null) {
editText.setText(FileUtils.getNameWithoutExtension(modpackFile));
}
FCLAlertDialog.Builder builder = new FCLAlertDialog.Builder(getContext());
builder.setAlertLevel(FCLAlertDialog.AlertLevel.ALERT);
builder.setCancelable(false);
builder.setTitle(getContext().getString(R.string.install_modpack));
builder.setMessage(getContext().getString(R.string.modpack_type_manual_warning));
builder.setPositiveButton(null);
builder.setNegativeButton(() -> {
if (updateVersion == null) {
DownloadPageManager.getInstance().dismissCurrentTempPage();
} else {
ManagePageManager.getInstance().dismissCurrentTempPage();
}
});
builder.create().show();
this.manifest = null;
isManuallyCreated = true;
} else if (exception != null) {
LOG.log(Level.WARNING, "Failed to read modpack manifest", exception);
FCLAlertDialog.Builder builder = new FCLAlertDialog.Builder(getContext());
builder.setAlertLevel(FCLAlertDialog.AlertLevel.ALERT);
builder.setCancelable(false);
builder.setTitle(getContext().getString(R.string.message_error));
builder.setMessage(getContext().getString(R.string.modpack_task_install_error));
builder.setNegativeButton(getContext().getString(com.tungsten.fcllibrary.R.string.dialog_positive), () -> {
if (updateVersion == null) {
DownloadPageManager.getInstance().dismissCurrentTempPage();
} else {
ManagePageManager.getInstance().dismissCurrentTempPage();
}
});
builder.create().show();
} else {
progressBar.setVisibility(View.GONE);
layout.setVisibility(View.VISIBLE);
name.setText(manifest.getName());
version.setText(manifest.getVersion());
author.setText(manifest.getAuthor());
if (updateVersion == null) {
editText.setText(manifest.getName().trim());
}
}
}).start();
}
@Override
protected void onInstall() {
String name;
if (updateVersion != null) {
name = updateVersion;
} else {
String str = editText.getText().toString();
if (installAsVersion.get()) {
if (StringUtils.isBlank(str)) {
Toast.makeText(getContext(), getContext().getString(R.string.input_not_empty), Toast.LENGTH_SHORT).show();
return;
} else if (profile.getRepository().versionIdConflicts(str)) {
Toast.makeText(getContext(), getContext().getString(R.string.install_new_game_already_exists), Toast.LENGTH_SHORT).show();
return;
} else if (!FCLGameRepository.isValidVersionId(str)) {
Toast.makeText(getContext(), getContext().getString(R.string.install_new_game_malformed), Toast.LENGTH_SHORT).show();
return;
}
} else {
if (StringUtils.isBlank(str)) {
Toast.makeText(getContext(), getContext().getString(R.string.input_not_empty), Toast.LENGTH_SHORT).show();
return;
} else if (ModpackHelper.isExternalGameNameConflicts(str) || Profiles.getProfiles().stream().anyMatch(p -> p.getName().equals(str))) {
Toast.makeText(getContext(), getContext().getString(R.string.install_new_game_already_exists), Toast.LENGTH_SHORT).show();
return;
} else if (!FCLGameRepository.isValidVersionId(str)) {
Toast.makeText(getContext(), getContext().getString(R.string.install_new_game_malformed), Toast.LENGTH_SHORT).show();
return;
}
}
name = str;
}
Task<?> task;
if (isManuallyCreated) {
task = ModpackInstaller.getModpackInstallTask(profile, modpackFile, name, charset);
} else {
if (updateVersion == null) {
task = ModpackInstaller.getModpackInstallTask(getContext(), profile, modpackFile, manifest, name);
} else {
task = ModpackInstaller.getModpackInstallTask(getContext(), profile, updateVersion, modpackFile, manifest, name);
}
}
ModpackInstaller.installModpack(getContext(), task, updateVersion != null);
}
}

View File

@ -75,7 +75,7 @@ public class ModpackDownloadPage extends DownloadPage {
public void onClick(View v) {
super.onClick(v);
if (v == installModpack) {
Versions.importModpack();
Versions.importModpack(getContext(), getParent());
}
}
}

View File

@ -0,0 +1,180 @@
package com.tungsten.fcl.ui.download;
import android.content.Context;
import androidx.appcompat.app.AppCompatDialog;
import com.tungsten.fcl.R;
import com.tungsten.fcl.game.ManuallyCreatedModpackException;
import com.tungsten.fcl.game.ModpackHelper;
import com.tungsten.fcl.setting.Profile;
import com.tungsten.fcl.ui.TaskDialog;
import com.tungsten.fcl.ui.manage.ManagePageManager;
import com.tungsten.fcl.util.TaskCancellationAction;
import com.tungsten.fclcore.mod.MismatchedModpackTypeException;
import com.tungsten.fclcore.mod.Modpack;
import com.tungsten.fclcore.mod.ModpackCompletionException;
import com.tungsten.fclcore.mod.UnsupportedModpackException;
import com.tungsten.fclcore.mod.server.ServerModpackManifest;
import com.tungsten.fclcore.task.Schedulers;
import com.tungsten.fclcore.task.Task;
import com.tungsten.fclcore.task.TaskExecutor;
import com.tungsten.fclcore.task.TaskListener;
import com.tungsten.fcllibrary.component.dialog.FCLAlertDialog;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.Charset;
public class ModpackInstaller {
public static void installModpack(Context context, Task<?> task, boolean update) {
TaskDialog pane = new TaskDialog(context, new TaskCancellationAction(AppCompatDialog::dismiss));
pane.setTitle(context.getString(R.string.install_modpack));
Schedulers.androidUIThread().execute(() -> {
TaskExecutor executor = task.executor(new TaskListener() {
@Override
public void onStop(boolean success, TaskExecutor executor) {
Schedulers.androidUIThread().execute(() -> {
if (success) {
FCLAlertDialog.Builder builder1 = new FCLAlertDialog.Builder(context);
builder1.setAlertLevel(FCLAlertDialog.AlertLevel.INFO);
builder1.setCancelable(false);
builder1.setMessage(context.getString(R.string.install_success));
builder1.setNegativeButton(context.getString(com.tungsten.fcllibrary.R.string.dialog_positive), () -> {
if (update) {
ManagePageManager.getInstance().dismissCurrentTempPage();
} else {
DownloadPageManager.getInstance().dismissCurrentTempPage();
}
});
builder1.create().show();
} else {
if (executor.getException() == null)
return;
if (executor.getException() instanceof ModpackCompletionException) {
if (executor.getException().getCause() instanceof FileNotFoundException) {
FCLAlertDialog.Builder builder1 = new FCLAlertDialog.Builder(context);
builder1.setAlertLevel(FCLAlertDialog.AlertLevel.INFO);
builder1.setCancelable(false);
builder1.setTitle(context.getString(R.string.install_failed));
builder1.setMessage(context.getString(R.string.modpack_type_curse_not_found));
builder1.setNegativeButton(context.getString(com.tungsten.fcllibrary.R.string.dialog_positive), () -> {
if (update) {
ManagePageManager.getInstance().dismissCurrentTempPage();
} else {
DownloadPageManager.getInstance().dismissCurrentTempPage();
}
});
builder1.create().show();
} else {
FCLAlertDialog.Builder builder1 = new FCLAlertDialog.Builder(context);
builder1.setAlertLevel(FCLAlertDialog.AlertLevel.INFO);
builder1.setCancelable(false);
builder1.setMessage(context.getString(R.string.install_success));
builder1.setNegativeButton(context.getString(com.tungsten.fcllibrary.R.string.dialog_positive), () -> {
if (update) {
ManagePageManager.getInstance().dismissCurrentTempPage();
} else {
DownloadPageManager.getInstance().dismissCurrentTempPage();
}
});
builder1.create().show();
}
} else {
InstallersPage.alertFailureMessage(context, executor.getException(), () -> {});
}
}
});
}
});
pane.setExecutor(executor);
pane.show();
executor.start();
});
}
public static Task<?> getModpackInstallTask(Profile profile, File selected, String name, Charset charset) {
return getModpackInstallTaskAsync(null, profile, null, selected, null, null, name, charset, true);
}
public static Task<?> getModpackInstallTask(Context context, Profile profile, ServerModpackManifest serverModpackManifest, Modpack modpack, String name) {
return getModpackInstallTask(context, profile, null, null, serverModpackManifest, modpack, name);
}
public static Task<?> getModpackInstallTask(Context context, Profile profile, File selected, Modpack modpack, String name) {
return getModpackInstallTask(context, profile, null, selected, null, modpack, name);
}
public static Task<?> getModpackInstallTask(Context context, Profile profile, String updateVersion, File selected, Modpack modpack, String name) {
return getModpackInstallTask(context, profile, updateVersion, selected, null, modpack, name);
}
public static Task<?> getModpackInstallTask(Context context, Profile profile, String updateVersion, File selected, ServerModpackManifest serverModpackManifest, Modpack modpack, String name) {
return getModpackInstallTaskAsync(context, profile, updateVersion, selected, serverModpackManifest, modpack, name, null, false);
}
private static Task<?> getModpackInstallTaskAsync(Context context, Profile profile, String updateVersion, File selected, ServerModpackManifest serverModpackManifest, Modpack modpack, String name, Charset charset, boolean isManuallyCreated) {
if (isManuallyCreated) {
return ModpackHelper.getInstallManuallyCreatedModpackTask(profile, selected, name, charset);
}
if ((selected == null && serverModpackManifest == null) || modpack == null || name == null) return null;
if (updateVersion != null) {
if (selected == null) {
FCLAlertDialog.Builder builder = new FCLAlertDialog.Builder(context);
builder.setAlertLevel(FCLAlertDialog.AlertLevel.ALERT);
builder.setCancelable(false);
builder.setTitle(context.getString(R.string.message_error));
builder.setMessage(context.getString(R.string.modpack_unsupported));
builder.setNegativeButton(context.getString(com.tungsten.fcllibrary.R.string.dialog_positive), null);
builder.create().show();
return null;
}
try {
if (serverModpackManifest != null) {
return ModpackHelper.getUpdateTask(profile, serverModpackManifest, modpack.getEncoding(), name, ModpackHelper.readModpackConfiguration(profile.getRepository().getModpackConfiguration(name)));
} else {
return ModpackHelper.getUpdateTask(profile, selected, modpack.getEncoding(), name, ModpackHelper.readModpackConfiguration(profile.getRepository().getModpackConfiguration(name)));
}
} catch (UnsupportedModpackException | ManuallyCreatedModpackException e) {
FCLAlertDialog.Builder builder = new FCLAlertDialog.Builder(context);
builder.setAlertLevel(FCLAlertDialog.AlertLevel.ALERT);
builder.setCancelable(false);
builder.setTitle(context.getString(R.string.message_error));
builder.setMessage(context.getString(R.string.modpack_unsupported));
builder.setNegativeButton(context.getString(com.tungsten.fcllibrary.R.string.dialog_positive), null);
builder.create().show();
} catch (MismatchedModpackTypeException e) {
FCLAlertDialog.Builder builder = new FCLAlertDialog.Builder(context);
builder.setAlertLevel(FCLAlertDialog.AlertLevel.ALERT);
builder.setCancelable(false);
builder.setTitle(context.getString(R.string.message_error));
builder.setMessage(context.getString(R.string.modpack_mismatched_type));
builder.setNegativeButton(context.getString(com.tungsten.fcllibrary.R.string.dialog_positive), null);
builder.create().show();
} catch (IOException e) {
FCLAlertDialog.Builder builder = new FCLAlertDialog.Builder(context);
builder.setAlertLevel(FCLAlertDialog.AlertLevel.ALERT);
builder.setCancelable(false);
builder.setTitle(context.getString(R.string.message_error));
builder.setMessage(context.getString(R.string.modpack_invalid));
builder.setNegativeButton(context.getString(com.tungsten.fcllibrary.R.string.dialog_positive), null);
builder.create().show();
}
return null;
} else {
if (serverModpackManifest != null) {
return ModpackHelper.getInstallTask(profile, serverModpackManifest, name, modpack)
.thenRunAsync(Schedulers.androidUIThread(), () -> profile.setSelectedVersion(name));
} else {
return ModpackHelper.getInstallTask(profile, selected, name, modpack)
.thenRunAsync(Schedulers.androidUIThread(), () -> profile.setSelectedVersion(name));
}
}
}
}

View File

@ -0,0 +1,73 @@
package com.tungsten.fcl.ui.download;
import android.content.Context;
import android.content.res.ColorStateList;
import android.view.View;
import android.widget.ScrollView;
import com.tungsten.fcl.R;
import com.tungsten.fcl.setting.Profile;
import com.tungsten.fclcore.task.Task;
import com.tungsten.fcllibrary.component.theme.ThemeEngine;
import com.tungsten.fcllibrary.component.ui.FCLTempPage;
import com.tungsten.fcllibrary.component.view.FCLButton;
import com.tungsten.fcllibrary.component.view.FCLEditText;
import com.tungsten.fcllibrary.component.view.FCLLinearLayout;
import com.tungsten.fcllibrary.component.view.FCLProgressBar;
import com.tungsten.fcllibrary.component.view.FCLTextView;
import com.tungsten.fcllibrary.component.view.FCLUILayout;
public abstract class ModpackPage extends FCLTempPage implements View.OnClickListener {
protected final Profile profile;
protected FCLProgressBar progressBar;
protected FCLLinearLayout layout;
protected ScrollView infoLayout;
protected FCLEditText editText;
protected FCLTextView name;
protected FCLTextView version;
protected FCLTextView author;
protected FCLButton install;
public ModpackPage(Context context, int id, FCLUILayout parent, int resId, Profile profile) {
super(context, id, parent, resId);
this.profile = profile;
}
@Override
public void onCreate() {
super.onCreate();
progressBar = findViewById(R.id.progress);
layout = findViewById(R.id.layout);
infoLayout = findViewById(R.id.info_layout);
editText = findViewById(R.id.name);
name = findViewById(R.id.modpack_name);
version = findViewById(R.id.version);
author = findViewById(R.id.author);
install = findViewById(R.id.install);
install.setOnClickListener(this);
ThemeEngine.getInstance().registerEvent(infoLayout, () -> infoLayout.setBackgroundTintList(new ColorStateList(new int[][] { { } }, new int[] { ThemeEngine.getInstance().getTheme().getLtColor() })));
}
@Override
public Task<?> refresh(Object... param) {
return null;
}
@Override
public void onRestart() {
}
protected abstract void onInstall();
@Override
public void onClick(View v) {
if (v == install) {
onInstall();
}
}
}

View File

@ -0,0 +1,170 @@
package com.tungsten.fcl.ui.download;
import android.app.Activity;
import android.content.Context;
import android.view.View;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatDialog;
import com.tungsten.fcl.R;
import com.tungsten.fcl.setting.Profile;
import com.tungsten.fcl.ui.PageManager;
import com.tungsten.fcl.ui.TaskDialog;
import com.tungsten.fcl.ui.manage.ManagePageManager;
import com.tungsten.fcl.util.RequestCodes;
import com.tungsten.fcl.util.TaskCancellationAction;
import com.tungsten.fclcore.mod.server.ServerModpackManifest;
import com.tungsten.fclcore.task.FileDownloadTask;
import com.tungsten.fclcore.task.GetTask;
import com.tungsten.fclcore.task.Schedulers;
import com.tungsten.fclcore.task.Task;
import com.tungsten.fclcore.task.TaskExecutor;
import com.tungsten.fclcore.util.gson.JsonUtils;
import com.tungsten.fcllibrary.browser.FileBrowser;
import com.tungsten.fcllibrary.browser.options.LibMode;
import com.tungsten.fcllibrary.browser.options.SelectionMode;
import com.tungsten.fcllibrary.component.ui.FCLTempPage;
import com.tungsten.fcllibrary.component.view.FCLLinearLayout;
import com.tungsten.fcllibrary.component.view.FCLUILayout;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
public class ModpackSelectionPage extends FCLTempPage implements View.OnClickListener {
private final Profile profile;
private final String updateVersion;
private FCLLinearLayout local;
private FCLLinearLayout remote;
public ModpackSelectionPage(Context context, int id, FCLUILayout parent, int resId, Profile profile, String updateVersion) {
super(context, id, parent, resId);
this.profile = profile;
this.updateVersion = updateVersion;
}
@Override
public void onCreate() {
super.onCreate();
local = findViewById(R.id.local);
remote = findViewById(R.id.remote);
local.setOnClickListener(this);
remote.setOnClickListener(this);
}
private void onChooseLocalFile() {
FileBrowser.Builder builder = new FileBrowser.Builder(getContext());
builder.setLibMode(LibMode.FILE_CHOOSER);
builder.setSelectionMode(SelectionMode.SINGLE_SELECTION);
ArrayList<String> suffix = new ArrayList<>();
suffix.add(".zip");
suffix.add(".mrpack");
builder.setSuffix(suffix);
builder.create().browse(getActivity(), RequestCodes.SELECT_MODPACK_CODE, ((requestCode, resultCode, data) -> {
if (requestCode == RequestCodes.SELECT_MODPACK_CODE && resultCode == Activity.RESULT_OK && data != null) {
String path = FileBrowser.getSelectedFiles(data).get(0);
if (path == null)
return;
File selectedFile = new File(path);
Schedulers.androidUIThread().execute(() -> {
LocalModpackPage page = new LocalModpackPage(getContext(), PageManager.PAGE_ID_TEMP, getParent(), R.layout.page_modpack, profile, updateVersion, selectedFile);
if (updateVersion == null) {
DownloadPageManager.getInstance().dismissCurrentTempPage();
DownloadPageManager.getInstance().showTempPage(page);
} else {
ManagePageManager.getInstance().dismissCurrentTempPage();
ManagePageManager.getInstance().showTempPage(page);
}
});
}
}));
}
private void onChooseRemoteFile() {
ModpackUrlDialog dialog = new ModpackUrlDialog(getContext(), urlString -> {
try {
URL url = new URL(urlString);
if (urlString.endsWith("server-manifest.json")) {
// if urlString ends with .json, we assume that the url is server-manifest.json
TaskDialog taskDialog = new TaskDialog(getContext(), new TaskCancellationAction(AppCompatDialog::dismiss));
taskDialog.setTitle(getContext().getString(R.string.message_downloading));
TaskExecutor executor = new GetTask(url).whenComplete(Schedulers.androidUIThread(), (result, e) -> {
ServerModpackManifest manifest = JsonUtils.fromMaybeMalformedJson(result, ServerModpackManifest.class);
if (manifest == null) {
Toast.makeText(getContext(), getContext().getString(R.string.modpack_type_server_malformed), Toast.LENGTH_SHORT).show();
} else if (e == null) {
RemoteModpackPage page = new RemoteModpackPage(getContext(), PageManager.PAGE_ID_TEMP, getParent(), R.layout.page_modpack, profile, updateVersion, manifest);
if (updateVersion == null) {
DownloadPageManager.getInstance().dismissCurrentTempPage();
DownloadPageManager.getInstance().showTempPage(page);
} else {
ManagePageManager.getInstance().dismissCurrentTempPage();
ManagePageManager.getInstance().showTempPage(page);
}
} else {
Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
}
}).executor();
taskDialog.setExecutor(executor);
taskDialog.show();
executor.start();
} else {
// otherwise we still consider the file as modpack zip file
// since casually the url may not ends with ".zip"
Path modpack = Files.createTempFile("modpack", ".zip");
TaskDialog taskDialog = new TaskDialog(getContext(), new TaskCancellationAction(AppCompatDialog::dismiss));
taskDialog.setTitle(getContext().getString(R.string.message_downloading));
TaskExecutor executor = new FileDownloadTask(url, modpack.toFile(), null)
.whenComplete(Schedulers.androidUIThread(), e -> {
if (e == null) {
LocalModpackPage page = new LocalModpackPage(getContext(), PageManager.PAGE_ID_TEMP, getParent(), R.layout.page_modpack, profile, updateVersion, modpack.toFile());
if (updateVersion == null) {
DownloadPageManager.getInstance().dismissCurrentTempPage();
DownloadPageManager.getInstance().showTempPage(page);
} else {
ManagePageManager.getInstance().dismissCurrentTempPage();
ManagePageManager.getInstance().showTempPage(page);
}
} else {
Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
}
}).executor();
taskDialog.setExecutor(executor);
taskDialog.show();
executor.start();
}
} catch (IOException e) {
Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
dialog.show();
}
@Override
public Task<?> refresh(Object... param) {
return null;
}
@Override
public void onRestart() {
}
@Override
public void onClick(View v) {
if (v == local) {
onChooseLocalFile();
}
if (v == remote) {
onChooseRemoteFile();
}
}
}

View File

@ -0,0 +1,52 @@
package com.tungsten.fcl.ui.download;
import android.content.Context;
import android.view.View;
import androidx.annotation.NonNull;
import com.tungsten.fcl.R;
import com.tungsten.fclcore.util.StringUtils;
import com.tungsten.fcllibrary.component.dialog.FCLDialog;
import com.tungsten.fcllibrary.component.view.FCLButton;
import com.tungsten.fcllibrary.component.view.FCLEditText;
public class ModpackUrlDialog extends FCLDialog implements View.OnClickListener {
private final Callback callback;
private FCLEditText editText;
private FCLButton positive;
private FCLButton negative;
public ModpackUrlDialog(@NonNull Context context, Callback callback) {
super(context);
this.callback = callback;
setCancelable(false);
setContentView(R.layout.dialog_modpack_url);
editText = findViewById(R.id.url);
positive = findViewById(R.id.positive);
negative = findViewById(R.id.negative);
positive.setOnClickListener(this);
negative.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v == positive) {
if (StringUtils.isNotBlank(editText.getText().toString())) {
callback.onPositive(editText.getText().toString());
dismiss();
}
}
if (v == negative) {
dismiss();
}
}
public interface Callback {
void onPositive(String urlString);
}
}

View File

@ -0,0 +1,101 @@
package com.tungsten.fcl.ui.download;
import android.content.Context;
import android.view.View;
import android.widget.Toast;
import com.tungsten.fcl.R;
import com.tungsten.fcl.game.FCLGameRepository;
import com.tungsten.fcl.setting.Profile;
import com.tungsten.fcl.ui.manage.ManagePageManager;
import com.tungsten.fclcore.mod.Modpack;
import com.tungsten.fclcore.mod.server.ServerModpackManifest;
import com.tungsten.fclcore.task.Task;
import com.tungsten.fclcore.util.StringUtils;
import com.tungsten.fcllibrary.component.dialog.FCLAlertDialog;
import com.tungsten.fcllibrary.component.view.FCLUILayout;
import java.io.IOException;
public class RemoteModpackPage extends ModpackPage {
private final String updateVersion;
private final ServerModpackManifest manifest;
private Modpack modpack;
public RemoteModpackPage(Context context, int id, FCLUILayout parent, int resId, Profile profile, String updateVersion, ServerModpackManifest manifest) {
super(context, id, parent, resId, profile);
this.updateVersion = updateVersion;
this.manifest = manifest;
}
@Override
public void onStart() {
super.onStart();
progressBar.setVisibility(View.VISIBLE);
layout.setVisibility(View.GONE);
try {
modpack = manifest.toModpack(null);
} catch (IOException e) {
FCLAlertDialog.Builder builder = new FCLAlertDialog.Builder(getContext());
builder.setAlertLevel(FCLAlertDialog.AlertLevel.ALERT);
builder.setCancelable(false);
builder.setTitle(getContext().getString(R.string.message_error));
builder.setMessage(getContext().getString(R.string.modpack_type_server_malformed));
builder.setNegativeButton(getContext().getString(com.tungsten.fcllibrary.R.string.dialog_positive), () -> {
if (updateVersion == null) {
DownloadPageManager.getInstance().dismissCurrentTempPage();
} else {
ManagePageManager.getInstance().dismissCurrentTempPage();
}
});
builder.create().show();
return;
}
progressBar.setVisibility(View.GONE);
layout.setVisibility(View.VISIBLE);
name.setText(manifest.getName());
version.setText(manifest.getVersion());
author.setText(manifest.getAuthor());
if (updateVersion != null) {
editText.setText(updateVersion);
editText.setEnabled(false);
} else {
editText.setText(manifest.getName().trim());
}
}
@Override
protected void onInstall() {
String name;
if (updateVersion != null) {
name = updateVersion;
} else {
String str = editText.getText().toString();
if (StringUtils.isBlank(str)) {
Toast.makeText(getContext(), getContext().getString(R.string.input_not_empty), Toast.LENGTH_SHORT).show();
return;
} else if (profile.getRepository().versionIdConflicts(str)) {
Toast.makeText(getContext(), getContext().getString(R.string.install_new_game_already_exists), Toast.LENGTH_SHORT).show();
return;
} else if (!FCLGameRepository.isValidVersionId(str)) {
Toast.makeText(getContext(), getContext().getString(R.string.install_new_game_malformed), Toast.LENGTH_SHORT).show();
return;
}
name = str;
}
Task<?> task;
if (updateVersion == null) {
task = ModpackInstaller.getModpackInstallTask(getContext(), profile, manifest, modpack, name);
} else {
task = ModpackInstaller.getModpackInstallTask(getContext(), profile, updateVersion, null, manifest, modpack, name);
}
ModpackInstaller.installModpack(getContext(), task, updateVersion != null);
}
}

View File

@ -119,7 +119,7 @@ public class ManagePage extends FCLCommonPage implements ManageUI.VersionLoadabl
}
private void updateGame() {
Versions.updateVersion(getProfile(), getVersion());
Versions.updateVersion(getContext(), getParent(), getProfile(), getVersion());
}
private void export() {

View File

@ -1,11 +1,13 @@
package com.tungsten.fcl.ui.version;
import static com.tungsten.fclcore.download.LibraryAnalyzer.LibraryType.MINECRAFT;
import static com.tungsten.fclcore.util.Logging.LOG;
import android.content.Context;
import android.view.View;
import android.widget.ListView;
import com.google.gson.JsonParseException;
import com.tungsten.fcl.R;
import com.tungsten.fcl.game.FCLGameRepository;
import com.tungsten.fcl.setting.Profile;
@ -13,12 +15,15 @@ import com.tungsten.fcl.setting.Profiles;
import com.tungsten.fcl.util.AndroidUtils;
import com.tungsten.fclcore.download.LibraryAnalyzer;
import com.tungsten.fclcore.fakefx.beans.binding.Bindings;
import com.tungsten.fclcore.mod.ModpackConfiguration;
import com.tungsten.fclcore.task.Schedulers;
import com.tungsten.fcllibrary.component.view.FCLButton;
import com.tungsten.fcllibrary.component.view.FCLProgressBar;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.stream.Collectors;
public class VersionList {
@ -61,7 +66,15 @@ public class VersionList {
libraries.append(": ").append(libraryVersion.replaceAll("(?i)" + libraryId, ""));
}
}
return new VersionListItem(profile, version.getId(), libraries.toString(), repository.getVersionIconImage(version.getId()));
String tag = null;
try {
ModpackConfiguration<?> config = profile.getRepository().readModpackConfiguration(version.getId());
if (config != null)
tag = config.getVersion();
} catch (IOException | JsonParseException e) {
LOG.log(Level.WARNING, "Failed to read modpack configuration from " + version, e);
}
return new VersionListItem(profile, version.getId(), libraries.toString(), tag, repository.getVersionIconImage(version.getId()));
})
.collect(Collectors.toList());
if (profile == Profiles.getSelectedProfile()) {

View File

@ -28,6 +28,7 @@ public class VersionListAdapter extends FCLAdapter {
FCLRadioButton radioButton;
AppCompatImageView icon;
FCLTextView title;
FCLTextView tag;
FCLTextView subtitle;
FCLImageButton delete;
}
@ -51,6 +52,7 @@ public class VersionListAdapter extends FCLAdapter {
viewHolder.radioButton = view.findViewById(R.id.radio);
viewHolder.icon = view.findViewById(R.id.icon);
viewHolder.title = view.findViewById(R.id.title);
viewHolder.tag = view.findViewById(R.id.tag);
viewHolder.subtitle = view.findViewById(R.id.subtitle);
viewHolder.delete = view.findViewById(R.id.delete);
view.setTag(viewHolder);
@ -62,6 +64,10 @@ public class VersionListAdapter extends FCLAdapter {
viewHolder.radioButton.checkProperty().bind(versionListItem.selectedProperty());
viewHolder.icon.setBackground(versionListItem.getDrawable());
viewHolder.title.setText(versionListItem.getVersion());
viewHolder.tag.setVisibility(versionListItem.getTag() == null ? View.GONE : View.VISIBLE);
if (versionListItem.getTag() != null) {
viewHolder.tag.setText(versionListItem.getTag());
}
viewHolder.subtitle.setText(versionListItem.getLibraries());
viewHolder.radioButton.setOnClickListener(view1 -> versionListItem.getProfile().setSelectedVersion(versionListItem.getVersion()));
viewHolder.delete.setOnClickListener(view1 -> Versions.deleteVersion(getContext(), versionListItem.getProfile(), versionListItem.getVersion()));

View File

@ -13,13 +13,15 @@ public class VersionListItem {
private final boolean isModpack;
private final BooleanProperty selected = new SimpleBooleanProperty();
private final String libraries;
private final String tag;
private final Drawable drawable;
public VersionListItem(Profile profile, String id, String libraries, Drawable drawable) {
public VersionListItem(Profile profile, String id, String libraries, String tag, Drawable drawable) {
this.profile = profile;
this.version = id;
this.libraries = libraries;
this.drawable = drawable;
this.tag = tag;
this.isModpack = profile.getRepository().isModpack(id);
selected.set(id.equals(profile.getSelectedVersion()));
@ -37,6 +39,10 @@ public class VersionListItem {
return libraries;
}
public String getTag() {
return tag;
}
public Drawable getDrawable() {
return drawable;
}

View File

@ -2,6 +2,9 @@ package com.tungsten.fcl.ui.version;
import android.app.Activity;
import android.content.Context;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatDialog;
import com.tungsten.fcl.R;
import com.tungsten.fcl.activity.MainActivity;
@ -9,14 +12,21 @@ import com.tungsten.fcl.game.LauncherHelper;
import com.tungsten.fcl.setting.Accounts;
import com.tungsten.fcl.setting.Profile;
import com.tungsten.fcl.setting.Profiles;
import com.tungsten.fcl.ui.PageManager;
import com.tungsten.fcl.ui.TaskDialog;
import com.tungsten.fcl.ui.account.CreateAccountDialog;
import com.tungsten.fcl.ui.download.DownloadPageManager;
import com.tungsten.fcl.ui.download.LocalModpackPage;
import com.tungsten.fcl.ui.download.ModpackSelectionPage;
import com.tungsten.fcl.ui.manage.ManagePageManager;
import com.tungsten.fcl.util.AndroidUtils;
import com.tungsten.fcl.util.RequestCodes;
import com.tungsten.fcl.util.TaskCancellationAction;
import com.tungsten.fclcore.auth.Account;
import com.tungsten.fclcore.auth.AccountFactory;
import com.tungsten.fclcore.download.game.GameAssetDownloadTask;
import com.tungsten.fclcore.mod.RemoteMod;
import com.tungsten.fclcore.task.FileDownloadTask;
import com.tungsten.fclcore.task.Schedulers;
import com.tungsten.fclcore.task.Task;
import com.tungsten.fclcore.task.TaskExecutor;
@ -26,52 +36,66 @@ import com.tungsten.fclcore.util.platform.OperatingSystem;
import com.tungsten.fcllibrary.browser.FileBrowser;
import com.tungsten.fcllibrary.browser.options.LibMode;
import com.tungsten.fcllibrary.component.dialog.FCLAlertDialog;
import com.tungsten.fcllibrary.component.view.FCLUILayout;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.logging.Level;
public class Versions {
public static void importModpack() {
public static void importModpack(Context context, FCLUILayout parent) {
Profile profile = Profiles.getSelectedProfile();
if (profile.getRepository().isLoaded()) {
//Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(profile), i18n("install.modpack"));
ModpackSelectionPage page = new ModpackSelectionPage(context, PageManager.PAGE_ID_TEMP, parent, R.layout.page_modpack_selection, profile, null);
DownloadPageManager.getInstance().showTempPage(page);
}
}
public static void downloadModpackImpl(Context context, Profile profile, String version, RemoteMod.Version file) {
/*
public static void downloadModpackImpl(Context context, FCLUILayout parent, Profile profile, RemoteMod.Version file) {
Path modpack;
URL downloadURL;
try {
modpack = Files.createTempFile("modpack", ".zip");
downloadURL = new URL(file.getFile().getUrl());
} catch (IOException e) {
Controllers.dialog(
i18n("install_failed_downloading_detail", file.getFile().getUrl()) + "\n" + StringUtils.getStackTrace(e),
i18n("download_failed"), MessageDialogPane.MessageType.ERROR);
FCLAlertDialog.Builder builder = new FCLAlertDialog.Builder(context);
builder.setAlertLevel(FCLAlertDialog.AlertLevel.ALERT);
builder.setCancelable(false);
builder.setTitle(context.getString(R.string.download_failed));
builder.setMessage(AndroidUtils.getLocalizedText(context, "install_failed_downloading_detail", file.getFile().getUrl()) + "\n" + StringUtils.getStackTrace(e));
builder.setNegativeButton(context.getString(com.tungsten.fcllibrary.R.string.dialog_positive), null);
builder.create().show();
return;
}
Controllers.taskDialog(
new FileDownloadTask(downloadURL, modpack.toFile())
.whenComplete(Schedulers.javafx(), e -> {
if (e == null) {
Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(profile, modpack.toFile()));
} else if (e instanceof CancellationException) {
Controllers.showToast(i18n("message.cancelled"));
} else {
Controllers.dialog(
i18n("install.failed.downloading.detail", file.getFile().getUrl()) + "\n" + StringUtils.getStackTrace(e),
i18n("download.failed"), MessageDialogPane.MessageType.ERROR);
}
}).executor(true),
i18n("message.downloading"),
TaskCancellationAction.NORMAL
);
*/
TaskDialog taskDialog = new TaskDialog(context, new TaskCancellationAction(AppCompatDialog::dismiss));
taskDialog.setTitle(context.getString(R.string.message_downloading));
TaskExecutor executor = new FileDownloadTask(downloadURL, modpack.toFile())
.whenComplete(Schedulers.androidUIThread(), e -> {
if (e == null) {
LocalModpackPage page = new LocalModpackPage(context, PageManager.PAGE_ID_TEMP, parent, R.layout.page_modpack, profile, null, modpack.toFile());
DownloadPageManager.getInstance().showTempPage(page);
} else if (e instanceof CancellationException) {
Toast.makeText(context, context.getString(R.string.message_cancelled), Toast.LENGTH_SHORT).show();
} else {
FCLAlertDialog.Builder builder = new FCLAlertDialog.Builder(context);
builder.setAlertLevel(FCLAlertDialog.AlertLevel.ALERT);
builder.setCancelable(false);
builder.setTitle(context.getString(R.string.download_failed));
builder.setMessage(AndroidUtils.getLocalizedText(context, "install_failed_downloading_detail", file.getFile().getUrl()) + "\n" + StringUtils.getStackTrace(e));
builder.setNegativeButton(context.getString(com.tungsten.fcllibrary.R.string.dialog_positive), null);
builder.create().show();
}
}).executor();
taskDialog.setExecutor(executor);
taskDialog.show();
executor.start();
}
public static void deleteVersion(Context context, Profile profile, String version) {
@ -137,8 +161,9 @@ public class Versions {
dialog.show();
}
public static void updateVersion(Profile profile, String version) {
//Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(profile, version));
public static void updateVersion(Context context, FCLUILayout parent, Profile profile, String version) {
ModpackSelectionPage page = new ModpackSelectionPage(context, PageManager.PAGE_ID_TEMP, parent, R.layout.page_modpack_selection, profile, version);
ManagePageManager.getInstance().showTempPage(page);
}
public static void updateGameAssets(Context context, Profile profile, String version) {

View File

@ -23,4 +23,6 @@ public class RequestCodes {
public static final int SELECT_CONTROLLER_CODE = 450;
public static final int SELECT_DOWNLOAD_FOLDER_CODE = 500;
public static final int SELECT_MODPACK_CODE = 550;
}

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="400dp"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:padding="10dp">
<com.tungsten.fcllibrary.component.view.FCLTextView
android:id="@+id/title"
android:text="@string/modpack_choose_remote_tooltip"
android:textSize="16sp"
android:singleLine="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintHorizontal_bias="0.5"/>
<com.tungsten.fcllibrary.component.view.FCLEditText
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:singleLine="true"
android:id="@+id/url"
android:textSize="14sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/title"
app:layout_constraintBottom_toTopOf="@+id/positive"/>
<com.tungsten.fcllibrary.component.view.FCLButton
android:id="@+id/positive"
android:text="@string/dialog_positive"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<com.tungsten.fcllibrary.component.view.FCLButton
android:id="@+id/negative"
android:text="@string/dialog_negative"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -43,13 +43,37 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.5">
<com.tungsten.fcllibrary.component.view.FCLTextView
app:auto_text_tint="true"
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.tungsten.fcllibrary.component.view.FCLTextView
app:auto_text_tint="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:layout_gravity="center"
android:id="@+id/title"/>
<com.tungsten.fcllibrary.component.view.FCLTextView
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:paddingTop="2dp"
android:paddingBottom="2dp"
android:layout_marginStart="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="11sp"
android:id="@+id/tag"
android:layout_gravity="center"
android:singleLine="true"
android:background="@drawable/bg_container_white"
app:auto_text_tint="true"
app:auto_text_background_tint="true"/>
</androidx.appcompat.widget.LinearLayoutCompat>
<com.tungsten.fcllibrary.component.view.FCLTextView
app:auto_text_tint="true"
android:textSize="11sp"

View File

@ -0,0 +1,196 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/ui_bg_color"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:paddingTop="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.tungsten.fcllibrary.component.view.FCLProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/progress"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<com.tungsten.fcllibrary.component.view.FCLLinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/layout"
android:orientation="vertical">
<ScrollView
android:id="@+id/info_layout"
android:background="@drawable/bg_container_white"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<com.tungsten.fcllibrary.component.view.FCLLinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.tungsten.fcllibrary.component.view.FCLLinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:orientation="horizontal">
<com.tungsten.fcllibrary.component.view.FCLTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/archive_name"
android:singleLine="true"
android:layout_gravity="center"
app:auto_text_tint="true"/>
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"/>
<com.tungsten.fcllibrary.component.view.FCLEditText
android:textSize="14sp"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:singleLine="true"
android:id="@+id/name"
app:auto_edit_tint="true"/>
</com.tungsten.fcllibrary.component.view.FCLLinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@android:color/darker_gray"/>
<com.tungsten.fcllibrary.component.view.FCLLinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:orientation="horizontal">
<com.tungsten.fcllibrary.component.view.FCLTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/modpack_name"
android:singleLine="true"
android:layout_gravity="center"
app:auto_text_tint="true"/>
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"/>
<com.tungsten.fcllibrary.component.view.FCLTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/modpack_name"
android:singleLine="true"
android:layout_gravity="center"
app:auto_text_tint="true"/>
</com.tungsten.fcllibrary.component.view.FCLLinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@android:color/darker_gray"/>
<com.tungsten.fcllibrary.component.view.FCLLinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:orientation="horizontal">
<com.tungsten.fcllibrary.component.view.FCLTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/archive_version"
android:singleLine="true"
android:layout_gravity="center"
app:auto_text_tint="true"/>
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"/>
<com.tungsten.fcllibrary.component.view.FCLTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/version"
android:singleLine="true"
android:layout_gravity="center"
app:auto_text_tint="true"/>
</com.tungsten.fcllibrary.component.view.FCLLinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@android:color/darker_gray"/>
<com.tungsten.fcllibrary.component.view.FCLLinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:orientation="horizontal">
<com.tungsten.fcllibrary.component.view.FCLTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/archive_author"
android:singleLine="true"
android:layout_gravity="center"
app:auto_text_tint="true"/>
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"/>
<com.tungsten.fcllibrary.component.view.FCLTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/author"
android:singleLine="true"
android:layout_gravity="center"
app:auto_text_tint="true"/>
</com.tungsten.fcllibrary.component.view.FCLLinearLayout>
</com.tungsten.fcllibrary.component.view.FCLLinearLayout>
</ScrollView>
<com.tungsten.fcllibrary.component.view.FCLButton
app:ripple="true"
android:id="@+id/install"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/button_install"/>
</com.tungsten.fcllibrary.component.view.FCLLinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/ui_bg_color"
android:padding="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.tungsten.fcllibrary.component.view.FCLLinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="15dp"
android:background="@drawable/bg_container_white_clickable"
android:orientation="horizontal"
android:id="@+id/local"
app:layout_constraintTop_toTopOf="parent"
app:auto_linear_background_tint="true">
<com.tungsten.fcllibrary.component.view.FCLTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/modpack_choose_local"
android:layout_gravity="center"
android:singleLine="true"
app:auto_text_tint="true"/>
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"/>
<com.tungsten.fcllibrary.component.view.FCLImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_baseline_arrow_forward_24"
android:layout_gravity="center"
app:auto_src_tint="true"/>
</com.tungsten.fcllibrary.component.view.FCLLinearLayout>
<com.tungsten.fcllibrary.component.view.FCLLinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="15dp"
android:background="@drawable/bg_container_white_clickable"
android:orientation="horizontal"
android:id="@+id/remote"
android:layout_marginTop="10dp"
app:layout_constraintTop_toBottomOf="@+id/local"
app:auto_linear_background_tint="true">
<com.tungsten.fcllibrary.component.view.FCLTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/modpack_choose_remote"
android:layout_gravity="center"
android:singleLine="true"
app:auto_text_tint="true"/>
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"/>
<com.tungsten.fcllibrary.component.view.FCLImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_baseline_arrow_forward_24"
android:layout_gravity="center"
app:auto_src_tint="true"/>
</com.tungsten.fcllibrary.component.view.FCLLinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -88,6 +88,8 @@
<string name="assets_download_all">检查资源文件完整性</string>
<string name="assets_index_malformed">资源文件的索引文件损坏。</string>
<string name="button_install">安装</string>
<string name="community">社区</string>
<string name="control_create">创建新布局</string>
@ -385,6 +387,7 @@
<string name="message_cancelled">操作已取消</string>
<string name="message_downloading">正在下载</string>
<string name="message_error">错误</string>
<string name="message_failed">操作失败</string>
<string name="message_unknown">未知</string>
<string name="message_copy">复制成功!</string>

View File

@ -99,6 +99,8 @@
<string name="assets_download_all">Validating assets integrity</string>
<string name="assets_index_malformed">Index files of downloaded assets were corrupted.</string>
<string name="button_install">Install</string>
<string name="community">Community</string>
<string name="control_create">Create Controller</string>
@ -404,6 +406,7 @@
<string name="message_cancelled">Operation was cancelled</string>
<string name="message_downloading">Downloading</string>
<string name="message_error">Error</string>
<string name="message_failed">Operation Failed</string>
<string name="message_unknown">Unknown</string>
<string name="message_copy">Copy successfully!</string>

View File

@ -2,6 +2,7 @@ package com.tungsten.fclcore.download;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import androidx.annotation.Nullable;
@ -78,7 +79,8 @@ public class ProcessService extends Service {
sendCode(code);
}
};
bridge.execute(null, callback);
Handler handler = new Handler();
handler.postDelayed(() -> bridge.execute(null, callback), 1000);
}
private void sendCode(int code) {

View File

@ -106,9 +106,7 @@ public class FileBrowserActivity extends FCLActivity implements View.OnClickList
}
currentPath = path;
currentText.setText(path.toString());
ThemeEngine.getInstance().registerEvent(currentText, () -> {
currentText.setBackgroundColor(ThemeEngine.getInstance().getTheme().getColor());
});
ThemeEngine.getInstance().registerEvent(currentText, () -> currentText.setBackgroundColor(ThemeEngine.getInstance().getTheme().getColor()));
FileBrowserAdapter adapter = new FileBrowserAdapter(this, fileBrowser, path, selectedFiles, new FileBrowserListener() {
@Override
public void onEnterDir(String path) {

View File

@ -21,8 +21,7 @@ public class FileOperator {
List<File> rawList;
if (files != null) {
rawList = Arrays.asList(files);
}
else {
} else {
rawList = Collections.emptyList();
}
Comparator<File> nameComparator = NameFileComparator.NAME_INSENSITIVE_COMPARATOR;
@ -36,17 +35,16 @@ public class FileOperator {
if (file.isFile()) {
for (String suffix : fileBrowser.getSuffix()) {
add = file.getAbsolutePath().endsWith(suffix);
break;
}
}
else {
} else {
add = true;
}
if (add) {
filterList.add(file);
}
}
}
else {
} else {
filterList.addAll(rawList);
}
if (fileBrowser.getLibMode() == LibMode.FOLDER_CHOOSER) {
@ -55,8 +53,7 @@ public class FileOperator {
list.add(file);
}
}
}
else {
} else {
list.addAll(filterList);
}
return list;

View File

@ -125,8 +125,7 @@ public class FileBrowserAdapter extends FCLAdapter {
viewHolder.description.setText(description);
if (selectedFiles.contains(file.getAbsolutePath()) && file.isFile()) {
viewHolder.parent.setBackgroundColor(Color.GRAY);
}
else {
} else {
viewHolder.parent.setBackground(getContext().getDrawable(R.drawable.clickable_parent));
}
viewHolder.parent.setOnClickListener(view1 -> {