Asynchronous CommonApi implementation + modpack source icons

This commit is contained in:
BuildTools 2023-08-16 11:17:04 +03:00 committed by ArtDev
parent 1542ea0204
commit 17cce29c00
6 changed files with 78 additions and 29 deletions

View File

@ -21,6 +21,7 @@ import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.Tools;
import net.kdt.pojavlaunch.modloaders.modpacks.ModItemAdapter;
import net.kdt.pojavlaunch.modloaders.modpacks.SelfReferencingFuture;
import net.kdt.pojavlaunch.modloaders.modpacks.api.CommonApi;
import net.kdt.pojavlaunch.modloaders.modpacks.api.CurseforgeApi;
import net.kdt.pojavlaunch.modloaders.modpacks.api.ModpackApi;
import net.kdt.pojavlaunch.modloaders.modpacks.api.ModrinthApi;
@ -52,7 +53,7 @@ public class SearchModFragment extends Fragment {
public SearchModFragment(){
super(R.layout.fragment_mod_search);
modpackApi = new CurseforgeApi();
modpackApi = new CommonApi();
mSearchFilters = new SearchFilters();
mSearchFilters.isModpack = true;
}

View File

@ -26,6 +26,7 @@ import net.kdt.pojavlaunch.Tools;
import net.kdt.pojavlaunch.modloaders.modpacks.api.ModpackApi;
import net.kdt.pojavlaunch.modloaders.modpacks.imagecache.ImageReceiver;
import net.kdt.pojavlaunch.modloaders.modpacks.imagecache.ModIconCache;
import net.kdt.pojavlaunch.modloaders.modpacks.models.Constants;
import net.kdt.pojavlaunch.modloaders.modpacks.models.ModDetail;
import net.kdt.pojavlaunch.modloaders.modpacks.models.ModItem;
@ -49,7 +50,7 @@ public class ModItemAdapter extends RecyclerView.Adapter<ModItemAdapter.ViewHold
private ModDetail mModDetail = null;
private ModItem mModItem = null;
private final TextView mTitle, mDescription;
private final ImageView mIconView;
private final ImageView mIconView, mSourceView;
private View mExtendedLayout;
private Spinner mExtendedSpinner;
private Button mExtendedButton;
@ -122,6 +123,7 @@ public class ModItemAdapter extends RecyclerView.Adapter<ModItemAdapter.ViewHold
mTitle = view.findViewById(R.id.mod_title_textview);
mDescription = view.findViewById(R.id.mod_body_textview);
mIconView = view.findViewById(R.id.mod_thumbnail_imageview);
mSourceView = view.findViewById(R.id.mod_source_imageview);
}
/** Display basic info about the moditem */
@ -153,6 +155,7 @@ public class ModItemAdapter extends RecyclerView.Adapter<ModItemAdapter.ViewHold
mIconView.setImageDrawable(drawable);
};
mIconCache.getImage(mImageReceiver, mModItem.getIconCacheTag(), mModItem.imageUrl);
mSourceView.setImageResource(getSourceDrawable(item.apiSource));
mTitle.setText(item.title);
mDescription.setText(item.description);
@ -208,6 +211,17 @@ public class ModItemAdapter extends RecyclerView.Adapter<ModItemAdapter.ViewHold
private boolean isExtended(){
return hasExtended() && mExtendedLayout.getVisibility() == View.VISIBLE;
}
private int getSourceDrawable(int apiSource) {
switch (apiSource) {
case Constants.SOURCE_CURSEFORGE:
return R.drawable.ic_curseforge;
case Constants.SOURCE_MODRINTH:
return R.drawable.ic_modrinth;
default:
throw new RuntimeException("Unknown API source");
}
}
}

View File

@ -1,17 +1,16 @@
package net.kdt.pojavlaunch.modloaders.modpacks.api;
import androidx.annotation.NonNull;
import net.kdt.pojavlaunch.PojavApplication;
import net.kdt.pojavlaunch.modloaders.modpacks.models.Constants;
import net.kdt.pojavlaunch.modloaders.modpacks.models.ModDetail;
import net.kdt.pojavlaunch.modloaders.modpacks.models.ModItem;
import net.kdt.pojavlaunch.modloaders.modpacks.models.SearchFilters;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
/**
* Group all apis under the same umbrella, as another layer of abstraction
@ -25,13 +24,25 @@ public class CommonApi implements ModpackApi {
public ModItem[] searchMod(SearchFilters searchFilters) {
ModItem[][] items = new ModItem[mModpackApis.length][];
int totalSize = 0;
// TODO unoptimized as hell
for(int i=0; i<mModpackApis.length; i++) {
items[i] = mModpackApis[i].searchMod(searchFilters);
totalSize += items[i].length;
Future<?>[] futures = new Future<?>[mModpackApis.length];
for(int i = 0; i < mModpackApis.length; i++) {
futures[i] = PojavApplication.sExecutorService.submit(new ApiDownloadTask(i, searchFilters));
}
if(Thread.interrupted()) {
cancelAllFutures(futures);
return null;
}
for(int i = 0; i < mModpackApis.length; i++) {
try {
items[i] = (ModItem[]) futures[i].get();
totalSize += items[i].length;
}catch (Exception e) {
cancelAllFutures(futures);
e.printStackTrace();
return null;
}
}
// Then build an array with all the mods
ModItem[] concatenatedItems = new ModItem[totalSize];
int copyOffset = 0;
@ -39,31 +50,52 @@ public class CommonApi implements ModpackApi {
System.arraycopy(apiItems, 0, concatenatedItems, copyOffset, apiItems.length);
copyOffset += apiItems.length;
}
if(Thread.interrupted()) return null;
Arrays.sort(concatenatedItems, (modItem, t1) -> modItem.title.compareToIgnoreCase(t1.title));
if(Thread.interrupted()) return null;
return concatenatedItems;
}
@Override
public ModDetail getModDetails(ModItem item) {
switch (item.apiSource) {
case Constants.SOURCE_MODRINTH:
return mModrinthApi.getModDetails(item);
case Constants.SOURCE_CURSEFORGE:
return mCurseforgeApi.getModDetails(item);
default:
throw new UnsupportedOperationException("Unknown API source: " + item.apiSource);
}
return getModpackApi(item.apiSource).getModDetails(item);
}
@Override
public ModLoader installMod(ModDetail modDetail, int selectedVersion) {
switch (modDetail.apiSource) {
return getModpackApi(modDetail.apiSource).installMod(modDetail, selectedVersion);
}
private @NonNull ModpackApi getModpackApi(int apiSource) {
switch (apiSource) {
case Constants.SOURCE_MODRINTH:
return mModrinthApi.installMod(modDetail, selectedVersion);
return mModrinthApi;
case Constants.SOURCE_CURSEFORGE:
return mCurseforgeApi.installMod(modDetail, selectedVersion);
return mCurseforgeApi;
default:
throw new UnsupportedOperationException("Unknown API source: " + modDetail.apiSource);
throw new UnsupportedOperationException("Unknown API source: " + apiSource);
}
}
private void cancelAllFutures(Future<?>[] futures) {
for(Future<?> future : futures) {
if(future == null) continue;
future.cancel(true);
}
}
private class ApiDownloadTask implements Callable<ModItem[]> {
private final int mModApi;
private final SearchFilters mSearchFilters;
private ApiDownloadTask(int modApi, SearchFilters searchFilters) {
this.mModApi = modApi;
this.mSearchFilters = searchFilters;
}
@Override
public ModItem[] call() {
return mModpackApis[mModApi].searchMod(mSearchFilters);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@ -24,10 +24,12 @@
<ImageView
android:id="@+id/mod_source_imageview"
android:layout_width="@dimen/_20sdp"
android:layout_height="@dimen/_20sdp"
android:scaleType="centerCrop"
android:layout_width="@dimen/_13sdp"
android:layout_height="@dimen/_13sdp"
android:layout_marginTop="3dp"
android:layout_marginEnd="3dp"
android:scaleType="centerCrop"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@mipmap/ic_launcher_foreground" />