mirror of
https://github.com/nextcloud/talk-android
synced 2025-07-06 20:39:47 +01:00
add retake, send actions and preview
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
This commit is contained in:
parent
547e9ebf8b
commit
67c421a067
@ -190,6 +190,7 @@ dependencies {
|
|||||||
implementation 'androidx.camera:camera-camera2:1.0.1'
|
implementation 'androidx.camera:camera-camera2:1.0.1'
|
||||||
implementation 'androidx.camera:camera-lifecycle:1.0.1'
|
implementation 'androidx.camera:camera-lifecycle:1.0.1'
|
||||||
implementation 'androidx.camera:camera-view:1.0.0-alpha20'
|
implementation 'androidx.camera:camera-view:1.0.0-alpha20'
|
||||||
|
implementation "androidx.exifinterface:exifinterface:1.3.3"
|
||||||
|
|
||||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||||
|
|
||||||
|
@ -24,12 +24,15 @@ package com.nextcloud.talk.activities;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Size;
|
import android.util.Size;
|
||||||
import android.view.OrientationEventListener;
|
import android.view.OrientationEventListener;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
|
import android.view.View;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
@ -39,6 +42,8 @@ import com.nextcloud.talk.models.TakePictureViewModel;
|
|||||||
import com.nextcloud.talk.utils.FileUtils;
|
import com.nextcloud.talk.utils.FileUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@ -53,6 +58,7 @@ import androidx.camera.core.ImageCaptureException;
|
|||||||
import androidx.camera.core.Preview;
|
import androidx.camera.core.Preview;
|
||||||
import androidx.camera.lifecycle.ProcessCameraProvider;
|
import androidx.camera.lifecycle.ProcessCameraProvider;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.exifinterface.media.ExifInterface;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
public class TakePhotoActivity extends AppCompatActivity {
|
public class TakePhotoActivity extends AppCompatActivity {
|
||||||
@ -99,7 +105,7 @@ public class TakePhotoActivity extends AppCompatActivity {
|
|||||||
viewModel.isTorchEnabled()
|
viewModel.isTorchEnabled()
|
||||||
.observe(
|
.observe(
|
||||||
this,
|
this,
|
||||||
enabled -> camera.getCameraControl().enableTorch(enabled));
|
enabled -> camera.getCameraControl().enableTorch(enabled));
|
||||||
|
|
||||||
binding.toggleTorch.setOnClickListener((v) -> viewModel.toggleTorchEnabled());
|
binding.toggleTorch.setOnClickListener((v) -> viewModel.toggleTorchEnabled());
|
||||||
binding.switchCamera.setOnClickListener((v) -> {
|
binding.switchCamera.setOnClickListener((v) -> {
|
||||||
@ -111,6 +117,20 @@ public class TakePhotoActivity extends AppCompatActivity {
|
|||||||
imageCapture,
|
imageCapture,
|
||||||
preview);
|
preview);
|
||||||
});
|
});
|
||||||
|
binding.retake.setOnClickListener((v) -> {
|
||||||
|
Uri uri = (Uri) binding.photoPreview.getTag();
|
||||||
|
File photoFile = new File(uri.getPath());
|
||||||
|
if (!photoFile.delete()) {
|
||||||
|
Log.w(TAG, "Error deleting temp camera image");
|
||||||
|
}
|
||||||
|
binding.takePhoto.setEnabled(true);
|
||||||
|
showCameraElements();
|
||||||
|
});
|
||||||
|
binding.send.setOnClickListener((v) -> {
|
||||||
|
Uri uri = (Uri) binding.photoPreview.getTag();
|
||||||
|
setResult(RESULT_OK, new Intent().setDataAndType(uri, "image/jpeg"));
|
||||||
|
finish();
|
||||||
|
});
|
||||||
} catch (IllegalArgumentException | ExecutionException | InterruptedException e) {
|
} catch (IllegalArgumentException | ExecutionException | InterruptedException e) {
|
||||||
Log.e(TAG, "Error taking picture", e);
|
Log.e(TAG, "Error taking picture", e);
|
||||||
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
|
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
|
||||||
@ -119,6 +139,28 @@ public class TakePhotoActivity extends AppCompatActivity {
|
|||||||
}, ContextCompat.getMainExecutor(this));
|
}, ContextCompat.getMainExecutor(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showCameraElements() {
|
||||||
|
binding.send.setVisibility(View.GONE);
|
||||||
|
binding.retake.setVisibility(View.GONE);
|
||||||
|
binding.photoPreview.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
binding.preview.setVisibility(View.VISIBLE);
|
||||||
|
binding.takePhoto.setVisibility(View.VISIBLE);
|
||||||
|
binding.switchCamera.setVisibility(View.VISIBLE);
|
||||||
|
binding.toggleTorch.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showPictureProcessingElements() {
|
||||||
|
binding.preview.setVisibility(View.GONE);
|
||||||
|
binding.takePhoto.setVisibility(View.GONE);
|
||||||
|
binding.switchCamera.setVisibility(View.GONE);
|
||||||
|
binding.toggleTorch.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
binding.send.setVisibility(View.VISIBLE);
|
||||||
|
binding.retake.setVisibility(View.VISIBLE);
|
||||||
|
binding.photoPreview.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
private ImageCapture getImageCapture() {
|
private ImageCapture getImageCapture() {
|
||||||
final ImageCapture imageCapture = new ImageCapture.Builder().setTargetResolution(new Size(720, 1280)).build();
|
final ImageCapture imageCapture = new ImageCapture.Builder().setTargetResolution(new Size(720, 1280)).build();
|
||||||
|
|
||||||
@ -145,7 +187,7 @@ public class TakePhotoActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
binding.takePhoto.setOnClickListener((v) -> {
|
binding.takePhoto.setOnClickListener((v) -> {
|
||||||
binding.takePhoto.setEnabled(false);
|
binding.takePhoto.setEnabled(false);
|
||||||
final String photoFileName = dateFormat.format(new Date())+ ".jpg";
|
final String photoFileName = dateFormat.format(new Date()) + ".jpg";
|
||||||
try {
|
try {
|
||||||
final File photoFile = FileUtils.getTempCacheFile(this, "photos/" + photoFileName);
|
final File photoFile = FileUtils.getTempCacheFile(this, "photos/" + photoFileName);
|
||||||
final ImageCapture.OutputFileOptions options =
|
final ImageCapture.OutputFileOptions options =
|
||||||
@ -155,24 +197,33 @@ public class TakePhotoActivity extends AppCompatActivity {
|
|||||||
ContextCompat.getMainExecutor(this),
|
ContextCompat.getMainExecutor(this),
|
||||||
new ImageCapture.OnImageSavedCallback() {
|
new ImageCapture.OnImageSavedCallback() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
|
public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
|
||||||
final Uri savedUri = Uri.fromFile(photoFile);
|
final Uri savedUri = Uri.fromFile(photoFile);
|
||||||
Log.i(TAG, "onImageSaved - savedUri:" + savedUri);
|
Log.i(TAG, "onImageSaved - savedUri:" + savedUri);
|
||||||
setResult(RESULT_OK, new Intent().setDataAndType(savedUri, "image/jpeg"));
|
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||||
finish();
|
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
|
||||||
}
|
try {
|
||||||
|
binding.photoPreview.setImageBitmap(
|
||||||
@Override
|
BitmapFactory.decodeStream(new FileInputStream(photoFile), null, options));
|
||||||
public void onError(@NonNull ImageCaptureException e) {
|
binding.photoPreview.setRotation(getImageOrientation(photoFile));
|
||||||
Log.e(TAG, "Error", e);
|
binding.photoPreview.setTag(savedUri);
|
||||||
|
showPictureProcessingElements();
|
||||||
if(!photoFile.delete()) {
|
} catch (FileNotFoundException e) {
|
||||||
Log.w(TAG, "Deleting picture failed");
|
Log.w(TAG, "Error reading image", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
binding.takePhoto.setEnabled(true);
|
|
||||||
}
|
@Override
|
||||||
});
|
public void onError(@NonNull ImageCaptureException e) {
|
||||||
|
Log.e(TAG, "Error", e);
|
||||||
|
|
||||||
|
if (!photoFile.delete()) {
|
||||||
|
Log.w(TAG, "Deleting picture failed");
|
||||||
|
}
|
||||||
|
binding.takePhoto.setEnabled(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Toast.makeText(this, R.string.take_photo_error_deleting_picture, Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, R.string.take_photo_error_deleting_picture, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
@ -181,6 +232,36 @@ public class TakePhotoActivity extends AppCompatActivity {
|
|||||||
return imageCapture;
|
return imageCapture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getImageOrientation(File imageFile) {
|
||||||
|
int rotate = 0;
|
||||||
|
try {
|
||||||
|
ExifInterface exif = new ExifInterface(imageFile.getAbsolutePath());
|
||||||
|
int orientation = exif.getAttributeInt(
|
||||||
|
ExifInterface.TAG_ORIENTATION,
|
||||||
|
ExifInterface.ORIENTATION_NORMAL);
|
||||||
|
|
||||||
|
switch (orientation) {
|
||||||
|
case ExifInterface.ORIENTATION_ROTATE_270:
|
||||||
|
rotate = 270;
|
||||||
|
break;
|
||||||
|
case ExifInterface.ORIENTATION_ROTATE_180:
|
||||||
|
rotate = 180;
|
||||||
|
break;
|
||||||
|
case ExifInterface.ORIENTATION_ROTATE_90:
|
||||||
|
rotate = 90;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rotate = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.i(TAG, "ImageOrientation - Exif orientation: " + orientation + " - " + "Rotate value: " + rotate);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.w(TAG, "Error calculation rotation value");
|
||||||
|
}
|
||||||
|
return rotate;
|
||||||
|
}
|
||||||
|
|
||||||
private Preview getPreview() {
|
private Preview getPreview() {
|
||||||
Preview preview = new Preview.Builder().build();
|
Preview preview = new Preview.Builder().build();
|
||||||
preview.setSurfaceProvider(binding.preview.getSurfaceProvider());
|
preview.setSurfaceProvider(binding.preview.getSurfaceProvider());
|
||||||
|
8
app/src/main/res/drawable/ic_autorenew.xml
Normal file
8
app/src/main/res/drawable/ic_autorenew.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<!-- drawable/autorenew.xml -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:height="24dp"
|
||||||
|
android:width="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path android:fillColor="#000" android:pathData="M12,6V9L16,5L12,1V4A8,8 0 0,0 4,12C4,13.57 4.46,15.03 5.24,16.26L6.7,14.8C6.25,13.97 6,13 6,12A6,6 0 0,1 12,6M18.76,7.74L17.3,9.2C17.74,10.04 18,11 18,12A6,6 0 0,1 12,18V15L8,19L12,23V20A8,8 0 0,0 20,12C20,10.43 19.54,8.97 18.76,7.74Z" />
|
||||||
|
</vector>
|
@ -34,6 +34,13 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/photo_preview"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/toggle_torch"
|
android:id="@+id/toggle_torch"
|
||||||
style="@style/Widget.AppTheme.Button.IconButton"
|
style="@style/Widget.AppTheme.Button.IconButton"
|
||||||
@ -41,8 +48,8 @@
|
|||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_marginTop="12dp"
|
|
||||||
android:layout_marginStart="0dp"
|
android:layout_marginStart="0dp"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
android:layout_marginEnd="12dp"
|
android:layout_marginEnd="12dp"
|
||||||
android:contentDescription="@string/take_photo_toggle_torch"
|
android:contentDescription="@string/take_photo_toggle_torch"
|
||||||
android:insetLeft="4dp"
|
android:insetLeft="4dp"
|
||||||
@ -68,9 +75,9 @@
|
|||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
android:layout_marginTop="12dp"
|
android:layout_marginTop="12dp"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:layout_marginStart="12dp"
|
|
||||||
android:contentDescription="@string/take_photo_switch_camera"
|
android:contentDescription="@string/take_photo_switch_camera"
|
||||||
android:insetLeft="4dp"
|
android:insetLeft="4dp"
|
||||||
android:insetTop="4dp"
|
android:insetTop="4dp"
|
||||||
@ -89,6 +96,34 @@
|
|||||||
app:layout_constraintEnd_toStartOf="@+id/toggle_torch"
|
app:layout_constraintEnd_toStartOf="@+id/toggle_torch"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/retake"
|
||||||
|
style="@style/Widget.AppTheme.Button.IconButton"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:contentDescription="@string/take_photo_switch_camera"
|
||||||
|
android:insetLeft="0dp"
|
||||||
|
android:insetTop="0dp"
|
||||||
|
android:insetRight="0dp"
|
||||||
|
android:insetBottom="0dp"
|
||||||
|
android:padding="0dp"
|
||||||
|
android:tint="@android:color/white"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:backgroundTint="@color/colorPrimary"
|
||||||
|
app:cornerRadius="@dimen/button_corner_radius"
|
||||||
|
app:elevation="0dp"
|
||||||
|
app:icon="@drawable/ic_autorenew"
|
||||||
|
app:iconGravity="textStart"
|
||||||
|
app:iconPadding="0dp"
|
||||||
|
app:iconSize="24dp"
|
||||||
|
app:iconTint="@color/white"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/takePhoto"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/takePhoto"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
android:id="@+id/takePhoto"
|
android:id="@+id/takePhoto"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@ -103,4 +138,32 @@
|
|||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:srcCompat="@drawable/ic_baseline_photo_camera_24" />
|
app:srcCompat="@drawable/ic_baseline_photo_camera_24" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/send"
|
||||||
|
style="@style/Widget.AppTheme.Button.IconButton"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:contentDescription="@string/take_photo_switch_camera"
|
||||||
|
android:insetLeft="0dp"
|
||||||
|
android:insetTop="0dp"
|
||||||
|
android:insetRight="0dp"
|
||||||
|
android:insetBottom="0dp"
|
||||||
|
android:padding="0dp"
|
||||||
|
android:tint="@android:color/white"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:backgroundTint="@color/colorPrimary"
|
||||||
|
app:cornerRadius="@dimen/button_corner_radius"
|
||||||
|
app:elevation="0dp"
|
||||||
|
app:icon="@drawable/ic_send"
|
||||||
|
app:iconGravity="textStart"
|
||||||
|
app:iconPadding="0dp"
|
||||||
|
app:iconSize="24dp"
|
||||||
|
app:iconTint="@color/white"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/takePhoto"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/takePhoto" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
Loading…
Reference in New Issue
Block a user