diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/PojavLauncherActivity.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/PojavLauncherActivity.java index 7f95c8bec..80fd40a60 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/PojavLauncherActivity.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/PojavLauncherActivity.java @@ -37,6 +37,7 @@ import net.kdt.pojavlaunch.fragments.CrashFragment; import net.kdt.pojavlaunch.fragments.LauncherFragment; import net.kdt.pojavlaunch.prefs.LauncherPreferences; import net.kdt.pojavlaunch.prefs.screens.LauncherPreferenceFragment; +import net.kdt.pojavlaunch.profiles.ProfileAdapter; import net.kdt.pojavlaunch.value.MinecraftAccount; import java.io.File; @@ -198,10 +199,14 @@ public class PojavLauncherActivity extends BaseLauncherActivity } //mAvailableVersions; - ArrayAdapter adapterVer = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, mAvailableVersions); - adapterVer.setDropDownViewResource(android.R.layout.simple_list_item_single_choice); - mVersionSelector.setAdapter(adapterVer); - + if(!LauncherPreferences.PREF_ENABLE_PROFILES) { + ArrayAdapter adapterVer = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, mAvailableVersions); + adapterVer.setDropDownViewResource(android.R.layout.simple_list_item_single_choice); + mVersionSelector.setAdapter(adapterVer); + }else{ + mVersionSelector.setAdapter(new ProfileAdapter(this)); + } + // statusIsLaunching(false); diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlDrawerData.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlDrawerData.java index 773a86841..68374be0f 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlDrawerData.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlDrawerData.java @@ -12,14 +12,14 @@ import static net.kdt.pojavlaunch.customcontrols.ControlDrawerData.Orientation.F import androidx.annotation.Keep; -@Keep +@androidx.annotation.Keep public class ControlDrawerData { public ArrayList buttonProperties; public ControlData properties; public Orientation orientation; - @Keep + @androidx.annotation.Keep public enum Orientation { DOWN, LEFT, diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ProfilesFragment.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ProfilesFragment.java new file mode 100644 index 000000000..e3af2c5a1 --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ProfilesFragment.java @@ -0,0 +1,20 @@ +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); + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java index f15c26b97..acb13ad1d 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java @@ -34,6 +34,7 @@ public class LauncherPreferences public static int PREF_CONTROL_BOTTOM_OFFSET = 0; public static int PREF_CONTROL_LEFT_OFFSET = 0; public static boolean PREF_SUSTAINED_PERFORMANCE = false; + public static boolean PREF_ENABLE_PROFILES = true; public static String PREF_GLES_SHRINK_HACK = "0"; diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/profiles/ProfileAdapter.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/profiles/ProfileAdapter.java new file mode 100644 index 000000000..c5e29fd52 --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/profiles/ProfileAdapter.java @@ -0,0 +1,114 @@ +package net.kdt.pojavlaunch.profiles; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.util.Base64; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import net.kdt.pojavlaunch.R; +import net.kdt.pojavlaunch.value.launcherprofiles.LauncherProfiles; +import net.kdt.pojavlaunch.value.launcherprofiles.MinecraftProfile; + +import java.util.HashMap; +import java.util.Map; +/* + * Adapter for listing launcher profiles in a Spinner + */ +public class ProfileAdapter extends BaseAdapter { + Map profiles; + Map iconCache; + static final String BASE64_PNG_HEADER = "data:image/png;base64,"; + static final MinecraftProfile DUMMY = new MinecraftProfile(); + String[] profileArray; + public ProfileAdapter(Context ctx) { + LauncherProfiles.update(); + profiles = LauncherProfiles.mainProfileJson.profiles; + profileArray = profiles.keySet().toArray(new String[0]); + iconCache = new HashMap<>(); + iconCache.put(null,BitmapFactory.decodeResource(ctx.getResources(),R.drawable.ic_menu_java)); + } + /* + * Gets how much profiles are loaded in the adapter right now + * @returns loaded profile count + */ + @Override + public int getCount() { + return profileArray.length; + } + + /* + * Gets the profile at a given index + * @param position index to retreive + * @returns MinecraftProfile or null if the index is out of bounds + */ + @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]); + }else{ + return null; + } + } + + /* + * Gets the item ID (crc64 hash of the profile name) for a given index + * @param position index to get the hash for + * @returns ID (crc64 of a profile name string) or -1 if the index is out of bounds + */ + @Override + public long getItemId(int position) { + if(position < profileArray.length) { + return StringCRC64.strhash(profileArray[position]); + }else{ + return -1L; + } + } + + @Override + 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]); + return v; + } + public void setViewProfile(View v, String nm) { + MinecraftProfile prof = profiles.get(nm); + if(prof == null) prof = DUMMY; + Bitmap cachedIcon = iconCache.get(nm); + ImageView iconView = v.findViewById(R.id.vprof_icon_view); + if(cachedIcon == null && prof.icon != null) { + 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); + }else{ + Log.i("IconParser","Unsupported icon: "+prof.icon); + cachedIcon = iconCache.get(null); + } + } + + iconView.setImageBitmap(cachedIcon); + if(prof.name != null && !prof.name.isEmpty()) + ((TextView)v.findViewById(R.id.vprof_profile_name_view)).setText(prof.name); + else + ((TextView)v.findViewById(R.id.vprof_profile_name_view)).setText(R.string.unnamed); + + TextView tv = v.findViewById(R.id.vprof_version_id_view); + if(prof.lastVersionId != null) switch (prof.lastVersionId) { + case "latest-release": + tv.setText(R.string.profiles_latest_release); + case "latest-snapshot": + tv.setText(R.string.profiles_latest_snapshot); + default: + tv.setText(prof.lastVersionId); + } else tv.setText(android.R.string.unknownName); + + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/profiles/ProfileEditor.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/profiles/ProfileEditor.java new file mode 100644 index 000000000..2cb402c26 --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/profiles/ProfileEditor.java @@ -0,0 +1,15 @@ +package net.kdt.pojavlaunch.profiles; + +import android.content.Context; +import android.view.View; +import android.widget.Spinner; +import android.widget.TextView; + +import org.w3c.dom.Text; + +public class ProfileEditor { + View mainView; + TextView profileNameView; + Spinner versionSpinner; + Context context; +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/profiles/StringCRC64.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/profiles/StringCRC64.java new file mode 100644 index 000000000..c8429139d --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/profiles/StringCRC64.java @@ -0,0 +1,64 @@ +package net.kdt.pojavlaunch.profiles; + +import java.nio.charset.StandardCharsets; + +public class StringCRC64 { + private final static long POLY = (long) 0xc96c5795d7870f42L; // ECMA-182 + private final static long[][] table; + static + { + table = new long[8][256]; + + for (int n = 0; n < 256; n++) + { + long crc = n; + for (int k = 0; k < 8; k++) + { + if ((crc & 1) == 1) + { + crc = (crc >>> 1) ^ POLY; + } + else + { + crc = (crc >>> 1); + } + } + table[0][n] = crc; + } + for (int n = 0; n < 256; n++) + { + long crc = table[0][n]; + for (int k = 1; k < 8; k++) + { + crc = table[0][(int) (crc & 0xff)] ^ (crc >>> 8); + table[k][n] = crc; + } + } + } + public static long strhash(String str) { + byte[] b = str.getBytes(StandardCharsets.US_ASCII); + long value = 0; + int idx = 0; + int len = b.length; + while (len >= 8) + { + value = table[7][(int) (value & 0xff ^ (b[idx] & 0xff))] + ^ table[6][(int) ((value >>> 8) & 0xff ^ (b[idx + 1] & 0xff))] + ^ table[5][(int) ((value >>> 16) & 0xff ^ (b[idx + 2] & 0xff))] + ^ table[4][(int) ((value >>> 24) & 0xff ^ (b[idx + 3] & 0xff))] + ^ table[3][(int) ((value >>> 32) & 0xff ^ (b[idx + 4] & 0xff))] + ^ table[2][(int) ((value >>> 40) & 0xff ^ (b[idx + 5] & 0xff))] + ^ table[1][(int) ((value >>> 48) & 0xff ^ (b[idx + 6] & 0xff))] + ^ table[0][(int) ((value >>> 56) ^ b[idx + 7] & 0xff)]; + idx += 8; + len -= 8; + } + while (len > 0) + { + value = table[0][(int) ((value ^ b[idx]) & 0xff)] ^ (value >>> 8); + idx++; + len--; + } + return ~value; + } +} diff --git a/app_pojavlauncher/src/main/res/layout/version_profile_editor.xml b/app_pojavlauncher/src/main/res/layout/version_profile_editor.xml new file mode 100644 index 000000000..7ad70f9e9 --- /dev/null +++ b/app_pojavlauncher/src/main/res/layout/version_profile_editor.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app_pojavlauncher/src/main/res/layout/version_profile_layout.xml b/app_pojavlauncher/src/main/res/layout/version_profile_layout.xml new file mode 100644 index 000000000..b936e5df0 --- /dev/null +++ b/app_pojavlauncher/src/main/res/layout/version_profile_layout.xml @@ -0,0 +1,41 @@ + + + + + + + + + \ No newline at end of file diff --git a/app_pojavlauncher/src/main/res/values/strings.xml b/app_pojavlauncher/src/main/res/values/strings.xml index 8a8459327..c496b71a4 100644 --- a/app_pojavlauncher/src/main/res/values/strings.xml +++ b/app_pojavlauncher/src/main/res/values/strings.xml @@ -282,5 +282,10 @@ Don\'t shrink textures Divides all textures by 2 Divides big textures by /2 or /4 - + Unnamed + Latest snapshot + Latest release + Editing profile + Name + Version