Android: Move game list over to RecyclerView
This commit is contained in:
parent
5bd39bc2c7
commit
7b45df0cc2
|
@ -17,6 +17,7 @@ import androidx.annotation.Nullable;
|
|||
import androidx.appcompat.widget.PopupMenu;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
|
|
@ -19,12 +19,10 @@ public class GameList {
|
|||
|
||||
private Activity mContext;
|
||||
private GameListEntry[] mEntries;
|
||||
private ListViewAdapter mAdapter;
|
||||
private ArrayList<OnRefreshListener> mRefreshListeners = new ArrayList<>();
|
||||
|
||||
public GameList(Activity context) {
|
||||
mContext = context;
|
||||
mAdapter = new ListViewAdapter();
|
||||
mEntries = new GameListEntry[0];
|
||||
}
|
||||
|
||||
|
@ -58,7 +56,6 @@ public class GameList {
|
|||
e.printStackTrace();
|
||||
}
|
||||
mEntries = newEntries;
|
||||
mAdapter.notifyDataSetChanged();
|
||||
for (OnRefreshListener listener : mRefreshListeners)
|
||||
listener.onGameListRefresh();
|
||||
});
|
||||
|
@ -72,41 +69,4 @@ public class GameList {
|
|||
public GameListEntry getEntry(int index) {
|
||||
return mEntries[index];
|
||||
}
|
||||
|
||||
private class ListViewAdapter extends BaseAdapter {
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mEntries.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return mEntries[position];
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewTypeCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = LayoutInflater.from(mContext)
|
||||
.inflate(R.layout.game_list_view_entry, parent, false);
|
||||
}
|
||||
|
||||
mEntries[position].fillView(convertView);
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
|
||||
public BaseAdapter getListViewAdapter() {
|
||||
return mAdapter;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,6 +80,8 @@ public class GameListEntry {
|
|||
return mFileTitle;
|
||||
}
|
||||
|
||||
public long getSize() { return mSize; }
|
||||
|
||||
public String getModifiedTime() {
|
||||
return mModifiedTime;
|
||||
}
|
||||
|
@ -105,88 +107,4 @@ public class GameListEntry {
|
|||
else
|
||||
return path;
|
||||
}
|
||||
|
||||
private String getSubTitle() {
|
||||
String fileName = getFileNameForPath(mPath);
|
||||
String sizeString = String.format("%.2f MB", (double) mSize / 1048576.0);
|
||||
return String.format("%s (%s)", fileName, sizeString);
|
||||
}
|
||||
|
||||
public void fillView(View view) {
|
||||
((TextView) view.findViewById(R.id.game_list_view_entry_title)).setText(mTitle);
|
||||
((TextView) view.findViewById(R.id.game_list_view_entry_subtitle)).setText(getSubTitle());
|
||||
|
||||
int regionDrawableId;
|
||||
switch (mRegion) {
|
||||
case NTSC_J:
|
||||
regionDrawableId = R.drawable.flag_jp;
|
||||
break;
|
||||
case PAL:
|
||||
regionDrawableId = R.drawable.flag_eu;
|
||||
break;
|
||||
case Other:
|
||||
regionDrawableId = R.drawable.ic_baseline_help_24;
|
||||
break;
|
||||
case NTSC_U:
|
||||
default:
|
||||
regionDrawableId = R.drawable.flag_us;
|
||||
break;
|
||||
}
|
||||
|
||||
((ImageView) view.findViewById(R.id.game_list_view_entry_region_icon))
|
||||
.setImageDrawable(ContextCompat.getDrawable(view.getContext(), regionDrawableId));
|
||||
|
||||
int typeDrawableId;
|
||||
switch (mType) {
|
||||
case PSExe:
|
||||
typeDrawableId = R.drawable.ic_emblem_system;
|
||||
break;
|
||||
|
||||
case Playlist:
|
||||
typeDrawableId = R.drawable.ic_baseline_playlist_play_24;
|
||||
break;
|
||||
|
||||
case PSF:
|
||||
typeDrawableId = R.drawable.ic_baseline_library_music_24;
|
||||
break;
|
||||
|
||||
case Disc:
|
||||
default:
|
||||
typeDrawableId = R.drawable.ic_media_cdrom;
|
||||
break;
|
||||
}
|
||||
|
||||
ImageView icon = ((ImageView) view.findViewById(R.id.game_list_view_entry_type_icon));
|
||||
icon.setImageDrawable(ContextCompat.getDrawable(view.getContext(), typeDrawableId));
|
||||
|
||||
if (mCoverPath != null) {
|
||||
new ImageLoadTask(icon).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mCoverPath);
|
||||
}
|
||||
|
||||
int compatibilityDrawableId;
|
||||
switch (mCompatibilityRating) {
|
||||
case DoesntBoot:
|
||||
compatibilityDrawableId = R.drawable.ic_star_1;
|
||||
break;
|
||||
case CrashesInIntro:
|
||||
compatibilityDrawableId = R.drawable.ic_star_2;
|
||||
break;
|
||||
case CrashesInGame:
|
||||
compatibilityDrawableId = R.drawable.ic_star_3;
|
||||
break;
|
||||
case GraphicalAudioIssues:
|
||||
compatibilityDrawableId = R.drawable.ic_star_4;
|
||||
break;
|
||||
case NoIssues:
|
||||
compatibilityDrawableId = R.drawable.ic_star_5;
|
||||
break;
|
||||
case Unknown:
|
||||
default:
|
||||
compatibilityDrawableId = R.drawable.ic_star_0;
|
||||
break;
|
||||
}
|
||||
|
||||
((ImageView) view.findViewById(R.id.game_list_view_compatibility_icon))
|
||||
.setImageDrawable(ContextCompat.getDrawable(view.getContext(), compatibilityDrawableId));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,29 @@
|
|||
package com.github.stenzek.duckstation;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public class GameListFragment extends Fragment {
|
||||
public class GameListFragment extends Fragment implements GameList.OnRefreshListener {
|
||||
private MainActivity mParent;
|
||||
private ListView mGameListView;
|
||||
private RecyclerView mRecyclerView;
|
||||
private GameListFragment.ViewAdapter mAdapter;
|
||||
|
||||
public GameListFragment(MainActivity parent) {
|
||||
super(R.layout.fragment_game_list);
|
||||
|
@ -29,40 +38,190 @@ public class GameListFragment extends Fragment {
|
|||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
mGameListView = view.findViewById(R.id.game_list_view);
|
||||
mGameListView.setAdapter(getGameList().getListViewAdapter());
|
||||
mGameListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
mParent.startEmulation(getGameList().getEntry(position).getPath(), mParent.shouldResumeStateByDefault());
|
||||
mAdapter = new GameListFragment.ViewAdapter(mParent, getGameList());
|
||||
getGameList().addRefreshListener(this);
|
||||
|
||||
mRecyclerView = view.findViewById(R.id.game_list_view);
|
||||
mRecyclerView.setAdapter(mAdapter);
|
||||
mRecyclerView.setLayoutManager(new LinearLayoutManager(mParent));
|
||||
mRecyclerView.addItemDecoration(new DividerItemDecoration(mRecyclerView.getContext(),
|
||||
DividerItemDecoration.VERTICAL));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
|
||||
getGameList().removeRefreshListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGameListRefresh() {
|
||||
mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||
private MainActivity mParent;
|
||||
private View mItemView;
|
||||
private GameListEntry mEntry;
|
||||
|
||||
public ViewHolder(@NonNull MainActivity parent, @NonNull View itemView) {
|
||||
super(itemView);
|
||||
mParent = parent;
|
||||
mItemView = itemView;
|
||||
mItemView.setOnClickListener(this);
|
||||
mItemView.setOnLongClickListener(this);
|
||||
}
|
||||
|
||||
private String getSubTitle() {
|
||||
String fileName = GameListEntry.getFileNameForPath(mEntry.getPath());
|
||||
String sizeString = String.format("%.2f MB", (double) mEntry.getSize() / 1048576.0);
|
||||
return String.format("%s (%s)", fileName, sizeString);
|
||||
}
|
||||
|
||||
public void bindToEntry(GameListEntry entry) {
|
||||
mEntry = entry;
|
||||
|
||||
((TextView) mItemView.findViewById(R.id.game_list_view_entry_title)).setText(entry.getTitle());
|
||||
((TextView) mItemView.findViewById(R.id.game_list_view_entry_subtitle)).setText(getSubTitle());
|
||||
|
||||
int regionDrawableId;
|
||||
switch (entry.getRegion()) {
|
||||
case NTSC_J:
|
||||
regionDrawableId = R.drawable.flag_jp;
|
||||
break;
|
||||
case PAL:
|
||||
regionDrawableId = R.drawable.flag_eu;
|
||||
break;
|
||||
case Other:
|
||||
regionDrawableId = R.drawable.ic_baseline_help_24;
|
||||
break;
|
||||
case NTSC_U:
|
||||
default:
|
||||
regionDrawableId = R.drawable.flag_us;
|
||||
break;
|
||||
}
|
||||
});
|
||||
mGameListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
|
||||
@Override
|
||||
public boolean onItemLongClick(AdapterView<?> parent, View view, int position,
|
||||
long id) {
|
||||
PopupMenu menu = new PopupMenu(getContext(), view, Gravity.RIGHT | Gravity.TOP);
|
||||
menu.getMenuInflater().inflate(R.menu.menu_game_list_entry, menu.getMenu());
|
||||
menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
if (id == R.id.game_list_entry_menu_start_game) {
|
||||
mParent.startEmulation(getGameList().getEntry(position).getPath(), false);
|
||||
return true;
|
||||
} else if (id == R.id.game_list_entry_menu_resume_game) {
|
||||
mParent.startEmulation(getGameList().getEntry(position).getPath(), true);
|
||||
return true;
|
||||
} else if (id == R.id.game_list_entry_menu_properties) {
|
||||
mParent.openGameProperties(getGameList().getEntry(position).getPath());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
((ImageView) mItemView.findViewById(R.id.game_list_view_entry_region_icon))
|
||||
.setImageDrawable(ContextCompat.getDrawable(mItemView.getContext(), regionDrawableId));
|
||||
|
||||
int typeDrawableId;
|
||||
switch (entry.getType()) {
|
||||
case PSExe:
|
||||
typeDrawableId = R.drawable.ic_emblem_system;
|
||||
break;
|
||||
|
||||
case Playlist:
|
||||
typeDrawableId = R.drawable.ic_baseline_playlist_play_24;
|
||||
break;
|
||||
|
||||
case PSF:
|
||||
typeDrawableId = R.drawable.ic_baseline_library_music_24;
|
||||
break;
|
||||
|
||||
case Disc:
|
||||
default:
|
||||
typeDrawableId = R.drawable.ic_media_cdrom;
|
||||
break;
|
||||
}
|
||||
|
||||
ImageView icon = ((ImageView) mItemView.findViewById(R.id.game_list_view_entry_type_icon));
|
||||
icon.setImageDrawable(ContextCompat.getDrawable(mItemView.getContext(), typeDrawableId));
|
||||
|
||||
final String coverPath = entry.getCoverPath();
|
||||
if (coverPath != null) {
|
||||
new ImageLoadTask(icon).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, coverPath);
|
||||
}
|
||||
|
||||
int compatibilityDrawableId;
|
||||
switch (entry.getCompatibilityRating()) {
|
||||
case DoesntBoot:
|
||||
compatibilityDrawableId = R.drawable.ic_star_1;
|
||||
break;
|
||||
case CrashesInIntro:
|
||||
compatibilityDrawableId = R.drawable.ic_star_2;
|
||||
break;
|
||||
case CrashesInGame:
|
||||
compatibilityDrawableId = R.drawable.ic_star_3;
|
||||
break;
|
||||
case GraphicalAudioIssues:
|
||||
compatibilityDrawableId = R.drawable.ic_star_4;
|
||||
break;
|
||||
case NoIssues:
|
||||
compatibilityDrawableId = R.drawable.ic_star_5;
|
||||
break;
|
||||
case Unknown:
|
||||
default:
|
||||
compatibilityDrawableId = R.drawable.ic_star_0;
|
||||
break;
|
||||
}
|
||||
|
||||
((ImageView) mItemView.findViewById(R.id.game_list_view_compatibility_icon))
|
||||
.setImageDrawable(ContextCompat.getDrawable(mItemView.getContext(), compatibilityDrawableId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mParent.startEmulation(mEntry.getPath(), mParent.shouldResumeStateByDefault());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
androidx.appcompat.widget.PopupMenu menu = new androidx.appcompat.widget.PopupMenu(mParent, v, Gravity.RIGHT | Gravity.TOP);
|
||||
menu.getMenuInflater().inflate(R.menu.menu_game_list_entry, menu.getMenu());
|
||||
menu.setOnMenuItemClickListener(new androidx.appcompat.widget.PopupMenu.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
if (id == R.id.game_list_entry_menu_start_game) {
|
||||
mParent.startEmulation(mEntry.getPath(), false);
|
||||
return true;
|
||||
} else if (id == R.id.game_list_entry_menu_resume_game) {
|
||||
mParent.startEmulation(mEntry.getPath(), true);
|
||||
return true;
|
||||
} else if (id == R.id.game_list_entry_menu_properties) {
|
||||
mParent.openGameProperties(mEntry.getPath());
|
||||
return true;
|
||||
}
|
||||
});
|
||||
menu.show();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
});
|
||||
menu.show();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ViewAdapter extends RecyclerView.Adapter<GameListFragment.ViewHolder> {
|
||||
private MainActivity mParent;
|
||||
private LayoutInflater mInflater;
|
||||
private GameList mGameList;
|
||||
|
||||
public ViewAdapter(@NonNull MainActivity parent, @NonNull GameList gameList) {
|
||||
mParent = parent;
|
||||
mInflater = LayoutInflater.from(parent);
|
||||
mGameList = gameList;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public GameListFragment.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
return new GameListFragment.ViewHolder(mParent, mInflater.inflate(R.layout.layout_game_list_entry, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull GameListFragment.ViewHolder holder, int position) {
|
||||
GameListEntry entry = mGameList.getEntry(position);
|
||||
holder.bindToEntry(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mGameList.getEntryCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
return R.layout.layout_game_list_entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ListView
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/game_list_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
|
|
@ -4,14 +4,17 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/linearLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:background="?android:attr/selectableItemBackground">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/game_list_view_entry_type_icon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:foregroundGravity="center_vertical"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:srcCompat="@drawable/ic_media_cdrom" />
|
||||
|
@ -21,7 +24,6 @@
|
|||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginRight="80dp"
|
||||
android:focusable="false"
|
||||
android:focusableInTouchMode="false"
|
||||
|
@ -50,7 +52,6 @@
|
|||
android:id="@+id/game_list_view_compatibility_icon"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:focusable="false"
|
||||
android:focusableInTouchMode="false"
|
||||
|
|
Loading…
Reference in New Issue