mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2025-09-17 16:47:14 -04:00
Infinite mod list implementation
This commit is contained in:
parent
04d6900bc4
commit
e21be296ec
@ -2,9 +2,7 @@ package net.kdt.pojavlaunch.fragments;
|
||||
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
@ -18,23 +16,14 @@ import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import net.kdt.pojavlaunch.PojavApplication;
|
||||
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;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.models.ModItem;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.models.SearchFilters;
|
||||
import net.kdt.pojavlaunch.profiles.VersionSelectorDialog;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class SearchModFragment extends Fragment {
|
||||
public class SearchModFragment extends Fragment implements ModItemAdapter.SearchResultCallback {
|
||||
|
||||
public static final String TAG = "SearchModFragment";
|
||||
private View mOverlay;
|
||||
@ -53,13 +42,12 @@ public class SearchModFragment extends Fragment {
|
||||
private RecyclerView mRecyclerview;
|
||||
private ModItemAdapter mModItemAdapter;
|
||||
private ProgressBar mSearchProgressBar;
|
||||
private Future<?> mSearchFuture;
|
||||
private TextView mStatusTextView;
|
||||
private ColorStateList mDefaultTextColor;
|
||||
|
||||
private ModpackApi modpackApi;
|
||||
|
||||
private SearchFilters mSearchFilters;
|
||||
private final SearchFilters mSearchFilters;
|
||||
|
||||
public SearchModFragment(){
|
||||
super(R.layout.fragment_mod_search);
|
||||
@ -71,7 +59,7 @@ public class SearchModFragment extends Fragment {
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
// You can only access resources after attaching to current context
|
||||
mModItemAdapter = new ModItemAdapter(getResources(), modpackApi);
|
||||
mModItemAdapter = new ModItemAdapter(getResources(), modpackApi, this);
|
||||
mOverlayTopCache = getResources().getDimension(R.dimen.fragment_padding_medium);
|
||||
|
||||
mOverlay = view.findViewById(R.id.search_mod_overlay);
|
||||
@ -96,15 +84,19 @@ public class SearchModFragment extends Fragment {
|
||||
}));
|
||||
|
||||
mSearchEditText.setOnEditorActionListener((v, actionId, event) -> {
|
||||
if(mSearchFuture != null && !mSearchFuture.isCancelled()) {
|
||||
mSearchFuture.cancel(true);
|
||||
}
|
||||
mSearchProgressBar.setVisibility(View.VISIBLE);
|
||||
mSearchFilters.name = mSearchEditText.getText().toString();
|
||||
mSearchFuture = new SelfReferencingFuture(new SearchModTask(mSearchFilters))
|
||||
.startOnExecutor(PojavApplication.sExecutorService);
|
||||
mModItemAdapter.performSearchQuery(mSearchFilters);
|
||||
return true;
|
||||
});
|
||||
|
||||
mOverlay.post(()->{
|
||||
int overlayHeight = mOverlay.getHeight();
|
||||
mRecyclerview.setPadding(mRecyclerview.getPaddingLeft(),
|
||||
mRecyclerview.getPaddingTop() + overlayHeight,
|
||||
mRecyclerview.getPaddingRight(),
|
||||
mRecyclerview.getPaddingBottom());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -113,35 +105,25 @@ public class SearchModFragment extends Fragment {
|
||||
mRecyclerview.removeOnScrollListener(mOverlayPositionListener);
|
||||
}
|
||||
|
||||
class SearchModTask implements SelfReferencingFuture.FutureInterface {
|
||||
@Override
|
||||
public void onSearchFinished() {
|
||||
mSearchProgressBar.setVisibility(View.GONE);
|
||||
mStatusTextView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private final SearchFilters mTaskFilters;
|
||||
SearchModTask(SearchFilters mSearchFilters) {
|
||||
this.mTaskFilters = mSearchFilters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(Future<?> myFuture) {
|
||||
ModItem[] items = modpackApi.searchMod(mTaskFilters);
|
||||
Log.d(SearchModFragment.class.toString(), Arrays.toString(items));
|
||||
Tools.runOnUiThread(() -> {
|
||||
ModItem[] localItems = items;
|
||||
if(myFuture.isCancelled()) return;
|
||||
mSearchProgressBar.setVisibility(View.GONE);
|
||||
if(localItems == null) {
|
||||
mStatusTextView.setVisibility(View.VISIBLE);
|
||||
mStatusTextView.setTextColor(Color.RED);
|
||||
mStatusTextView.setText(R.string.search_modpack_error);
|
||||
}else if(localItems.length == 0) {
|
||||
mStatusTextView.setVisibility(View.VISIBLE);
|
||||
mStatusTextView.setTextColor(mDefaultTextColor);
|
||||
mStatusTextView.setText(R.string.search_modpack_no_result);
|
||||
localItems = null;
|
||||
}else{
|
||||
mStatusTextView.setVisibility(View.GONE);
|
||||
}
|
||||
mModItemAdapter.setModItems(localItems, mSelectedVersion.getText().toString());
|
||||
});
|
||||
@Override
|
||||
public void onSearchError(int error) {
|
||||
mSearchProgressBar.setVisibility(View.GONE);
|
||||
mStatusTextView.setVisibility(View.VISIBLE);
|
||||
switch(error) {
|
||||
case ERROR_INTERNAL:
|
||||
mStatusTextView.setTextColor(Color.RED);
|
||||
mStatusTextView.setText(R.string.search_modpack_error);
|
||||
break;
|
||||
case ERROR_NO_RESULTS:
|
||||
mStatusTextView.setTextColor(mDefaultTextColor);
|
||||
mStatusTextView.setText(R.string.search_modpack_no_result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,23 +29,103 @@ 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;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.models.SearchFilters;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.models.SearchResult;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class ModItemAdapter extends RecyclerView.Adapter<ModItemAdapter.ViewHolder> {
|
||||
public class ModItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
private static final ModItem[] MOD_ITEMS_EMPTY = new ModItem[0];
|
||||
private static final int VIEW_TYPE_MOD_ITEM = 0;
|
||||
private static final int VIEW_TYPE_LOADING = 1;
|
||||
|
||||
/* Used when versions haven't loaded yet, default text to reduce layout shifting */
|
||||
private final SimpleArrayAdapter<String> mLoadingAdapter = new SimpleArrayAdapter<>(Collections.singletonList("Loading"));
|
||||
private final ModIconCache mIconCache = new ModIconCache();
|
||||
private final SearchResultCallback mSearchResultCallback;
|
||||
private ModItem[] mModItems;
|
||||
private final ModpackApi mModpackApi;
|
||||
|
||||
/* Cache for ever so slightly rounding the image for the corner not to stick out of the layout */
|
||||
private final float mCornerDimensionCache;
|
||||
|
||||
private Future<?> mTaskInProgress;
|
||||
private SearchFilters mSearchFilters;
|
||||
private SearchResult mCurrentResult;
|
||||
|
||||
|
||||
public ModItemAdapter(Resources resources, ModpackApi api, SearchResultCallback callback) {
|
||||
mCornerDimensionCache = resources.getDimension(R.dimen._1sdp) / 250;
|
||||
mModpackApi = api;
|
||||
mModItems = new ModItem[]{};
|
||||
mSearchResultCallback = callback;
|
||||
}
|
||||
|
||||
public void performSearchQuery(SearchFilters searchFilters) {
|
||||
if(mTaskInProgress != null) {
|
||||
mTaskInProgress.cancel(true);
|
||||
mTaskInProgress = null;
|
||||
}
|
||||
this.mSearchFilters = searchFilters;
|
||||
mTaskInProgress = new SelfReferencingFuture(new SearchApiTask(mSearchFilters, null))
|
||||
.startOnExecutor(PojavApplication.sExecutorService);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
|
||||
LayoutInflater layoutInflater = LayoutInflater.from(viewGroup.getContext());
|
||||
View view;
|
||||
switch (viewType) {
|
||||
case VIEW_TYPE_MOD_ITEM:
|
||||
// Create a new view, which defines the UI of the list item
|
||||
view = layoutInflater.inflate(R.layout.view_mod, viewGroup, false);
|
||||
return new ViewHolder(view);
|
||||
case VIEW_TYPE_LOADING:
|
||||
// Create a new view, which is actually just the progress bar
|
||||
view = layoutInflater.inflate(R.layout.view_loading, viewGroup, false);
|
||||
return new LoadingViewHolder(view);
|
||||
default:
|
||||
throw new RuntimeException("Unimplemented view type!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
|
||||
switch (getItemViewType(position)) {
|
||||
case VIEW_TYPE_MOD_ITEM:
|
||||
((ModItemAdapter.ViewHolder)holder).setStateLimited(mModItems[position]);
|
||||
break;
|
||||
case VIEW_TYPE_LOADING:
|
||||
loadMoreResults();
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Unimplemented view type!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if(mModItems.length == 0) return 0;
|
||||
return mModItems.length+1;
|
||||
}
|
||||
|
||||
private void loadMoreResults() {
|
||||
if(mTaskInProgress != null) return;
|
||||
mTaskInProgress = new SelfReferencingFuture(new SearchApiTask(mSearchFilters, mCurrentResult))
|
||||
.startOnExecutor(PojavApplication.sExecutorService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
if(position < mModItems.length) return VIEW_TYPE_MOD_ITEM;
|
||||
return VIEW_TYPE_LOADING;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Basic viewholder with expension capabilities
|
||||
*/
|
||||
@ -228,38 +308,67 @@ public class ModItemAdapter extends RecyclerView.Adapter<ModItemAdapter.ViewHold
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ModItemAdapter(Resources resources, ModpackApi api) {
|
||||
mCornerDimensionCache = resources.getDimension(R.dimen._1sdp) / 250;
|
||||
mModpackApi = api;
|
||||
mModItems = new ModItem[]{};
|
||||
/**
|
||||
* The view holder used to hold the progress bar at the end of the list
|
||||
*/
|
||||
private static class LoadingViewHolder extends RecyclerView.ViewHolder {
|
||||
public LoadingViewHolder(View view) {
|
||||
super(view);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
public void setModItems(ModItem[] items, String targetMcVersion){
|
||||
// TODO: Use targetMcVersion to affect default selected modpack version
|
||||
if(items != null) mModItems = items;
|
||||
else mModItems = MOD_ITEMS_EMPTY;
|
||||
notifyDataSetChanged();
|
||||
private class SearchApiTask implements SelfReferencingFuture.FutureInterface {
|
||||
private final SearchFilters mSearchFilters;
|
||||
private final SearchResult mPreviousResult;
|
||||
|
||||
private SearchApiTask(SearchFilters searchFilters, SearchResult previousResult) {
|
||||
this.mSearchFilters = searchFilters;
|
||||
this.mPreviousResult = previousResult;
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
@Override
|
||||
public void run(Future<?> myFuture) {
|
||||
SearchResult result = mModpackApi.searchMod(mSearchFilters, mPreviousResult);
|
||||
ModItem[] resultModItems = result != null ? result.results : null;
|
||||
Tools.runOnUiThread(() -> {
|
||||
if(myFuture.isCancelled()) return;
|
||||
|
||||
if(resultModItems == null) {
|
||||
mSearchResultCallback.onSearchError(SearchResultCallback.ERROR_INTERNAL);
|
||||
}else if(resultModItems.length == 0) {
|
||||
mSearchResultCallback.onSearchError(SearchResultCallback.ERROR_NO_RESULTS);
|
||||
}else{
|
||||
mSearchResultCallback.onSearchFinished();
|
||||
}
|
||||
mCurrentResult = result;
|
||||
if(resultModItems == null) {
|
||||
mModItems = MOD_ITEMS_EMPTY;
|
||||
mTaskInProgress = null;
|
||||
notifyDataSetChanged();
|
||||
return;
|
||||
}
|
||||
if(mPreviousResult != null) {
|
||||
ModItem[] newModItems = new ModItem[resultModItems.length + mModItems.length];
|
||||
System.arraycopy(mModItems, 0, newModItems, 0, mModItems.length);
|
||||
System.arraycopy(resultModItems, 0, newModItems, mModItems.length, resultModItems.length);
|
||||
mModItems = newModItems;
|
||||
mTaskInProgress = null;
|
||||
notifyItemChanged(mModItems.length);
|
||||
notifyItemRangeInserted(mModItems.length+1, newModItems.length);
|
||||
return;
|
||||
}
|
||||
mModItems = resultModItems;
|
||||
mTaskInProgress = null;
|
||||
notifyDataSetChanged();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
|
||||
// Create a new view, which defines the UI of the list item
|
||||
View view = LayoutInflater.from(viewGroup.getContext())
|
||||
.inflate(R.layout.view_mod, viewGroup, false);
|
||||
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder viewHolder, final int position) {
|
||||
viewHolder.setStateLimited(mModItems[position]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mModItems.length;
|
||||
public interface SearchResultCallback {
|
||||
int ERROR_INTERNAL = 0;
|
||||
int ERROR_NO_RESULTS = 1;
|
||||
void onSearchFinished();
|
||||
void onSearchError(int error);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ 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 net.kdt.pojavlaunch.modloaders.modpacks.models.SearchResult;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.Callable;
|
||||
@ -21,22 +22,36 @@ public class CommonApi implements ModpackApi {
|
||||
private final ModpackApi mModrinthApi = new ModrinthApi();
|
||||
private final ModpackApi[] mModpackApis = new ModpackApi[]{mModrinthApi, mCurseforgeApi};
|
||||
@Override
|
||||
public ModItem[] searchMod(SearchFilters searchFilters) {
|
||||
ModItem[][] items = new ModItem[mModpackApis.length][];
|
||||
public SearchResult searchMod(SearchFilters searchFilters, SearchResult previousPageResult) {
|
||||
CommonApiSearchResult commonApiSearchResult = (CommonApiSearchResult) previousPageResult;
|
||||
// If there are no previous page results, create a new array. Otherwise, use the one from the previous page
|
||||
SearchResult[] results = commonApiSearchResult == null ?
|
||||
new SearchResult[mModpackApis.length] : commonApiSearchResult.searchResults;
|
||||
|
||||
int totalSize = 0;
|
||||
int totalTotalSize = 0;
|
||||
|
||||
Future<?>[] futures = new Future<?>[mModpackApis.length];
|
||||
for(int i = 0; i < mModpackApis.length; i++) {
|
||||
futures[i] = PojavApplication.sExecutorService.submit(new ApiDownloadTask(i, searchFilters));
|
||||
// If there is an array and its length is zero, this means that we've exhausted the results for this
|
||||
// search query and we don't need to actually do the search
|
||||
if(results[i] != null && results[i].results.length == 0) continue;
|
||||
futures[i] = PojavApplication.sExecutorService.submit(new ApiDownloadTask(i, searchFilters,
|
||||
results[i]));
|
||||
}
|
||||
|
||||
if(Thread.interrupted()) {
|
||||
cancelAllFutures(futures);
|
||||
return null;
|
||||
}
|
||||
// Count up all the results
|
||||
for(int i = 0; i < mModpackApis.length; i++) {
|
||||
Future<?> future = futures[i];
|
||||
if(future == null) continue;
|
||||
try {
|
||||
items[i] = (ModItem[]) futures[i].get();
|
||||
totalSize += items[i].length;
|
||||
SearchResult searchResult = results[i] = (SearchResult) future.get();
|
||||
totalSize += searchResult.results.length;
|
||||
totalTotalSize += searchResult.totalResultCount;
|
||||
}catch (Exception e) {
|
||||
cancelAllFutures(futures);
|
||||
e.printStackTrace();
|
||||
@ -46,14 +61,22 @@ public class CommonApi implements ModpackApi {
|
||||
// Then build an array with all the mods
|
||||
ModItem[] concatenatedItems = new ModItem[totalSize];
|
||||
int copyOffset = 0;
|
||||
for(ModItem[] apiItems : items) {
|
||||
System.arraycopy(apiItems, 0, concatenatedItems, copyOffset, apiItems.length);
|
||||
copyOffset += apiItems.length;
|
||||
for(SearchResult result : results) {
|
||||
ModItem[] searchResults = result.results;
|
||||
// If the length is zero, we don't need to perform needless copies
|
||||
if(searchResults.length == 0) continue;
|
||||
System.arraycopy(searchResults, 0, concatenatedItems, copyOffset, searchResults.length);
|
||||
copyOffset += searchResults.length;
|
||||
}
|
||||
if(Thread.interrupted()) return null;
|
||||
Arrays.sort(concatenatedItems, (modItem, t1) -> modItem.title.compareToIgnoreCase(t1.title));
|
||||
if(Thread.interrupted()) return null;
|
||||
return concatenatedItems;
|
||||
// Recycle or create new search result
|
||||
if(commonApiSearchResult == null) commonApiSearchResult = new CommonApiSearchResult();
|
||||
commonApiSearchResult.searchResults = results;
|
||||
commonApiSearchResult.totalResultCount = totalTotalSize;
|
||||
commonApiSearchResult.results = concatenatedItems;
|
||||
return commonApiSearchResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -84,18 +107,24 @@ public class CommonApi implements ModpackApi {
|
||||
}
|
||||
}
|
||||
|
||||
private class ApiDownloadTask implements Callable<ModItem[]> {
|
||||
private class ApiDownloadTask implements Callable<SearchResult> {
|
||||
private final int mModApi;
|
||||
private final SearchFilters mSearchFilters;
|
||||
private final SearchResult mPreviousPageResult;
|
||||
|
||||
private ApiDownloadTask(int modApi, SearchFilters searchFilters) {
|
||||
private ApiDownloadTask(int modApi, SearchFilters searchFilters, SearchResult previousPageResult) {
|
||||
this.mModApi = modApi;
|
||||
this.mSearchFilters = searchFilters;
|
||||
this.mPreviousPageResult = previousPageResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModItem[] call() {
|
||||
return mModpackApis[mModApi].searchMod(mSearchFilters);
|
||||
public SearchResult call() {
|
||||
return mModpackApis[mModApi].searchMod(mSearchFilters, mPreviousPageResult);
|
||||
}
|
||||
}
|
||||
|
||||
class CommonApiSearchResult extends SearchResult {
|
||||
SearchResult[] searchResults = new SearchResult[mModpackApis.length];
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import net.kdt.pojavlaunch.modloaders.modpacks.models.CurseManifest;
|
||||
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 net.kdt.pojavlaunch.modloaders.modpacks.models.SearchResult;
|
||||
import net.kdt.pojavlaunch.progresskeeper.ProgressKeeper;
|
||||
import net.kdt.pojavlaunch.utils.FileUtils;
|
||||
import net.kdt.pojavlaunch.utils.ZipUtils;
|
||||
@ -40,17 +41,21 @@ public class CurseforgeApi implements ModpackApi{
|
||||
private final ApiHandler mApiHandler = new ApiHandler("https://api.curseforge.com/v1", "$2a$10$Vxkj4kH1Ekf8EsS4Mx8b2eVTHsht107Lk2erVEUtnbqvojsLy.jYq");
|
||||
|
||||
@Override
|
||||
public ModItem[] searchMod(SearchFilters searchFilters) {
|
||||
public SearchResult searchMod(SearchFilters searchFilters, SearchResult previousPageResult) {
|
||||
CurseforgeSearchResult curseforgeSearchResult = (CurseforgeSearchResult) previousPageResult;
|
||||
HashMap<String, Object> params = new HashMap<>();
|
||||
params.put("gameId", CURSEFORGE_MINECRAFT_GAME_ID);
|
||||
params.put("classId", searchFilters.isModpack ? CURSEFORGE_MODPACK_CLASS_ID : CURSEFORGE_MOD_CLASS_ID);
|
||||
params.put("searchFilter", searchFilters.name);
|
||||
if(searchFilters.mcVersion != null && !searchFilters.mcVersion.isEmpty())
|
||||
params.put("gameVersion", searchFilters.mcVersion);
|
||||
if(previousPageResult != null)
|
||||
params.put("index", curseforgeSearchResult.previousOffset);
|
||||
JsonObject response = mApiHandler.get("mods/search", params, JsonObject.class);
|
||||
if(response == null) return null;
|
||||
JsonArray dataArray = response.getAsJsonArray("data");
|
||||
if(dataArray == null) return null;
|
||||
JsonObject paginationInfo = response.getAsJsonObject("pagination");
|
||||
ArrayList<ModItem> modItemList = new ArrayList<>(dataArray.size());
|
||||
for(int i = 0; i < dataArray.size(); i++) {
|
||||
JsonObject dataElement = dataArray.get(i).getAsJsonObject();
|
||||
@ -69,7 +74,12 @@ public class CurseforgeApi implements ModpackApi{
|
||||
dataElement.getAsJsonObject("logo").get("thumbnailUrl").getAsString());
|
||||
modItemList.add(modItem);
|
||||
}
|
||||
return modItemList.toArray(new ModItem[0]);
|
||||
if(curseforgeSearchResult == null) curseforgeSearchResult = new CurseforgeSearchResult();
|
||||
curseforgeSearchResult.results = modItemList.toArray(new ModItem[0]);
|
||||
curseforgeSearchResult.totalResultCount = paginationInfo.get("totalCount").getAsInt();
|
||||
curseforgeSearchResult.previousOffset += dataArray.size();
|
||||
return curseforgeSearchResult;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -215,4 +225,8 @@ public class CurseforgeApi implements ModpackApi{
|
||||
if(manifest.minecraft.modLoaders.length < 1) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
class CurseforgeSearchResult extends SearchResult {
|
||||
int previousOffset;
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import net.kdt.pojavlaunch.modloaders.ModloaderDownloadListener;
|
||||
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 net.kdt.pojavlaunch.modloaders.modpacks.models.SearchResult;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@ -18,11 +19,20 @@ import java.io.File;
|
||||
*/
|
||||
public interface ModpackApi {
|
||||
|
||||
/**
|
||||
* @param searchFilters Filters
|
||||
* @param offset the offset into the list of search results
|
||||
* @return the list of mod items from specified offset
|
||||
*/
|
||||
SearchResult searchMod(SearchFilters searchFilters, SearchResult previousPageResult);
|
||||
|
||||
/**
|
||||
* @param searchFilters Filters
|
||||
* @return A list of mod items
|
||||
*/
|
||||
ModItem[] searchMod(SearchFilters searchFilters);
|
||||
default SearchResult searchMod(SearchFilters searchFilters) {
|
||||
return searchMod(searchFilters, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the mod details
|
||||
|
@ -11,6 +11,7 @@ import net.kdt.pojavlaunch.modloaders.modpacks.models.ModDetail;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.models.ModItem;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.models.ModrinthIndex;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.models.SearchFilters;
|
||||
import net.kdt.pojavlaunch.modloaders.modpacks.models.SearchResult;
|
||||
import net.kdt.pojavlaunch.progresskeeper.DownloaderProgressWrapper;
|
||||
import net.kdt.pojavlaunch.utils.ZipUtils;
|
||||
|
||||
@ -27,7 +28,8 @@ public class ModrinthApi implements ModpackApi{
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModItem[] searchMod(SearchFilters searchFilters) {
|
||||
public SearchResult searchMod(SearchFilters searchFilters, SearchResult previousPageResult) {
|
||||
ModrinthSearchResult modrinthSearchResult = (ModrinthSearchResult) previousPageResult;
|
||||
HashMap<String, Object> params = new HashMap<>();
|
||||
|
||||
// Build the facets filters
|
||||
@ -39,7 +41,9 @@ public class ModrinthApi implements ModpackApi{
|
||||
facetString.append("]");
|
||||
params.put("facets", facetString.toString());
|
||||
params.put("query", searchFilters.name);
|
||||
params.put("limit", 100);
|
||||
params.put("limit", 50);
|
||||
if(modrinthSearchResult != null)
|
||||
params.put("offset", modrinthSearchResult.previousOffset);
|
||||
|
||||
JsonObject response = mApiHandler.get("search", params, JsonObject.class);
|
||||
if(response == null) return null;
|
||||
@ -58,8 +62,11 @@ public class ModrinthApi implements ModpackApi{
|
||||
hit.get("icon_url").getAsString()
|
||||
);
|
||||
}
|
||||
|
||||
return items;
|
||||
if(modrinthSearchResult == null) modrinthSearchResult = new ModrinthSearchResult();
|
||||
modrinthSearchResult.previousOffset += responseHits.size();
|
||||
modrinthSearchResult.results = items;
|
||||
modrinthSearchResult.totalResultCount = response.get("total_hits").getAsInt();
|
||||
return modrinthSearchResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -124,4 +131,8 @@ public class ModrinthApi implements ModpackApi{
|
||||
return createInfo(modrinthIndex);
|
||||
}
|
||||
}
|
||||
|
||||
class ModrinthSearchResult extends SearchResult {
|
||||
int previousOffset;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,6 @@
|
||||
package net.kdt.pojavlaunch.modloaders.modpacks.models;
|
||||
|
||||
public class SearchResult {
|
||||
public int totalResultCount;
|
||||
public ModItem[] results;
|
||||
}
|
@ -101,7 +101,7 @@
|
||||
android:id="@+id/search_mod_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="@dimen/_65sdp"
|
||||
android:paddingTop="@dimen/_15sdp"
|
||||
android:clipToPadding="false"
|
||||
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
12
app_pojavlauncher/src/main/res/layout/view_loading.xml
Normal file
12
app_pojavlauncher/src/main/res/layout/view_loading.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp"
|
||||
android:indeterminate="true">
|
||||
|
||||
</ProgressBar>
|
Loading…
x
Reference in New Issue
Block a user