version list page
This commit is contained in:
parent
e09ff00da5
commit
384c7fdb64
|
@ -258,8 +258,6 @@ public class FCLGameRepository extends DefaultGameRepository {
|
|||
if (id == null || !isLoaded())
|
||||
return FCLPath.CONTEXT.getDrawable(R.drawable.img_grass);
|
||||
|
||||
VersionSetting vs = getLocalVersionSettingOrCreate(id);
|
||||
|
||||
Version version = getVersion(id).resolve(this);
|
||||
File iconFile = getVersionIconFile(id);
|
||||
if (iconFile.exists())
|
||||
|
|
|
@ -7,6 +7,7 @@ import com.google.gson.annotations.JsonAdapter;
|
|||
import com.tungsten.fcl.game.FCLCacheRepository;
|
||||
import com.tungsten.fcl.game.FCLGameRepository;
|
||||
import com.tungsten.fcl.util.WeakListenerHolder;
|
||||
import com.tungsten.fclauncher.FCLPath;
|
||||
import com.tungsten.fclcore.download.DefaultDependencyManager;
|
||||
import com.tungsten.fclcore.download.DownloadProvider;
|
||||
import com.tungsten.fclcore.event.EventBus;
|
||||
|
@ -86,7 +87,7 @@ public final class Profile implements Observable {
|
|||
}
|
||||
|
||||
public Profile(String name) {
|
||||
this(name, new File(".minecraft"));
|
||||
this(name, new File(FCLPath.SHARED_COMMON_DIR));
|
||||
}
|
||||
|
||||
public Profile(String name, File initialGameDir) {
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
package com.tungsten.fcl.ui.version;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.tungsten.fcl.R;
|
||||
import com.tungsten.fcl.setting.Profile;
|
||||
import com.tungsten.fcl.setting.Profiles;
|
||||
import com.tungsten.fcl.ui.UIManager;
|
||||
import com.tungsten.fcl.util.RequestCodes;
|
||||
import com.tungsten.fclcore.util.StringUtils;
|
||||
import com.tungsten.fcllibrary.browser.FileBrowser;
|
||||
import com.tungsten.fcllibrary.browser.options.LibMode;
|
||||
import com.tungsten.fcllibrary.component.dialog.FCLDialog;
|
||||
import com.tungsten.fcllibrary.component.view.FCLButton;
|
||||
import com.tungsten.fcllibrary.component.view.FCLEditText;
|
||||
import com.tungsten.fcllibrary.component.view.FCLImageButton;
|
||||
import com.tungsten.fcllibrary.component.view.FCLTextView;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class AddProfileDialog extends FCLDialog implements View.OnClickListener {
|
||||
|
||||
private FCLEditText editText;
|
||||
private FCLTextView pathText;
|
||||
private FCLImageButton editPath;
|
||||
private FCLButton positive;
|
||||
private FCLButton negative;
|
||||
|
||||
public AddProfileDialog(@NonNull Context context) {
|
||||
super(context);
|
||||
setContentView(R.layout.dialog_add_profile);
|
||||
setCancelable(false);
|
||||
editText = findViewById(R.id.name);
|
||||
pathText = findViewById(R.id.path);
|
||||
editPath = findViewById(R.id.edit);
|
||||
positive = findViewById(R.id.positive);
|
||||
negative = findViewById(R.id.negative);
|
||||
editPath.setOnClickListener(this);
|
||||
positive.setOnClickListener(this);
|
||||
negative.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (view == editPath) {
|
||||
FileBrowser.Builder builder = new FileBrowser.Builder(getContext());
|
||||
builder.setLibMode(LibMode.FOLDER_CHOOSER);
|
||||
builder.setTitle(getContext().getString(R.string.profile_select));
|
||||
builder.create().browse(UIManager.getInstance().getVersionUI().getActivity(), RequestCodes.SELECT_PROFILE_CODE, (requestCode, resultCode, data) -> {
|
||||
if (requestCode == RequestCodes.SELECT_PROFILE_CODE && resultCode == Activity.RESULT_OK && data != null) {
|
||||
ArrayList<String> strings = FileBrowser.getSelectedFiles(data);
|
||||
pathText.setText(strings.get(0));
|
||||
}
|
||||
});
|
||||
}
|
||||
if (view == positive) {
|
||||
if (StringUtils.isBlank(editText.getText().toString()) || StringUtils.isBlank(pathText.getText().toString())) {
|
||||
Toast.makeText(getContext(), getContext().getString(R.string.profile_add_alert), Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Profiles.getProfiles().add(new Profile(editText.getText().toString(), new File(pathText.getText().toString())));
|
||||
UIManager.getInstance().getVersionUI().refreshProfile();
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
if (view == negative) {
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package com.tungsten.fcl.ui.version;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.tungsten.fcl.R;
|
||||
import com.tungsten.fcl.setting.Profile;
|
||||
import com.tungsten.fcl.setting.Profiles;
|
||||
import com.tungsten.fcl.ui.UIManager;
|
||||
import com.tungsten.fclcore.fakefx.collections.ObservableList;
|
||||
import com.tungsten.fcllibrary.component.FCLAdapter;
|
||||
import com.tungsten.fcllibrary.component.view.FCLImageButton;
|
||||
import com.tungsten.fcllibrary.component.view.FCLRadioButton;
|
||||
import com.tungsten.fcllibrary.component.view.FCLTextView;
|
||||
|
||||
public class ProfileListAdapter extends FCLAdapter {
|
||||
|
||||
private ObservableList<Profile> list;
|
||||
|
||||
public ProfileListAdapter(Context context, ObservableList<Profile> list) {
|
||||
super(context);
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
static class ViewHolder {
|
||||
FCLRadioButton radioButton;
|
||||
FCLTextView name;
|
||||
FCLTextView path;
|
||||
FCLImageButton delete;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int i) {
|
||||
return list.get(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int i, View view, ViewGroup viewGroup) {
|
||||
final ViewHolder viewHolder;
|
||||
if (view == null) {
|
||||
viewHolder = new ViewHolder();
|
||||
view = LayoutInflater.from(getContext()).inflate(R.layout.item_profile, null);
|
||||
viewHolder.radioButton = view.findViewById(R.id.radio);
|
||||
viewHolder.name = view.findViewById(R.id.name);
|
||||
viewHolder.path = view.findViewById(R.id.path);
|
||||
viewHolder.delete = view.findViewById(R.id.delete);
|
||||
view.setTag(viewHolder);
|
||||
}
|
||||
else {
|
||||
viewHolder = (ViewHolder) view.getTag();
|
||||
}
|
||||
Profile profile = list.get(i);
|
||||
viewHolder.radioButton.setChecked(profile == Profiles.getSelectedProfile());
|
||||
viewHolder.name.setText(profile.getName());
|
||||
viewHolder.path.setText(profile.getGameDir().getAbsolutePath());
|
||||
viewHolder.radioButton.setOnClickListener(view1 -> {
|
||||
Profiles.setSelectedProfile(profile);
|
||||
notifyDataSetChanged();
|
||||
UIManager.getInstance().getVersionUI().refresh();
|
||||
});
|
||||
viewHolder.delete.setOnClickListener(view1 -> {
|
||||
Profiles.getProfiles().remove(profile);
|
||||
UIManager.getInstance().getVersionUI().refresh();
|
||||
UIManager.getInstance().getVersionUI().refreshProfile();
|
||||
});
|
||||
return view;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package com.tungsten.fcl.ui.version;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.tungsten.fcl.R;
|
||||
import com.tungsten.fclcore.util.FutureCallback;
|
||||
import com.tungsten.fcllibrary.component.dialog.FCLDialog;
|
||||
import com.tungsten.fcllibrary.component.view.FCLButton;
|
||||
import com.tungsten.fcllibrary.component.view.FCLEditText;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class RenameVersionDialog extends FCLDialog implements View.OnClickListener {
|
||||
|
||||
private final FutureCallback<String> callback;
|
||||
private final CompletableFuture<String> future = new CompletableFuture<>();
|
||||
|
||||
private FCLEditText editText;
|
||||
private FCLButton positive;
|
||||
private FCLButton negative;
|
||||
|
||||
public RenameVersionDialog(@NonNull Context context, String oldName, FutureCallback<String> callback) {
|
||||
super(context);
|
||||
setContentView(R.layout.dialog_rename_version);
|
||||
setCancelable(false);
|
||||
this.callback = callback;
|
||||
editText = findViewById(R.id.new_name);
|
||||
positive = findViewById(R.id.positive);
|
||||
negative = findViewById(R.id.negative);
|
||||
positive.setOnClickListener(this);
|
||||
negative.setOnClickListener(this);
|
||||
editText.setText(oldName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (view == positive) {
|
||||
positive.setEnabled(false);
|
||||
negative.setEnabled(false);
|
||||
callback.call(editText.getText().toString(), () -> {
|
||||
positive.setEnabled(true);
|
||||
negative.setEnabled(true);
|
||||
future.complete(editText.getText().toString());
|
||||
dismiss();
|
||||
}, msg -> {
|
||||
positive.setEnabled(true);
|
||||
negative.setEnabled(true);
|
||||
Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show();
|
||||
});
|
||||
}
|
||||
if (view == negative) {
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<String> getFuture() {
|
||||
return future;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package com.tungsten.fcl.ui.version;
|
||||
|
||||
import static com.tungsten.fclcore.util.Lang.threadPool;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
|
||||
import com.tungsten.fcl.R;
|
||||
import com.tungsten.fcl.ui.UIManager;
|
||||
import com.tungsten.fcllibrary.component.FCLAdapter;
|
||||
import com.tungsten.fcllibrary.component.view.FCLImageButton;
|
||||
import com.tungsten.fcllibrary.component.view.FCLRadioButton;
|
||||
import com.tungsten.fcllibrary.component.view.FCLTextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class VersionListAdapter extends FCLAdapter {
|
||||
|
||||
private final ArrayList<VersionListItem> list;
|
||||
|
||||
public VersionListAdapter(Context context, ArrayList<VersionListItem> list) {
|
||||
super(context);
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
static class ViewHolder {
|
||||
FCLRadioButton radioButton;
|
||||
AppCompatImageView icon;
|
||||
FCLTextView title;
|
||||
FCLTextView subtitle;
|
||||
FCLImageButton rename;
|
||||
FCLImageButton copy;
|
||||
FCLImageButton browse;
|
||||
FCLImageButton delete;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int i) {
|
||||
return list.get(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int i, View view, ViewGroup viewGroup) {
|
||||
final ViewHolder viewHolder;
|
||||
if (view == null) {
|
||||
viewHolder = new ViewHolder();
|
||||
view = LayoutInflater.from(getContext()).inflate(R.layout.item_version, null);
|
||||
viewHolder.radioButton = view.findViewById(R.id.radio);
|
||||
viewHolder.icon = view.findViewById(R.id.icon);
|
||||
viewHolder.title = view.findViewById(R.id.title);
|
||||
viewHolder.subtitle = view.findViewById(R.id.subtitle);
|
||||
viewHolder.rename = view.findViewById(R.id.rename);
|
||||
viewHolder.copy = view.findViewById(R.id.copy);
|
||||
viewHolder.browse = view.findViewById(R.id.browse);
|
||||
viewHolder.delete = view.findViewById(R.id.delete);
|
||||
view.setTag(viewHolder);
|
||||
}
|
||||
else {
|
||||
viewHolder = (ViewHolder) view.getTag();
|
||||
}
|
||||
VersionListItem versionListItem = list.get(i);
|
||||
versionListItem.checkSelection();
|
||||
viewHolder.radioButton.setChecked(versionListItem.selectedProperty().get());
|
||||
viewHolder.icon.setBackground(versionListItem.getDrawable());
|
||||
viewHolder.title.setText(versionListItem.getVersion());
|
||||
viewHolder.subtitle.setText(versionListItem.getLibraries());
|
||||
viewHolder.radioButton.setOnClickListener(view1 -> {
|
||||
versionListItem.getProfile().setSelectedVersion(versionListItem.getVersion());
|
||||
notifyDataSetChanged();
|
||||
});
|
||||
viewHolder.rename.setOnClickListener(view1 -> {
|
||||
Versions.renameVersion(getContext(), versionListItem.getProfile(), versionListItem.getVersion());
|
||||
});
|
||||
viewHolder.copy.setOnClickListener(view1 -> {
|
||||
|
||||
});
|
||||
viewHolder.browse.setOnClickListener(view1 -> {
|
||||
Versions.openFolder(UIManager.getInstance().getVersionUI().getActivity(), versionListItem.getProfile(), versionListItem.getVersion());
|
||||
});
|
||||
viewHolder.delete.setOnClickListener(view1 -> {
|
||||
Versions.deleteVersion(getContext(), versionListItem.getProfile(), versionListItem.getVersion());
|
||||
});
|
||||
return view;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.tungsten.fcl.ui.version;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import com.tungsten.fcl.setting.Profile;
|
||||
import com.tungsten.fclcore.fakefx.beans.property.BooleanProperty;
|
||||
import com.tungsten.fclcore.fakefx.beans.property.SimpleBooleanProperty;
|
||||
|
||||
public class VersionListItem {
|
||||
|
||||
private final Profile profile;
|
||||
private final String version;
|
||||
private final boolean isModpack;
|
||||
private final BooleanProperty selected = new SimpleBooleanProperty();
|
||||
private final String libraries;
|
||||
private final Drawable drawable;
|
||||
|
||||
public VersionListItem(Profile profile, String id, String libraries, Drawable drawable) {
|
||||
this.profile = profile;
|
||||
this.version = id;
|
||||
this.libraries = libraries;
|
||||
this.drawable = drawable;
|
||||
this.isModpack = profile.getRepository().isModpack(id);
|
||||
|
||||
selected.set(id.equals(profile.getSelectedVersion()));
|
||||
}
|
||||
|
||||
public Profile getProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getLibraries() {
|
||||
return libraries;
|
||||
}
|
||||
|
||||
public Drawable getDrawable() {
|
||||
return drawable;
|
||||
}
|
||||
|
||||
public BooleanProperty selectedProperty() {
|
||||
return selected;
|
||||
}
|
||||
|
||||
public void checkSelection() {
|
||||
selected.set(version.equals(profile.getSelectedVersion()));
|
||||
}
|
||||
|
||||
public boolean canUpdate() {
|
||||
return isModpack;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,17 +1,97 @@
|
|||
package com.tungsten.fcl.ui.version;
|
||||
|
||||
import android.content.Context;
|
||||
import static com.tungsten.fclcore.download.LibraryAnalyzer.LibraryType.MINECRAFT;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.widget.ListView;
|
||||
|
||||
import com.tungsten.fcl.R;
|
||||
import com.tungsten.fcl.setting.Profiles;
|
||||
import com.tungsten.fclcore.download.LibraryAnalyzer;
|
||||
import com.tungsten.fclcore.task.Schedulers;
|
||||
import com.tungsten.fcllibrary.component.ui.FCLCommonUI;
|
||||
import com.tungsten.fcllibrary.component.view.FCLButton;
|
||||
import com.tungsten.fcllibrary.component.view.FCLProgressBar;
|
||||
import com.tungsten.fcllibrary.component.view.FCLUILayout;
|
||||
|
||||
public class VersionUI extends FCLCommonUI {
|
||||
import java.util.ArrayList;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class VersionUI extends FCLCommonUI implements View.OnClickListener {
|
||||
|
||||
private FCLButton refresh;
|
||||
private FCLButton newProfile;
|
||||
private FCLProgressBar progressBar;
|
||||
private ListView profileListView;
|
||||
private ListView versionListView;
|
||||
|
||||
public VersionUI(Context context, FCLUILayout parent, int id) {
|
||||
super(context, parent, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
refresh = findViewById(R.id.refresh);
|
||||
newProfile = findViewById(R.id.new_profile);
|
||||
progressBar = findViewById(R.id.progress);
|
||||
profileListView = findViewById(R.id.profile_list);
|
||||
versionListView = findViewById(R.id.version_list);
|
||||
|
||||
refresh.setOnClickListener(this);
|
||||
newProfile.setOnClickListener(this);
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
refresh.setEnabled(false);
|
||||
versionListView.setVisibility(View.GONE);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
refreshProfile();
|
||||
Profiles.getSelectedProfile().getRepository().refreshVersionsAsync().whenComplete(Schedulers.androidUIThread(), exception -> {
|
||||
ArrayList<VersionListItem> children = (ArrayList<VersionListItem>) Profiles.getSelectedProfile().getRepository().getDisplayVersions()
|
||||
.map(version -> {
|
||||
String game = Profiles.getSelectedProfile().getRepository().getGameVersion(version.getId()).orElse(getContext().getString(R.string.message_unknown));
|
||||
StringBuilder libraries = new StringBuilder(game);
|
||||
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(Profiles.getSelectedProfile().getRepository().getResolvedPreservingPatchesVersion(version.getId()));
|
||||
for (LibraryAnalyzer.LibraryMark mark : analyzer) {
|
||||
String libraryId = mark.getLibraryId();
|
||||
String libraryVersion = mark.getLibraryVersion();
|
||||
if (libraryId.equals(MINECRAFT.getPatchId())) continue;
|
||||
int resId = getContext().getResources().getIdentifier("install_installer_" + libraryId.replace("-", "_"), "string", getContext().getPackageName());
|
||||
if (resId != 0 && getContext().getString(resId) != null) {
|
||||
libraries.append(", ").append(getContext().getString(resId));
|
||||
if (libraryVersion != null)
|
||||
libraries.append(": ").append(libraryVersion.replaceAll("(?i)" + libraryId, ""));
|
||||
}
|
||||
}
|
||||
return new VersionListItem(Profiles.getSelectedProfile(), version.getId(), libraries.toString(), Profiles.getSelectedProfile().getRepository().getVersionIconImage(version.getId()));
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
VersionListAdapter adapter = new VersionListAdapter(getContext(), children);
|
||||
versionListView.setAdapter(adapter);
|
||||
refresh.setEnabled(true);
|
||||
versionListView.setVisibility(View.VISIBLE);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
}).start();
|
||||
}
|
||||
|
||||
public void refreshProfile() {
|
||||
ProfileListAdapter adapter = new ProfileListAdapter(getContext(), Profiles.getProfiles());
|
||||
profileListView.setAdapter(adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (view == refresh) {
|
||||
refresh();
|
||||
}
|
||||
if (view == newProfile) {
|
||||
AddProfileDialog dialog = new AddProfileDialog(getContext());
|
||||
dialog.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
package com.tungsten.fcl.ui.version;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
|
||||
import com.tungsten.fcl.R;
|
||||
import com.tungsten.fcl.setting.Profile;
|
||||
import com.tungsten.fcl.ui.UIManager;
|
||||
import com.tungsten.fcl.util.RequestCodes;
|
||||
import com.tungsten.fclcore.download.game.GameAssetDownloadTask;
|
||||
import com.tungsten.fclcore.game.GameDirectoryType;
|
||||
import com.tungsten.fclcore.task.Schedulers;
|
||||
import com.tungsten.fclcore.task.Task;
|
||||
import com.tungsten.fclcore.task.TaskExecutor;
|
||||
import com.tungsten.fclcore.util.Logging;
|
||||
import com.tungsten.fclcore.util.StringUtils;
|
||||
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 java.io.IOException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class Versions {
|
||||
|
||||
public static void deleteVersion(Context context, Profile profile, String version) {
|
||||
boolean isIndependent = profile.getVersionSetting(version).getGameDirType() == GameDirectoryType.VERSION_FOLDER;
|
||||
String message = isIndependent ? String.format(context.getString(R.string.version_manage_remove_confirm_independent), version) : String.format(context.getString(R.string.version_manage_remove_confirm), version);
|
||||
|
||||
FCLAlertDialog.Builder builder = new FCLAlertDialog.Builder(context);
|
||||
builder.setAlertLevel(FCLAlertDialog.AlertLevel.ALERT);
|
||||
builder.setMessage(message);
|
||||
builder.setPositiveButton(() -> {
|
||||
profile.getRepository().removeVersionFromDisk(version);
|
||||
UIManager.getInstance().getVersionUI().refresh();
|
||||
});
|
||||
builder.setNegativeButton(null);
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
public static CompletableFuture<String> renameVersion(Context context, Profile profile, String version) {
|
||||
RenameVersionDialog dialog = new RenameVersionDialog(context, version, (newName, resolve, reject) -> {
|
||||
if (!OperatingSystem.isNameValid(newName)) {
|
||||
reject.accept(context.getString(R.string.install_new_game_malformed));
|
||||
return;
|
||||
}
|
||||
if (profile.getRepository().renameVersion(version, newName)) {
|
||||
resolve.run();
|
||||
profile.getRepository().refreshVersionsAsync()
|
||||
.thenRunAsync(Schedulers.androidUIThread(), () -> {
|
||||
if (profile.getRepository().hasVersion(newName)) {
|
||||
profile.setSelectedVersion(newName);
|
||||
}
|
||||
UIManager.getInstance().getVersionUI().refresh();
|
||||
}).start();
|
||||
} else {
|
||||
reject.accept(context.getString(R.string.version_manage_rename_fail));
|
||||
}
|
||||
});
|
||||
dialog.show();
|
||||
return dialog.getFuture();
|
||||
}
|
||||
|
||||
/*
|
||||
public static void exportVersion(Profile profile, String version) {
|
||||
Controllers.getDecorator().startWizard(new ExportWizardProvider(profile, version), i18n("modpack.wizard"));
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
public static void openFolder(Activity context, Profile profile, String version) {
|
||||
FileBrowser.Builder builder = new FileBrowser.Builder(context);
|
||||
builder.setLibMode(LibMode.FILE_BROWSER);
|
||||
builder.setInitDir(profile.getRepository().getRunDirectory(version).getAbsolutePath());
|
||||
builder.create().browse(context, RequestCodes.BROWSE_VERSION_DIR_CODE, null);
|
||||
}
|
||||
|
||||
/*
|
||||
public static void duplicateVersion(Profile profile, String version) {
|
||||
Controllers.prompt(
|
||||
new PromptDialogPane.Builder(i18n("version.manage.duplicate.prompt"), (res, resolve, reject) -> {
|
||||
String newVersionName = ((PromptDialogPane.Builder.StringQuestion) res.get(1)).getValue();
|
||||
boolean copySaves = ((PromptDialogPane.Builder.BooleanQuestion) res.get(2)).getValue();
|
||||
Task.runAsync(() -> profile.getRepository().duplicateVersion(version, newVersionName, copySaves))
|
||||
.thenComposeAsync(profile.getRepository().refreshVersionsAsync())
|
||||
.whenComplete(Schedulers.androidUIThread(), (result, exception) -> {
|
||||
if (exception == null) {
|
||||
resolve.run();
|
||||
} else {
|
||||
reject.accept(StringUtils.getStackTrace(exception));
|
||||
profile.getRepository().removeVersionFromDisk(newVersionName);
|
||||
}
|
||||
}).start();
|
||||
})
|
||||
.addQuestion(new PromptDialogPane.Builder.HintQuestion(i18n("version.manage.duplicate.confirm")))
|
||||
.addQuestion(new PromptDialogPane.Builder.StringQuestion(null, version,
|
||||
new Validator(i18n("install.new_game.already_exists"), newVersionName -> !profile.getRepository().hasVersion(newVersionName))))
|
||||
.addQuestion(new PromptDialogPane.Builder.BooleanQuestion(i18n("version.manage.duplicate.duplicate_save"), false)));
|
||||
}
|
||||
|
||||
public static void updateVersion(Profile profile, String version) {
|
||||
Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(profile, version));
|
||||
}
|
||||
|
||||
public static void updateGameAssets(Profile profile, String version) {
|
||||
TaskExecutor executor = new GameAssetDownloadTask(profile.getDependency(), profile.getRepository().getVersion(version), GameAssetDownloadTask.DOWNLOAD_INDEX_FORCIBLY, true)
|
||||
.executor();
|
||||
Controllers.taskDialog(executor, i18n("version.manage.redownload_assets_index"), TaskCancellationAction.NO_CANCEL);
|
||||
executor.start();
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
public static void cleanVersion(Profile profile, String id) {
|
||||
try {
|
||||
profile.getRepository().clean(id);
|
||||
} catch (IOException e) {
|
||||
Logging.LOG.log(Level.WARNING, "Unable to clean game directory", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -3,4 +3,8 @@ package com.tungsten.fcl.util;
|
|||
public class RequestCodes {
|
||||
|
||||
public static final int PERMISSION_REQUEST_CODE = 0;
|
||||
|
||||
public static final int BROWSE_VERSION_DIR_CODE = 50;
|
||||
|
||||
public static final int SELECT_PROFILE_CODE = 100;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<vector
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z"/>
|
||||
</vector>
|
|
@ -0,0 +1,93 @@
|
|||
<?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"
|
||||
android:padding="10dp"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLTextView
|
||||
android:id="@+id/title"
|
||||
android:text="@string/version_new_profile"
|
||||
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"/>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/name_layout"
|
||||
app:layout_constraintTop_toBottomOf="@+id/title"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLTextView
|
||||
android:singleLine="true"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/profile_name"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLEditText
|
||||
android:singleLine="true"
|
||||
android:id="@+id/name"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/path_layout"
|
||||
app:layout_constraintTop_toBottomOf="@+id/name_layout"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLTextView
|
||||
android:singleLine="true"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/profile_path"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLTextView
|
||||
android:singleLine="true"
|
||||
android:id="@+id/path"
|
||||
android:layout_width="250dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLImageButton
|
||||
app:auto_tint="true"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_baseline_edit_24"
|
||||
android:id="@+id/edit"/>
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLButton
|
||||
android:layout_marginTop="10dp"
|
||||
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_constraintTop_toBottomOf="@id/path_layout"/>
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLButton
|
||||
android:layout_marginTop="10dp"
|
||||
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_constraintTop_toBottomOf="@id/path_layout"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:padding="10dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLTextView
|
||||
android:id="@+id/title"
|
||||
android:text="@string/version_manage_rename_message"
|
||||
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"/>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/details"
|
||||
android:layout_marginTop="10dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLTextView
|
||||
android:singleLine="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/version_manage_rename_new"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLEditText
|
||||
android:layout_marginStart="10dp"
|
||||
android:singleLine="true"
|
||||
android:id="@+id/new_name"
|
||||
android:layout_width="250dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLButton
|
||||
android:layout_marginTop="10dp"
|
||||
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_constraintTop_toBottomOf="@+id/details"/>
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLButton
|
||||
android:layout_marginTop="10dp"
|
||||
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_constraintTop_toBottomOf="@+id/details"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -0,0 +1,64 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="10dp"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_item"
|
||||
android:padding="5dp">
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLRadioButton
|
||||
android:id="@+id/radio"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintVertical_bias="0.5"/>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
app:layout_constraintStart_toEndOf="@+id/radio"
|
||||
app:layout_constraintEnd_toStartOf="@+id/delete"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintVertical_bias="0.5">
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLTextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:id="@+id/name"/>
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLTextView
|
||||
android:textSize="11sp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:id="@+id/path"/>
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLImageButton
|
||||
android:id="@+id/delete"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_baseline_delete_24"
|
||||
app:auto_tint="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintVertical_bias="0.5"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -0,0 +1,106 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:paddingBottom="10dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:background="@drawable/bg_item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:padding="5dp">
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLRadioButton
|
||||
android:id="@+id/radio"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintVertical_bias="0.5"/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/radio"
|
||||
app:layout_constraintVertical_bias="0.5"/>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
app:layout_constraintStart_toEndOf="@+id/icon"
|
||||
app:layout_constraintEnd_toStartOf="@+id/rename"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintVertical_bias="0.5">
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLTextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:id="@+id/title"/>
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLTextView
|
||||
android:textSize="11sp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:id="@+id/subtitle"/>
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLImageButton
|
||||
android:id="@+id/rename"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_baseline_edit_24"
|
||||
app:auto_tint="true"
|
||||
app:layout_constraintEnd_toStartOf="@+id/copy"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintVertical_bias="0.5"/>
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLImageButton
|
||||
android:id="@+id/copy"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_baseline_content_copy_24"
|
||||
app:auto_tint="true"
|
||||
app:layout_constraintEnd_toStartOf="@+id/browse"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintVertical_bias="0.5"/>
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLImageButton
|
||||
android:id="@+id/browse"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_baseline_folder_24"
|
||||
app:auto_tint="true"
|
||||
app:layout_constraintEnd_toStartOf="@+id/delete"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintVertical_bias="0.5"/>
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLImageButton
|
||||
android:id="@+id/delete"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_baseline_delete_24"
|
||||
app:auto_tint="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintVertical_bias="0.5"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,7 +1,65 @@
|
|||
<?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">
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/left"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintWidth_percent="0.3">
|
||||
|
||||
<ListView
|
||||
android:id="@+id/profile_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:divider="@android:color/transparent"
|
||||
android:dividerHeight="0dp"/>
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLButton
|
||||
android:id="@+id/refresh"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/message_refresh"/>
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLButton
|
||||
android:id="@+id/new_profile"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/version_new_profile"/>
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="10dp"
|
||||
app:layout_constraintStart_toEndOf="@+id/left"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<ListView
|
||||
android:id="@+id/version_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:divider="@android:color/transparent"
|
||||
android:dividerHeight="0dp" />
|
||||
|
||||
<com.tungsten.fcllibrary.component.view.FCLProgressBar
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:id="@+id/progress"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -59,6 +59,7 @@
|
|||
<string name="exception_artifact_malformed">无法校验文件。</string>
|
||||
<string name="exception_ssl_handshake">缺少 SSL 证书。</string>
|
||||
|
||||
<string name="install_new_game_malformed">无效的名称</string>
|
||||
<string name="install_failed_downloading_timeout">下载超时</string>
|
||||
<string name="install_failed_downloading_detail">无法下载</string>
|
||||
|
||||
|
@ -73,8 +74,21 @@
|
|||
<string name="launch_state_waiting_launching">等待游戏启动</string>
|
||||
<string name="launch_state_done">完成</string>
|
||||
|
||||
<string name="message_refresh">刷新</string>
|
||||
<string name="message_cancelled">操作已取消</string>
|
||||
<string name="message_unknown">未知</string>
|
||||
|
||||
<string name="profile_shared">公有目录</string>
|
||||
<string name="profile_private">私有目录</string>
|
||||
<string name="profile_name">名称</string>
|
||||
<string name="profile_path">路径</string>
|
||||
<string name="profile_select">选择目录</string>
|
||||
<string name="profile_add_alert">请先填写名称与路径!</string>
|
||||
|
||||
<string name="version_manage_remove_confirm">你确定要删除 %s 吗? 该操作无法撤回!</string>
|
||||
<string name="version_manage_remove_confirm_independent">该版本启用了版本隔离,删除该版本将会一并删除存档及其他数据。你仍要删除 %s 吗?</string>
|
||||
<string name="version_manage_rename_message">重命名版本</string>
|
||||
<string name="version_manage_rename_new">新名称</string>
|
||||
<string name="version_manage_rename_fail">重命名失败</string>
|
||||
<string name="version_new_profile">新建目录</string>
|
||||
</resources>
|
|
@ -67,6 +67,15 @@
|
|||
<string name="exception_artifact_malformed">Cannot verify the integrity of the downloaded files.</string>
|
||||
<string name="exception_ssl_handshake">Unable to establish SSL connection due to missing SSL certificates in current Java installation.</string>
|
||||
|
||||
<string name="install_installer_fabric" translatable="false">Fabric</string>
|
||||
<string name="install_installer_fabric_api" translatable="false">Fabric API</string>
|
||||
<string name="install_installer_forge" translatable="false">Forge</string>
|
||||
<string name="install_installer_game" translatable="false">Minecraft</string>
|
||||
<string name="install_installer_liteloader" translatable="false">LiteLoader</string>
|
||||
<string name="install_installer_optifine" translatable="false">OptiFine</string>
|
||||
<string name="install_installer_quilt" translatable="false">Quilt</string>
|
||||
<string name="install_installer_quilt_api" translatable="false">QSL/QFAPI</string>
|
||||
<string name="install_new_game_malformed">Invalid Name</string>
|
||||
<string name="install_failed_downloading_timeout">Download timeout</string>
|
||||
<string name="install_failed_downloading_detail">Unable to download</string>
|
||||
|
||||
|
@ -81,8 +90,21 @@
|
|||
<string name="launch_state_waiting_launching">Waiting for the game to launch</string>
|
||||
<string name="launch_state_done">Completing launch</string>
|
||||
|
||||
<string name="message_refresh">Refresh</string>
|
||||
<string name="message_cancelled">Operation was cancelled</string>
|
||||
<string name="message_unknown">Unknown</string>
|
||||
|
||||
<string name="profile_shared">Shared Directory</string>
|
||||
<string name="profile_private">Private Directory</string>
|
||||
<string name="profile_name">Name</string>
|
||||
<string name="profile_path">Path</string>
|
||||
<string name="profile_select">Select Directory</string>
|
||||
<string name="profile_add_alert">Please fill the name and path first!</string>
|
||||
|
||||
<string name="version_manage_remove_confirm">Are you sure you want to permanently remove the version %s? This action cannot be undone!</string>
|
||||
<string name="version_manage_remove_confirm_independent">Since this instance is stored in an isolated directory, deleting it will also delete its saves and other data. Do you still want to delete instance %s?</string>
|
||||
<string name="version_manage_rename_message">Rename version</string>
|
||||
<string name="version_manage_rename_new">New name</string>
|
||||
<string name="version_manage_rename_fail">Rename failed</string>
|
||||
<string name="version_new_profile">New Directory</string>
|
||||
</resources>
|
|
@ -1,6 +1,11 @@
|
|||
package com.tungsten.fclcore.task;
|
||||
|
||||
import com.tungsten.fclcore.event.EventManager;
|
||||
import com.tungsten.fclcore.fakefx.beans.property.ReadOnlyDoubleProperty;
|
||||
import com.tungsten.fclcore.fakefx.beans.property.ReadOnlyDoubleWrapper;
|
||||
import com.tungsten.fclcore.fakefx.beans.property.ReadOnlyStringProperty;
|
||||
import com.tungsten.fclcore.fakefx.beans.property.ReadOnlyStringWrapper;
|
||||
import com.tungsten.fclcore.util.InvocationDispatcher;
|
||||
import com.tungsten.fclcore.util.Logging;
|
||||
import com.tungsten.fclcore.util.ReflectionHelper;
|
||||
import com.tungsten.fclcore.util.function.ExceptionalConsumer;
|
||||
|
@ -296,6 +301,12 @@ public abstract class Task<T> {
|
|||
}
|
||||
|
||||
private long lastTime = Long.MIN_VALUE;
|
||||
private final ReadOnlyDoubleWrapper progress = new ReadOnlyDoubleWrapper(this, "progress", -1);
|
||||
private final InvocationDispatcher<Double> progressUpdate = InvocationDispatcher.runOn(Schedulers.androidUIThread(), progress::set);
|
||||
|
||||
public ReadOnlyDoubleProperty progressProperty() {
|
||||
return progress.getReadOnlyProperty();
|
||||
}
|
||||
|
||||
protected void updateProgress(long progress, long total) {
|
||||
updateProgress(1.0 * progress / total);
|
||||
|
@ -312,11 +323,18 @@ public abstract class Task<T> {
|
|||
}
|
||||
|
||||
protected void updateProgressImmediately(double progress) {
|
||||
// TODO: update progress
|
||||
progressUpdate.accept(progress);
|
||||
}
|
||||
|
||||
private final ReadOnlyStringWrapper message = new ReadOnlyStringWrapper(this, "message", null);
|
||||
private final InvocationDispatcher<String> messageUpdate = InvocationDispatcher.runOn(Schedulers.androidUIThread(), message::set);
|
||||
|
||||
public final ReadOnlyStringProperty messageProperty() {
|
||||
return message.getReadOnlyProperty();
|
||||
}
|
||||
|
||||
protected final void updateMessage(String newMessage) {
|
||||
// TODO: update message
|
||||
messageUpdate.accept(newMessage);
|
||||
}
|
||||
|
||||
public final T run() throws Exception {
|
||||
|
@ -334,7 +352,11 @@ public abstract class Task<T> {
|
|||
}
|
||||
|
||||
private void doSubTask(Task<?> task) throws Exception {
|
||||
message.bind(task.message);
|
||||
progress.bind(task.progress);
|
||||
task.run();
|
||||
message.unbind();
|
||||
progress.unbind();
|
||||
}
|
||||
|
||||
public final TaskExecutor executor() {
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package com.tungsten.fclcore.util;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface FutureCallback<T> {
|
||||
|
||||
/**
|
||||
* Callback of future, called after future finishes.
|
||||
* This callback gives the feedback whether the result of future is acceptable or not,
|
||||
* if not, giving the reason, and future will be relaunched when necessary.
|
||||
* @param result result of the future
|
||||
* @param resolve accept the result
|
||||
* @param reject reject the result with failure reason
|
||||
*/
|
||||
void call(T result, Runnable resolve, Consumer<String> reject);
|
||||
}
|
|
@ -3,6 +3,8 @@ package com.tungsten.fcllibrary.anim;
|
|||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.os.Handler;
|
||||
import android.view.View;
|
||||
|
||||
import com.tungsten.fcllibrary.component.view.FCLDynamicIsland;
|
||||
|
||||
|
@ -10,6 +12,8 @@ public class DynamicIslandAnim {
|
|||
|
||||
private final FCLDynamicIsland view;
|
||||
|
||||
private Thread thread;
|
||||
private Handler handler;
|
||||
private ObjectAnimator expandScaleAnimatorX;
|
||||
private ObjectAnimator shrinkScaleAnimatorX;
|
||||
private ObjectAnimator expandScaleAnimatorY;
|
||||
|
@ -18,12 +22,17 @@ public class DynamicIslandAnim {
|
|||
private ObjectAnimator shrinkAdjustAnimatorX;
|
||||
private ObjectAnimator expandAdjustAnimatorY;
|
||||
private ObjectAnimator shrinkAdjustAnimatorY;
|
||||
private ObjectAnimator hideAnimator;
|
||||
|
||||
public DynamicIslandAnim(FCLDynamicIsland view) {
|
||||
this.view = view;
|
||||
this.handler = new Handler();
|
||||
}
|
||||
|
||||
public void refresh(float scale) {
|
||||
if (thread != null) {
|
||||
thread.interrupt();
|
||||
}
|
||||
if (expandScaleAnimatorX != null && expandScaleAnimatorX.isRunning()) {
|
||||
expandScaleAnimatorX.cancel();
|
||||
}
|
||||
|
@ -48,6 +57,9 @@ public class DynamicIslandAnim {
|
|||
if (shrinkAdjustAnimatorY != null && shrinkAdjustAnimatorY.isRunning()) {
|
||||
shrinkAdjustAnimatorY.cancel();
|
||||
}
|
||||
if (hideAnimator != null && hideAnimator.isRunning()) {
|
||||
hideAnimator.cancel();
|
||||
}
|
||||
expandScaleAnimatorX = ObjectAnimator.ofFloat(view, "scaleX", scale / 2f, 0.95f).setDuration(300);
|
||||
shrinkScaleAnimatorX = ObjectAnimator.ofFloat(view, "scaleX", 0.95f, scale / 2f).setDuration(300);
|
||||
expandScaleAnimatorY = ObjectAnimator.ofFloat(view, "scaleY", 0.5f, 0.95f).setDuration(300);
|
||||
|
@ -56,9 +68,12 @@ public class DynamicIslandAnim {
|
|||
shrinkAdjustAnimatorX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.95f).setDuration(200);
|
||||
expandAdjustAnimatorY = ObjectAnimator.ofFloat(view, "scaleY", 0.95f, 1f).setDuration(200);
|
||||
shrinkAdjustAnimatorY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.95f).setDuration(200);
|
||||
hideAnimator = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f).setDuration(2000);
|
||||
}
|
||||
|
||||
public void run(String text) {
|
||||
view.setVisibility(View.VISIBLE);
|
||||
view.setAlpha(1f);
|
||||
shrinkScaleAnimatorX.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
|
@ -73,6 +88,32 @@ public class DynamicIslandAnim {
|
|||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
shrinkAdjustAnimatorX.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
thread = new Thread(() -> {
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
if (!thread.isInterrupted()) {
|
||||
handler.post(() -> {
|
||||
hideAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
view.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
hideAnimator.start();
|
||||
});
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
}
|
||||
});
|
||||
shrinkAdjustAnimatorX.start();
|
||||
shrinkAdjustAnimatorY.start();
|
||||
}
|
||||
|
|
|
@ -120,16 +120,18 @@ public class FileBrowserActivity extends FCLActivity implements View.OnClickList
|
|||
selectedFiles.remove(path);
|
||||
}
|
||||
else {
|
||||
if (fileBrowser.getLibMode() == LibMode.FOLDER_CHOOSER || fileBrowser.getSelectionMode() == SelectionMode.SINGLE_SELECTION) {
|
||||
if (fileBrowser.getSelectionMode() == SelectionMode.SINGLE_SELECTION) {
|
||||
selectedFiles = new ArrayList<>();
|
||||
}
|
||||
selectedFiles.add(path);
|
||||
}
|
||||
adapter1.setSelectedFiles(selectedFiles);
|
||||
adapter1.notifyDataSetChanged();
|
||||
System.out.println(selectedFiles);
|
||||
}
|
||||
});
|
||||
listView.setAdapter(adapter);
|
||||
System.out.println(selectedFiles);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -134,7 +134,7 @@ public class FileBrowserAdapter extends FCLAdapter {
|
|||
if (file.isDirectory()) {
|
||||
listener.onEnterDir(file.getAbsolutePath());
|
||||
}
|
||||
if (fileBrowser.getLibMode() != LibMode.FILE_BROWSER && !(fileBrowser.getLibMode() == LibMode.FILE_CHOOSER && file.isDirectory()) && !(fileBrowser.getLibMode() == LibMode.FOLDER_CHOOSER && file.isFile())) {
|
||||
if (fileBrowser.getLibMode() != LibMode.FILE_BROWSER && fileBrowser.getLibMode() != LibMode.FOLDER_CHOOSER && !(fileBrowser.getLibMode() == LibMode.FILE_CHOOSER)) {
|
||||
listener.onSelect(this, file.getAbsolutePath());
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue