From 3cfaec3b4c7410e1abdfcbb2678be97a944de565 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Fri, 30 Jun 2023 10:33:36 +0300 Subject: [PATCH] Add UI for OptiFine installation TBD: actually install OptiFine --- app_pojavlauncher/build.gradle | 2 + .../fragments/ForgeInstallFragment.java | 119 +++----------- .../fragments/ModVersionListFragment.java | 153 ++++++++++++++++++ .../fragments/OptiFineInstallFragment.java | 60 +++++++ .../fragments/ProfileTypeSelectFragment.java | 3 +- .../modloaders/ForgeDownloadTask.java | 2 +- .../pojavlaunch/modloaders/ForgeUtils.java | 1 + .../modloaders/OFDownloadPageScraper.java | 45 ++++++ .../modloaders/OptiFineDownloadTask.java | 53 ++++++ .../modloaders/OptiFineScraper.java | 89 ++++++++++ .../pojavlaunch/modloaders/OptiFineUtils.java | 28 ++++ .../OptiFineVersionListAdapter.java | 77 +++++++++ ...ller.xml => fragment_mod_version_list.xml} | 6 +- .../main/res/layout/fragment_profile_type.xml | 9 ++ .../src/main/res/values/strings.xml | 4 + 15 files changed, 549 insertions(+), 102 deletions(-) create mode 100644 app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ModVersionListFragment.java create mode 100644 app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/OptiFineInstallFragment.java create mode 100644 app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/OFDownloadPageScraper.java create mode 100644 app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/OptiFineDownloadTask.java create mode 100644 app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/OptiFineScraper.java create mode 100644 app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/OptiFineUtils.java create mode 100644 app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/OptiFineVersionListAdapter.java rename app_pojavlauncher/src/main/res/layout/{fragment_forge_installer.xml => fragment_mod_version_list.xml} (94%) diff --git a/app_pojavlauncher/build.gradle b/app_pojavlauncher/build.gradle index d621c5f08..06841906c 100644 --- a/app_pojavlauncher/build.gradle +++ b/app_pojavlauncher/build.gradle @@ -194,6 +194,8 @@ dependencies { implementation 'org.tukaani:xz:1.8' implementation 'com.github.PojavLauncherTeam:exp4j:60eaec6f78' + implementation 'net.sourceforge.htmlcleaner:htmlcleaner:2.6.1' + // implementation 'net.sourceforge.streamsupport:streamsupport-cfuture:1.7.0' implementation fileTree(dir: 'libs', include: ['*.jar']) diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ForgeInstallFragment.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ForgeInstallFragment.java index 1cc86e620..fe609697f 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ForgeInstallFragment.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ForgeInstallFragment.java @@ -2,15 +2,10 @@ package net.kdt.pojavlaunch.fragments; import android.content.Context; import android.content.Intent; -import android.os.Bundle; import android.view.LayoutInflater; -import android.view.View; -import android.widget.ExpandableListView; -import android.widget.ProgressBar; +import android.widget.ExpandableListAdapter; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.Fragment; import net.kdt.pojavlaunch.JavaGUILauncherActivity; import net.kdt.pojavlaunch.R; @@ -18,129 +13,59 @@ import net.kdt.pojavlaunch.Tools; import net.kdt.pojavlaunch.modloaders.ForgeDownloadTask; import net.kdt.pojavlaunch.modloaders.ForgeUtils; import net.kdt.pojavlaunch.modloaders.ForgeVersionListAdapter; -import net.kdt.pojavlaunch.modloaders.ModloaderDownloadListener; import net.kdt.pojavlaunch.modloaders.ModloaderListenerProxy; import java.io.File; import java.io.IOException; import java.util.List; -public class ForgeInstallFragment extends Fragment implements Runnable, View.OnClickListener, ExpandableListView.OnChildClickListener, ModloaderDownloadListener { +public class ForgeInstallFragment extends ModVersionListFragment> { public static final String TAG = "ForgeInstallFragment"; private static ModloaderListenerProxy sTaskProxy; - private ExpandableListView mExpandableListView; - private ProgressBar mProgressBar; - private File mDestinationFile; - private LayoutInflater mInflater; - private View mRetryView; - - public ForgeInstallFragment() { - super(R.layout.fragment_forge_installer); - } @Override public void onAttach(@NonNull Context context) { super.onAttach(context); - this.mInflater = LayoutInflater.from(context); - this.mDestinationFile = new File(Tools.DIR_CACHE, "forge-installer.jar"); } @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - mProgressBar = view.findViewById(R.id.forge_list_progress_bar); - mExpandableListView = view.findViewById(R.id.forge_expandable_version_list); - mExpandableListView.setOnChildClickListener(this); - mRetryView = view.findViewById(R.id.forge_installer_retry_layout); - view.findViewById(R.id.forge_installer_retry_button).setOnClickListener(this); - if(sTaskProxy != null) { - mExpandableListView.setEnabled(false); - sTaskProxy.attachListener(this); - } - new Thread(this).start(); + public int getTitleText() { + return R.string.forge_dl_select_version; } @Override - public void onDestroyView() { - if(sTaskProxy != null) sTaskProxy.detachListener(); - super.onDestroyView(); + public int getNoDataMsg() { + return R.string.forge_dl_no_installer; } @Override - public void run() { - try { - List forgeVersions = ForgeUtils.downloadForgeVersions(); - Tools.runOnUiThread(()->{ - if(forgeVersions != null) { - mExpandableListView.setAdapter(new ForgeVersionListAdapter(forgeVersions, mInflater)); - }else{ - mRetryView.setVisibility(View.VISIBLE); - } - mProgressBar.setVisibility(View.GONE); - }); - }catch (IOException e) { - Tools.runOnUiThread(()-> { - if (getContext() != null) { - Tools.showError(getContext(), e); - mRetryView.setVisibility(View.VISIBLE); - mProgressBar.setVisibility(View.GONE); - } - }); - } + public ModloaderListenerProxy getTaskProxy() { + return sTaskProxy; + } + @Override + public void setTaskProxy(ModloaderListenerProxy proxy) { + sTaskProxy = proxy; } @Override - public void onClick(View view) { - mRetryView.setVisibility(View.GONE); - mProgressBar.setVisibility(View.VISIBLE); - new Thread(this).start(); + public List loadVersionList() throws IOException { + return ForgeUtils.downloadForgeVersions(); } @Override - public boolean onChildClick(ExpandableListView expandableListView, View view, int i, int i1, long l) { - String forgeVersion = (String)expandableListView.getExpandableListAdapter().getChild(i, i1); - sTaskProxy = new ModloaderListenerProxy(); - ForgeDownloadTask downloadTask = new ForgeDownloadTask(sTaskProxy, forgeVersion, mDestinationFile); - sTaskProxy.attachListener(this); - mExpandableListView.setEnabled(false); - new Thread(downloadTask).start(); - return true; + public ExpandableListAdapter createAdapter(List versionList, LayoutInflater layoutInflater) { + return new ForgeVersionListAdapter(versionList, layoutInflater); } @Override - public void onDownloadFinished(File downloadedFile) { - Tools.runOnUiThread(()->{ - Context context = requireContext(); - sTaskProxy.detachListener(); - sTaskProxy = null; - mExpandableListView.setEnabled(true); - Intent modInstallerStartIntent = new Intent(context, JavaGUILauncherActivity.class); - ForgeUtils.addAutoInstallArgs(modInstallerStartIntent, downloadedFile, true); - context.startActivity(modInstallerStartIntent); - }); + public Runnable createDownloadTask(Object selectedVersion, ModloaderListenerProxy listenerProxy) { + return new ForgeDownloadTask(listenerProxy, (String) selectedVersion, new File(Tools.DIR_CACHE, "forge-installer.jar")); } @Override - public void onDataNotAvailable() { - Tools.runOnUiThread(()->{ - Context context = requireContext(); - sTaskProxy.detachListener(); - sTaskProxy = null; - mExpandableListView.setEnabled(true); - Tools.dialog(context, - context.getString(R.string.global_error), - context.getString(R.string.forge_dl_no_installer)); - }); - } - - @Override - public void onDownloadError(Exception e) { - Tools.runOnUiThread(()->{ - Context context = requireContext(); - sTaskProxy.detachListener(); - sTaskProxy = null; - mExpandableListView.setEnabled(true); - Tools.showError(context, e); - }); + public void onDownloadFinished(Context context, File downloadedFile) { + Intent modInstallerStartIntent = new Intent(context, JavaGUILauncherActivity.class); + ForgeUtils.addAutoInstallArgs(modInstallerStartIntent, downloadedFile, true); + context.startActivity(modInstallerStartIntent); } } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ModVersionListFragment.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ModVersionListFragment.java new file mode 100644 index 000000000..1313323fe --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ModVersionListFragment.java @@ -0,0 +1,153 @@ +package net.kdt.pojavlaunch.fragments; + +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ExpandableListAdapter; +import android.widget.ExpandableListView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import net.kdt.pojavlaunch.R; +import net.kdt.pojavlaunch.Tools; +import net.kdt.pojavlaunch.modloaders.ModloaderDownloadListener; +import net.kdt.pojavlaunch.modloaders.ModloaderListenerProxy; + +import java.io.File; +import java.io.IOException; + +public abstract class ModVersionListFragment extends Fragment implements Runnable, View.OnClickListener, ExpandableListView.OnChildClickListener, ModloaderDownloadListener { + public static final String TAG = "ForgeInstallFragment"; + //private static ModloaderListenerProxy sTaskProxy; + private ExpandableListView mExpandableListView; + private ProgressBar mProgressBar; + private LayoutInflater mInflater; + private View mRetryView; + + public ModVersionListFragment() { + super(R.layout.fragment_mod_version_list); + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + this.mInflater = LayoutInflater.from(context); + //this.mDestinationFile = new File(Tools.DIR_CACHE, "forge-installer.jar"); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + ((TextView)view.findViewById(R.id.title_textview)).setText(getTitleText()); + mProgressBar = view.findViewById(R.id.mod_dl_list_progress); + mExpandableListView = view.findViewById(R.id.mod_dl_expandable_version_list); + mExpandableListView.setOnChildClickListener(this); + mRetryView = view.findViewById(R.id.mod_dl_retry_layout); + view.findViewById(R.id.forge_installer_retry_button).setOnClickListener(this); + ModloaderListenerProxy taskProxy = getTaskProxy(); + if(taskProxy != null) { + mExpandableListView.setEnabled(false); + taskProxy.attachListener(this); + } + new Thread(this).start(); + } + + @Override + public void onDestroyView() { + ModloaderListenerProxy taskProxy = getTaskProxy(); + if(taskProxy != null) taskProxy.detachListener(); + super.onDestroyView(); + } + + @Override + public void run() { + try { + T versions = loadVersionList(); + Tools.runOnUiThread(()->{ + if(versions != null) { + mExpandableListView.setAdapter(createAdapter(versions, mInflater)); + }else{ + mRetryView.setVisibility(View.VISIBLE); + } + mProgressBar.setVisibility(View.GONE); + }); + }catch (IOException e) { + Tools.runOnUiThread(()-> { + if (getContext() != null) { + Tools.showError(getContext(), e); + mRetryView.setVisibility(View.VISIBLE); + mProgressBar.setVisibility(View.GONE); + } + }); + } + } + + @Override + public void onClick(View view) { + mRetryView.setVisibility(View.GONE); + mProgressBar.setVisibility(View.VISIBLE); + new Thread(this).start(); + } + + @Override + public boolean onChildClick(ExpandableListView expandableListView, View view, int i, int i1, long l) { + Object forgeVersion = expandableListView.getExpandableListAdapter().getChild(i, i1); + ModloaderListenerProxy taskProxy = new ModloaderListenerProxy(); + Runnable downloadTask = createDownloadTask(forgeVersion, taskProxy); + //ForgeDownloadTask downloadTask = new ForgeDownloadTask(taskProxy, forgeVersion, mDestinationFile); + setTaskProxy(taskProxy); + taskProxy.attachListener(this); + mExpandableListView.setEnabled(false); + new Thread(downloadTask).start(); + return true; + } + + @Override + public void onDownloadFinished(File downloadedFile) { + Tools.runOnUiThread(()->{ + Context context = requireContext(); + getTaskProxy().detachListener(); + setTaskProxy(null); + mExpandableListView.setEnabled(true); + onDownloadFinished(context, downloadedFile); + }); + } + + @Override + public void onDataNotAvailable() { + Tools.runOnUiThread(()->{ + Context context = requireContext(); + getTaskProxy().detachListener(); + setTaskProxy(null); + mExpandableListView.setEnabled(true); + Tools.dialog(context, + context.getString(R.string.global_error), + context.getString(getNoDataMsg())); + }); + } + + @Override + public void onDownloadError(Exception e) { + Tools.runOnUiThread(()->{ + Context context = requireContext(); + getTaskProxy().detachListener(); + setTaskProxy(null); + mExpandableListView.setEnabled(true); + Tools.showError(context, e); + }); + } + + public abstract int getTitleText(); + public abstract int getNoDataMsg(); + public abstract ModloaderListenerProxy getTaskProxy(); + public abstract T loadVersionList() throws IOException; + public abstract void setTaskProxy(ModloaderListenerProxy proxy); + public abstract ExpandableListAdapter createAdapter(T versionList, LayoutInflater layoutInflater); + public abstract Runnable createDownloadTask(Object selectedVersion, ModloaderListenerProxy listenerProxy); + public abstract void onDownloadFinished(Context context, File downloadedFile); +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/OptiFineInstallFragment.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/OptiFineInstallFragment.java new file mode 100644 index 000000000..5718c5623 --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/OptiFineInstallFragment.java @@ -0,0 +1,60 @@ +package net.kdt.pojavlaunch.fragments; + +import android.content.Context; +import android.view.LayoutInflater; +import android.widget.ExpandableListAdapter; + +import net.kdt.pojavlaunch.R; +import net.kdt.pojavlaunch.Tools; +import net.kdt.pojavlaunch.modloaders.ModloaderListenerProxy; +import net.kdt.pojavlaunch.modloaders.OptiFineDownloadTask; +import net.kdt.pojavlaunch.modloaders.OptiFineUtils; +import net.kdt.pojavlaunch.modloaders.OptiFineVersionListAdapter; + +import java.io.File; +import java.io.IOException; + +public class OptiFineInstallFragment extends ModVersionListFragment { + public static final String TAG = "OptiFineInstallFragment"; + private static ModloaderListenerProxy sTaskProxy; + @Override + public int getTitleText() { + return R.string.of_dl_select_version; + } + + @Override + public int getNoDataMsg() { + return R.string.of_dl_failed_to_scrape; + } + + @Override + public ModloaderListenerProxy getTaskProxy() { + return sTaskProxy; + } + + @Override + public OptiFineUtils.OptiFineVersions loadVersionList() throws IOException { + return OptiFineUtils.downloadOptiFineVersions(); + } + + @Override + public void setTaskProxy(ModloaderListenerProxy proxy) { + sTaskProxy = proxy; + } + + @Override + public ExpandableListAdapter createAdapter(OptiFineUtils.OptiFineVersions versionList, LayoutInflater layoutInflater) { + return new OptiFineVersionListAdapter(versionList, layoutInflater); + } + + @Override + public Runnable createDownloadTask(Object selectedVersion, ModloaderListenerProxy listenerProxy) { + return new OptiFineDownloadTask((OptiFineUtils.OptiFineVersion) selectedVersion, + new File(Tools.DIR_CACHE, "optifine-installer.jar"), listenerProxy); + } + + @Override + public void onDownloadFinished(Context context, File downloadedFile) { + Tools.dialog(context, "Not yet complete", "Installation of OptiFine is not yet implemented. To be done!"); + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ProfileTypeSelectFragment.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ProfileTypeSelectFragment.java index 2c9fc8460..6b742d55f 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ProfileTypeSelectFragment.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ProfileTypeSelectFragment.java @@ -6,7 +6,6 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentActivity; import net.kdt.pojavlaunch.R; import net.kdt.pojavlaunch.Tools; @@ -22,6 +21,8 @@ public class ProfileTypeSelectFragment extends Fragment { super.onViewCreated(view, savedInstanceState); view.findViewById(R.id.vanilla_profile).setOnClickListener(v -> Tools.swapFragment(requireActivity(), ProfileEditorFragment.class, ProfileEditorFragment.TAG, false, new Bundle(1))); + view.findViewById(R.id.optifine_profile).setOnClickListener(v -> Tools.swapFragment(requireActivity(), OptiFineInstallFragment.class, + OptiFineInstallFragment.TAG, false, null)); view.findViewById(R.id.modded_profile_fabric).setOnClickListener((v)-> Tools.swapFragment(requireActivity(), FabricInstallFragment.class, FabricInstallFragment.TAG, false, null)); view.findViewById(R.id.modded_profile_forge).setOnClickListener((v)-> diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/ForgeDownloadTask.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/ForgeDownloadTask.java index 0f8c1a4cf..60dcd9b2d 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/ForgeDownloadTask.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/ForgeDownloadTask.java @@ -14,7 +14,7 @@ import java.io.IOException; public class ForgeDownloadTask implements Runnable, Tools.DownloaderFeedback { private final String mForgeUrl; private final String mForgeVersion; - public final File mDestinationFile; + private final File mDestinationFile; private final ModloaderDownloadListener mListener; public ForgeDownloadTask(ModloaderDownloadListener listener, String forgeVersion, File destinationFile) { this.mListener = listener; diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/ForgeUtils.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/ForgeUtils.java index 7c68ccad1..31420de90 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/ForgeUtils.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/ForgeUtils.java @@ -31,6 +31,7 @@ public class ForgeUtils { return null; } try { + //of_test(); return DownloadUtils.downloadStringCached(FORGE_METADATA_URL, "forge_versions", input -> { try { ForgeVersionListHandler handler = new ForgeVersionListHandler(); diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/OFDownloadPageScraper.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/OFDownloadPageScraper.java new file mode 100644 index 000000000..62d74b2eb --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/OFDownloadPageScraper.java @@ -0,0 +1,45 @@ +package net.kdt.pojavlaunch.modloaders; + +import org.htmlcleaner.HtmlCleaner; +import org.htmlcleaner.HtmlNode; +import org.htmlcleaner.TagNode; +import org.htmlcleaner.TagNodeVisitor; + +import java.io.IOException; +import java.net.URL; + +public class OFDownloadPageScraper implements TagNodeVisitor { + public static String run(String urlInput) throws IOException{ + return new OFDownloadPageScraper().runInner(urlInput); + } + + private String mDownloadFullUrl; + + private String runInner(String url) throws IOException { + HtmlCleaner htmlCleaner = new HtmlCleaner(); + htmlCleaner.clean(new URL(url)).traverse(this); + return mDownloadFullUrl; + } + + @Override + public boolean visit(TagNode parentNode, HtmlNode htmlNode) { + if(isDownloadUrl(parentNode, htmlNode)) { + TagNode tagNode = (TagNode) htmlNode; + String href = tagNode.getAttributeByName("href"); + if(!href.startsWith("https://")) href = "https://optifine.net/"+href; + this.mDownloadFullUrl = href; + return false; + } + return true; + } + + public boolean isDownloadUrl(TagNode parentNode, HtmlNode htmlNode) { + if(!(htmlNode instanceof TagNode)) return false; + if(parentNode == null) return false; + TagNode tagNode = (TagNode) htmlNode; + if(!(parentNode.getName().equals("span") + && "Download".equals(parentNode.getAttributeByName("id")))) return false; + return tagNode.getName().equals("a") && + "onDownload()".equals(tagNode.getAttributeByName("onclick")); + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/OptiFineDownloadTask.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/OptiFineDownloadTask.java new file mode 100644 index 000000000..9ea1653eb --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/OptiFineDownloadTask.java @@ -0,0 +1,53 @@ +package net.kdt.pojavlaunch.modloaders; + +import com.kdt.mcgui.ProgressLayout; + +import net.kdt.pojavlaunch.R; +import net.kdt.pojavlaunch.Tools; +import net.kdt.pojavlaunch.progresskeeper.ProgressKeeper; +import net.kdt.pojavlaunch.utils.DownloadUtils; + +import java.io.File; +import java.io.IOException; + +public class OptiFineDownloadTask implements Runnable, Tools.DownloaderFeedback{ + private final OptiFineUtils.OptiFineVersion mOptiFineVersion; + private final File mDestinationFile; + private final ModloaderDownloadListener mListener; + + public OptiFineDownloadTask(OptiFineUtils.OptiFineVersion mOptiFineVersion, File mDestinationFile, ModloaderDownloadListener mListener) { + this.mOptiFineVersion = mOptiFineVersion; + this.mDestinationFile = mDestinationFile; + this.mListener = mListener; + } + + @Override + public void run() { + ProgressKeeper.submitProgress(ProgressLayout.INSTALL_MODPACK, 0, R.string.of_dl_progress, mOptiFineVersion.downloadUrl); + try { + if(runCatching()) mListener.onDownloadFinished(mDestinationFile); + }catch (IOException e) { + mListener.onDownloadError(e); + } + ProgressKeeper.submitProgress(ProgressLayout.INSTALL_MODPACK, -1, -1); + } + + public boolean runCatching() throws IOException { + String downloadUrl = scrapeDownloadsPage(); + if(downloadUrl == null) return false; + DownloadUtils.downloadFileMonitored(downloadUrl, mDestinationFile, new byte[8192], this); + return true; + } + + public String scrapeDownloadsPage() throws IOException{ + String scrapeResult = OFDownloadPageScraper.run(mOptiFineVersion.downloadUrl); + if(scrapeResult == null) mListener.onDataNotAvailable(); + return scrapeResult; + } + + @Override + public void updateProgress(int curr, int max) { + int progress100 = (int)(((float)curr / (float)max)*100f); + ProgressKeeper.submitProgress(ProgressLayout.INSTALL_MODPACK, progress100, R.string.of_dl_progress, mOptiFineVersion.versionName); + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/OptiFineScraper.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/OptiFineScraper.java new file mode 100644 index 000000000..048b972ce --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/OptiFineScraper.java @@ -0,0 +1,89 @@ +package net.kdt.pojavlaunch.modloaders; + +import net.kdt.pojavlaunch.utils.DownloadUtils; + +import org.htmlcleaner.HtmlCleaner; +import org.htmlcleaner.TagNode; + +import java.util.ArrayList; +import java.util.List; + +public class OptiFineScraper implements DownloadUtils.ParseCallback { + private final OptiFineUtils.OptiFineVersions mOptiFineVersions; + private List mListInProgress; + private String mMinecraftVersion; + + public OptiFineScraper() { + mOptiFineVersions = new OptiFineUtils.OptiFineVersions(); + mOptiFineVersions.minecraftVersions = new ArrayList<>(); + mOptiFineVersions.optifineVersions = new ArrayList<>(); + } + + @Override + public OptiFineUtils.OptiFineVersions process(String input) throws DownloadUtils.ParseException { + HtmlCleaner htmlCleaner = new HtmlCleaner(); + TagNode tagNode = htmlCleaner.clean(input); + traverseTagNode(tagNode); + insertVersionContent(null); + if(mOptiFineVersions.optifineVersions.size() < 1 || + mOptiFineVersions.minecraftVersions.size() < 1) throw new DownloadUtils.ParseException(null); + return mOptiFineVersions; + } + + public void traverseTagNode(TagNode tagNode) { + if(isDownloadLine(tagNode) && mMinecraftVersion != null) { + traverseDownloadLine(tagNode); + } else if(isMinecraftVersionTag(tagNode)) { + insertVersionContent(tagNode); + } else { + for(TagNode tagNodes : tagNode.getChildTags()) { + traverseTagNode(tagNodes); + } + } + } + + private boolean isDownloadLine(TagNode tagNode) { + return tagNode.getName().equals("tr") && + tagNode.hasAttribute("class") && + tagNode.getAttributeByName("class").startsWith("downloadLine"); + } + + private boolean isMinecraftVersionTag(TagNode tagNode) { + return tagNode.getName().equals("h2") && + tagNode.getText().toString().startsWith("Minecraft "); + } + + private void traverseDownloadLine(TagNode tagNode) { + OptiFineUtils.OptiFineVersion optiFineVersion = new OptiFineUtils.OptiFineVersion(); + for(TagNode subNode : tagNode.getChildTags()) { + if(!subNode.getName().equals("td")) continue; + switch(subNode.getAttributeByName("class")) { + case "colFile": + optiFineVersion.versionName = subNode.getText().toString(); + break; + case "colMirror": + optiFineVersion.downloadUrl = getLinkHref(subNode); + } + } + mListInProgress.add(optiFineVersion); + } + private String getLinkHref(TagNode parent) { + for(TagNode subNode : parent.getChildTags()) { + if(subNode.getName().equals("a") && subNode.hasAttribute("href")) { + return subNode.getAttributeByName("href").replace("http://", "https://"); + } + } + return null; + } + + private void insertVersionContent(TagNode tagNode) { + if(mListInProgress != null && mMinecraftVersion != null) { + mOptiFineVersions.minecraftVersions.add(mMinecraftVersion); + mOptiFineVersions.optifineVersions.add(mListInProgress); + } + if(tagNode != null) { + mMinecraftVersion = tagNode.getText().toString(); + mListInProgress = new ArrayList<>(); + } + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/OptiFineUtils.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/OptiFineUtils.java new file mode 100644 index 000000000..bb0e5967e --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/OptiFineUtils.java @@ -0,0 +1,28 @@ +package net.kdt.pojavlaunch.modloaders; + +import net.kdt.pojavlaunch.utils.DownloadUtils; + +import java.io.IOException; +import java.util.List; + +public class OptiFineUtils { + + public static OptiFineVersions downloadOptiFineVersions() throws IOException { + try { + return DownloadUtils.downloadStringCached("https://optifine.net/downloads", + "of_downloads_page", new OptiFineScraper()); + }catch (DownloadUtils.ParseException e) { + e.printStackTrace(); + return null; + } + } + + public static class OptiFineVersions { + public List minecraftVersions; + public List> optifineVersions; + } + public static class OptiFineVersion { + public String versionName; + public String downloadUrl; + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/OptiFineVersionListAdapter.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/OptiFineVersionListAdapter.java new file mode 100644 index 000000000..a63111398 --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/OptiFineVersionListAdapter.java @@ -0,0 +1,77 @@ +package net.kdt.pojavlaunch.modloaders; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseExpandableListAdapter; +import android.widget.ExpandableListAdapter; +import android.widget.TextView; + +public class OptiFineVersionListAdapter extends BaseExpandableListAdapter implements ExpandableListAdapter { + + private final OptiFineUtils.OptiFineVersions mOptiFineVersions; + private final LayoutInflater mLayoutInflater; + + public OptiFineVersionListAdapter(OptiFineUtils.OptiFineVersions optiFineVersions, LayoutInflater mLayoutInflater) { + mOptiFineVersions = optiFineVersions; + this.mLayoutInflater = mLayoutInflater; + } + + @Override + public int getGroupCount() { + return mOptiFineVersions.minecraftVersions.size(); + } + + @Override + public int getChildrenCount(int i) { + return mOptiFineVersions.optifineVersions.get(i).size(); + } + + @Override + public Object getGroup(int i) { + return mOptiFineVersions.minecraftVersions.get(i); + } + + @Override + public Object getChild(int i, int i1) { + return mOptiFineVersions.optifineVersions.get(i).get(i1); + } + + @Override + public long getGroupId(int i) { + return i; + } + + @Override + public long getChildId(int i, int i1) { + return i1; + } + + @Override + public boolean hasStableIds() { + return true; + } + + @Override + public View getGroupView(int i, boolean b, View convertView, ViewGroup viewGroup) { + if(convertView == null) + convertView = mLayoutInflater.inflate(android.R.layout.simple_expandable_list_item_1, viewGroup, false); + + ((TextView) convertView).setText((String)getGroup(i)); + + return convertView; + } + + @Override + public View getChildView(int i, int i1, boolean b, View convertView, ViewGroup viewGroup) { + if(convertView == null) + convertView = mLayoutInflater.inflate(android.R.layout.simple_expandable_list_item_1, viewGroup, false); + ((TextView) convertView).setText(((OptiFineUtils.OptiFineVersion)getChild(i,i1)).versionName); + return convertView; + } + + @Override + public boolean isChildSelectable(int i, int i1) { + return true; + } +} diff --git a/app_pojavlauncher/src/main/res/layout/fragment_forge_installer.xml b/app_pojavlauncher/src/main/res/layout/fragment_mod_version_list.xml similarity index 94% rename from app_pojavlauncher/src/main/res/layout/fragment_forge_installer.xml rename to app_pojavlauncher/src/main/res/layout/fragment_mod_version_list.xml index 40f710ad3..0c644ba71 100644 --- a/app_pojavlauncher/src/main/res/layout/fragment_forge_installer.xml +++ b/app_pojavlauncher/src/main/res/layout/fragment_mod_version_list.xml @@ -36,7 +36,7 @@ @@ -44,7 +44,7 @@ + + diff --git a/app_pojavlauncher/src/main/res/values/strings.xml b/app_pojavlauncher/src/main/res/values/strings.xml index b6bb0dcc0..da26fa683 100644 --- a/app_pojavlauncher/src/main/res/values/strings.xml +++ b/app_pojavlauncher/src/main/res/values/strings.xml @@ -391,4 +391,8 @@ Vanilla-like versions Modded versions Select versions + Select OptiFine version + Failed to get the OptiFine download link + Downloading %s + Create OptiFine profile