add list of minio objects

master
agp8x 2021-09-06 11:17:11 +02:00
parent bed1f84a9d
commit 24c7629cc9
6 changed files with 155 additions and 24 deletions

View File

@ -3,7 +3,8 @@
<component name="DesignSurface">
<option name="filePathToZoomLevelMap">
<map>
<entry key="app/src/main/res/layout/activity_main.xml" value="0.1" />
<entry key="app/src/main/res/layout/activity_main.xml" value="0.25" />
<entry key="app/src/main/res/layout/main_object_list_entry.xml" value="0.5505208333333333" />
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml" value="0.3353846153846154" />
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml" value="0.3353846153846154" />
</map>

View File

@ -17,20 +17,33 @@ import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.io.File;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import io.minio.BucketExistsArgs;
import io.minio.ListObjectsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.Result;
import io.minio.UploadObjectArgs;
import io.minio.errors.ErrorResponseException;
import io.minio.errors.InsufficientDataException;
import io.minio.errors.InternalException;
import io.minio.errors.InvalidResponseException;
import io.minio.errors.MinioException;
import io.minio.errors.ServerException;
import io.minio.errors.XmlParserException;
import io.minio.messages.Item;
public class MainActivity extends AppCompatActivity {
@ -41,6 +54,9 @@ public class MainActivity extends AppCompatActivity {
private MinioClient minio;
private String bucket;
private ActivityResultLauncher<Intent> photoLauncher;
private RecyclerView objectList;
private ArrayList<String> objectNames;
private ObjectListAdapter objectListAdapter;
@Override
@ -48,6 +64,14 @@ public class MainActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
thumb = findViewById(R.id.imageView);
// list of all objects in bucket
objectList = findViewById(R.id.objectList);
objectNames = new ArrayList<>();
objectListAdapter = new ObjectListAdapter(objectNames);
objectList.setAdapter(objectListAdapter);
objectList.setLayoutManager(new LinearLayoutManager(this));
minio = MinioClient.builder()
.endpoint(getString(R.string.minio_host))
.credentials(getString(R.string.minio_access_key), getString(R.string.minio_secret_key))
@ -63,10 +87,36 @@ public class MainActivity extends AppCompatActivity {
handlePhotoCallback();
}
});
listObjects();
}
private void listObjects() {
Runnable listObjects = new Runnable() {
@Override
public void run() {
Iterable<Result<Item>> objects = minio.listObjects(ListObjectsArgs.builder().bucket(bucket).prefix("Photos/").build());
objectNames.clear();
for (Result<Item> object : objects) {
try {
Item item = object.get();
objectNames.add(item.objectName());
Log.i(TAG, "list: '" + item.objectName() + "' is dir?: "+ item.isDir());
} catch (InvalidKeyException | IOException | NoSuchAlgorithmException | MinioException e) {
e.printStackTrace();
Log.e(TAG, "something went wrong with minio", e);
}
}
runOnUiThread(() -> {
objectListAdapter.notifyDataSetChanged();
});
}
};
new Thread(listObjects).start();
}
private static void checkOrCreateBucket(MinioClient client, String bucket) {
Runnable check = () -> { // lambda syntax: short for `new Runnable{}`
// network IO is not allowed in UI-Thread, needs to be run separately
try {
boolean isPresent = client.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
if (!isPresent) {
@ -80,6 +130,7 @@ public class MainActivity extends AppCompatActivity {
Log.e(TAG, "something went wrong with minio", e);
}
};
// here, we just start a new Thread. Better: use a service with an interface for separation of concerns
new Thread(check).start();
}
@ -137,7 +188,7 @@ public class MainActivity extends AppCompatActivity {
Runnable upload = () -> {
try {
String filename = currentPhotoPath.substring(currentPhotoPath.lastIndexOf("/"));
String filename = "Photos/" + currentPhotoPath.substring(currentPhotoPath.lastIndexOf("/"));
minio.uploadObject(UploadObjectArgs.builder().bucket(bucket).object(filename).filename(currentPhotoPath).build());
} catch (InvalidKeyException | IOException | NoSuchAlgorithmException | MinioException e) {
e.printStackTrace();
@ -145,6 +196,7 @@ public class MainActivity extends AppCompatActivity {
}
};
new Thread(upload).start();
listObjects();
}
public void onButtonClick(View view) {

View File

@ -0,0 +1,60 @@
package de.clkl.android.miniofotoapp;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.Arrays;
import java.util.List;
public class ObjectListAdapter extends RecyclerView.Adapter<ObjectListAdapter.ViewHolder> {
private List<String> objects;
private static List<String> IMAGE_FILE_TYPES = Arrays.asList(".jpg", ".png");
private static boolean isImage(String name){
return IMAGE_FILE_TYPES.stream().anyMatch(s -> name.toLowerCase().endsWith(s));
}
public ObjectListAdapter(List<String> objects) {
this.objects = objects;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
Context ctx = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(ctx);
View objectView = inflater.inflate(R.layout.main_object_list_entry, parent, false);
ViewHolder viewHolder = new ViewHolder(objectView);
return viewHolder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
String object = objects.get(position);
holder.name.setText(object);
}
@Override
public int getItemCount() {
return objects.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private final TextView name;
private final View thumb;
public ViewHolder(@NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.objectListContent);
thumb = itemView.findViewById(R.id.objectListImage);
}
}
}

View File

@ -6,38 +6,36 @@
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="148dp"
android:layout_marginTop="112dp"
android:text="@string/button"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:onClick="onButtonClick"
android:text="@string/button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:contentDescription="@string/thumbnail"
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="40dp"
android:layout_marginTop="56dp"
android:layout_width="372dp"
android:layout_height="259dp"
android:layout_marginStart="8dp"
android:layout_marginTop="36dp"
android:adjustViewBounds="false"
android:contentDescription="@string/thumbnail"
android:scaleType="fitCenter"
app:layout_constraintStart_toStartOf="@+id/button"
app:layout_constraintTop_toBottomOf="@+id/button"
app:srcCompat="@android:drawable/ic_dialog_alert"
android:adjustViewBounds="false"
android:scaleType="fitCenter"
/>
app:srcCompat="@android:drawable/ic_dialog_alert" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/objectList"
android:layout_width="409dp"
android:layout_height="354dp"
android:layout_marginTop="12dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/objectListContent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<ImageView
android:id="@+id/objectListImage"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_weight="1"
app:srcCompat="@android:drawable/ic_dialog_info" />
</LinearLayout>

View File

@ -5,7 +5,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath "com.android.tools.build:gradle:7.0.1"
classpath 'com.android.tools.build:gradle:7.0.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files