初级相册应用。
This commit is contained in:
@@ -17,10 +17,20 @@ android {
|
|||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildFeatures {
|
||||||
|
viewBinding true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'androidx.appcompat:appcompat:1.0.0'
|
implementation 'androidx.appcompat:appcompat:1.0.0'
|
||||||
implementation 'com.google.android.material:material:1.0.0'
|
implementation 'com.google.android.material:material:1.0.0'
|
||||||
|
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||||
|
implementation 'androidx.cardview:cardview:1.0.0'
|
||||||
|
implementation 'androidx.viewpager:viewpager:1.0.0'
|
||||||
|
implementation 'com.github.bumptech.glide:glide:4.12.0'
|
||||||
|
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
|
||||||
|
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="cc.winboll.gallery">
|
package="cc.winboll.gallery">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
@@ -26,6 +29,18 @@
|
|||||||
|
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".SettingsActivity"
|
||||||
|
android:label="@string/settings_title"/>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".AlbumActivity"
|
||||||
|
android:label="@string/app_name"/>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".ImageViewerActivity"
|
||||||
|
android:label="@string/app_name"/>
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.max_aspect"
|
android:name="android.max_aspect"
|
||||||
android:value="4.0"/>
|
android:value="4.0"/>
|
||||||
|
|||||||
22
app/src/main/java/cc/winboll/gallery/Album.java
Normal file
22
app/src/main/java/cc/winboll/gallery/Album.java
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package cc.winboll.gallery;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
public class Album {
|
||||||
|
private String name;
|
||||||
|
private String path;
|
||||||
|
private Uri coverUri;
|
||||||
|
private int imageCount;
|
||||||
|
|
||||||
|
public Album(String name, String path, Uri coverUri, int imageCount) {
|
||||||
|
this.name = name;
|
||||||
|
this.path = path;
|
||||||
|
this.coverUri = coverUri;
|
||||||
|
this.imageCount = imageCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() { return name; }
|
||||||
|
public String getPath() { return path; }
|
||||||
|
public Uri getCoverUri() { return coverUri; }
|
||||||
|
public int getImageCount() { return imageCount; }
|
||||||
|
}
|
||||||
131
app/src/main/java/cc/winboll/gallery/AlbumActivity.java
Normal file
131
app/src/main/java/cc/winboll/gallery/AlbumActivity.java
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
package cc.winboll.gallery;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.widget.Toast;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
import androidx.core.app.ActivityCompat;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class AlbumActivity extends AppCompatActivity {
|
||||||
|
private static final int PERMISSION_REQUEST_CODE = 101;
|
||||||
|
public static final String EXTRA_ALBUM_PATH = "album_path";
|
||||||
|
public static final String EXTRA_ALBUM_NAME = "album_name";
|
||||||
|
private RecyclerView recyclerView;
|
||||||
|
private ImageAdapter adapter;
|
||||||
|
private String albumPath;
|
||||||
|
private String albumName;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_main);
|
||||||
|
|
||||||
|
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||||
|
setSupportActionBar(toolbar);
|
||||||
|
|
||||||
|
albumPath = getIntent().getStringExtra(EXTRA_ALBUM_PATH);
|
||||||
|
albumName = getIntent().getStringExtra(EXTRA_ALBUM_NAME);
|
||||||
|
|
||||||
|
getSupportActionBar().setTitle(albumName);
|
||||||
|
|
||||||
|
recyclerView = findViewById(R.id.recycler_view);
|
||||||
|
recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
|
||||||
|
adapter = new ImageAdapter();
|
||||||
|
recyclerView.setAdapter(adapter);
|
||||||
|
|
||||||
|
adapter.setOnImageClickListener((position, urls) -> {
|
||||||
|
Intent intent = new Intent(this, ImageViewerActivity.class);
|
||||||
|
intent.putParcelableArrayListExtra(ImageViewerActivity.EXTRA_IMAGE_URLS, urls);
|
||||||
|
intent.putExtra(ImageViewerActivity.EXTRA_POSITION, position);
|
||||||
|
startActivity(intent);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (checkPermission()) {
|
||||||
|
loadImages();
|
||||||
|
} else {
|
||||||
|
requestPermission();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkPermission() {
|
||||||
|
return ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||||
|
== PackageManager.PERMISSION_GRANTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requestPermission() {
|
||||||
|
ActivityCompat.requestPermissions(this,
|
||||||
|
new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE},
|
||||||
|
PERMISSION_REQUEST_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
|
||||||
|
@NonNull int[] grantResults) {
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||||
|
if (requestCode == PERMISSION_REQUEST_CODE) {
|
||||||
|
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
loadImages();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadImages() {
|
||||||
|
ArrayList<Uri> imageUrls = new ArrayList<>();
|
||||||
|
ContentResolver contentResolver = getContentResolver();
|
||||||
|
Uri collection = android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
||||||
|
|
||||||
|
String selection = android.provider.MediaStore.Images.Media.DATA + " LIKE ?";
|
||||||
|
String[] selectionArgs = new String[]{albumPath + "%"};
|
||||||
|
String sortOrder = android.provider.MediaStore.Images.Media.DATE_ADDED + " DESC";
|
||||||
|
|
||||||
|
try (Cursor cursor = contentResolver.query(collection, null, selection, selectionArgs, sortOrder)) {
|
||||||
|
if (cursor != null) {
|
||||||
|
int dataColumn = cursor.getColumnIndexOrThrow(android.provider.MediaStore.Images.Media.DATA);
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
String path = cursor.getString(dataColumn);
|
||||||
|
if (path != null && path.startsWith(albumPath + "/")) {
|
||||||
|
long id = cursor.getLong(cursor.getColumnIndexOrThrow(android.provider.MediaStore.Images.Media._ID));
|
||||||
|
Uri contentUri = Uri.withAppendedPath(collection, String.valueOf(id));
|
||||||
|
imageUrls.add(contentUri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imageUrls.isEmpty()) {
|
||||||
|
Toast.makeText(this, R.string.no_images_found, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
adapter.setData(imageUrls);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
getMenuInflater().inflate(R.menu.menu_main, menu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||||
|
if (item.getItemId() == R.id.action_refresh) {
|
||||||
|
if (checkPermission()) {
|
||||||
|
loadImages();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
71
app/src/main/java/cc/winboll/gallery/AlbumAdapter.java
Normal file
71
app/src/main/java/cc/winboll/gallery/AlbumAdapter.java
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package cc.winboll.gallery;
|
||||||
|
|
||||||
|
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 com.bumptech.glide.Glide;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder> {
|
||||||
|
private ArrayList<Album> albums = new ArrayList<>();
|
||||||
|
private OnAlbumClickListener listener;
|
||||||
|
|
||||||
|
public interface OnAlbumClickListener {
|
||||||
|
void onAlbumClick(Album album);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnAlbumClickListener(OnAlbumClickListener listener) {
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(ArrayList<Album> albums) {
|
||||||
|
this.albums = albums;
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
View view = LayoutInflater.from(parent.getContext())
|
||||||
|
.inflate(R.layout.item_album, parent, false);
|
||||||
|
return new ViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||||
|
Album album = albums.get(position);
|
||||||
|
Glide.with(holder.coverImage.getContext())
|
||||||
|
.load(album.getCoverUri())
|
||||||
|
.centerCrop()
|
||||||
|
.into(holder.coverImage);
|
||||||
|
holder.albumName.setText(album.getName());
|
||||||
|
holder.imageCount.setText(album.getImageCount() + " photos");
|
||||||
|
|
||||||
|
holder.itemView.setOnClickListener(v -> {
|
||||||
|
if (listener != null) {
|
||||||
|
listener.onAlbumClick(album);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return albums.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
ImageView coverImage;
|
||||||
|
TextView albumName;
|
||||||
|
TextView imageCount;
|
||||||
|
ViewHolder(View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
coverImage = itemView.findViewById(R.id.album_cover);
|
||||||
|
albumName = itemView.findViewById(R.id.album_name);
|
||||||
|
imageCount = itemView.findViewById(R.id.image_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
65
app/src/main/java/cc/winboll/gallery/ImageAdapter.java
Normal file
65
app/src/main/java/cc/winboll/gallery/ImageAdapter.java
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package cc.winboll.gallery;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import com.bumptech.glide.Glide;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ViewHolder> {
|
||||||
|
private ArrayList<Uri> imageUrls = new ArrayList<>();
|
||||||
|
private OnImageClickListener listener;
|
||||||
|
|
||||||
|
public interface OnImageClickListener {
|
||||||
|
void onImageClick(int position, ArrayList<Uri> urls);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnImageClickListener(OnImageClickListener listener) {
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(ArrayList<Uri> urls) {
|
||||||
|
this.imageUrls = urls;
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
View view = LayoutInflater.from(parent.getContext())
|
||||||
|
.inflate(R.layout.item_gallery, parent, false);
|
||||||
|
return new ViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||||
|
Glide.with(holder.imageView.getContext())
|
||||||
|
.load(imageUrls.get(position))
|
||||||
|
.centerCrop()
|
||||||
|
.into(holder.imageView);
|
||||||
|
|
||||||
|
holder.imageView.setOnClickListener(v -> {
|
||||||
|
if (listener != null) {
|
||||||
|
listener.onImageClick(position, imageUrls);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return imageUrls.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
ImageView imageView;
|
||||||
|
ViewHolder(View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
imageView = itemView.findViewById(R.id.image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
52
app/src/main/java/cc/winboll/gallery/ImagePagerAdapter.java
Normal file
52
app/src/main/java/cc/winboll/gallery/ImagePagerAdapter.java
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package cc.winboll.gallery;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.viewpager.widget.PagerAdapter;
|
||||||
|
import com.bumptech.glide.Glide;
|
||||||
|
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class ImagePagerAdapter extends PagerAdapter {
|
||||||
|
private ArrayList<Uri> imageUrls;
|
||||||
|
|
||||||
|
public ImagePagerAdapter(ArrayList<Uri> imageUrls) {
|
||||||
|
this.imageUrls = imageUrls;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount() {
|
||||||
|
return imageUrls.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Object instantiateItem(@NonNull ViewGroup container, int position) {
|
||||||
|
View view = LayoutInflater.from(container.getContext())
|
||||||
|
.inflate(R.layout.item_image_pager, container, false);
|
||||||
|
ImageView imageView = view.findViewById(R.id.image);
|
||||||
|
|
||||||
|
Glide.with(imageView.getContext())
|
||||||
|
.load(imageUrls.get(position))
|
||||||
|
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||||
|
.skipMemoryCache(true)
|
||||||
|
.into(imageView);
|
||||||
|
|
||||||
|
container.addView(view);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
|
||||||
|
container.removeView((View) object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
|
||||||
|
return view == object;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package cc.winboll.gallery;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import androidx.viewpager.widget.ViewPager;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class ImageViewerActivity extends Activity implements ViewPager.OnPageChangeListener {
|
||||||
|
public static final String EXTRA_IMAGE_URLS = "image_urls";
|
||||||
|
public static final String EXTRA_POSITION = "position";
|
||||||
|
|
||||||
|
private ArrayList<Uri> imageUrls;
|
||||||
|
private int currentPosition;
|
||||||
|
private ViewPager viewPager;
|
||||||
|
private View toolbar;
|
||||||
|
private ImageButton btnBack;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||||
|
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||||
|
setContentView(R.layout.activity_image_viewer);
|
||||||
|
|
||||||
|
imageUrls = getIntent().getParcelableArrayListExtra(EXTRA_IMAGE_URLS);
|
||||||
|
currentPosition = getIntent().getIntExtra(EXTRA_POSITION, 0);
|
||||||
|
|
||||||
|
viewPager = findViewById(R.id.view_pager);
|
||||||
|
toolbar = findViewById(R.id.toolbar);
|
||||||
|
btnBack = findViewById(R.id.btn_back);
|
||||||
|
|
||||||
|
ImagePagerAdapter adapter = new ImagePagerAdapter(imageUrls);
|
||||||
|
viewPager.setAdapter(adapter);
|
||||||
|
viewPager.setCurrentItem(currentPosition);
|
||||||
|
viewPager.addOnPageChangeListener(this);
|
||||||
|
|
||||||
|
btnBack.setOnClickListener(v -> finish());
|
||||||
|
|
||||||
|
viewPager.setOnClickListener(v -> toggleToolbar());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void toggleToolbar() {
|
||||||
|
if (toolbar.getVisibility() == View.VISIBLE) {
|
||||||
|
toolbar.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
toolbar.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageSelected(int position) {
|
||||||
|
currentPosition = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageScrollStateChanged(int state) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackPressed() {
|
||||||
|
if (viewPager.getCurrentItem() > 0) {
|
||||||
|
viewPager.setCurrentItem(viewPager.getCurrentItem() - 1);
|
||||||
|
} else {
|
||||||
|
super.onBackPressed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,19 +1,169 @@
|
|||||||
package cc.winboll.gallery;
|
package cc.winboll.gallery;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.provider.MediaStore;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.widget.Toast;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.appcompat.widget.Toolbar;
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
import androidx.core.app.ActivityCompat;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
private static final int PERMISSION_REQUEST_CODE = 100;
|
||||||
|
private RecyclerView recyclerView;
|
||||||
|
private AlbumAdapter adapter;
|
||||||
|
private Preferences prefs;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
|
|
||||||
Toolbar toolbar=(Toolbar)findViewById(R.id.toolbar);
|
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||||
setSupportActionBar(toolbar);
|
setSupportActionBar(toolbar);
|
||||||
|
|
||||||
|
prefs = new Preferences(this);
|
||||||
|
|
||||||
|
recyclerView = findViewById(R.id.recycler_view);
|
||||||
|
recyclerView.setLayoutManager(new GridLayoutManager(this, 2));
|
||||||
|
adapter = new AlbumAdapter();
|
||||||
|
recyclerView.setAdapter(adapter);
|
||||||
|
|
||||||
|
adapter.setOnAlbumClickListener(album -> {
|
||||||
|
Intent intent = new Intent(this, AlbumActivity.class);
|
||||||
|
intent.putExtra(AlbumActivity.EXTRA_ALBUM_PATH, album.getPath());
|
||||||
|
intent.putExtra(AlbumActivity.EXTRA_ALBUM_NAME, album.getName());
|
||||||
|
startActivity(intent);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (checkPermission()) {
|
||||||
|
loadAlbums();
|
||||||
|
} else {
|
||||||
|
requestPermission();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean checkPermission() {
|
||||||
|
return ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||||
|
== PackageManager.PERMISSION_GRANTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requestPermission() {
|
||||||
|
ActivityCompat.requestPermissions(this,
|
||||||
|
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
|
||||||
|
PERMISSION_REQUEST_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
|
||||||
|
@NonNull int[] grantResults) {
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||||
|
if (requestCode == PERMISSION_REQUEST_CODE) {
|
||||||
|
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
loadAlbums();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadAlbums() {
|
||||||
|
String folderPath = prefs.getFolderPath();
|
||||||
|
File baseFolder = new File(folderPath);
|
||||||
|
|
||||||
|
if (!baseFolder.exists() || !baseFolder.isDirectory()) {
|
||||||
|
folderPath = Environment.getExternalStorageDirectory() + "/DCIM";
|
||||||
|
baseFolder = new File(folderPath);
|
||||||
|
if (!baseFolder.exists()) {
|
||||||
|
folderPath = Environment.getExternalStorageDirectory() + "/Pictures";
|
||||||
|
baseFolder = new File(folderPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<Album> albums = new ArrayList<>();
|
||||||
|
|
||||||
|
File[] subfolders = baseFolder.listFiles(File::isDirectory);
|
||||||
|
if (subfolders != null) {
|
||||||
|
for (File subfolder : subfolders) {
|
||||||
|
ArrayList<Uri> images = getImagesInFolder(subfolder.getAbsolutePath());
|
||||||
|
if (!images.isEmpty()) {
|
||||||
|
Uri latestImage = images.get(0);
|
||||||
|
albums.add(new Album(subfolder.getName(), subfolder.getAbsolutePath(), latestImage, images.size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (albums.isEmpty()) {
|
||||||
|
Toast.makeText(this, R.string.no_images_found, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
adapter.setData(albums);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<Uri> getImagesInFolder(String folderPath) {
|
||||||
|
ArrayList<Uri> imageUrls = new ArrayList<>();
|
||||||
|
ContentResolver contentResolver = getContentResolver();
|
||||||
|
Uri collection = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
||||||
|
|
||||||
|
String selection = MediaStore.Images.Media.DATA + " LIKE ?";
|
||||||
|
String[] selectionArgs = new String[]{folderPath + "/%"};
|
||||||
|
String sortOrder = MediaStore.Images.Media.DATE_ADDED + " DESC";
|
||||||
|
|
||||||
|
try (Cursor cursor = contentResolver.query(collection, null, selection, selectionArgs, sortOrder)) {
|
||||||
|
if (cursor != null) {
|
||||||
|
int dataColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
String path = cursor.getString(dataColumn);
|
||||||
|
if (path != null) {
|
||||||
|
long id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID));
|
||||||
|
Uri contentUri = Uri.withAppendedPath(collection, String.valueOf(id));
|
||||||
|
imageUrls.add(contentUri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return imageUrls;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
getMenuInflater().inflate(R.menu.menu_main, menu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||||
|
int id = item.getItemId();
|
||||||
|
if (id == R.id.action_settings) {
|
||||||
|
startActivity(new Intent(this, SettingsActivity.class));
|
||||||
|
return true;
|
||||||
|
} else if (id == R.id.action_refresh) {
|
||||||
|
if (checkPermission()) {
|
||||||
|
loadAlbums();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
if (checkPermission()) {
|
||||||
|
loadAlbums();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
28
app/src/main/java/cc/winboll/gallery/Preferences.java
Normal file
28
app/src/main/java/cc/winboll/gallery/Preferences.java
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package cc.winboll.gallery;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
|
public class Preferences {
|
||||||
|
private static final String PREF_NAME = "gallery_prefs";
|
||||||
|
private static final String KEY_FOLDER_PATH = "folder_path";
|
||||||
|
private static final String DEFAULT_PATH = "/storage/emulated/0/DCIM";
|
||||||
|
|
||||||
|
public static String getDefaultPath() {
|
||||||
|
return DEFAULT_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final SharedPreferences prefs;
|
||||||
|
|
||||||
|
public Preferences(Context context) {
|
||||||
|
prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFolderPath() {
|
||||||
|
return prefs.getString(KEY_FOLDER_PATH, DEFAULT_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFolderPath(String path) {
|
||||||
|
prefs.edit().putString(KEY_FOLDER_PATH, path).apply();
|
||||||
|
}
|
||||||
|
}
|
||||||
38
app/src/main/java/cc/winboll/gallery/SettingsActivity.java
Normal file
38
app/src/main/java/cc/winboll/gallery/SettingsActivity.java
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package cc.winboll.gallery;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
public class SettingsActivity extends AppCompatActivity {
|
||||||
|
private Preferences prefs;
|
||||||
|
private EditText editFolderPath;
|
||||||
|
private TextView textCurrentPath;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_settings);
|
||||||
|
|
||||||
|
prefs = new Preferences(this);
|
||||||
|
|
||||||
|
editFolderPath = findViewById(R.id.edit_folder_path);
|
||||||
|
textCurrentPath = findViewById(R.id.text_current_path);
|
||||||
|
Button btnSave = findViewById(R.id.btn_save);
|
||||||
|
|
||||||
|
String currentPath = prefs.getFolderPath();
|
||||||
|
editFolderPath.setText(currentPath);
|
||||||
|
textCurrentPath.setText("Current: " + currentPath);
|
||||||
|
|
||||||
|
btnSave.setOnClickListener(v -> {
|
||||||
|
String newPath = editFolderPath.getText().toString().trim();
|
||||||
|
if (!newPath.isEmpty()) {
|
||||||
|
prefs.setFolderPath(newPath);
|
||||||
|
textCurrentPath.setText("Current: " + newPath);
|
||||||
|
}
|
||||||
|
finish();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
9
app/src/main/res/drawable/ic_back.xml
Normal file
9
app/src/main/res/drawable/ic_back.xml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
|
||||||
|
</vector>
|
||||||
32
app/src/main/res/layout/activity_image_viewer.xml
Normal file
32
app/src/main/res/layout/activity_image_viewer.xml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/black">
|
||||||
|
|
||||||
|
<androidx.viewpager.widget.ViewPager
|
||||||
|
android:id="@+id/view_pager"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="top"
|
||||||
|
android:background="#CC000000"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/btn_back"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:src="@drawable/ic_back"
|
||||||
|
android:contentDescription="Back"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
@@ -1,22 +1,28 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
|
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
|
||||||
|
|
||||||
<androidx.appcompat.widget.Toolbar
|
<androidx.appcompat.widget.Toolbar
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
|
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recycler_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/black"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
39
app/src/main/res/layout/activity_settings.xml
Normal file
39
app/src/main/res/layout/activity_settings.xml
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/folder_path"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/edit_folder_path"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:hint="@string/enter_folder_path"
|
||||||
|
android:inputType="text"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_current_path"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textColor="#888888"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_save"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="@string/save"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
37
app/src/main/res/layout/item_album.xml
Normal file
37
app/src/main/res/layout/item_album.xml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="2dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/album_cover"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="120dp"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
android:background="@color/black"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/album_name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:background="#80000000"
|
||||||
|
android:padding="4dp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/image_count"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="top|end"
|
||||||
|
android:background="#80000000"
|
||||||
|
android:padding="4dp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="10sp"/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
15
app/src/main/res/layout/item_gallery.xml
Normal file
15
app/src/main/res/layout/item_gallery.xml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="2dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/image"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="120dp"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
android:background="@color/black"/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
14
app/src/main/res/layout/item_image_pager.xml
Normal file
14
app/src/main/res/layout/item_image_pager.xml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/black">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/image"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:scaleType="fitCenter"/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
15
app/src/main/res/menu/menu_main.xml
Normal file
15
app/src/main/res/menu/menu_main.xml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_settings"
|
||||||
|
android:title="@string/settings"
|
||||||
|
app:showAsAction="never"/>
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_refresh"
|
||||||
|
android:title="@string/refresh"
|
||||||
|
app:showAsAction="never"/>
|
||||||
|
|
||||||
|
</menu>
|
||||||
@@ -3,4 +3,6 @@
|
|||||||
<color name="colorPrimary">#009688</color>
|
<color name="colorPrimary">#009688</color>
|
||||||
<color name="colorPrimaryDark">#00796B</color>
|
<color name="colorPrimaryDark">#00796B</color>
|
||||||
<color name="colorAccent">#FF9800</color>
|
<color name="colorAccent">#FF9800</color>
|
||||||
|
<color name="black">#000000</color>
|
||||||
|
<color name="white">#FFFFFF</color>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,4 +1,11 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Gallery</string>
|
<string name="app_name">Gallery</string>
|
||||||
|
<string name="refresh">Refresh</string>
|
||||||
|
<string name="settings">Settings</string>
|
||||||
|
<string name="settings_title">Settings</string>
|
||||||
|
<string name="folder_path">Folder Path</string>
|
||||||
|
<string name="enter_folder_path">Enter folder path</string>
|
||||||
|
<string name="save">Save</string>
|
||||||
|
<string name="cancel">Cancel</string>
|
||||||
|
<string name="no_images_found">No images found</string>
|
||||||
</resources>
|
</resources>
|
||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
@@ -7,4 +7,4 @@
|
|||||||
# Location of the SDK. This is only used by Gradle.
|
# Location of the SDK. This is only used by Gradle.
|
||||||
# For customization when using a Version Control System, please read the
|
# For customization when using a Version Control System, please read the
|
||||||
# header note.
|
# header note.
|
||||||
#sdk.dir=
|
sdk.dir=/home/jian/Android/Sdk
|
||||||
Reference in New Issue
Block a user