mirror of
				https://github.com/pierre42100/ComunicAndroid
				synced 2025-11-04 11:34:06 +00:00 
			
		
		
		
	Can save some uploaded images
This commit is contained in:
		@@ -13,6 +13,10 @@
 | 
			
		||||
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <!-- To save file (eg. images) into user storage -->
 | 
			
		||||
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <application
 | 
			
		||||
        android:allowBackup="true"
 | 
			
		||||
        android:fullBackupContent="@xml/backup_scheme"
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,8 @@ import android.widget.ImageView;
 | 
			
		||||
 | 
			
		||||
import org.communiquons.android.comunic.client.data.runnables.ImageLoadRunnable;
 | 
			
		||||
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Image load manager / helper
 | 
			
		||||
 *
 | 
			
		||||
@@ -95,6 +97,20 @@ public class ImageLoadHelper {
 | 
			
		||||
        clean();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check out whether an image view is loading or not
 | 
			
		||||
     *
 | 
			
		||||
     * @param v The target view
 | 
			
		||||
     * @return TRUE if loading / FALSE else
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean IsLoading(View v){
 | 
			
		||||
 | 
			
		||||
        return threads.containsKey(v)
 | 
			
		||||
                && threads.get(v) != null
 | 
			
		||||
                && Objects.requireNonNull(threads.get(v)).isAlive()
 | 
			
		||||
                && !Objects.requireNonNull(threads.get(v)).isInterrupted();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Clean the list of pending operations
 | 
			
		||||
     */
 | 
			
		||||
 
 | 
			
		||||
@@ -28,12 +28,12 @@ public class ImageLoadRunnable implements Runnable {
 | 
			
		||||
    /**
 | 
			
		||||
     * Debug tag
 | 
			
		||||
     */
 | 
			
		||||
    private static final String TAG = "ImageLoadRunnable";
 | 
			
		||||
    private static final String TAG = ImageLoadRunnable.class.getSimpleName();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Image load lock
 | 
			
		||||
     */
 | 
			
		||||
    public static ReentrantLock ImageLoadLock = null;
 | 
			
		||||
    private static ReentrantLock ImageLoadLock = null;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * An array map with all the pending images associated with their URLs
 | 
			
		||||
@@ -89,11 +89,7 @@ public class ImageLoadRunnable implements Runnable {
 | 
			
		||||
        //Create the parent directory if required
 | 
			
		||||
        ImageLoadUtils.create_parent_directory(mContext);
 | 
			
		||||
 | 
			
		||||
        //Determine the filename for the requested URL
 | 
			
		||||
        String filename = ImageLoadUtils.IMAGE_CACHE_DIRECTORY + ImageLoadUtils.get_file_name(url);
 | 
			
		||||
 | 
			
		||||
        //Create file object
 | 
			
		||||
        file = new File(mContext.getCacheDir(), filename);
 | 
			
		||||
        file = ImageLoadUtils.getFileForImage(mContext, url);
 | 
			
		||||
 | 
			
		||||
        //Check no thread is already running for the following image
 | 
			
		||||
        if (!pendingOperation.containsKey(url)) {
 | 
			
		||||
@@ -181,7 +177,8 @@ public class ImageLoadRunnable implements Runnable {
 | 
			
		||||
                        " deleted");
 | 
			
		||||
 | 
			
		||||
                //Delete file
 | 
			
		||||
                file.delete();
 | 
			
		||||
                if(!file.delete())
 | 
			
		||||
                    Log.e(TAG, "Could not delete file " + file.getPath() + " !");
 | 
			
		||||
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ public class ImageLoadUtils {
 | 
			
		||||
    /**
 | 
			
		||||
     * The main folder in the cache directory that stores the file
 | 
			
		||||
     */
 | 
			
		||||
    public static final String IMAGE_CACHE_DIRECTORY = "img_cache/";
 | 
			
		||||
    private static final String IMAGE_CACHE_DIRECTORY = "img_cache/";
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the file name, based on the URL name
 | 
			
		||||
@@ -30,10 +30,28 @@ public class ImageLoadUtils {
 | 
			
		||||
     * @param url The URL of the file
 | 
			
		||||
     * @return The name of the file, composed of characters that can be used in filename
 | 
			
		||||
     */
 | 
			
		||||
    public static String get_file_name(String url){
 | 
			
		||||
    private static String get_file_name(String url){
 | 
			
		||||
        return StringsUtils.sha1(url);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the File object corresponding to an image URL
 | 
			
		||||
     *
 | 
			
		||||
     * Warning ! In some cases, the file might not exists
 | 
			
		||||
     *
 | 
			
		||||
     * @param context Application context
 | 
			
		||||
     * @param url URL of the target image
 | 
			
		||||
     * @return File object pointing on the image
 | 
			
		||||
     */
 | 
			
		||||
    public static File getFileForImage(Context context, String url){
 | 
			
		||||
 | 
			
		||||
        //Determine the filename for the requested URL
 | 
			
		||||
        String filename = IMAGE_CACHE_DIRECTORY + ImageLoadUtils.get_file_name(url);
 | 
			
		||||
 | 
			
		||||
        //Create file object
 | 
			
		||||
        return new File(context.getCacheDir(), filename);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create cache images files parent directory if it does not exist
 | 
			
		||||
     *
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
package org.communiquons.android.comunic.client.ui.activities;
 | 
			
		||||
 | 
			
		||||
import android.Manifest;
 | 
			
		||||
import android.app.Activity;
 | 
			
		||||
import android.app.AlertDialog;
 | 
			
		||||
import android.app.Dialog;
 | 
			
		||||
@@ -25,6 +26,7 @@ import android.widget.Toast;
 | 
			
		||||
 | 
			
		||||
import org.communiquons.android.comunic.client.BuildConfig;
 | 
			
		||||
import org.communiquons.android.comunic.client.R;
 | 
			
		||||
import org.communiquons.android.comunic.client.ui.utils.PermissionsUtils;
 | 
			
		||||
import org.communiquons.crashreporter.CrashReporter;
 | 
			
		||||
import org.communiquons.android.comunic.client.data.enums.VirtualDirectoryType;
 | 
			
		||||
import org.communiquons.android.comunic.client.data.helpers.APIRequestHelper;
 | 
			
		||||
@@ -193,6 +195,11 @@ public class MainActivity extends BaseActivity implements
 | 
			
		||||
        GetCallConfigurationTask callConfigurationTask = new GetCallConfigurationTask(this);
 | 
			
		||||
        callConfigurationTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
 | 
			
		||||
        getTasksManager().addTask(callConfigurationTask);
 | 
			
		||||
 | 
			
		||||
        //Request a few permissions
 | 
			
		||||
        PermissionsUtils.RequestPermissions(this,
 | 
			
		||||
                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 
 | 
			
		||||
@@ -91,6 +91,7 @@ class CommentsAdapter extends ArrayAdapter<Comment> {
 | 
			
		||||
 | 
			
		||||
        //Update comment image (if any)
 | 
			
		||||
        EnlargeableWebImageView commentImage = view.findViewById(R.id.comment_image);
 | 
			
		||||
        commentImage.setCanSaveImageToGallery(true);
 | 
			
		||||
        if(comment.getImage_url().length() < 5)
 | 
			
		||||
            commentImage.setVisibility(View.GONE);
 | 
			
		||||
        else {
 | 
			
		||||
 
 | 
			
		||||
@@ -136,6 +136,7 @@ public class ConversationMessageAdapter extends RecyclerView.Adapter {
 | 
			
		||||
 | 
			
		||||
            mMessage.setOnLongClickListener(this);
 | 
			
		||||
            mImage.setOnLongClickListener(this);
 | 
			
		||||
            mImage.setCanSaveImageToGallery(true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
 
 | 
			
		||||
@@ -415,6 +415,7 @@ public class PostsAdapter extends BaseRecyclerViewAdapter {
 | 
			
		||||
            super(itemView);
 | 
			
		||||
 | 
			
		||||
            mPostImage = new EnlargeableWebImageView(getContext());
 | 
			
		||||
            mPostImage.setCanSaveImageToGallery(true);
 | 
			
		||||
            getAdditionalViewsLayout().addView(mPostImage,
 | 
			
		||||
                    new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
 | 
			
		||||
                            UiUtils.GetPixel(getContext(), 200)));
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,44 @@
 | 
			
		||||
package org.communiquons.android.comunic.client.ui.utils;
 | 
			
		||||
 | 
			
		||||
import android.app.Activity;
 | 
			
		||||
import android.content.pm.PackageManager;
 | 
			
		||||
import android.support.annotation.NonNull;
 | 
			
		||||
import android.support.v4.app.ActivityCompat;
 | 
			
		||||
import android.support.v4.content.ContextCompat;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Permissions utilities
 | 
			
		||||
 *
 | 
			
		||||
 * @author Pierre HUBERT
 | 
			
		||||
 */
 | 
			
		||||
public class PermissionsUtils {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Request some permissions from the user
 | 
			
		||||
     *
 | 
			
		||||
     * @param activity Activity that perform the request
 | 
			
		||||
     * @param permissions Requested permissions
 | 
			
		||||
     */
 | 
			
		||||
    public static void RequestPermissions(@NonNull Activity activity, String[] permissions, int c){
 | 
			
		||||
 | 
			
		||||
        ArrayList<String> permissionsToRequest = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
        for(String permission : permissions){
 | 
			
		||||
            if(ContextCompat.checkSelfPermission(activity, permission)
 | 
			
		||||
                    != PackageManager.PERMISSION_GRANTED)
 | 
			
		||||
                permissionsToRequest.add(permission);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        //Ask for permissions if required
 | 
			
		||||
        if(permissionsToRequest.size() > 0){
 | 
			
		||||
            String[] permissionsArray = permissionsToRequest.toArray(new String[0]);
 | 
			
		||||
            assert permissionsArray != null;
 | 
			
		||||
            ActivityCompat.requestPermissions(activity, permissionsArray, c);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -2,11 +2,22 @@ package org.communiquons.android.comunic.client.ui.views;
 | 
			
		||||
 | 
			
		||||
import android.app.AlertDialog;
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.graphics.Bitmap;
 | 
			
		||||
import android.provider.MediaStore;
 | 
			
		||||
import android.util.AttributeSet;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.MenuItem;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.widget.PopupMenu;
 | 
			
		||||
import android.widget.Toast;
 | 
			
		||||
 | 
			
		||||
import org.communiquons.android.comunic.client.R;
 | 
			
		||||
import org.communiquons.android.comunic.client.data.helpers.ImageLoadHelper;
 | 
			
		||||
import org.communiquons.android.comunic.client.data.utils.ImageLoadUtils;
 | 
			
		||||
import org.communiquons.android.comunic.client.ui.utils.BitmapUtils;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Enlargeable images view.
 | 
			
		||||
@@ -17,13 +28,21 @@ import org.communiquons.android.comunic.client.R;
 | 
			
		||||
 * Created by pierre on 4/28/18.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
public class EnlargeableWebImageView extends WebImageView {
 | 
			
		||||
public class EnlargeableWebImageView extends WebImageView implements PopupMenu.OnMenuItemClickListener {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Debug tag
 | 
			
		||||
     */
 | 
			
		||||
    private static final String TAG = EnlargeableWebImageView.class.getSimpleName();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Optional additional OnClick Listener
 | 
			
		||||
     */
 | 
			
		||||
    private OnClickListener mOnClickListener;
 | 
			
		||||
 | 
			
		||||
    private boolean mCanSaveImageToGallery;
 | 
			
		||||
 | 
			
		||||
    public EnlargeableWebImageView(Context context) {
 | 
			
		||||
        super(context);
 | 
			
		||||
        init();
 | 
			
		||||
@@ -68,6 +87,14 @@ public class EnlargeableWebImageView extends WebImageView {
 | 
			
		||||
        return mOnClickListener == null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isCanSaveImageToGallery() {
 | 
			
		||||
        return mCanSaveImageToGallery;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setCanSaveImageToGallery(boolean mCanSaveImageToGallery) {
 | 
			
		||||
        this.mCanSaveImageToGallery = mCanSaveImageToGallery;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Open the image in large dimensions
 | 
			
		||||
     */
 | 
			
		||||
@@ -86,5 +113,80 @@ public class EnlargeableWebImageView extends WebImageView {
 | 
			
		||||
                .show();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        //Offer the user to save if image if possible
 | 
			
		||||
        if(isCanSaveImageToGallery()){
 | 
			
		||||
            image.setOnLongClickListener(this::openContextMenu);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Open context menu for the image
 | 
			
		||||
     */
 | 
			
		||||
    private boolean openContextMenu(View v){
 | 
			
		||||
 | 
			
		||||
        //Show popup menu
 | 
			
		||||
        PopupMenu popupMenu = new PopupMenu(getContext(), v);
 | 
			
		||||
        popupMenu.inflate(R.menu.image_menu);
 | 
			
		||||
        popupMenu.setOnMenuItemClickListener(this);
 | 
			
		||||
 | 
			
		||||
        if(ImageLoadHelper.IsLoading(this))
 | 
			
		||||
            popupMenu.getMenu().findItem(R.id.action_save_image_in_gallery).setEnabled(false);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        popupMenu.show();
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean onMenuItemClick(MenuItem item) {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        if(item.getItemId() == R.id.action_save_image_in_gallery){
 | 
			
		||||
 | 
			
		||||
            if(!saveImageToGallery())
 | 
			
		||||
                Toast.makeText(getContext(), R.string.err_save_image_in_gallery, Toast.LENGTH_SHORT).show();
 | 
			
		||||
            else
 | 
			
		||||
                Toast.makeText(getContext(), R.string.success_save_image_in_gallery, Toast.LENGTH_SHORT).show();
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Save the current image in this {@link WebImageView} into the gallery
 | 
			
		||||
     *
 | 
			
		||||
     * @return TRUE in case of success / FALSE else
 | 
			
		||||
     */
 | 
			
		||||
    private boolean saveImageToGallery(){
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            if (ImageLoadHelper.IsLoading(this))
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            File file = ImageLoadUtils.getFileForImage(getContext(), getCurrURL());
 | 
			
		||||
 | 
			
		||||
            if (!file.isFile()) {
 | 
			
		||||
                Log.e(TAG, "Image is not a file!");
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Bitmap bm = BitmapUtils.openResized(file, 1500, 1500);
 | 
			
		||||
 | 
			
		||||
            //Save the image into the gallery
 | 
			
		||||
            return MediaStore.Images.Media.insertImage(
 | 
			
		||||
                    getContext().getContentResolver(),
 | 
			
		||||
                    bm,
 | 
			
		||||
                    "Comunic image",
 | 
			
		||||
                    getCurrURL()
 | 
			
		||||
            ) != null;
 | 
			
		||||
 | 
			
		||||
        } catch (Exception e){
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								app/src/main/res/menu/image_menu.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/src/main/res/menu/image_menu.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
 | 
			
		||||
 | 
			
		||||
    <item
 | 
			
		||||
        android:id="@+id/action_save_image_in_gallery"
 | 
			
		||||
        android:title="@string/action_save_image_in_gallery"
 | 
			
		||||
        />
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</menu>
 | 
			
		||||
@@ -335,4 +335,7 @@
 | 
			
		||||
    <string name="action_hang_up">Raccrocher</string>
 | 
			
		||||
    <string name="action_switch_camera">Changer de caméra</string>
 | 
			
		||||
    <string name="action_stop_camera">Arrêter la caméra</string>
 | 
			
		||||
    <string name="action_save_image_in_gallery">Enregistrer dans la gallerie</string>
 | 
			
		||||
    <string name="err_save_image_in_gallery">Une erreur a survenue lors de l\'enregistrement de l\'image dans la gallerie !</string>
 | 
			
		||||
    <string name="success_save_image_in_gallery">L\'image a bien été enregistrée dans la gallerie !</string>
 | 
			
		||||
</resources>
 | 
			
		||||
@@ -334,4 +334,7 @@
 | 
			
		||||
    <string name="action_hang_up">Hang up</string>
 | 
			
		||||
    <string name="action_switch_camera">Switch camera</string>
 | 
			
		||||
    <string name="action_stop_camera">Stop camera</string>
 | 
			
		||||
    <string name="action_save_image_in_gallery">Save in gallery</string>
 | 
			
		||||
    <string name="err_save_image_in_gallery">Could not save the image in the gallery!</string>
 | 
			
		||||
    <string name="success_save_image_in_gallery">Successfully saved the image into the gallery!</string>
 | 
			
		||||
</resources>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user