add list of minio objects
parent
bed1f84a9d
commit
24c7629cc9
|
|
@ -3,7 +3,8 @@
|
||||||
<component name="DesignSurface">
|
<component name="DesignSurface">
|
||||||
<option name="filePathToZoomLevelMap">
|
<option name="filePathToZoomLevelMap">
|
||||||
<map>
|
<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.xml" value="0.3353846153846154" />
|
||||||
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml" value="0.3353846153846154" />
|
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml" value="0.3353846153846154" />
|
||||||
</map>
|
</map>
|
||||||
|
|
|
||||||
|
|
@ -17,20 +17,33 @@ import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.core.content.FileProvider;
|
import androidx.core.content.FileProvider;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import io.minio.BucketExistsArgs;
|
import io.minio.BucketExistsArgs;
|
||||||
|
import io.minio.ListObjectsArgs;
|
||||||
import io.minio.MakeBucketArgs;
|
import io.minio.MakeBucketArgs;
|
||||||
import io.minio.MinioClient;
|
import io.minio.MinioClient;
|
||||||
|
import io.minio.Result;
|
||||||
import io.minio.UploadObjectArgs;
|
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.MinioException;
|
||||||
|
import io.minio.errors.ServerException;
|
||||||
|
import io.minio.errors.XmlParserException;
|
||||||
|
import io.minio.messages.Item;
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
|
@ -41,6 +54,9 @@ public class MainActivity extends AppCompatActivity {
|
||||||
private MinioClient minio;
|
private MinioClient minio;
|
||||||
private String bucket;
|
private String bucket;
|
||||||
private ActivityResultLauncher<Intent> photoLauncher;
|
private ActivityResultLauncher<Intent> photoLauncher;
|
||||||
|
private RecyclerView objectList;
|
||||||
|
private ArrayList<String> objectNames;
|
||||||
|
private ObjectListAdapter objectListAdapter;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -48,6 +64,14 @@ public class MainActivity extends AppCompatActivity {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
thumb = findViewById(R.id.imageView);
|
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()
|
minio = MinioClient.builder()
|
||||||
.endpoint(getString(R.string.minio_host))
|
.endpoint(getString(R.string.minio_host))
|
||||||
.credentials(getString(R.string.minio_access_key), getString(R.string.minio_secret_key))
|
.credentials(getString(R.string.minio_access_key), getString(R.string.minio_secret_key))
|
||||||
|
|
@ -63,10 +87,36 @@ public class MainActivity extends AppCompatActivity {
|
||||||
handlePhotoCallback();
|
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) {
|
private static void checkOrCreateBucket(MinioClient client, String bucket) {
|
||||||
Runnable check = () -> { // lambda syntax: short for `new Runnable{}`
|
Runnable check = () -> { // lambda syntax: short for `new Runnable{}`
|
||||||
|
// network IO is not allowed in UI-Thread, needs to be run separately
|
||||||
try {
|
try {
|
||||||
boolean isPresent = client.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
|
boolean isPresent = client.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
|
||||||
if (!isPresent) {
|
if (!isPresent) {
|
||||||
|
|
@ -80,6 +130,7 @@ public class MainActivity extends AppCompatActivity {
|
||||||
Log.e(TAG, "something went wrong with minio", e);
|
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();
|
new Thread(check).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -137,7 +188,7 @@ public class MainActivity extends AppCompatActivity {
|
||||||
Runnable upload = () -> {
|
Runnable upload = () -> {
|
||||||
|
|
||||||
try {
|
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());
|
minio.uploadObject(UploadObjectArgs.builder().bucket(bucket).object(filename).filename(currentPhotoPath).build());
|
||||||
} catch (InvalidKeyException | IOException | NoSuchAlgorithmException | MinioException e) {
|
} catch (InvalidKeyException | IOException | NoSuchAlgorithmException | MinioException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|
@ -145,6 +196,7 @@ public class MainActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
new Thread(upload).start();
|
new Thread(upload).start();
|
||||||
|
listObjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onButtonClick(View view) {
|
public void onButtonClick(View view) {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,38 +6,36 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".MainActivity">
|
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
|
<Button
|
||||||
android:id="@+id/button"
|
android:id="@+id/button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="148dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="112dp"
|
android:layout_marginTop="16dp"
|
||||||
android:text="@string/button"
|
|
||||||
android:onClick="onButtonClick"
|
android:onClick="onButtonClick"
|
||||||
|
android:text="@string/button"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:contentDescription="@string/thumbnail"
|
|
||||||
android:id="@+id/imageView"
|
android:id="@+id/imageView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="372dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="259dp"
|
||||||
android:layout_marginStart="40dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginTop="56dp"
|
android:layout_marginTop="36dp"
|
||||||
|
android:adjustViewBounds="false"
|
||||||
|
android:contentDescription="@string/thumbnail"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
app:layout_constraintStart_toStartOf="@+id/button"
|
app:layout_constraintStart_toStartOf="@+id/button"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/button"
|
app:layout_constraintTop_toBottomOf="@+id/button"
|
||||||
app:srcCompat="@android:drawable/ic_dialog_alert"
|
app:srcCompat="@android:drawable/ic_dialog_alert" />
|
||||||
android:adjustViewBounds="false"
|
|
||||||
android:scaleType="fitCenter"
|
<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>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -5,7 +5,7 @@ buildscript {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
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
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue