- Removed profiles fragment because Serpent begged me not to use viewpager
 - Progressed further with the profiles dialog, now it's actually usable
 - Now launcher doesn't have profile amnesia
 - More splitting of raw version selector and profile selector
 Bugs:
 - Saving profiles in the editor does nothing
 TODO:
 - Implement launching the game with selected profile
 - Replace "Unknown" version ID in profiles with mProfile.selectedVersion for ease of migration
This commit is contained in:
artdeell 2021-12-02 23:21:32 +03:00
parent 0fc0623978
commit 4961acf10d
8 changed files with 275 additions and 111 deletions

View File

@ -17,6 +17,10 @@ import androidx.annotation.Nullable;
import androidx.appcompat.app.*;
import com.kdt.pickafile.*;
import java.io.*;
import java.util.ArrayList;
import net.kdt.pojavlaunch.extra.ExtraCore;
import net.kdt.pojavlaunch.extra.ExtraListener;
import net.kdt.pojavlaunch.fragments.*;
import net.kdt.pojavlaunch.multirt.MultiRTConfigDialog;
import net.kdt.pojavlaunch.multirt.MultiRTUtils;
@ -24,6 +28,8 @@ import net.kdt.pojavlaunch.prefs.*;
import net.kdt.pojavlaunch.tasks.*;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.PopupMenu;
import net.kdt.pojavlaunch.value.*;
import org.apache.commons.io.IOUtils;
@ -38,7 +44,7 @@ public abstract class BaseLauncherActivity extends BaseActivity {
public JMinecraftVersionList mVersionList;
public MinecraftDownloaderTask mTask;
public MinecraftAccount mProfile;
public String[] mAvailableVersions;
//public String[] mAvailableVersions;
public boolean mIsAssetsProcessing = false;
protected boolean canBack = false;
@ -119,10 +125,73 @@ public abstract class BaseLauncherActivity extends BaseActivity {
Tools.updateWindowSize(this);
System.out.println("call to onPostResume; E");
}
public void setupVersionSelector() {
final androidx.appcompat.widget.PopupMenu popup = new PopupMenu(this, mVersionSelector);
popup.getMenuInflater().inflate(R.menu.menu_versionopt, popup.getMenu());
PerVersionConfigDialog dialog = new PerVersionConfigDialog(this);
this.mVersionSelector.setOnLongClickListener((v)->dialog.openConfig(this.mProfile.selectedVersion));
this.mVersionSelector.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener(){
@Override
public void onItemSelected(AdapterView<?> p1, View p2, int p3, long p4)
{
mProfile.selectedVersion = p1.getItemAtPosition(p3).toString();
PojavProfile.setCurrentProfile(BaseLauncherActivity.this, mProfile);
if (PojavProfile.isFileType(BaseLauncherActivity.this)) {
try {
PojavProfile.setCurrentProfile(BaseLauncherActivity.this, mProfile.save());
} catch (IOException e) {
Tools.showError(BaseLauncherActivity.this, e);
}
}
}
@Override
public void onNothingSelected(AdapterView<?> p1)
{
// TODO: Implement this method
}
});
popup.setOnMenuItemClickListener(item -> true);
}
ExtraListener<ArrayList<String>> versionListener;
@Override
protected void onPause() {
super.onPause();
if((!LauncherPreferences.PREF_ENABLE_PROFILES) && versionListener != null) ExtraCore.removeExtraListenerFromValue("lac_version_list",versionListener);
}
public static void updateVersionSpinner(Context ctx, ArrayList<String> value, Spinner mVersionSelector, String defaultSelection) {
if(value != null && value.size() > 0) {
ArrayAdapter<String> adapter = new ArrayAdapter<String>(ctx, android.R.layout.simple_spinner_item, value);
adapter.setDropDownViewResource(android.R.layout.simple_list_item_single_choice);
mVersionSelector.setAdapter(adapter);
mVersionSelector.setSelection(RefreshVersionListTask.selectAt(value, defaultSelection));
} else {
mVersionSelector.setSelection(RefreshVersionListTask.selectAt(PojavLauncherActivity.basicVersionList, defaultSelection));
}
}
@Override
protected void onResume(){
super.onResume();
if(!LauncherPreferences.PREF_ENABLE_PROFILES) {
ArrayList<String> vlst = (ArrayList<String>) ExtraCore.getValue("lac_version_list");
if(vlst != null) {
setupVersionSelector();
updateVersionSpinner(this, vlst, mVersionSelector, mProfile.selectedVersion);
}
versionListener = (key, value) -> {
if(value != null) {
setupVersionSelector();
updateVersionSpinner(this, value, mVersionSelector, mProfile.selectedVersion);
}
return false;
};
ExtraCore.addExtraListener("lac_version_list",versionListener);
}
System.out.println("call to onResume");
final int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
final View decorView = getWindow().getDecorView();

View File

@ -6,6 +6,7 @@ import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_HIDE_SIDEBAR;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_NOTCH_SIZE;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.Typeface;
@ -36,11 +37,15 @@ import net.kdt.pojavlaunch.fragments.ConsoleFragment;
import net.kdt.pojavlaunch.fragments.CrashFragment;
import net.kdt.pojavlaunch.fragments.LauncherFragment;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import net.kdt.pojavlaunch.prefs.PerVersionConfigDialog;
import net.kdt.pojavlaunch.prefs.screens.LauncherPreferenceFragment;
import net.kdt.pojavlaunch.profiles.ProfileAdapter;
import net.kdt.pojavlaunch.profiles.ProfileEditor;
import net.kdt.pojavlaunch.value.MinecraftAccount;
import net.kdt.pojavlaunch.value.launcherprofiles.LauncherProfiles;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@ -175,33 +180,42 @@ public class PojavLauncherActivity extends BaseLauncherActivity
});
// Setup the minecraft version list
List<String> versions = new ArrayList<>();
final File fVers = new File(Tools.DIR_HOME_VERSION);
try {
if (fVers.listFiles().length < 1) {
throw new Exception(getString(R.string.error_no_version));
}
for (File fVer : fVers.listFiles()) {
if (fVer.isDirectory())
versions.add(fVer.getName());
}
} catch (Exception e) {
versions.add(getString(R.string.global_error) + ":");
versions.add(e.getMessage());
} finally {
mAvailableVersions = versions.toArray(new String[0]);
}
setupBasicList(this);
//mAvailableVersions;
if(!LauncherPreferences.PREF_ENABLE_PROFILES) {
ArrayAdapter<String> adapterVer = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, mAvailableVersions);
ArrayAdapter<String> adapterVer = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, basicVersionList);
adapterVer.setDropDownViewResource(android.R.layout.simple_list_item_single_choice);
mVersionSelector.setAdapter(adapterVer);
}else{
mVersionSelector.setAdapter(new ProfileAdapter(this));
ProfileAdapter pad = new ProfileAdapter(this);
ProfileEditor dialog = new ProfileEditor(this,(name)->{
pad.notifyDataSetChanged();
LauncherProfiles.update();
});
mVersionSelector.setOnLongClickListener((v)->dialog.show(mProfile.selectedProfile));
mVersionSelector.setAdapter(pad);
mVersionSelector.setSelection(pad.resolveProfileIndex(mProfile.selectedProfile));
mVersionSelector.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener(){
@Override
public void onItemSelected(AdapterView<?> p1, View p2, int p3, long p4)
{
mProfile.selectedProfile = p1.getItemAtPosition(p3).toString();
PojavProfile.setCurrentProfile(PojavLauncherActivity.this, mProfile);
if (PojavProfile.isFileType(PojavLauncherActivity.this)) {
try {
PojavProfile.setCurrentProfile(PojavLauncherActivity.this, mProfile.save());
} catch (IOException e) {
Tools.showError(PojavLauncherActivity.this, e);
}
}
}
@Override
public void onNothingSelected(AdapterView<?> p1)
{
// TODO: Implement this method
}
});
}
//
statusIsLaunching(false);
@ -221,12 +235,35 @@ public class PojavLauncherActivity extends BaseLauncherActivity
});
changeLookAndFeel(PREF_HIDE_SIDEBAR);
}
private void setupProfileSelector() {
}
private void selectTabPage(int pageIndex){
viewPager.setCurrentItem(pageIndex);
setTabActive(pageIndex);
}
public static String[] basicVersionList;
public static void setupBasicList(Context ctx) {
List<String> versions = new ArrayList<>();
final File fVers = new File(Tools.DIR_HOME_VERSION);
try {
if (fVers.listFiles().length < 1) {
throw new Exception(ctx.getString(R.string.error_no_version));
}
for (File fVer : fVers.listFiles()) {
if (fVer.isDirectory())
versions.add(fVer.getName());
}
} catch (Exception e) {
versions.add(ctx.getString(R.string.global_error) + ":");
versions.add(e.getMessage());
} finally {
basicVersionList = versions.toArray(new String[0]);
}
}
private void pickAccount() {
try {
mProfile = PojavProfile.getCurrentProfileContent(this);

View File

@ -1,20 +0,0 @@
package net.kdt.pojavlaunch.fragments;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import net.kdt.pojavlaunch.R;
public class ProfilesFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.version_profile_editor,container,false);
}
}

View File

@ -1,6 +1,7 @@
package net.kdt.pojavlaunch.profiles;
import android.content.Context;
import android.database.DataSetObserver;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Base64;
@ -16,23 +17,29 @@ import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.value.launcherprofiles.LauncherProfiles;
import net.kdt.pojavlaunch.value.launcherprofiles.MinecraftProfile;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/*
* Adapter for listing launcher profiles in a Spinner
*/
public class ProfileAdapter extends BaseAdapter {
Map<String, MinecraftProfile> profiles;
Map<String, Bitmap> iconCache;
ArrayList<DataSetObserver> observers = new ArrayList<>();
static final Map<String, Bitmap> iconCache = new HashMap<>();
static final String BASE64_PNG_HEADER = "data:image/png;base64,";
static final MinecraftProfile DUMMY = new MinecraftProfile();
String[] profileArray;
List<String> profileList;
public ProfileAdapter(Context ctx) {
LauncherProfiles.update();
profiles = LauncherProfiles.mainProfileJson.profiles;
profileArray = profiles.keySet().toArray(new String[0]);
iconCache = new HashMap<>();
profileList = Arrays.asList(profiles.keySet().toArray(new String[0]));
if(!iconCache.containsKey(null))
iconCache.put(null,BitmapFactory.decodeResource(ctx.getResources(),R.drawable.ic_menu_java));
}
/*
* Gets how much profiles are loaded in the adapter right now
@ -40,24 +47,31 @@ public class ProfileAdapter extends BaseAdapter {
*/
@Override
public int getCount() {
return profileArray.length;
return profileList.size();
}
/*
* Gets the profile at a given index
* @param position index to retreive
* @returns MinecraftProfile or null if the index is out of bounds
* @returns MinecraftProfile name or null
*/
@Override
public Object getItem(int position) {
//safe since the second check in the and statement will be skipped if the first one fails
if(position < profileArray.length && profiles.containsKey(profileArray[position])) {
return profiles.get(profileArray[position]);
if(position < profileList.size() && profiles.containsKey(profileList.get(position))) {
return profileList.get(position);
}else{
return null;
}
}
public int resolveProfileIndex(String name) {
return profileList.indexOf(name);
}
public void fireProfileEdit() {
notifyDataSetChanged();
}
/*
* Gets the item ID (crc64 hash of the profile name) for a given index
* @param position index to get the hash for
@ -65,8 +79,8 @@ public class ProfileAdapter extends BaseAdapter {
*/
@Override
public long getItemId(int position) {
if(position < profileArray.length) {
return StringCRC64.strhash(profileArray[position]);
if(position < profileList.size()) {
return StringCRC64.strhash(profileList.get(position));
}else{
return -1L;
}
@ -76,7 +90,7 @@ public class ProfileAdapter extends BaseAdapter {
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) v = LayoutInflater.from(parent.getContext()).inflate(R.layout.version_profile_layout,parent,false);
setViewProfile(v,profileArray[position]);
setViewProfile(v,profileList.get(position));
return v;
}
public void setViewProfile(View v, String nm) {
@ -88,6 +102,7 @@ public class ProfileAdapter extends BaseAdapter {
if (prof.icon.startsWith(BASE64_PNG_HEADER)) {
byte[] pngBytes = Base64.decode(prof.icon.substring(BASE64_PNG_HEADER.length()), Base64.DEFAULT);
cachedIcon = BitmapFactory.decodeByteArray(pngBytes,0,pngBytes.length);
iconCache.put(nm,cachedIcon);
}else{
Log.i("IconParser","Unsupported icon: "+prof.icon);
cachedIcon = iconCache.get(null);

View File

@ -1,15 +1,111 @@
package net.kdt.pojavlaunch.profiles;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.kdt.pojavlaunch.BaseLauncherActivity;
import net.kdt.pojavlaunch.PojavLauncherActivity;
import net.kdt.pojavlaunch.PojavProfile;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.extra.ExtraCore;
import net.kdt.pojavlaunch.extra.ExtraListener;
import net.kdt.pojavlaunch.tasks.RefreshVersionListTask;
import net.kdt.pojavlaunch.value.launcherprofiles.LauncherProfiles;
import net.kdt.pojavlaunch.value.launcherprofiles.MinecraftProfile;
import org.w3c.dom.Text;
public class ProfileEditor {
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashMap;
public class ProfileEditor implements ExtraListener<ArrayList<String>> {
View mainView;
TextView profileNameView;
ImageView profileIconView;
Spinner versionSpinner;
AlertDialog dialog;
Context context;
String selectedVersionId;
String editingProfile;
EditSaveCallback cb;
public ProfileEditor(Context _ctx, EditSaveCallback cb) {
context = _ctx;
this.cb = cb;
LayoutInflater infl = LayoutInflater.from(_ctx);
mainView = infl.inflate(R.layout.version_profile_editor,null);
AlertDialog.Builder bldr = new AlertDialog.Builder(_ctx);
bldr.setView(mainView);
profileNameView = mainView.findViewById(R.id.vprof_editior_profile_name);
versionSpinner = mainView.findViewById(R.id.vprof_editor_version_spinner);
profileIconView = mainView.findViewById(R.id.vprof_editor_icon);
bldr.setPositiveButton(R.string.global_save,this::save);
bldr.setNegativeButton(android.R.string.cancel,(dialog,which)->destroy(dialog));
bldr.setOnDismissListener(this::destroy);
dialog = bldr.create();
}
public boolean show(@NonNull String profile) {
MinecraftProfile prof = LauncherProfiles.mainProfileJson.profiles.get(profile);
if(prof == null) return true;
editingProfile = profile;
ExtraCore.addExtraListener("lac_version_list",this);
profileNameView.setText(prof.name);
if(ProfileAdapter.iconCache.containsKey(profile)) {
Log.i("ProfileEditor","Icon resolved!");
profileIconView.setImageBitmap(ProfileAdapter.iconCache.get(profile));
}else {
Log.i("ProfileEditor","No resolved icon.");
Log.i("ProfileEditor", ProfileAdapter.iconCache.keySet().toString());
profileIconView.setImageBitmap(ProfileAdapter.iconCache.get(null));
}
if(prof.lastVersionId != null && !"latest-release".equals(prof.lastVersionId) && !"latest-snapshot".equals(prof.lastVersionId))
selectedVersionId = prof.lastVersionId;
else if(prof.lastVersionId != null) switch (prof.lastVersionId) {
case "latest-release":
selectedVersionId = ((HashMap<String,String>)ExtraCore.getValue("release_table")).get("release");
case "latest-snapshot":
selectedVersionId = ((HashMap<String,String>)ExtraCore.getValue("release_table")).get("snapshot");
}else{
if(PojavLauncherActivity.basicVersionList.length > 0) {
selectedVersionId = PojavLauncherActivity.basicVersionList[0];
}
}
ArrayList<String> versions = (ArrayList<String>) ExtraCore.getValue("lac_version_list");
BaseLauncherActivity.updateVersionSpinner(context,versions,versionSpinner, selectedVersionId);
dialog.show();
return true;
}
public void save(DialogInterface dialog, int which) {
cb.onSave(editingProfile);
MinecraftProfile prof = LauncherProfiles.mainProfileJson.profiles.get(editingProfile);
prof.name = profileNameView.getText().toString();
prof.lastVersionId = (String)versionSpinner.getSelectedItem();
destroy(dialog);
}
public void destroy(@NonNull DialogInterface dialog) {
ExtraCore.removeExtraListenerFromValue("lac_version_list",this);
editingProfile = null;
selectedVersionId = null;
}
@Override
public boolean onValueSet(String key, @Nullable ArrayList<String> value) {
if(value != null) ((Activity)context).runOnUiThread(()->{
BaseLauncherActivity.updateVersionSpinner(context,value,versionSpinner, selectedVersionId);
});
return false;
}
public interface EditSaveCallback {
void onSave(String name);
}
}

View File

@ -13,6 +13,8 @@ import android.widget.AdapterView.*;
import java.io.*;
import java.util.*;
import net.kdt.pojavlaunch.*;
import net.kdt.pojavlaunch.extra.ExtraCore;
import net.kdt.pojavlaunch.extra.ExtraListener;
import net.kdt.pojavlaunch.multirt.MultiRTUtils;
import net.kdt.pojavlaunch.multirt.RTSpinnerAdapter;
import net.kdt.pojavlaunch.prefs.*;
@ -41,6 +43,8 @@ public class RefreshVersionListTask extends AsyncTask<Void, Void, ArrayList<Stri
Log.i("ExtVL", "Syncing to external: " + url);
list = Tools.GLOBAL_GSON.fromJson(DownloadUtils.downloadString(url), JMinecraftVersionList.class);
Log.i("ExtVL","Downloaded the version list, len="+list.versions.length);
if(list.latest != null && ExtraCore.getValue("release_table") == null)
ExtraCore.setValue("release_table",list.latest);
Collections.addAll(versions,list.versions);
}
mActivity.mVersionList = new JMinecraftVersionList();
@ -60,55 +64,7 @@ public class RefreshVersionListTask extends AsyncTask<Void, Void, ArrayList<Stri
protected void onPostExecute(ArrayList<String> result)
{
super.onPostExecute(result);
final PopupMenu popup = new PopupMenu(mActivity, mActivity.mVersionSelector);
popup.getMenuInflater().inflate(R.menu.menu_versionopt, popup.getMenu());
if(result != null && result.size() > 0) {
ArrayAdapter<String> adapter = new ArrayAdapter<String>(mActivity, android.R.layout.simple_spinner_item, result);
adapter.setDropDownViewResource(android.R.layout.simple_list_item_single_choice);
mActivity.mVersionSelector.setAdapter(adapter);
mActivity.mVersionSelector.setSelection(selectAt(result.toArray(new String[0]), mActivity.mProfile.selectedVersion));
} else {
mActivity.mVersionSelector.setSelection(selectAt(mActivity.mAvailableVersions, mActivity.mProfile.selectedVersion));
}
PerVersionConfigDialog dialog = new PerVersionConfigDialog(this.mActivity);
mActivity.mVersionSelector.setOnLongClickListener((v)->dialog.openConfig(mActivity.mProfile.selectedVersion));
mActivity.mVersionSelector.setOnItemSelectedListener(new OnItemSelectedListener(){
@Override
public void onItemSelected(AdapterView<?> p1, View p2, int p3, long p4)
{
mActivity.mProfile.selectedVersion = p1.getItemAtPosition(p3).toString();
PojavProfile.setCurrentProfile(mActivity, mActivity.mProfile);
if (PojavProfile.isFileType(mActivity)) {
try {
PojavProfile.setCurrentProfile(mActivity, mActivity.mProfile.save());
} catch (IOException e) {
Tools.showError(mActivity, e);
}
}
}
@Override
public void onNothingSelected(AdapterView<?> p1)
{
// TODO: Implement this method
}
});
/*mActivity.mVersionSelector.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener(){
@Override
public boolean onItemLongClick(AdapterView<?> p1, View p2, int p3, long p4)
{
// Implement copy, remove, reinstall,...
return true;
}
});
*/
popup.setOnMenuItemClickListener(item -> true);
ExtraCore.setValue("lac_version_list",result);
}
private ArrayList<String> filter(JMinecraftVersionList.Version[] list1, File[] list2) {
@ -133,7 +89,17 @@ public class RefreshVersionListTask extends AsyncTask<Void, Void, ArrayList<Stri
return output;
}
private int selectAt(String[] strArr, String select) {
public static int selectAt(String[] strArr, String select) {
int count = 0;
for(String str : strArr){
if (str.equals(select)) {
return count;
}
count++;
}
return -1;
}
public static int selectAt(List<String> strArr, String select) {
int count = 0;
for(String str : strArr){
if (str.equals(select)) {

View File

@ -18,6 +18,7 @@ public class MinecraftAccount
public String profileId = "00000000-0000-0000-0000-000000000000"; // profile UUID, for obtaining skin
public String username = "Steve";
public String selectedVersion = "1.7.10";
public String selectedProfile = "";
public boolean isMicrosoft = false;
public String msaRefreshToken = "0";
public String skinFaceBase64;

View File

@ -7,8 +7,8 @@
<ImageView
android:id="@+id/vprof_editor_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_height="32dp"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
@ -51,7 +51,7 @@
app:layout_constraintTop_toBottomOf="@+id/vprof_editor_icon" />
<Spinner
android:id="@+id/spinner2"
android:id="@+id/vprof_editor_version_spinner"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
@ -66,7 +66,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/profiles_profile_version"
app:layout_constraintBottom_toTopOf="@+id/spinner2"
app:layout_constraintStart_toStartOf="@+id/spinner2" />
app:layout_constraintBottom_toTopOf="@+id/vprof_editor_version_spinner"
app:layout_constraintStart_toStartOf="@+id/vprof_editor_version_spinner" />
</androidx.constraintlayout.widget.ConstraintLayout>