- Fixed the issue of being unable to scroll to the end when the keyboard was visible in VM creator.
- Lists in the Rom store and Software & driver now load gradually when scrolling instead of loading everything at once to improve performance.
- Bugs fixed.
This commit is contained in:
An Bui 2026-01-26 21:48:46 +07:00
parent be7079d8d2
commit bf89310916
13 changed files with 166 additions and 60 deletions

View file

@ -108,25 +108,8 @@ public class CqcmActivity extends AppCompatActivity {
if (JSONUtils.isValidFromString(_map)) {
mapForCreateNewVM = new Gson().fromJson(_map, new TypeToken<HashMap<String, Object>>() {
}.getType());
if (mapForCreateNewVM.containsKey("imgName")) {
imgName = Objects.requireNonNull(mapForCreateNewVM.get("imgName")).toString();
}
if (mapForCreateNewVM.containsKey("imgIcon")) {
imgIcon = Objects.requireNonNull(mapForCreateNewVM.get("imgIcon")).toString();
}
if (mapForCreateNewVM.containsKey("imgPath")) {
imgPath = Objects.requireNonNull(mapForCreateNewVM.get("imgPath")).toString();
}
if (mapForCreateNewVM.containsKey("imgArch")) {
imgArch = Objects.requireNonNull(mapForCreateNewVM.get("imgArch")).toString();
}
if (mapForCreateNewVM.containsKey("imgCdrom")) {
imgCdrom = Objects.requireNonNull(mapForCreateNewVM.get("imgCdrom")).toString();
}
if (mapForCreateNewVM.containsKey("imgExtra")) {
imgExtra = Objects.requireNonNull(mapForCreateNewVM.get("imgExtra")).toString();
}
VMManager.createNewVM(imgName, imgIcon, imgPath, imgArch, imgCdrom, imgExtra, vmID, VMManager.startRandomPort());
mapForCreateNewVM.put("vmID", VMManager.startRamdomVMID());
VMManager.addVM(mapForCreateNewVM, -1);
} else {
Toast.makeText(getApplicationContext(), "The data for the new virtual machine is corrupted and cannot be created.", Toast.LENGTH_LONG).show();
}

View file

@ -66,7 +66,6 @@ import java.util.Random;
public class VMManager {
public static final String TAG = "VMManager";
public static String finalJson = "";
public static String pendingDeviceID = "";
public static String generatedVMId = "";
public static int restoredVMs = 0;

View file

@ -115,6 +115,8 @@ public class VMCreatorActivity extends AppCompatActivity {
setSupportActionBar(binding.toolbar);
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
UIUtils.setOnApplyWindowInsetsListener(binding.main);
binding.collapsingToolbarLayout.setSubtitle(MainSettingsManager.getArch(this));
binding.btnCreate.setOnClickListener(v -> startCreateVM());
@ -996,11 +998,11 @@ public class VMCreatorActivity extends AppCompatActivity {
FileUtils.moveAFile(AppConfig.vmFolder + _filename.replace(".cvbi", ""), AppConfig.vmFolder + vmID);
if (!jObj.has("drive") && !jObj.has("cdrom") && !jObj.has("qemu")) {
UIUtils.oneDialog(getResources().getString(R.string.problem_has_been_detected), getResources().getString(R.string.this_rom_is_missing_too_much_information), true, false, this);
DialogUtils.oneDialog(this, getResources().getString(R.string.problem_has_been_detected), getResources().getString(R.string.this_rom_is_missing_too_much_information), R.drawable.warning_24px);
}
if (!jObj.has("versioncode")) {
UIUtils.oneDialog(getResources().getString(R.string.problem_has_been_detected), getResources().getString(R.string.this_rom_may_not_be_compatible), true, false, this);
DialogUtils.oneDialog(this, getResources().getString(R.string.problem_has_been_detected), getResources().getString(R.string.this_rom_may_not_be_compatible), R.drawable.warning_24px);
}
if (jObj.has("author") && !jObj.isNull("author") && jObj.has("desc") && !jObj.isNull("desc")) {

View file

@ -29,6 +29,7 @@ import androidx.core.view.GravityCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.behavior.HideViewOnScrollBehavior;
import com.google.android.material.bottomnavigation.BottomNavigationView;
@ -104,6 +105,7 @@ public class MainActivity extends AppCompatActivity implements RomStoreFragment.
private RomStoreHomeAdpater adapterRomStore;
private SoftwareStoreHomeAdapter adapterSoftwareStore;
private final List<DataRoms> listSearchData = new ArrayList<>();
private LinearLayoutManager layoutManager;
public static CallbackInterface.HomeCallToVmsListener homeCallToVmsListener;
@ -275,7 +277,25 @@ public class MainActivity extends AppCompatActivity implements RomStoreFragment.
}
});
binding.rvSearch.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
binding.rvSearch.setLayoutManager(layoutManager);
binding.rvSearch.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int totalItemCount = layoutManager.getItemCount();
int lastVisibleItem = layoutManager.findLastVisibleItemPosition();
if (lastVisibleItem >= totalItemCount - 2) {
if (currentSearchMode == SEARCH_ROM_STORE) {
adapterRomStore.loadMore();
} else {
adapterSoftwareStore.loadMore();
}
}
}
});
binding.searchview.getEditText().
@ -605,9 +625,13 @@ public class MainActivity extends AppCompatActivity implements RomStoreFragment.
binding.rvSearch.setVisibility(View.VISIBLE);
if (currentSearchMode == SEARCH_ROM_STORE ) {
if (adapterRomStore != null) adapterRomStore.notifyDataSetChanged();
if (adapterRomStore != null) {
adapterRomStore.submitList(listSearchData);
}
} else {
if (adapterSoftwareStore != null) adapterSoftwareStore.notifyDataSetChanged();
if (adapterSoftwareStore != null) {
adapterSoftwareStore.submitList(listSearchData);
}
}
}

View file

@ -7,6 +7,7 @@ import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
@ -35,6 +36,7 @@ public class RomStoreFragment extends Fragment {
HomeRomStoreViewModel homeRomStoreViewModel;
RomStoreHomeAdpater mAdapter;
List<DataRoms> data = new ArrayList<>();
LinearLayoutManager layoutManager;
public static RomStoreCallToHomeListener romStoreCallToHomeListener;
public interface RomStoreCallToHomeListener {
@ -62,8 +64,23 @@ public class RomStoreFragment extends Fragment {
super.onViewCreated(view, savedInstanceState);
mAdapter = new RomStoreHomeAdpater(getContext(), data, false);
layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
binding.rvRomlist.setAdapter(mAdapter);
binding.rvRomlist.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
binding.rvRomlist.setLayoutManager(layoutManager);
binding.rvRomlist.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int totalItemCount = layoutManager.getItemCount();
int lastVisibleItem = layoutManager.findLastVisibleItemPosition();
if (lastVisibleItem >= totalItemCount - 2) {
mAdapter.loadMore();
}
}
});
homeRomStoreViewModel = new ViewModelProvider(requireActivity()).get(HomeRomStoreViewModel.class);
homeRomStoreViewModel.getRomsList().observe(getViewLifecycleOwner(), roms -> {
@ -71,9 +88,7 @@ public class RomStoreFragment extends Fragment {
loadFromServer();
} else {
binding.linearload.setVisibility(View.GONE);
data.clear();
data.addAll(roms);
mAdapter.notifyDataSetChanged();
mAdapter.submitList(roms);
}
});
}
@ -121,7 +136,9 @@ public class RomStoreFragment extends Fragment {
homeRomStoreViewModel.setRomsList(dataRoms);
data.clear();
data.addAll(dataRoms);
mAdapter.notifyDataSetChanged();
mAdapter.submitList(data);
SharedData.dataRomStore.addAll(dataRoms);
romStoreCallToHomeListener.updateSearchStatus(true);
}

View file

@ -19,19 +19,23 @@ import com.vectras.vm.R;
import com.vectras.vm.RomInfo;
import com.vectras.vm.utils.UIUtils;
import java.util.ArrayList;
import java.util.List;
public class RomStoreHomeAdpater extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final Context context;
private final LayoutInflater inflater;
private final List<DataRoms> dataRom;
private List<DataRoms> fullList;
private final List<DataRoms> displayList;
private final boolean isBrighterItemBackground;
public RomStoreHomeAdpater(Context context, List<DataRoms> data, boolean isBrighterItemBackground) {
this.context = context;
inflater = LayoutInflater.from(context);
dataRom = data;
fullList = data;
this.isBrighterItemBackground = isBrighterItemBackground;
displayList = new ArrayList<>();
loadMore();
}
// Inflate the layout when viewholder created
@ -49,7 +53,7 @@ public class RomStoreHomeAdpater extends RecyclerView.Adapter<RecyclerView.ViewH
// Get current position of item in recyclerview to bind data and assign values from list
final MyHolder myHolder = (MyHolder) holder;
final DataRoms current = dataRom.get(position);
final DataRoms current = displayList.get(position);
Glide.with(context).load(current.romIcon).override(180, 180).placeholder(R.drawable.ic_computer_180dp_with_padding).error(R.drawable.ic_computer_180dp_with_padding).into(myHolder.ivIcon);
myHolder.textName.setText(current.romName);
myHolder.textSize.setText(current.romArch + " - " + current.fileSize);
@ -79,13 +83,13 @@ public class RomStoreHomeAdpater extends RecyclerView.Adapter<RecyclerView.ViewH
myHolder.textAvail.setTextColor(Color.RED);
}
UIUtils.setBackgroundItemInList(myHolder.linearItem, position, dataRom.size(), isBrighterItemBackground);
UIUtils.setBackgroundItemInList(myHolder.linearItem, position, displayList.size(), isBrighterItemBackground);
}
// return total item from List
@Override
public int getItemCount() {
return dataRom == null ? 0 : dataRom.size();
return displayList == null ? 0 : displayList.size();
}
static class MyHolder extends RecyclerView.ViewHolder {
@ -106,4 +110,24 @@ public class RomStoreHomeAdpater extends RecyclerView.Adapter<RecyclerView.ViewH
}
}
public void loadMore() {
int currentSize = displayList.size();
int nextLimit = Math.min(currentSize + 10, fullList.size());
if (currentSize >= nextLimit) return;
displayList.addAll(fullList.subList(currentSize, nextLimit));
notifyItemRangeInserted(currentSize, nextLimit - currentSize);
}
public void submitList(List<DataRoms> newData) {
fullList.clear();
fullList = new ArrayList<>(newData);
displayList.clear();
notifyDataSetChanged();
loadMore();
}
}

View file

@ -7,6 +7,7 @@ import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
@ -19,7 +20,6 @@ import com.vectras.vm.AppConfig;
import com.vectras.vm.main.romstore.DataRoms;
import com.vectras.vm.databinding.FragmentHomeSoftwareStoreBinding;
import com.vectras.vm.main.core.SharedData;
import com.vectras.vm.main.romstore.RomStoreFragment;
import com.vectras.vm.network.RequestNetwork;
import com.vectras.vm.network.RequestNetworkController;
@ -37,8 +37,9 @@ public class SoftwareStoreFragment extends Fragment {
SoftwareStoreViewModel homeSoftwareStoreViewModel;
SoftwareStoreHomeAdapter mAdapter;
List<DataRoms> data = new ArrayList<>();
LinearLayoutManager layoutManager;
public static RomStoreFragment.RomStoreCallToHomeListener softwareStoreCallToHomeListener;
public static SoftwareStoreFragment.SoftwareStoreCallToHomeListener softwareStoreCallToHomeListener;
public interface SoftwareStoreCallToHomeListener {
void updateSearchStatus(boolean isReady);
}
@ -64,8 +65,23 @@ public class SoftwareStoreFragment extends Fragment {
super.onViewCreated(view, savedInstanceState);
mAdapter = new SoftwareStoreHomeAdapter(getContext(), data, false);
layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
binding.rvSoftwarelist.setAdapter(mAdapter);
binding.rvSoftwarelist.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
binding.rvSoftwarelist.setLayoutManager(layoutManager);
binding.rvSoftwarelist.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int totalItemCount = layoutManager.getItemCount();
int lastVisibleItem = layoutManager.findLastVisibleItemPosition();
if (lastVisibleItem >= totalItemCount - 2) {
mAdapter.loadMore();
}
}
});
homeSoftwareStoreViewModel = new ViewModelProvider(requireActivity()).get(SoftwareStoreViewModel.class);
homeSoftwareStoreViewModel.getSoftwareList().observe(getViewLifecycleOwner(), roms -> {
@ -73,9 +89,7 @@ public class SoftwareStoreFragment extends Fragment {
loadFromServer();
} else {
binding.linearload.setVisibility(View.GONE);
data.clear();
data.addAll(roms);
mAdapter.notifyDataSetChanged();
mAdapter.submitList(roms);
}
});
}
@ -123,7 +137,9 @@ public class SoftwareStoreFragment extends Fragment {
homeSoftwareStoreViewModel.setSoftwareList(dataSoftware);
data.clear();
data.addAll(dataSoftware);
mAdapter.notifyDataSetChanged();
mAdapter.submitList(data);
SharedData.dataSoftwareStore.addAll(dataSoftware);
softwareStoreCallToHomeListener.updateSearchStatus(true);
}

View file

@ -20,19 +20,23 @@ import com.vectras.vm.RomInfo;
import com.vectras.vm.main.romstore.DataRoms;
import com.vectras.vm.utils.UIUtils;
import java.util.ArrayList;
import java.util.List;
public class SoftwareStoreHomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final Context context;
private final LayoutInflater inflater;
private final List<DataRoms> dataRom;
private List<DataRoms> fullList;
private final List<DataRoms> displayList;
private final boolean isBrighterItemBackground;
public SoftwareStoreHomeAdapter(Context context, List<DataRoms> data, boolean isBrighterItemBackground) {
this.context = context;
inflater = LayoutInflater.from(context);
dataRom = data;
fullList = data;
this.isBrighterItemBackground = isBrighterItemBackground;
displayList = new ArrayList<>();
loadMore();
}
// Inflate the layout when viewholder created
@ -50,7 +54,7 @@ public class SoftwareStoreHomeAdapter extends RecyclerView.Adapter<RecyclerView.
// Get current position of item in recyclerview to bind data and assign values from list
final MyHolder myHolder = (MyHolder) holder;
final DataRoms current = dataRom.get(position);
final DataRoms current = displayList.get(position);
Glide.with(context).load(current.romIcon).override(180, 180).placeholder(R.drawable.ic_computer_180dp_with_padding).error(R.drawable.ic_computer_180dp_with_padding).into(myHolder.ivIcon);
myHolder.textName.setText(current.romName);
myHolder.textSize.setText(current.romSize);
@ -80,13 +84,13 @@ public class SoftwareStoreHomeAdapter extends RecyclerView.Adapter<RecyclerView.
myHolder.textAvail.setTextColor(Color.RED);
}
UIUtils.setBackgroundItemInList(myHolder.linearItem, position, dataRom.size(), isBrighterItemBackground);
UIUtils.setBackgroundItemInList(myHolder.linearItem, position, displayList.size(), isBrighterItemBackground);
}
// return total item from List
@Override
public int getItemCount() {
return dataRom == null ? 0 : dataRom.size();
return displayList == null ? 0 : displayList.size();
}
static class MyHolder extends RecyclerView.ViewHolder {
@ -107,4 +111,24 @@ public class SoftwareStoreHomeAdapter extends RecyclerView.Adapter<RecyclerView.
}
}
public void loadMore() {
int currentSize = displayList.size();
int nextLimit = Math.min(currentSize + 10, fullList.size());
if (currentSize >= nextLimit) return;
displayList.addAll(fullList.subList(currentSize, nextLimit));
notifyItemRangeInserted(currentSize, nextLimit - currentSize);
}
public void submitList(List<DataRoms> newData) {
fullList.clear();
fullList = new ArrayList<>(newData);
displayList.clear();
notifyDataSetChanged();
loadMore();
}
}

View file

@ -78,7 +78,7 @@ public class DialogUtils {
positiveButton.setOnClickListener(v -> {
if (_onPositive != null) _onPositive.run();
dialog.dismiss();
safeDismiss((Activity) context, dialog);
});
// dialog.setPositiveButton(_textPositiveButton, (dialog2, which) -> {
@ -139,12 +139,12 @@ public class DialogUtils {
positiveButton.setOnClickListener(v -> {
if (_onPositive != null) _onPositive.run();
dialog.dismiss();
safeDismiss((Activity) context, dialog);
});
negativeButton.setOnClickListener(v -> {
if (_onNegative != null) _onNegative.run();
dialog.dismiss();
safeDismiss((Activity) context, dialog);
});
// dialog.setPositiveButton(_textPositiveButton, (dialog2, which) -> {
// if (_onPositive != null) _onPositive.run();
@ -208,17 +208,17 @@ public class DialogUtils {
positiveButton.setOnClickListener(v -> {
if (_onPositive != null) _onPositive.run();
dialog.dismiss();
safeDismiss((Activity) context, dialog);
});
negativeButton.setOnClickListener(v -> {
if (_onNegative != null) _onNegative.run();
dialog.dismiss();
safeDismiss((Activity) context, dialog);
});
neutralButton.setOnClickListener(v -> {
if (_onNeutral != null) _onNeutral.run();
dialog.dismiss();
safeDismiss((Activity) context, dialog);
});
// dialog.setPositiveButton(_textPositiveButton, (dialog2, which) -> {