Delete Image Permanently from Trashbin in Phimpme App

In the Phimpme Android application, users can perform various operations on the images including renaming an image, sharing images, deleting images from the storage etc. However, with the implementation of the Trash Bin feature in the app, the user is now provided with the option to restore back the deleted images. Whenever the delete operation is performed, the selected images are moved to the Trash Bin and the user has the option to either delete the photos permanently or restoring back the deleted photos by navigating to the Trash bin section. So in this post, I’d be discussing the implementation of permanently deleting image/images from the Trashbin.

Step 1

Firstly, we need to add permanent delete option in the popup menu provided in the itemview in the TrashView section. Every item in the Trashbin section displays a popup menu with two options-restore and delete permanently. The permanent delete option has been implemented in the itemview by adding the following lines of code.

<?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/delete_permanently”
    android:title=“@string/delete_permanently”
    app:showAsAction=“never” />
</menu>

Step 2

Now when the user opts to permanently delete any photo from the bin, a function deletePermanent would be invoked passing-in the trashbin object corresponding to the selected item as the parameter. Inside the deletePermanent method, a check is performed to determine whether the corresponding image file exists or not using the .exists method of the File class and if the result is true the file is deleted permanently using the .delete method of the File class. The method deletePermanent returns a boolean value depending on whether the image file is deleted permanently from the storage or not. The code snippets used to implement the deletePermanent method is provided below.

private boolean deletePermanent(TrashBinRealmModel trashBinRealmModel){
  boolean succ = false;
  String path = trashBinRealmModel.getTrashbinpath();
  File file = new File(Environment.getExternalStorageDirectory() + “/” + “.nomedia”);
  //File file = new File(Environment.getExternalStorageDirectory() + “/” + “TrashBin”);
  if(file.exists()){
      File file1 = new File(path);
      if(file1.exists()){
          succ = file1.delete();
      }
  }
  return succ;
}

Step 3

The function deletePermanent used implemented in the previous step returns a boolean value which will be used in this step. So if the deletePermanent method returns true indicating that the image has been deleted from the trashbin, first a method deleteFromRealm is invoked passing-in the path of the image in the Trashbin to delete the corresponding image’s record from the realm database. Thereafter, that particular trashbin item is removed from the ArrayList<TrashbinRealmModel> populating the TrashBin adapter to display the items in the TrashBin Activity and the adapter is notified of this change by the use of NotifyItemRemoved and NotifyItemRangeChanged methods of the RecyclerView adapter class passing-in the position of the item as parameter to the former and position along with the size of the updated list as parameters to the latter function. After the adapter is updated about the change in the dataset, the adapter re-populates the recyclerview thus displaying the remaining items in the trashbin section. The code snippets implementing the above-mentioned operations are provided below.

if(deletePermanent(trashBinRealmModel)){
  deleteFromRealm(trashItemsList.get(position).getTrashbinpath());
  trashItemsList.remove(position);
  notifyItemRemoved(position);
  notifyItemRangeChanged(position, trashItemsList.size());
}
private void deleteFromRealm(final String path){
  Realm realm = Realm.getDefaultInstance();
  realm.executeTransaction(new Realm.Transaction() {
      @Override public void execute(Realm realm) {
          RealmResults<TrashBinRealmModel> trashBinRealmModels = realm.where(TrashBinRealmModel.class).equalTo
                  (“trashbinpath”, path).findAll();
          trashBinRealmModels.deleteAllFromRealm();
      }
  });
}

This is how we have implemented the functionality to permanently delete an image from the Trashbin section in the Phimpme Android application. To get the full source code, please refer to the Phimpme Android Github repository listed in the resource section below.

Resources

  1. Android Developer documentation –https://developer.android.com/reference/java/io/File
  2. Github-Phimpme Android Repository – https://github.com/fossasia/phimpme-android/
  3. Realm database operations Android – https://www.androidhive.info/2016/05/android-working-with-realm-database-replacing-sqlite-core-data/
Continue ReadingDelete Image Permanently from Trashbin in Phimpme App

Compressing Images in Resolution in Phimpme Android Application

In the Phimpme Android application, users can perform various operations on images such as editing an image, sharing an image, moving the image to another folder, printing a pdf version of the image and many more. However, another important functionality that has been implemented is the option to compress an image. Two modes of compress operation have been implemented namely compress by size and compress by dimensions. In the previous blog post I discussed the implementation of compress by size operation. So in this blog post, I will be discussing how we achieved the functionality to compress any image by resolution.

Step 1

First, we need to add an option in the bottombar menu(in the SingleMediaActivity) to compress the image being viewed. The option to compress an image has been added by implementing the following lines of code in the  menu_bottom_view_pager.xml file.

<item
      android:id=“@+id/action_compress”
      android:orderInCategory=“2”
      app:showAsAction=“always”
      android:icon=“@drawable/compressicn”
      android:title=“Compress”/>

Step 2

Now on selecting the compress option, the user would be prompted to choose the compress mode i.e compress by size or compress by dimension. Once the user opts for compressing the image by resolution, a dialog containing the various resolutions options to choose from is to be displayed. Code snippets used to implement the dialog along with seekbar is displayed below.

<android.support.v7.widget.CardView
  xmlns:android=“http://schemas.android.com/apk/res/android”
  xmlns:app=“http://schemas.android.com/apk/vn.mbm.phimp.me”
  android:layout_width=“match_parent”
  android:layout_height=“wrap_content”
  app:cardCornerRadius=“2dp”
  android:id=“@+id/dialog_chose_provider_title”>
  <LinearLayout
      android:layout_width=“match_parent”
      android:layout_height=“wrap_content”
      android:orientation=“vertical”>

      <TextView
          android:id=“@+id/compress_title”
          android:layout_width=“match_parent”
          android:layout_height=“wrap_content”
          android:padding=“24dp”
          android:text=“@string/compress_by_dimension”
          android:textColor=“@color/md_dark_primary_text”
          android:textSize=“18sp”
          android:textStyle=“bold” />

      <ListView
          android:id=“@+id/listview”
          android:layout_width=“match_parent”
          android:layout_height=“321dp”
          android:layout_alignParentStart=“true”
          android:layout_centerVertical=“true”/>

  </LinearLayout>
</android.support.v7.widget.CardView>

A screenshot displaying the resolutions option dialog is provided below.

Step 3

Now in this final step as mentioned for the compress by size post, we would use the image compression library Compressor to obtain the compress by resolution functionality. After the user has specified the new resolution required, the Compressor class of the library is instantiated by passing-in the context as the parameter and some of its functions are invoked simaltaneously. The functions invoked are setMaxWidth(), setMaxHeight(),  setCompressFormat(), setDestinationDirectoryPath(), compressToFile().

setMaxWidth() – to set the width of the output image.

setMaxHeight() – to set the height of the output image.

setCompressFormat(Bitmap.CompressFormat) – to determine the format of the output compressed image.

setDestinationDirectoryPath(File) – to specify the path to which the compressed image is to be saved.

compressToFile(File) – to perform the compress operation, passing-in the file object of the corresponding image to be compressed.

The compressToFile() function performs the final compress operation and saves the compressed image to the specified path.

Code snippets to implement the above mentioned operations are given below

private void compressDim() {
  ListCompressAdapter lviewAdapter;
  ArrayList<String> compress_option= new ArrayList<String>();
  MediaDetailsMap<String,String> mediaDetailsMap = SingleMediaActivity.mediacompress.getMainDetails(this);
  //gives in the form like 1632×1224 (2.0 MP) , getting width and height of it
  String dim[]=mediaDetailsMap.get(“Resolution”).split(“x”);
  int  width= Integer.parseInt(dim[0].replaceAll(” “,“”));
  String ht[]=dim[1].split(” “);
  int height= Integer.parseInt(ht[0]);
  LayoutInflater inflater = getLayoutInflater();
  final View dialogLayout = inflater.inflate(R.layout.dialog_compresspixel, null);
  TextView title = (TextView) dialogLayout.findViewById(R.id.compress_title);
  title.setBackgroundColor(getPrimaryColor());
  //create options of compress in dimensions in multiple of 2
  int awidth=width;
  int aheight=height;
  ListView listView = (ListView)dialogLayout.findViewById(R.id.listview);
  while ((width%2==0)&&(height%2==0)) {
      compress_option.add(width + ” X “ + height);
      width=width/2;
      height=height/2;
  }

  lviewAdapter = new ListCompressAdapter(this, compress_option);
  listView.setAdapter(lviewAdapter);
  final int finalWidth = awidth;
  final int finalHeight = aheight;
  listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
      @Override
      public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
          if (position==0){
              cwidth[0] = finalWidth ;
              cheight[0] = finalHeight;}
          else{
              cwidth[0] = finalWidth /(position*2);
              cheight[0] = finalHeight /(position*2);}
          view.setBackgroundColor(R.color.md_light_blue_A400);
          new SaveCompressedImage().execute(“Resolution”);
          finish();
      }
  });
new Compressor(getApplicationContext())
      .setMaxWidth(cwidth[0])
      .setMaxHeight(cheight[0])
      .setCompressFormat(Bitmap.CompressFormat.JPEG)
      .setDestinationDirectoryPath( FileUtilsCompress.createFolders().getPath())
      .compressToFile(new File(saveFilePath));

This is how we have implemented the functionality to compress an image by size in the Phimpme Android application. To get the full source code, please refer to the Phimpme Android Github repository listed in the resource section below.

Resources

  1. Android Developer documentation –https://developer.android.com/reference/java/io/File
  2. Github-Phimpme Android Repository – https://github.com/fossasia/phimpme-android/
  3. Compressor Library – https://github.com/zetbaitsu/Compressor

 

Continue ReadingCompressing Images in Resolution in Phimpme Android Application

Compress Images Size in Phimpme Android application

In the Phimpme Android application, users can perform various operations on images such as editing an image, sharing an image, moving the image to another folder, printing a pdf version of the image and many more. However, another important functionality that has been implemented is the option to compress an image. Two modes of compress operation have been implemented namely compress by size and compress by dimensions. So in this blog post, I will be discussing how we achieved the functionality to compress any image by size.

Step 1

First, we need to add an option in the bottom bar menu(in the SingleMediaActivity) to compress the image being viewed. The option to compress an image has been added by implementing the following lines of code in the  menu_bottom_view_pager.xml file.

<item
      android:id=“@+id/action_compress”
      android:orderInCategory=“2”
      app:showAsAction=“always”
      android:icon=“@drawable/compressicn”
      android:title=“Compress”/>

Step 2

Now on selecting the compress option, the user would be prompted to choose the compress mode i.e compress by size or compress by dimension. Once the user has opted for the size mode a dialog with a seekbar to set the compress percentage is to be displayed. Code snippets used to implement the dialog along with seekbar is displayed below.

<RelativeLayout
  android:layout_width=“wrap_content”
  android:layout_height=“wrap_content”
  android:layout_marginTop=“8dp”>

  <SeekBar
      android:id=“@+id/seekBar”
      android:layout_width=“match_parent”
      android:layout_height=“wrap_content”
      android:layout_weight=“0.65”
      android:max=“90”
      android:progressBackgroundTint=“@color/colorPrimary”
      android:thumb=“@drawable/ic_location_on_black_24dp” />

  <TextView
      android:id=“@+id/textview2”
      android:layout_width=“wrap_content”
      android:layout_height=“wrap_content”
      android:layout_alignParentEnd=“true”
      android:layout_below=“@+id/seekBar”
      android:layout_marginBottom=“5dp”
      android:layout_marginEnd=“16dp”
      android:text=“95%”
      android:textAppearance=“@style/TextAppearance.AppCompat.Body1”
      android:textSize=“16sp” />
</RelativeLayout>

A screenshot displaying the dialog to set the compress percentage is provided below

Step 3

Here to obtain the compress functionality we have used an open-sourced custom image compression library Compressor. After the user has set the compress percentage, the Compressor class of the library is instantiated by passing-in the context as the parameter and some of its functions are invoked simultaneously. The functions invoked are setQuality(), setCompressFormat(), setDestinationDirectoryPath(), compressToFile().

setQuality(int) – to set the percentage compressed.

setCompressFormat(Bitmap.CompressFormat) – to determine the format of the output compressed image.

setDestinationDirectoryPath(File) – to specify the path to which the compressed image is to be saved.

compressToFile(File) – to perform the compress operation, passing-in the file object of the corresponding image to be compressed.

The compressToFile() function performs the final compress operation and saves the compressed image to the specified path.

Code snippets to implement the above-mentioned operations are given below

private void compressSize() {

  LayoutInflater inflater = getLayoutInflater();
  View dialogLayout = inflater.inflate(R.layout.dialog_compresssize, null);
  TextView title = (TextView) dialogLayout.findViewById(R.id.compress_title);
  title.setBackgroundColor(getPrimaryColor());
  SeekBar percentsize = (SeekBar) dialogLayout.findViewById(R.id.seekBar);
  percentsize.getThumb().setColorFilter(getAccentColor(), PorterDuff.Mode.SRC_IN);
  percentsize.setProgress(0);
  final TextView percent=(TextView)dialogLayout.findViewById(R.id.textview2);
  percentsize.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
      @Override
      public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
          //options of compress by size from 5% to 9;
          int progress1=95-progress;
          progress1=progress1-progress1%5;
          percent.setText(progress1+“%”);
          percentagecompress=progress1;}

      @Override
      public void onStartTrackingTouch(SeekBar seekBar) {
          //do nothing
      }

      @Override
      public void onStopTrackingTouch(SeekBar seekBar) {
          //do nothing
      }
  });}
new Compressor(getApplicationContext())
.setQuality(percentagecompress)
.setCompressFormat(Bitmap.CompressFormat.JPEG)
.setDestinationDirectoryPath(FileUtilsCompress.createFolders().getPath())
.compressToFile(new File(saveFilePath));

This is how we have implemented the functionality to compress an image by size in the Phimpme Android application. To get the full source code, please refer to the Phimpme Android Github repository.

Resources

  1. Android Developer documentation –https://developer.android.com/reference/java/io/File
  2. Compressor Library – https://github.com/zetbaitsu/Compressor
  3. Seekbar Tutorial – https://abhiandroid.com/ui/seekbar
Continue ReadingCompress Images Size in Phimpme Android application

Implementing Undo Operation in Phimpme Android application

In the Phimpme Android application, users can perform various operations on the images available including renaming an image, sharing images, deleting images from the storage etc. However, there might occur a scenario where the user accidentally or in a rush performs some action and would want to undo it the very next second, so in such cases the undo action feature comes in pretty handy. So in this blog post, I will be discussing the undo operation option implemented for the delete image feature in Phimpme Android app.

Step 1

Firstly, we need to add an “Undo” action button in the Snackbar that displays the success operation message. With this addition, the user would have time to undo an operation until the snackbar message is being displayed on the screen. The undo action button can be added to the Snackbar by the use of the setAction method of the Snackbar class. The code snippets used to implement the button is provided below

Snackbar snackbar = SnackBarHandler.showWithBottomMargin2(mDrawerLayout, String.valueOf(no) + ” “ + getString(R.string
              .trashbin_move_onefile),
      navigationView.getHeight
              (), Snackbar.LENGTH_SHORT);
snackbar.setAction(“UNDO”, new View.OnClickListener() {
  @Override
  public void onClick(View view) {
      getAlbum().moveAllMedia(getApplicationContext(), getAlbum().getPath(), media1);
      refreshListener.onRefresh();
  }
});
snackbar.show();

Step 2

When the user performs the delete operation, first the photos are moved to the trashbin and the user have the option to delete them from there. Now, if the user opts for undo operation, on clicking the undo button the function moveallMedia will be invoked passing-in context, the path of the current album and an ArrayList<Media> containing the deleted media on which the undo operation is to be performed upon, as parameters. Here the ArrayList<Media> passed as a parameter contains the trashbin paths of the images deleted by the previous action. A method storeDeletedFilesTemporarily has been used that returns the list containing the deleted images trashbin paths. The implementation of the method storeDeletedFilesTemporarily has been provided below.

private ArrayList<Media> storeDeletedFilesTemporarily(){
ArrayList<Media> deletedImages = new ArrayList<>();
if(!all_photos && !fav_photos && editMode){
for(Media m: getAlbum().getSelectedMedia()){
String name = m.getPath().substring(m.getPath().lastIndexOf(“/”) + 1);
deletedImages.add(new Media(Environment.getExternalStorageDirectory() + “/” + “.nomedia” + “/” + name));
}
} else if(all_photos && !fav_photos && editMode){
for(Media m: selectedMedias){
String name = m.getPath().substring(m.getPath().lastIndexOf(“/”) + 1);
deletedImages.add(new Media(Environment.getExternalStorageDirectory() + “/” + “.nomedia” + “/” + name));
}
}
return deletedImages;
}

Step 3

Now in the final step, I’d discuss the implementation of the moveAllMedia method that actually completes the undo operation. As I mentioned earlier that on performing the delete operation the images are moved to the bin folder(which is hidden from the other applications), so the moveAllMedia method here will again move the images from the trashbin folder to the current folder. With this operation deleted images would be stored back to their original folder and their trashbin record would be simultaneously deleted from the Realm database. The code implementation of the moveAllMedia method is provided below.

public int moveAllMedia(Context context, String targetDir, ArrayList<Media> albummedia){
 int n = 0;
 try
 {
    int index=-1;
    for(int i =0;i<albummedia.size(); i++)
    {
       String s = albummedia.get(i).getPath();
       int indexOfLastSlash = s.lastIndexOf(“/”);
       String fileName = s.substring(indexOfLastSlash + 1);

       if(!albummedia.get(i).getPath().equals(targetDir+“/”+fileName)){
          index=-1;
       }else{
          index=i;
          break;

       }
    }
    if(index!=-1)
    {
       n = –1;
    }else{
       for (int i = 0; i < albummedia.size(); i++) {

          if (moveMedia(context, albummedia.get(i).getPath(), targetDir)) {
             String from = albummedia.get(i).getPath();
             scanFile(context, new String[]{ from, StringUtils.getPhotoPathMoved(albummedia.get(i).getPath(),
                   targetDir) },
                   new MediaScannerConnection.OnScanCompletedListener() {
                      @Override
                      public void onScanCompleted(String s, Uri uri) {
                         Log.d(“scanFile”, “onScanCompleted: “ + s);
                      }
                   });
             media.remove(albummedia.get(i));
             n++;
          }
       }
       setCount(media.size());
    }
 } catch (Exception e) { e.printStackTrace(); }
 return n;

}

This is how we have implemented the functionality to perform Undo operation in the Phimpme Android application. To get the full source code, please refer to the Phimpme Android Github repository.

Resources

  1. Android Developer documentation –https://developer.android.com/reference/java/io/File
  2. MediaScanner Tutorial – https://stackoverflow.com/questions/9414955/trigger-mediascanner-on-specific-path-folder-how-to/25086535

 

Continue ReadingImplementing Undo Operation in Phimpme Android application

Option to Restore Deleted Images in Phimpme Android Application

In the Phimpme Android application, users can perform various operations on the images including renaming an image, sharing images, deleting images from the storage etc. However with the implementation of Trash Bin feature in the app, the user is now provided with the option to restore back the deleted images. Whenever the delete operation is performed, the selected images are moved to the Trash Bin and the user has the option to either delete the photos permanently or restoring back the deleted photos by navigating to the Trash bin section. So, in this post I’d be discussing the implementation of restore image/images functionality.

Step 1

Firstly, we need to add restore option in the popup menu provided in the itemview in the TrashView section. Every item in the Trashbin section displays a popup menu with two options-restore and delete permanently. The popup menu along with the two options have been implemented by adding the following lines of code.

<?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/restore_option”
    android:title=“@string/restore_photo”
    app:showAsAction=“never” />

<item
    android:id=“@+id/delete_permanently”
    android:title=“@string/delete_permanently”
    app:showAsAction=“never” />
</menu>

Step 2

Now after the user opts to restore a particular image, the corresponding realm object for the image would be retrieved from the Realm database. This realm object would contain attributes namely trashbinpath, oldpath, datetime, timeperiod. Here the oldpath attribute contains the path where it  was stored in the device storage before the delete operation was performed on the image. Thereafter to restore the image to its old path, a move operation would be performed which would move the image from the TrashBin section to the album it was stored in before deletion. With this move operation, the image is restored to its old path and is visible in the respective album resulting in the removal/deletion of the image from the TrashBin section. The method implemented to perform the above mentioned operations is provided below.

private boolean restoreImage(TrashBinRealmModel trashBinRealmModel){
  String oldpath = trashBinRealmModel.getOldpath();
  boolean success = false;
  try {
      String from = trashBinRealmModel.getTrashbinpath();
      if (success = moveMedia(context, from, targetDir)) {
          scanFile(context, new String[]{ from, StringUtils.getPhotoPathMoved(pathofmed, targetDir) });
      }
  } catch (Exception e) { e.printStackTrace(); }
  return success;
}

Step 3

In the previous step, the move operation for the restore feature was performed by the restoreImage method which inturn uses method moveMedia() to get the job done. So in this step, I’d be discussing about the implementation of the moveMedia() method. Inside the moveMedia() method, moveFile method of ContentHelper class is invoked passing-in context, sourcefile, and the destination folder as the parameters. Thereafter a normal rename operation is performed by the use of the renameTo method to move the file to destination folder. Now if the rename operation is performed successfully, the file is moved to its old path whereas if the rename operation fails to get the job done, a copy operation is initiated to copy the file to the destination folder and the image  the is deleted from the trashbin section if the copy operation is successful. The code snippets used to implement the moveMedia and moveFile are provided below.

private boolean moveMedia(Context context, String source, String targetDir) {
 File from = new File(source);
 File to = new File(targetDir);
 return ContentHelper.moveFile(context, from, to);
}
public static boolean moveFile(Context context, @NonNull final File source, @NonNull final File targetDir) {
 // First try the normal rename.
 File target = new File(targetDir, source.getName());

 boolean success = source.renameTo(target);

 if (!success) {
    success = copyFile(context, source, targetDir);
    if (success) {
       success = deleteFile(context, source);
    }
 }
 //if (success) scanFile(context, new String[]{ source.getPath(), target.getPath() });
 return success;

}

This is how we have implemented the functionality to restore a deleted image in the Phimpme Android application. To get the full source code, please refer to the Phimpme Android Github repository listed in the resource section below.

Resources

  1. Android Developer documentation –https://developer.android.com/reference/java/io/File
  2. Github-Phimpme Android Repository – https://github.com/fossasia/phimpme-android/
  3. Renaming a file in java – http://stacktips.com/tutorials/java/how-to-delete-and-rename-a-file-in-java
Continue ReadingOption to Restore Deleted Images in Phimpme Android Application

Move Photos from one Path to Another in Phimpme Android Application

In the Phimpme Android application, users can perform various operations on images such as editing an image, sharing an image, printing a pdf version of the image and many more. However, another important functionality that has been implemented is the option to move an image from one path(folder) to another. So in this blog post, I will be discussing how we achieved the functionality to move any image.

Step 1

First, we need to add an option in the overflow menu to move any no of images from one folder to another. The option to move an image has been added by implementing the following lines of code in the  menu_view_pager.xml file.

<item
  android:id=“@+id/action_move”
  app:showAsAction=“never”
  android:title=“Move”/>

Step 2

Now after the user opts for the move operation, a bottomSheetDialog containing all the albums/folders in the storage to choose for moving the photos into will be displayed. Once the user selects the required location to move the photos to, a method moveSelectedMedia would be invoked passing-in the context and the destination path as the parameters. Thereafter inside the method moveSelectedMedia, first a check would be performed to determine whether the selected photos(to move) are already present in the folder(path folder and destination folder both are same), if true the operation would be terminated as the photos are already present in the destination folder, and if false the selected photos would be moved to the destination folder one by one by the use of another method moveMedia. The code snippets used to implement the moveSelectedMedia is provided below.

public int moveSelectedMedia(Context context, String targetDir) {
 int n = 0;
 try
 {
    int index=-1;
    for(int i =0;i<selectedMedias.size();i++)
    {
       String s = selectedMedias.get(i).getPath();
       int indexOfLastSlash = s.lastIndexOf(“/”);
       String fileName = s.substring(indexOfLastSlash + 1);

       if(!selectedMedias.get(i).getPath().equals(targetDir+“/”+fileName)){
          index=-1;
       }else{
          index=i;
          break;

       }
    }
    if(index!=-1)
    {
       n = –1;
    }else{
       for (int i = 0; i < selectedMedias.size(); i++) {

          if (moveMedia(context, selectedMedias.get(i).getPath(), targetDir)) {
             String from = selectedMedias.get(i).getPath();
             scanFile(context, new String[]{ from, StringUtils.getPhotoPathMoved(selectedMedias.get(i).getPath(), targetDir) },
                   new MediaScannerConnection.OnScanCompletedListener() {
                      @Override
                      public void onScanCompleted(String s, Uri uri) {
                         Log.d(“scanFile”, “onScanCompleted: “ + s);
                      }
                   });
             media.remove(selectedMedias.get(i));
             n++;
          }
       }
       setCount(media.size());
    }
 } catch (Exception e) { e.printStackTrace(); }
 return n;
}

Step 3

In this step, I’d discuss the use and implementation of the moveMedia method mentioned in the earlier step. So the moveMedia is used to move a single photo to a particular destination, taking-in the context, the oldpath of the photo and the destination folder as parameters. Inside this method another method moveFile of the ContentHelper class is invoked passing-in the context, File object of the photo and File object of the destination folder as parameters. Now inside the moveFile method the actual move operation takes place. First the photo is tried to move by doing a normal rename operation by using the renameTo function of the File class. The success of the rename operation updates the path of the photo to the destination path and deletes the original path of the photo whereas if the normal rename operation fails, then the photo is moved by first performing a copy operation to copy the photo to the destination folder and then deleting the original photo. The code snippets used to implement the moveMedia and moveFile functions are provided below.

private boolean moveMedia(Context context, String source, String targetDir) {
 File from = new File(source);
 File to = new File(targetDir);
 return ContentHelper.moveFile(context, from, to);
}
public static boolean moveFile(Context context, @NonNull final File source, @NonNull final File targetDir) {
 // First try the normal rename.
 File target = new File(targetDir, source.getName());

 boolean success = source.renameTo(target);

 if (!success) {
    success = copyFile(context, source, targetDir);
    if (success) {
       success = deleteFile(context, source);
    }
 }

 //if (success) scanFile(context, new String[]{ source.getPath(), target.getPath() });
 return success;
}

And at last, after the photos are moved successfully the media adapter is called with the updated photos list to display thus displaying the remaining photos in the folder.

This is how we have implemented the functionality to move images from one path to another in the Phimpme Android application. To get the full source code, please refer to the Phimpme Android Github repository listed in the resource section below.

Resources

1. Android Developer documentation –              https://developer.android.com/reference/java/io/File

2. Github-Phimpme Android Repository – https://github.com/fossasia/phimpme- android/

3. Renaming a file in java – http://stacktips.com/tutorials/java/how-to-delete-and-rename-a-file-in-java

Continue ReadingMove Photos from one Path to Another in Phimpme Android Application

Option to Rename an Image in Phimpme Android Application

In the Phimpme Android application, users can perform various operations on images such as editing an image, sharing an image, moving the image to another folder, printing a pdf version of the image and many more. However, another important functionality that has been implemented is the option to rename an image. So in this blog post, I will be discussing how we achieved the functionality to rename an image.

Step 1

First, we need to add an option in the overflow menu to rename the image being viewed. The option to rename an image has been added by implementing the following lines of code in the  menu_view_pager.xml file.

<item
  android:id=“@+id/rename_photo”
  app:showAsAction=“never”
  android:title=“@string/Rename”/>

Step 2

Now after the user chooses the option to rename any image from the overflow menu, an alert dialog with an edittext would be displayed to the user with the old name and provide the user to add a new name for the photo. The dialog box with edittext has been implemented with the following lines of XML code.

<android.support.v7.widget.CardView
  android:layout_width=“match_parent”
  android:layout_height=“wrap_content”
  app:cardCornerRadius=“2dp”
  android:id=“@+id/description_dialog_card”>
  <ScrollView
      android:layout_width=“match_parent”
      android:layout_height=“match_parent”>
      <LinearLayout
          android:layout_width=“match_parent”
          android:layout_height=“wrap_content”
          android:orientation=“vertical”>
          <TextView
              android:id=“@+id/description_dialog_title”
              android:layout_width=“match_parent”
              android:textColor=“@color/md_dark_primary_text”
              android:layout_height=“wrap_content”
              android:background=“@color/md_dark_appbar”
              android:padding=“24dp”
              android:text=“@string/type_description”
              android:textSize=“18sp”
              android:textStyle=“bold” />
          <LinearLayout
              android:id=“@+id/rl_description_dialog”
              android:layout_width=“match_parent”
              android:layout_height=“wrap_content”
              android:orientation=“horizontal”
              android:padding=“15dp”>
              <EditText
                  android:id=“@+id/description_edittxt”
                  android:layout_width=“fill_parent”
                  android:layout_height=“wrap_content”
                  android:padding=“15dp”
                  android:hint=“@string/description_hint”
                  android:textColorHint=“@color/grey”
                  android:layout_margin=“20dp”
                  android:gravity=“top|left”
                  android:inputType=“textCapSentences|textMultiLine”
                  android:maxLength=“2000”
                  android:maxLines=“4”
                  android:selectAllOnFocus=“true”/>
              <ImageButton
                  android:layout_width=“@dimen/mic_image”
                  android:layout_height=“@dimen/mic_image”
                  android:layout_alignRight=“@+id/description_edittxt”
                  app2:srcCompat=“@drawable/ic_mic_black”
                  android:layout_gravity=“center”
                  android:background=“@color/transparent”
                  android:paddingEnd=“10dp”
                  android:paddingTop=“12dp”
                  android:id=“@+id/voice_input”/>
          </LinearLayout>
      </LinearLayout>
  </ScrollView>
</android.support.v7.widget.CardView>

The screenshot displaying the dialog with edittext is provided below.

Step 3

Now after retrieving the new name entered by the user for the photo we would extract the extension of the old name which can be .jpg, .png etc. Thereafter we’d need to create a new File object passing in the new path of the image(the path folder remains the same only the image name gets changed to a new one) as the constructor parameter. Now using the renameTo method of the File class the old image file can be renamed. However, with this rename operation the image reference would not be automatically updated in the MediaStore database. So we’d need to delete the old file path from the Android system MediaStore database which keeps a URI reference to all the media files present on the device. At last, we’d need to invoke the MediaScanner class to scan all the media files so that the new file path of the renamed image is scanned and is picked up by the MediaStore database. This can be done with the help of an action intent to initiate the media scan action. The code changes implemented to perform the above-mentioned operation is given below.

public void onClick(View dialog) {
      if (editTextNewName.length() != 0) {
          int index = file.getPath().lastIndexOf(“/”);
          String path = file.getPath().substring(0, index);
          File newname = new File(path + “/” + editTextNewName.getText().toString() + “.” +
                  imageextension);
          if(file.renameTo(newname)){
              ContentResolver resolver = getApplicationContext().getContentResolver();
              resolver.delete(
                      MediaStore.Images.Media.EXTERNAL_CONTENT_URI, MediaStore.Images.Media.DATA +
                              “=?”, new String[] { file.getAbsolutePath() });
              Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
              intent.setData(Uri.fromFile(newname));
              getApplicationContext().sendBroadcast(intent);
          }
          if(!allPhotoMode){
              int a = getAlbum().getCurrentMediaIndex();
              getAlbum().getMedia(a).setPath(newname.getPath());
          }else {
              listAll.get(current_image_pos).setPath(newname.getPath());
          }
          renameDialog.dismiss();
          SnackBarHandler.showWithBottomMargin(parentView, getString(R.string.rename_succes), navigationView
                  .getHeight());
      } else {
          SnackBarHandler.showWithBottomMargin(parentView, getString(R.string.insert_something),
                  navigationView.getHeight());
          editTextNewName.requestFocus();
      }
  }
});

This is how we have implemented the functionality to rename an image in the Phimpme Android application. To get the full source code, please refer to the Phimpme Android Github repository listed in the resource section below.

Resources

1.Android Developer documentation-https://developer.android.com/reference/java/io/File

2.Github-Phimpme Android Repository – https://github.com/fossasia/phimpme-android/

3.Renaming a file in java – http://stacktips.com/tutorials/java/how-to-delete-and-rename-a-file-in-java

 

Continue ReadingOption to Rename an Image in Phimpme Android Application

Option to rename albums in the Phimpme Android Application

In the Phimpme Android application, users can perform various operations on the albums available such as creating a zip file of the album, hiding an album and many more. However, one another useful functionality that has been added to the Phimpme Android application is the option to rename albums. So in this post, I will be discussing the implementation of the renaming functionality.

Step 1

First we need to add an option in the overflow menu to rename an album while we long-select an album or we are viewing photos inside a particular album. The option in the overflow menu can be added by integrating the following lines of code in the menu_albums.xml file(this file contains the xml code for overflow menu options provided for albums).

<item
android:id=”@+id/renameAlbum”
android:title=”@string/rename”
app:showAsAction=”never” />

Step 2

Now after the user selects the option in the overflow menu to rename the current viewing album, an alertdialog with an edittext would be displayed to the user to enter the new name for the album. The alertdialog containing the edittext has been implemented with the following lines of code.

<android.support.v7.widget.CardView
xmlns:android=”http://schemas.android.com/apk/res/android”
xmlns:app=”http://schemas.android.com/apk/vn.mbm.phimp.me”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
app:cardCornerRadius=”2dp”
android:id=”@+id/dialog_chose_provider_title”>
<LinearLayout
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:orientation=”vertical”>
<TextView
android:id=”@+id/rename_title”
android:layout_width=”match_parent”
android:textColor=”@color/md_dark_primary_text”
android:layout_height=”wrap_content”
android:background=”@color/md_dark_appbar”
android:padding=”24dp”
android:text=”@string/rename_photo_action”
android:textSize=”18sp”
android:textStyle=”bold” />
<RelativeLayout
android:id=”@+id/container_edit_text”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:orientation=”vertical”
android:padding=”24dp”/>
</LinearLayout>
</android.support.v7.widget.CardView>

The screenshot of the dialog to enter the new name is provided below.

Step 3

Finally, after retrieving the new name for the album entered by the user, the renameAlbum method is invoked by passing in the application context and new name as the parameters. Now inside the renameAlbum method, a new file path is created by the use of the getAlbumPathRenamed method of the StringUtils class and the current path of the album is changed to the new path generated earlier. Similarly path of each media inside the album is changed accordingly by the use of the method getPhotoPathRenamedAlbumChange of the StrinUtils class by looping through the media objects one by one. The lines of code implemented to perform the above-mentioned operations are provided below.

public boolean renameAlbum(final Context context, String newName) {
 found_id_album = false;
 boolean success;
 File newDir = new File(StringUtils.getAlbumPathRenamed(getPath(), newName));
 File oldDir = new File(getPath());
 success = oldDir.renameTo(newDir);
 if(success) {
    for (final Media m : media) {
       File from = new File(m.getPath());
       File to = new File(StringUtils.getPhotoPathRenamedAlbumChange(m.getPath(), newName));
       scanFile(context, new String[]{ from.getAbsolutePath() });
       scanFile(context, new String[]{ to.getAbsolutePath() }, new MediaScannerConnection.OnScanCompletedListener() {
          @Override
          public void onScanCompleted(String s, Uri uri) {
             if (!found_id_album) {
                id = MediaStoreProvider.getAlbumId(context, s);
                found_id_album = true;
             }
             Log.d(s, “onScanCompleted: “+s);
             m.setPath(s); m.setUri(uri.toString());
          }
       });
    }
    path = newDir.getAbsolutePath();
    name = newName;
 }
 return success;
}

This is how we have implemented the functionality to rename particular albums in the Phimpme Android application. To get the full source code, please refer to the Phimpme Android Github repository listed in the resource section below.

Resources

1.Android Developer Guide – https://developer.android.com/reference/android/media/MediaScannerConnection

2.Github-Phimpme Android Repository – https://github.com/fossasia/phimpme-android/

3.Media Scanner tutorial –https://stackoverflow.com/questions/13270789/how-to-run-media-scanner-in-android

Continue ReadingOption to rename albums in the Phimpme Android Application