Bladeren bron

Implement game selector.

Item selection is currently not implemented.
Miku AuahDark 3 jaren geleden
bovenliggende
commit
cee0ca9661

+ 70 - 0
app/src/normal/java/org/love2d/android/GameListAdapter.java

@@ -0,0 +1,70 @@
+package org.love2d.android;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.io.File;
+
+public class GameListAdapter extends RecyclerView.Adapter<GameListAdapter.ViewHolder> {
+
+    private Data[] data = null;
+
+    @NonNull
+    @Override
+    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_game, parent, false);
+        ViewHolder holder = new ViewHolder(view);
+
+        return holder;
+    }
+
+    @Override
+    public void onBindViewHolder(ViewHolder holder, int position) {
+        Data data = this.data[position];
+        holder.setName(data.path.getName());
+        holder.setIsDirectory(data.directory);
+    }
+
+    @Override
+    public int getItemCount() {
+        return data != null ? data.length : 0;
+    }
+
+    public void setData(Data[] data) {
+        this.data = data;
+    }
+
+    static class ViewHolder extends RecyclerView.ViewHolder {
+
+        private final TextView name;
+        private final ImageView image;
+
+        public ViewHolder(View itemView) {
+            super(itemView);
+
+            name = itemView.findViewById(R.id.textView);
+            image = itemView.findViewById(R.id.imageView);
+        }
+
+        public void setName(String name) {
+            this.name.setText(name);
+        }
+
+        public void setIsDirectory(boolean directory) {
+            this.image.setImageResource(directory ? R.drawable.ic_baseline_folder_32 : R.drawable.ic_baseline_insert_drive_file_32);
+        }
+    }
+
+    static class Data {
+        // Absolute path of the file.
+        public File path;
+        // Denote if this game is a directory.
+        public boolean directory;
+    }
+}

+ 115 - 2
app/src/normal/java/org/love2d/android/MainActivity.java

@@ -2,6 +2,9 @@ package org.love2d.android;
 
 import androidx.appcompat.app.AlertDialog;
 import androidx.appcompat.app.AppCompatActivity;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
 import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
 
 import android.content.Intent;
@@ -10,19 +13,40 @@ import android.os.Bundle;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
+import android.view.View;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.zip.ZipFile;
 
 public class MainActivity extends AppCompatActivity {
 
+    private Executor executor = Executors.newSingleThreadExecutor();
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
 
+        RecyclerView recyclerView = findViewById(R.id.recyclerView);
         SwipeRefreshLayout swipeLayout = findViewById(R.id.swipeRefreshLayout);
+        ConstraintLayout noGameText = findViewById(R.id.constraintLayout);
+
+        GameListAdapter adapter = new GameListAdapter();
+
+            // Set refresh listener
         swipeLayout.setOnRefreshListener(() -> {
-            // TODO: Actually update list of games
-            swipeLayout.setRefreshing(false);
+            scanGames(adapter, noGameText, swipeLayout);
         });
+
+        // Set layout manager and adapter
+        recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
+        recyclerView.setAdapter(adapter);
+
+        scanGames(adapter, noGameText, null);
     }
 
     @Override
@@ -69,4 +93,93 @@ public class MainActivity extends AppCompatActivity {
 
         return builder.setMessage(message.toString()).create();
     }
+
+    private void scanGames(GameListAdapter adapter, ConstraintLayout noGameText, SwipeRefreshLayout swipeRefreshLayout) {
+        final MainActivity current = this;
+
+        executor.execute(() -> {
+            File extDir = getExternalFilesDir("games");
+
+            if (!extDir.isDirectory()) {
+                if (!extDir.mkdir()) {
+                    // Scan failure, abort
+                    if (swipeRefreshLayout != null) {
+                        swipeRefreshLayout.setRefreshing(false);
+                    }
+
+                    new AlertDialog.Builder(current)
+                        .setTitle("Scan error")
+                        .setMessage("Scan failure")
+                        .setPositiveButton(R.string.ok, (dialog1, which) -> { })
+                        .create()
+                        .show();
+                    return;
+                }
+            }
+
+            ArrayList<GameListAdapter.Data> validGames = new ArrayList<>();
+            File[] files = extDir.listFiles();
+
+            if (files != null) {
+                for (File file: files) {
+                    GameListAdapter.Data gameData = null;
+
+                    if (file.isDirectory()) {
+                        if (isValidGamedir(file)) {
+                            gameData = new GameListAdapter.Data();
+                            gameData.path = file;
+                            gameData.directory = true;
+                        }
+                    } else {
+                        if (isValidLovegame(file)) {
+                            gameData = new GameListAdapter.Data();
+                            gameData.path = file;
+                            gameData.directory = false;
+                        }
+                    }
+
+                    if (gameData != null) {
+                        validGames.add(gameData);
+                    }
+                }
+            }
+
+            boolean empty = validGames.isEmpty();
+
+            runOnUiThread(() -> {
+                if (empty) {
+                    adapter.setData(null);
+                } else {
+                    GameListAdapter.Data[] gameDatas = new GameListAdapter.Data[validGames.size()];
+                    validGames.toArray(gameDatas);
+                    adapter.setData(gameDatas);
+                }
+
+                adapter.notifyDataSetChanged();
+
+                if (swipeRefreshLayout != null) {
+                    swipeRefreshLayout.setRefreshing(false);
+                }
+
+                noGameText.setVisibility(empty ? View.VISIBLE : View.INVISIBLE);
+            });
+        });
+    }
+
+    public static boolean isValidLovegame(File file) {
+        boolean valid = false;
+
+        try {
+            ZipFile zip = new ZipFile(file, ZipFile.OPEN_READ);
+            valid = zip.getEntry("main.lua") != null;
+            zip.close();
+        } catch (IOException ignored) { }
+
+        return valid;
+    }
+
+    public static boolean isValidGamedir(File file) {
+        File mainLua = new File(file, "main.lua");
+        return mainLua.isFile();
+    }
 }

+ 2 - 0
app/src/normal/res/layout/activity_main.xml

@@ -12,6 +12,7 @@
         android:layout_height="match_parent">
 
         <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/recyclerView"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             tools:listitem="@layout/row_game">
@@ -20,6 +21,7 @@
     </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
 
     <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/constraintLayout"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:padding="8dp"