├── .gitignore ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── me │ │ └── kaelaela │ │ └── gallerysample │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── me │ │ │ └── kaelaela │ │ │ └── gallerysample │ │ │ ├── AbstractListAdapter.java │ │ │ ├── ContentUtil.java │ │ │ ├── GalleryActivity.java │ │ │ ├── GallerySampleApplication.java │ │ │ ├── ImageListAdapter.java │ │ │ ├── MainActivity.java │ │ │ └── MessengerImageListAdapter.java │ └── res │ │ ├── drawable │ │ ├── ic_arrow_back_black_24dp.xml │ │ ├── ic_close_black_24dp.xml │ │ ├── ic_file_upload_white_24dp.xml │ │ ├── ic_photo_camera_black_24dp.xml │ │ ├── ic_photo_library_black_24dp.xml │ │ ├── ic_storage_white_24dp.xml │ │ ├── shape_circle.xml │ │ └── shape_image_selected.xml │ │ ├── layout │ │ ├── activity_gallery.xml │ │ ├── activity_main.xml │ │ ├── item_messenger_thumbnail.xml │ │ └── item_thumbnail.xml │ │ ├── menu │ │ └── main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── me │ └── kaelaela │ └── gallerysample │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .idea/ 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.0" 6 | defaultConfig { 7 | applicationId "me.kaelaela.gallerysample" 8 | minSdkVersion 16 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:25.1.0' 28 | compile "com.android.support:design:25.1.0" 29 | compile 'com.facebook.fresco:fresco:1.0.1' 30 | testCompile 'junit:junit:4.12' 31 | } 32 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/a13576/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/me/kaelaela/gallerysample/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package me.kaelaela.gallerysample; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("me.kaelaela.gallerysample", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaelaela/gallerysample/AbstractListAdapter.java: -------------------------------------------------------------------------------- 1 | package me.kaelaela.gallerysample; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.support.v7.widget.RecyclerView.ViewHolder; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public abstract class AbstractListAdapter extends RecyclerView.Adapter { 9 | List items = new ArrayList<>(); 10 | 11 | abstract public void addItem(I item); 12 | 13 | abstract public void addAllItem(List receivedItems); 14 | 15 | abstract public void removeItem(I item); 16 | 17 | abstract public void removeAllItem(); 18 | 19 | abstract public void integrateItem(); 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaelaela/gallerysample/ContentUtil.java: -------------------------------------------------------------------------------- 1 | package me.kaelaela.gallerysample; 2 | 3 | import android.Manifest; 4 | import android.content.ContentResolver; 5 | import android.content.Context; 6 | import android.content.pm.PackageManager; 7 | import android.database.Cursor; 8 | import android.os.Build; 9 | import android.provider.MediaStore; 10 | import android.support.v7.app.AppCompatActivity; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | public class ContentUtil { 15 | public static void setImageList(Context context, AbstractListAdapter adapter) { 16 | ContentResolver resolver = context.getContentResolver(); 17 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 18 | if (context.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { 19 | ((AppCompatActivity) context).requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 0); 20 | return; 21 | } 22 | } 23 | Cursor c = resolver.query(MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, null, null, null, 24 | MediaStore.Images.Thumbnails.IMAGE_ID + " DESC"); 25 | List thumbnailIds = new ArrayList<>();//Get original data by this id. 26 | List thumbnailPaths = new ArrayList<>(); 27 | if (c != null) { 28 | c.moveToFirst(); 29 | while (!c.isAfterLast()) { 30 | String data = c.getString(c.getColumnIndex(MediaStore.Images.Thumbnails.DATA)); 31 | String imageId = c.getString(c.getColumnIndex(MediaStore.Images.Thumbnails.IMAGE_ID)); 32 | thumbnailPaths.add(data); 33 | thumbnailIds.add(imageId); 34 | c.moveToNext(); 35 | } 36 | c.close(); 37 | } 38 | adapter.addAllItem(thumbnailPaths); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaelaela/gallerysample/GalleryActivity.java: -------------------------------------------------------------------------------- 1 | package me.kaelaela.gallerysample; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.graphics.Point; 6 | import android.os.Bundle; 7 | import android.support.annotation.NonNull; 8 | import android.support.annotation.Nullable; 9 | import android.support.design.widget.FloatingActionButton; 10 | import android.support.design.widget.Snackbar; 11 | import android.support.v4.content.PermissionChecker; 12 | import android.support.v7.app.AppCompatActivity; 13 | import android.support.v7.widget.GridLayoutManager; 14 | import android.support.v7.widget.RecyclerView; 15 | import android.view.Display; 16 | import android.view.View; 17 | import android.widget.Toast; 18 | 19 | public class GalleryActivity extends AppCompatActivity { 20 | 21 | private final int COLUMN_COUNT = 3; 22 | private ImageListAdapter adapter; 23 | private FloatingActionButton fab; 24 | 25 | public static Intent getIntent(Context context) { 26 | return new Intent(context, GalleryActivity.class); 27 | } 28 | 29 | @Override 30 | protected void onCreate(@Nullable Bundle savedInstanceState) { 31 | super.onCreate(savedInstanceState); 32 | setContentView(R.layout.activity_gallery); 33 | 34 | fab = (FloatingActionButton) findViewById(R.id.fab); 35 | fab.hide(); 36 | fab.setOnClickListener(new View.OnClickListener() { 37 | @Override 38 | public void onClick(View v) { 39 | Toast.makeText(v.getContext(), "画像を送信しました", Toast.LENGTH_LONG).show(); 40 | finish(); 41 | } 42 | }); 43 | 44 | Display display = getWindowManager().getDefaultDisplay(); 45 | RecyclerView recyclerView = (RecyclerView) findViewById(R.id.image_list); 46 | Point point = new Point(); 47 | display.getSize(point); 48 | adapter = new ImageListAdapter(point.x, COLUMN_COUNT, new ImageListAdapter.OnItemClickListener() { 49 | @Override 50 | public void onItemClick(int count) { 51 | if (count <= 0) { 52 | ((FloatingActionButton) findViewById(R.id.fab)).hide(); 53 | } else { 54 | ((FloatingActionButton) findViewById(R.id.fab)).show(); 55 | } 56 | } 57 | 58 | @Override 59 | public void onOverCount() { 60 | Snackbar.make(findViewById(R.id.activity_gallery), "一度に送信できるのは5枚までです", Snackbar.LENGTH_SHORT).show(); 61 | } 62 | }); 63 | recyclerView.setLayoutManager(new GridLayoutManager(this, COLUMN_COUNT)); 64 | recyclerView.setAdapter(adapter); 65 | ContentUtil.setImageList(this, adapter); 66 | } 67 | 68 | @Override 69 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 70 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 71 | switch (requestCode) { 72 | case 0: 73 | for (int result : grantResults) { 74 | if (result == PermissionChecker.PERMISSION_GRANTED) { 75 | ContentUtil.setImageList(this, adapter); 76 | } else { 77 | finish(); 78 | } 79 | } 80 | break; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaelaela/gallerysample/GallerySampleApplication.java: -------------------------------------------------------------------------------- 1 | package me.kaelaela.gallerysample; 2 | 3 | import android.app.Application; 4 | import com.facebook.drawee.backends.pipeline.Fresco; 5 | 6 | public class GallerySampleApplication extends Application { 7 | @Override 8 | public void onCreate() { 9 | super.onCreate(); 10 | Fresco.initialize(this); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaelaela/gallerysample/ImageListAdapter.java: -------------------------------------------------------------------------------- 1 | package me.kaelaela.gallerysample; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | import android.animation.AnimatorSet; 6 | import android.animation.ObjectAnimator; 7 | import android.net.Uri; 8 | import android.support.v4.content.ContextCompat; 9 | import android.support.v7.widget.GridLayoutManager; 10 | import android.support.v7.widget.RecyclerView; 11 | import android.text.TextUtils; 12 | import android.view.LayoutInflater; 13 | import android.view.View; 14 | import android.view.ViewGroup; 15 | import android.view.animation.Interpolator; 16 | import android.view.animation.OvershootInterpolator; 17 | import android.widget.CheckBox; 18 | import com.facebook.drawee.backends.pipeline.Fresco; 19 | import com.facebook.drawee.interfaces.DraweeController; 20 | import com.facebook.drawee.view.SimpleDraweeView; 21 | import com.facebook.imagepipeline.common.ResizeOptions; 22 | import com.facebook.imagepipeline.request.ImageRequest; 23 | import com.facebook.imagepipeline.request.ImageRequestBuilder; 24 | import java.io.File; 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | public class ImageListAdapter extends AbstractListAdapter { 29 | 30 | private final float AFTER_ANIMATED_SIZE = 0.95f; 31 | private final float DEFAULT_SIZE = 1f; 32 | private final int DEFAULT_ANIM_DURATION = 300; 33 | private final int MAX_COUNT = 5; 34 | private final Interpolator INTERPOLATOR = new OvershootInterpolator(4); 35 | 36 | private OnItemClickListener listener; 37 | private final List selectedUrls = new ArrayList<>(); 38 | private final int thumbnailWidth; 39 | 40 | public ImageListAdapter(int displayWidth, int columnCount, OnItemClickListener listener) { 41 | thumbnailWidth = displayWidth / columnCount; 42 | this.listener = listener; 43 | } 44 | 45 | @Override 46 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 47 | LayoutInflater inflater = LayoutInflater.from(parent.getContext()); 48 | return new ImageItemViewHolder(inflater.inflate(R.layout.item_thumbnail, parent, false)); 49 | } 50 | 51 | @Override 52 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 53 | if (holder instanceof ImageItemViewHolder) { 54 | ImageItemViewHolder viewHolder = (ImageItemViewHolder) holder; 55 | viewHolder.bind(items.get(position)); 56 | } 57 | } 58 | 59 | @Override 60 | public int getItemCount() { 61 | return items.size(); 62 | } 63 | 64 | @Override 65 | public void addItem(String item) { 66 | if (TextUtils.isEmpty(item)) { 67 | return; 68 | } 69 | items.add(item); 70 | notifyItemChanged(items.size()); 71 | } 72 | 73 | @Override 74 | public void addAllItem(List urls) { 75 | items.clear(); 76 | items.addAll(urls); 77 | } 78 | 79 | @Override 80 | public void removeItem(String item) { 81 | Integer count = null; 82 | for (int i = 0; i < items.size(); i++) { 83 | String url = items.get(i); 84 | if (url.equals(item)) { 85 | count = i; 86 | } 87 | } 88 | if (count != null) { 89 | items.remove((int) count); 90 | } 91 | } 92 | 93 | @Override 94 | public void removeAllItem() { 95 | items.clear(); 96 | notifyDataSetChanged(); 97 | } 98 | 99 | @Override 100 | public void integrateItem() { 101 | } 102 | 103 | public interface OnItemClickListener { 104 | void onItemClick(int count); 105 | 106 | void onOverCount(); 107 | } 108 | 109 | public class ImageItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { 110 | final SimpleDraweeView thumbnail; 111 | final CheckBox check; 112 | private String url; 113 | 114 | public ImageItemViewHolder(final View itemView) { 115 | super(itemView); 116 | itemView.setOnClickListener(this); 117 | thumbnail = (SimpleDraweeView) itemView.findViewById(R.id.thumbnail); 118 | thumbnail.setOnClickListener(this); 119 | check = (CheckBox) itemView.findViewById(R.id.check); 120 | check.setOnClickListener(this); 121 | fixHeight(); 122 | } 123 | 124 | private void fixHeight() { 125 | GridLayoutManager.LayoutParams params = (GridLayoutManager.LayoutParams) itemView.getLayoutParams(); 126 | params.height = thumbnailWidth; 127 | itemView.setLayoutParams(params); 128 | } 129 | 130 | public void bind(String url) { 131 | if (TextUtils.isEmpty(url)) { 132 | return; 133 | } 134 | this.url = url; 135 | ImageRequest request = ImageRequestBuilder 136 | .newBuilderWithSource(Uri.fromFile(new File(url))) 137 | .setProgressiveRenderingEnabled(true) 138 | .setLocalThumbnailPreviewsEnabled(true) 139 | .setResizeOptions(new ResizeOptions(thumbnailWidth, thumbnailWidth)) 140 | .build(); 141 | DraweeController controller = Fresco.newDraweeControllerBuilder() 142 | .setOldController(thumbnail.getController()) 143 | .setImageRequest(request) 144 | .build(); 145 | thumbnail.setController(controller); 146 | toggle(url); 147 | } 148 | 149 | private void toggle(String url) { 150 | boolean isContain = false; 151 | for (String s : selectedUrls) { 152 | if (s.equals(url)) { 153 | isContain = true; 154 | } 155 | } 156 | check.setChecked(isContain); 157 | thumbnail.setScaleX(isContain ? AFTER_ANIMATED_SIZE : DEFAULT_SIZE); 158 | thumbnail.setScaleY(isContain ? AFTER_ANIMATED_SIZE : DEFAULT_SIZE); 159 | itemView.setBackground(isContain ? ContextCompat 160 | .getDrawable(itemView.getContext(), R.drawable.shape_image_selected) : null); 161 | } 162 | 163 | public void bounceAnimation(final View view, boolean isChecked, AnimatorListenerAdapter adapter) { 164 | view.setEnabled(false); 165 | AnimatorSet animatorSet = new AnimatorSet(); 166 | 167 | ObjectAnimator bounceAnimX = ObjectAnimator.ofFloat(view, "scaleX", 168 | isChecked ? DEFAULT_SIZE : AFTER_ANIMATED_SIZE, 169 | isChecked ? AFTER_ANIMATED_SIZE : DEFAULT_SIZE); 170 | bounceAnimX.setDuration(DEFAULT_ANIM_DURATION); 171 | bounceAnimX.setInterpolator(INTERPOLATOR); 172 | 173 | ObjectAnimator bounceAnimY = ObjectAnimator.ofFloat(view, "scaleY", 174 | isChecked ? DEFAULT_SIZE : AFTER_ANIMATED_SIZE, 175 | isChecked ? AFTER_ANIMATED_SIZE : DEFAULT_SIZE); 176 | bounceAnimY.setDuration(DEFAULT_ANIM_DURATION); 177 | bounceAnimY.setInterpolator(INTERPOLATOR); 178 | bounceAnimY.addListener(adapter); 179 | animatorSet.play(bounceAnimX).with(bounceAnimY); 180 | animatorSet.addListener(new AnimatorListenerAdapter() { 181 | @Override 182 | public void onAnimationEnd(Animator animation) { 183 | view.setEnabled(true); 184 | } 185 | }); 186 | animatorSet.start(); 187 | } 188 | 189 | @Override 190 | public void onClick(final View v) { 191 | if (!selectedUrls.contains(url) && selectedUrls.size() == MAX_COUNT) { 192 | listener.onOverCount(); 193 | return; 194 | } 195 | 196 | check.setChecked(!check.isChecked()); 197 | bounceAnimation(thumbnail, check.isChecked(), new AnimatorListenerAdapter() { 198 | @Override 199 | public void onAnimationStart(Animator animation) { 200 | itemView.setBackground(ContextCompat 201 | .getDrawable(itemView.getContext(), R.drawable.shape_image_selected)); 202 | } 203 | }); 204 | 205 | if (selectedUrls.contains(url)) { 206 | selectedUrls.remove(url); 207 | } else { 208 | selectedUrls.add(url); 209 | } 210 | listener.onItemClick(selectedUrls.size()); 211 | } 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaelaela/gallerysample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package me.kaelaela.gallerysample; 2 | 3 | import android.content.Intent; 4 | import android.graphics.Point; 5 | import android.os.Bundle; 6 | import android.support.annotation.NonNull; 7 | import android.support.design.widget.BottomSheetBehavior; 8 | import android.support.design.widget.FloatingActionButton; 9 | import android.support.design.widget.Snackbar; 10 | import android.support.v4.content.PermissionChecker; 11 | import android.support.v7.app.AppCompatActivity; 12 | import android.support.v7.widget.GridLayoutManager; 13 | import android.support.v7.widget.LinearLayoutManager; 14 | import android.support.v7.widget.RecyclerView; 15 | import android.view.Display; 16 | import android.view.Menu; 17 | import android.view.MenuItem; 18 | import android.view.View; 19 | import android.widget.Toast; 20 | 21 | import static android.support.design.widget.BottomSheetBehavior.STATE_COLLAPSED; 22 | import static android.support.design.widget.BottomSheetBehavior.STATE_HIDDEN; 23 | 24 | public class MainActivity extends AppCompatActivity { 25 | 26 | private static final int REQUEST_FROM_MAIN = 0; 27 | private static final int COLUMN_COUNT = 3; 28 | private AbstractListAdapter adapter; 29 | private FloatingActionButton fab; 30 | 31 | @Override 32 | protected void onCreate(Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | setContentView(R.layout.activity_main); 35 | findViewById(R.id.gallery_button).setOnClickListener(new View.OnClickListener() { 36 | @Override 37 | public void onClick(View v) { 38 | startActivity(GalleryActivity.getIntent(v.getContext())); 39 | } 40 | }); 41 | 42 | final View bottomSheet = findViewById(R.id.gallery_bottom_sheet); 43 | final BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet); 44 | behavior.setState(STATE_HIDDEN); 45 | final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.bottom_image_list); 46 | findViewById(R.id.messenger_button).setOnClickListener(new View.OnClickListener() { 47 | @Override 48 | public void onClick(View v) { 49 | adapter = new MessengerImageListAdapter(new MessengerImageListAdapter.OnItemClickListener() { 50 | @Override 51 | public void onItemClick() { 52 | behavior.setState(STATE_HIDDEN); 53 | } 54 | }); 55 | recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this, 56 | LinearLayoutManager.HORIZONTAL, false)); 57 | recyclerView.setAdapter(adapter); 58 | findViewById(R.id.tools_layout).setVisibility(View.GONE); 59 | switch (behavior.getState()) { 60 | case STATE_COLLAPSED: 61 | behavior.setState(STATE_HIDDEN); 62 | break; 63 | case STATE_HIDDEN: 64 | behavior.setState(STATE_COLLAPSED); 65 | break; 66 | } 67 | } 68 | }); 69 | fab = (FloatingActionButton) findViewById(R.id.main_fab); 70 | fab.hide(); 71 | fab.setOnClickListener(new View.OnClickListener() { 72 | @Override 73 | public void onClick(View view) { 74 | fab.hide(); 75 | Toast.makeText(view.getContext(), "画像を送信しました", Toast.LENGTH_SHORT).show(); 76 | behavior.setState(STATE_HIDDEN); 77 | } 78 | }); 79 | 80 | Display display = getWindowManager().getDefaultDisplay(); 81 | final Point point = new Point(); 82 | display.getSize(point); 83 | findViewById(R.id.insta_button).setOnClickListener(new View.OnClickListener() { 84 | @Override 85 | public void onClick(View v) { 86 | adapter = new ImageListAdapter(point.x, COLUMN_COUNT, new ImageListAdapter.OnItemClickListener() { 87 | @Override 88 | public void onItemClick(int count) { 89 | if (count <= 0) { 90 | fab.hide(); 91 | } else { 92 | fab.show(); 93 | } 94 | } 95 | 96 | @Override 97 | public void onOverCount() { 98 | Snackbar.make(findViewById(R.id.activity_main), "一度に送信できるのは5枚までです", Snackbar.LENGTH_SHORT).show(); 99 | } 100 | }); 101 | recyclerView.setLayoutManager(new GridLayoutManager(MainActivity.this, COLUMN_COUNT)); 102 | recyclerView.setAdapter(adapter); 103 | findViewById(R.id.tools_layout).setVisibility(View.VISIBLE); 104 | switch (behavior.getState()) { 105 | case STATE_COLLAPSED: 106 | behavior.setState(STATE_HIDDEN); 107 | break; 108 | case STATE_HIDDEN: 109 | behavior.setState(STATE_COLLAPSED); 110 | break; 111 | } 112 | } 113 | }); 114 | 115 | behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { 116 | @Override 117 | public void onStateChanged(@NonNull View bottomSheet, int newState) { 118 | if (newState == STATE_COLLAPSED) { 119 | ContentUtil.setImageList(MainActivity.this, adapter); 120 | recyclerView.scrollToPosition(0); 121 | } else if (newState == STATE_HIDDEN) { 122 | fab.hide(); 123 | } 124 | } 125 | 126 | @Override 127 | public void onSlide(@NonNull View bottomSheet, float slideOffset) { 128 | 129 | } 130 | }); 131 | 132 | findViewById(R.id.close_button).setOnClickListener(new View.OnClickListener() { 133 | @Override 134 | public void onClick(View v) { 135 | behavior.setState(STATE_HIDDEN); 136 | fab.hide(); 137 | } 138 | }); 139 | 140 | findViewById(R.id.camera_button).setOnClickListener(new View.OnClickListener() { 141 | @Override 142 | public void onClick(View view) { 143 | Toast.makeText(view.getContext(), "カメラ起動", Toast.LENGTH_SHORT).show(); 144 | behavior.setState(STATE_HIDDEN); 145 | fab.hide(); 146 | } 147 | }); 148 | findViewById(R.id.photo_library_button).setOnClickListener(new View.OnClickListener() { 149 | @Override 150 | public void onClick(View v) { 151 | behavior.setState(STATE_HIDDEN); 152 | startActivity(GalleryActivity.getIntent(v.getContext())); 153 | fab.hide(); 154 | } 155 | }); 156 | } 157 | 158 | @Override 159 | public boolean onCreateOptionsMenu(Menu menu) { 160 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { 161 | getMenuInflater().inflate(R.menu.main, menu); 162 | } 163 | return super.onCreateOptionsMenu(menu); 164 | } 165 | 166 | @Override 167 | public boolean onOptionsItemSelected(MenuItem item) { 168 | switch (item.getItemId()) { 169 | case R.id.saf: 170 | Intent intent; 171 | intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); 172 | intent.addCategory(Intent.CATEGORY_OPENABLE); 173 | intent.setType("image/*"); 174 | startActivityForResult(intent, REQUEST_FROM_MAIN); 175 | break; 176 | } 177 | return super.onOptionsItemSelected(item); 178 | } 179 | 180 | @Override 181 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 182 | super.onActivityResult(requestCode, resultCode, data); 183 | if (resultCode == RESULT_OK && requestCode == REQUEST_FROM_MAIN) { 184 | Snackbar.make(findViewById(android.R.id.content), data.getData().getPath(), Snackbar.LENGTH_SHORT).show(); 185 | } 186 | } 187 | 188 | @Override 189 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 190 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 191 | switch (requestCode) { 192 | case 0: 193 | for (int result : grantResults) { 194 | if (result == PermissionChecker.PERMISSION_GRANTED) { 195 | ContentUtil.setImageList(this, adapter); 196 | } else { 197 | finish(); 198 | } 199 | } 200 | break; 201 | } 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaelaela/gallerysample/MessengerImageListAdapter.java: -------------------------------------------------------------------------------- 1 | package me.kaelaela.gallerysample; 2 | 3 | import android.net.Uri; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.text.TextUtils; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.Button; 10 | import android.widget.Toast; 11 | import com.facebook.drawee.backends.pipeline.Fresco; 12 | import com.facebook.drawee.interfaces.DraweeController; 13 | import com.facebook.drawee.view.SimpleDraweeView; 14 | import com.facebook.imagepipeline.common.ResizeOptions; 15 | import com.facebook.imagepipeline.request.ImageRequest; 16 | import com.facebook.imagepipeline.request.ImageRequestBuilder; 17 | import java.io.File; 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | public class MessengerImageListAdapter extends AbstractListAdapter { 22 | 23 | private OnItemClickListener listener; 24 | private List selectedUrls = new ArrayList<>(5); 25 | 26 | public MessengerImageListAdapter(OnItemClickListener listener) { 27 | this.listener = listener; 28 | } 29 | 30 | @Override 31 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 32 | LayoutInflater inflater = LayoutInflater.from(parent.getContext()); 33 | return new MessengerImageViewHolder(inflater.inflate(R.layout.item_messenger_thumbnail, parent, false)); 34 | } 35 | 36 | @Override 37 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 38 | if (holder instanceof MessengerImageViewHolder) { 39 | MessengerImageViewHolder viewHolder = (MessengerImageViewHolder) holder; 40 | viewHolder.bind(items.get(position)); 41 | } 42 | } 43 | 44 | @Override 45 | public int getItemCount() { 46 | return items.size(); 47 | } 48 | 49 | @Override 50 | public void addItem(String item) { 51 | items.add(item); 52 | notifyItemInserted(items.size()); 53 | } 54 | 55 | @Override 56 | public void addAllItem(List receivedItems) { 57 | items.clear(); 58 | items.addAll(receivedItems); 59 | notifyDataSetChanged(); 60 | } 61 | 62 | @Override 63 | public void removeItem(String item) { 64 | Integer count = null; 65 | for (int i = 0; i < items.size(); i++) { 66 | String url = items.get(i); 67 | if (url.equals(item)) { 68 | count = i; 69 | } 70 | } 71 | if (count != null) { 72 | items.remove((int) count); 73 | } 74 | } 75 | 76 | @Override 77 | public void removeAllItem() { 78 | items.clear(); 79 | } 80 | 81 | @Override 82 | public void integrateItem() { 83 | 84 | } 85 | 86 | public interface OnItemClickListener { 87 | void onItemClick(); 88 | } 89 | 90 | public class MessengerImageViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { 91 | 92 | private final int THUMBNAIL_SIZE; 93 | private String url; 94 | private View shadow; 95 | private Button sendButton; 96 | private SimpleDraweeView thumbnail; 97 | 98 | public MessengerImageViewHolder(View itemView) { 99 | super(itemView); 100 | itemView.setOnClickListener(this); 101 | thumbnail = (SimpleDraweeView) itemView.findViewById(R.id.thumbnail); 102 | thumbnail.setOnClickListener(this); 103 | sendButton = (Button) itemView.findViewById(R.id.send_button); 104 | sendButton.setOnClickListener(this); 105 | shadow = itemView.findViewById(R.id.shadow); 106 | THUMBNAIL_SIZE = itemView.getContext().getResources().getDimensionPixelSize(R.dimen.messenger_thumbnail_side); 107 | } 108 | 109 | public void bind(String url) { 110 | if (TextUtils.isEmpty(url)) { 111 | return; 112 | } 113 | this.url = url; 114 | ImageRequest request = ImageRequestBuilder 115 | .newBuilderWithSource(Uri.fromFile(new File(url))) 116 | .setProgressiveRenderingEnabled(true) 117 | .setLocalThumbnailPreviewsEnabled(true) 118 | .setResizeOptions(new ResizeOptions(THUMBNAIL_SIZE, THUMBNAIL_SIZE)) 119 | .build(); 120 | DraweeController controller = Fresco.newDraweeControllerBuilder() 121 | .setOldController(thumbnail.getController()) 122 | .setImageRequest(request) 123 | .build(); 124 | thumbnail.setController(controller); 125 | toggle(); 126 | } 127 | 128 | private void toggle() { 129 | boolean isContain = false; 130 | for (String s : selectedUrls) { 131 | if (s.equals(url)) { 132 | isContain = true; 133 | } 134 | } 135 | sendButton.setVisibility(isContain ? View.VISIBLE : View.GONE); 136 | shadow.setVisibility(isContain ? View.VISIBLE : View.GONE); 137 | } 138 | 139 | @Override 140 | public void onClick(View v) { 141 | if (v == sendButton) { 142 | Toast.makeText(v.getContext(), "送信しました", Toast.LENGTH_SHORT).show(); 143 | sendButton.setVisibility(View.GONE); 144 | shadow.setVisibility(View.GONE); 145 | listener.onItemClick(); 146 | } else { 147 | shadow.setVisibility(sendButton.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE); 148 | sendButton.setVisibility(sendButton.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE); 149 | } 150 | 151 | if (selectedUrls.contains(url)) { 152 | selectedUrls.remove(url); 153 | } else { 154 | selectedUrls.add(url); 155 | } 156 | } 157 | } 158 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_back_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_close_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_file_upload_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_photo_camera_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_photo_library_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_storage_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_circle.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_image_selected.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_gallery.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 |