Carousel in the PostCreationActivity, change PhotoEditActivity to be more intuitive
This commit is contained in:
parent
1a2a971de6
commit
d6e7d2377f
|
@ -157,6 +157,7 @@ dependencies {
|
|||
implementation 'com.github.ligi.tracedroid:lib:3.0'
|
||||
implementation 'com.github.ligi.tracedroid:supportemail:3.0'
|
||||
|
||||
implementation 'com.github.ImaginativeShohag:Why-Not-Image-Carousel:v1.1.0'
|
||||
|
||||
/**
|
||||
* Not in release, so not mentioned in licenses list
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
package com.h.pixeldroid.postCreation
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.ContentResolver
|
||||
import android.content.ContentValues
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.media.MediaScannerConnection
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.provider.MediaStore
|
||||
import android.provider.OpenableColumns
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
|
@ -12,10 +19,12 @@ import android.view.ViewGroup
|
|||
import android.widget.Button
|
||||
import android.widget.Toast
|
||||
import androidx.core.net.toFile
|
||||
import androidx.core.net.toUri
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import com.h.pixeldroid.utils.BaseActivity
|
||||
import com.h.pixeldroid.MainActivity
|
||||
|
@ -33,11 +42,18 @@ import io.reactivex.schedulers.Schedulers
|
|||
import kotlinx.android.synthetic.main.activity_post_creation.*
|
||||
import kotlinx.android.synthetic.main.image_album_creation.view.*
|
||||
import okhttp3.MultipartBody
|
||||
import org.imaginativeworld.whynotimagecarousel.CarouselItem
|
||||
import org.imaginativeworld.whynotimagecarousel.ImageCarousel
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
import retrofit2.HttpException
|
||||
import retrofit2.Response
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.OutputStream
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
private const val TAG = "Post Creation Activity"
|
||||
private const val MORE_PICTURES_REQUEST_CODE = 0xffff
|
||||
|
@ -45,9 +61,6 @@ private const val MORE_PICTURES_REQUEST_CODE = 0xffff
|
|||
|
||||
class PostCreationActivity : BaseActivity() {
|
||||
|
||||
private lateinit var recycler : RecyclerView
|
||||
private lateinit var adapter : PostCreationAdapter
|
||||
|
||||
private lateinit var accessToken: String
|
||||
private lateinit var pixelfedAPI: PixelfedAPI
|
||||
|
||||
|
@ -100,10 +113,9 @@ class PostCreationActivity : BaseActivity() {
|
|||
progressList = posts.map { 0 } as ArrayList<Int>
|
||||
upload()
|
||||
|
||||
adapter = PostCreationAdapter(posts)
|
||||
recycler = findViewById(R.id.image_grid)
|
||||
recycler.layoutManager = GridLayoutManager(this, 3)
|
||||
recycler.adapter = adapter
|
||||
|
||||
val carousel: ImageCarousel = findViewById(R.id.carousel)
|
||||
carousel.addData(posts.map { CarouselItem(it) })
|
||||
|
||||
// get the description and send the post
|
||||
findViewById<Button>(R.id.post_creation_send_button).setOnClickListener {
|
||||
|
@ -117,7 +129,79 @@ class PostCreationActivity : BaseActivity() {
|
|||
progressList = posts.map { 0 } as ArrayList<Int>
|
||||
upload()
|
||||
}
|
||||
|
||||
findViewById<Button>(R.id.editPhotoButton).setOnClickListener {
|
||||
onClick(carousel.currentPosition)
|
||||
}
|
||||
|
||||
findViewById<Button>(R.id.addPhotoButton).setOnClickListener {
|
||||
val intent = Intent(it.context, CameraActivity::class.java)
|
||||
this@PostCreationActivity.startActivityForResult(intent, MORE_PICTURES_REQUEST_CODE)
|
||||
}
|
||||
|
||||
findViewById<Button>(R.id.savePhotoButton).setOnClickListener {
|
||||
|
||||
val name = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS", Locale.US)
|
||||
.format(System.currentTimeMillis()) + ".png"
|
||||
val pair = getOutputFile(name)
|
||||
val outputStream: OutputStream = pair.first
|
||||
val path: String = pair.second
|
||||
|
||||
contentResolver.openInputStream(posts[carousel.currentPosition].toUri())!!.use { input ->
|
||||
outputStream.use { output ->
|
||||
input.copyTo(output)
|
||||
}
|
||||
}
|
||||
|
||||
if(path.startsWith("file")) {
|
||||
MediaScannerConnection.scanFile(
|
||||
this,
|
||||
arrayOf(path.toUri().toFile().absolutePath),
|
||||
null
|
||||
) { path, uri ->
|
||||
if (uri == null) {
|
||||
Log.e(
|
||||
"NEW IMAGE SCAN FAILED",
|
||||
"Tried to scan $path, but it failed"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Snackbar.make(
|
||||
it, getString(R.string.save_image_success),
|
||||
Snackbar.LENGTH_LONG
|
||||
).show()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
private fun getOutputFile(name: String): Pair<OutputStream, String> {
|
||||
val outputStream: OutputStream
|
||||
val path: String
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
val resolver: ContentResolver = contentResolver
|
||||
val contentValues = ContentValues()
|
||||
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, name)
|
||||
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/png")
|
||||
contentValues.put(
|
||||
MediaStore.MediaColumns.RELATIVE_PATH,
|
||||
Environment.DIRECTORY_PICTURES
|
||||
)
|
||||
val imageUri: Uri =
|
||||
resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)!!
|
||||
path = imageUri.toString()
|
||||
outputStream = resolver.openOutputStream(Objects.requireNonNull(imageUri))!!
|
||||
} else {
|
||||
@Suppress("DEPRECATION") val imagesDir =
|
||||
Environment.getExternalStoragePublicDirectory(getString(R.string.app_name))
|
||||
imagesDir.mkdir()
|
||||
val file = File(imagesDir, name)
|
||||
path = Uri.fromFile(file).toString()
|
||||
outputStream = file.outputStream()
|
||||
}
|
||||
return Pair(outputStream, path)
|
||||
}
|
||||
|
||||
|
||||
private fun validateDescription(): Boolean {
|
||||
val textField = findViewById<TextInputLayout>(R.id.postTextInputLayout)
|
||||
|
@ -268,13 +352,13 @@ class PostCreationActivity : BaseActivity() {
|
|||
if (requestCode == positionResult) {
|
||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||
posts[positionResult] = data.getStringExtra("result")!!
|
||||
adapter.notifyItemChanged(positionResult)
|
||||
|
||||
carousel.addData(posts.map { CarouselItem(it) })
|
||||
|
||||
muListOfIds[positionResult] = ""
|
||||
progressList[positionResult] = 0
|
||||
upload(editedImage = positionResult)
|
||||
} else if(resultCode == Activity.RESULT_CANCELED){
|
||||
Toast.makeText(applicationContext, "Editing canceled", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
} else if(resultCode != Activity.RESULT_CANCELED){
|
||||
Toast.makeText(applicationContext, "Error while editing", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
} else if (requestCode == MORE_PICTURES_REQUEST_CODE) {
|
||||
|
@ -287,16 +371,16 @@ class PostCreationActivity : BaseActivity() {
|
|||
progressList.add(0)
|
||||
muListOfIds.add("")
|
||||
}
|
||||
adapter.notifyDataSetChanged()
|
||||
|
||||
carousel.addData(posts.map { CarouselItem(it) })
|
||||
|
||||
upload(newImagesStartingIndex = posts.size - count)
|
||||
} else if(resultCode == Activity.RESULT_CANCELED){
|
||||
Toast.makeText(applicationContext, "Adding images canceled", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
} else if(resultCode != Activity.RESULT_CANCELED){
|
||||
Toast.makeText(applicationContext, "Error while adding images", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
inner class PostCreationAdapter(private val posts: ArrayList<String>): RecyclerView.Adapter<PostCreationAdapter.ViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
|
@ -349,4 +433,5 @@ class PostCreationActivity : BaseActivity() {
|
|||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
|
@ -43,46 +43,50 @@ class EditImageFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
|||
seekbarSaturation.max = SATURATION_MAX
|
||||
seekbarSaturation.progress = SATURATION_START
|
||||
|
||||
seekbarBrightness.setOnSeekBarChangeListener(this)
|
||||
seekbarContrast.setOnSeekBarChangeListener(this)
|
||||
seekbarSaturation.setOnSeekBarChangeListener(this)
|
||||
setOnSeekBarChangeListeners(this)
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
private fun setOnSeekBarChangeListeners(listener: EditImageFragment?){
|
||||
seekbarBrightness.setOnSeekBarChangeListener(listener)
|
||||
seekbarContrast.setOnSeekBarChangeListener(listener)
|
||||
seekbarSaturation.setOnSeekBarChangeListener(listener)
|
||||
}
|
||||
|
||||
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
|
||||
var prog = progress
|
||||
|
||||
if(listener != null) {
|
||||
listener?.let {
|
||||
when(seekBar!!.id) {
|
||||
R.id.seekbar_brightness -> listener!!.onBrightnessChange(progress - 100)
|
||||
R.id.seekbar_brightness -> it.onBrightnessChange(progress - 100)
|
||||
R.id.seekbar_saturation -> {
|
||||
prog += 10
|
||||
val tempProgress = .10f * prog
|
||||
listener!!.onSaturationChange(tempProgress)
|
||||
it.onSaturationChange(.10f * prog)
|
||||
}
|
||||
R.id.seekbar_contrast -> {
|
||||
val tempProgress = .10f * prog
|
||||
listener!!.onContrastChange(tempProgress)
|
||||
it.onContrastChange(.10f * prog)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun resetControl() {
|
||||
// Make sure to ignore seekbar change events, since we don't want to have the reset cause
|
||||
// filter applications due to the onProgressChanged calls
|
||||
setOnSeekBarChangeListeners(null)
|
||||
seekbarBrightness.progress = BRIGHTNESS_START
|
||||
seekbarContrast.progress = CONTRAST_START
|
||||
seekbarSaturation.progress = SATURATION_START
|
||||
setOnSeekBarChangeListeners(this)
|
||||
}
|
||||
|
||||
override fun onStartTrackingTouch(seekBar: SeekBar?) {
|
||||
if(listener != null)
|
||||
listener!!.onEditStarted()
|
||||
listener?.onEditStarted()
|
||||
}
|
||||
|
||||
override fun onStopTrackingTouch(seekBar: SeekBar?) {
|
||||
if(listener != null)
|
||||
listener!!.onEditCompleted()
|
||||
listener?.onEditCompleted()
|
||||
}
|
||||
|
||||
fun setListener(listener: PhotoEditActivity) {
|
||||
|
|
|
@ -32,7 +32,6 @@ class FilterListFragment : Fragment() {
|
|||
val view = inflater.inflate(R.layout.fragment_filter_list, container, false)
|
||||
|
||||
tbItemList = ArrayList()
|
||||
adapter = ThumbnailAdapter(requireActivity(), tbItemList, this)
|
||||
|
||||
recyclerView = view.findViewById(R.id.recycler_view)
|
||||
recyclerView.layoutManager = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
|
||||
|
@ -40,6 +39,8 @@ class FilterListFragment : Fragment() {
|
|||
|
||||
val space = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8f, resources.displayMetrics).toInt()
|
||||
recyclerView.addItemDecoration(SpaceItemDecoration(space))
|
||||
|
||||
adapter = ThumbnailAdapter(requireActivity(), tbItemList, this)
|
||||
recyclerView.adapter = adapter
|
||||
|
||||
return view
|
||||
|
@ -99,10 +100,13 @@ class FilterListFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
fun resetSelectedFilter(){
|
||||
adapter.resetSelected()
|
||||
displayImage(null)
|
||||
}
|
||||
|
||||
fun onFilterSelected(filter: Filter) {
|
||||
if(listener != null ){
|
||||
listener!!.onFilterSelected(filter)
|
||||
}
|
||||
listener?.onFilterSelected(filter)
|
||||
}
|
||||
|
||||
fun setListener(listFragmentListener: PhotoEditActivity) {
|
||||
|
|
|
@ -2,20 +2,14 @@ package com.h.pixeldroid.postCreation.photoEdit
|
|||
|
||||
import android.app.Activity
|
||||
import android.app.AlertDialog
|
||||
import android.content.ContentResolver
|
||||
import android.content.ContentValues
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Point
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.media.MediaScannerConnection
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.provider.MediaStore
|
||||
import android.util.Log
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View.GONE
|
||||
|
@ -23,15 +17,13 @@ import android.view.View.VISIBLE
|
|||
import android.widget.Toast
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.net.toFile
|
||||
import androidx.core.net.toUri
|
||||
import com.bumptech.glide.Glide
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.h.pixeldroid.utils.BaseActivity
|
||||
import com.h.pixeldroid.R
|
||||
import com.h.pixeldroid.postCreation.PostCreationActivity
|
||||
import com.h.pixeldroid.utils.BaseActivity
|
||||
import com.yalantis.ucrop.UCrop
|
||||
import com.zomato.photofilters.imageprocessors.Filter
|
||||
import com.zomato.photofilters.imageprocessors.subfilters.BrightnessSubFilter
|
||||
|
@ -41,8 +33,6 @@ import kotlinx.android.synthetic.main.activity_photo_edit.*
|
|||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.OutputStream
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors.newSingleThreadExecutor
|
||||
import java.util.concurrent.Future
|
||||
|
@ -50,10 +40,11 @@ import java.util.concurrent.Future
|
|||
// This is an arbitrary number we are using to keep track of the permission
|
||||
// request. Where an app has multiple context for requesting permission,
|
||||
// this can help differentiate the different contexts.
|
||||
private const val REQUEST_CODE_PERMISSIONS_SAVE_PHOTO = 8
|
||||
private const val REQUEST_CODE_PERMISSIONS_SEND_PHOTO = 7
|
||||
private val REQUIRED_PERMISSIONS = arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
private val REQUIRED_PERMISSIONS = arrayOf(
|
||||
android.Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
)
|
||||
|
||||
class PhotoEditActivity : BaseActivity() {
|
||||
|
||||
|
@ -108,7 +99,7 @@ class PhotoEditActivity : BaseActivity() {
|
|||
initialUri = intent.getParcelableExtra("picture_uri")
|
||||
imageUri = initialUri
|
||||
|
||||
// set on-click listener
|
||||
// Crop button on-click listener
|
||||
cropButton.setOnClickListener {
|
||||
startCrop()
|
||||
}
|
||||
|
@ -122,7 +113,6 @@ class PhotoEditActivity : BaseActivity() {
|
|||
}
|
||||
|
||||
|
||||
//<editor-fold desc="ON LAUNCH">
|
||||
private fun loadImage() {
|
||||
originalImage = MediaStore.Images.Media.getBitmap(contentResolver, imageUri)
|
||||
compressedImage = resizeImage(originalImage!!)
|
||||
|
@ -169,43 +159,54 @@ class PhotoEditActivity : BaseActivity() {
|
|||
|
||||
when(item.itemId) {
|
||||
android.R.id.home -> {
|
||||
onBackPressed()
|
||||
}
|
||||
R.id.action_upload -> {
|
||||
saveImageToGallery(false)
|
||||
if (noEdits()) onBackPressed()
|
||||
else {
|
||||
val builder = AlertDialog.Builder(this)
|
||||
builder.apply {
|
||||
setMessage(R.string.save_before_returning)
|
||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
saveImageToGallery()
|
||||
}
|
||||
setNegativeButton(R.string.no_cancel_edit) { _, _ ->
|
||||
onBackPressed()
|
||||
}
|
||||
}
|
||||
// Create the AlertDialog
|
||||
builder.show()
|
||||
}
|
||||
}
|
||||
R.id.action_save -> {
|
||||
saveImageToGallery(true)
|
||||
return true
|
||||
saveImageToGallery()
|
||||
}
|
||||
R.id.action_reset -> {
|
||||
resetControls()
|
||||
actualFilter = null
|
||||
imageUri = initialUri
|
||||
loadImage()
|
||||
filterListFragment.resetSelectedFilter()
|
||||
}
|
||||
}
|
||||
|
||||
//<editor-fold desc="FILTERS">
|
||||
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
//</editor-fold>
|
||||
fun onFilterSelected(filter: Filter) {
|
||||
resetControls()
|
||||
filteredImage = compressedOriginalImage!!.copy(BITMAP_CONFIG, true)
|
||||
image_preview.setImageBitmap(filter.processFilter(filteredImage))
|
||||
compressedImage = filteredImage.copy(BITMAP_CONFIG, true)
|
||||
actualFilter = filter
|
||||
resetControls()
|
||||
}
|
||||
|
||||
private fun resetControls() {
|
||||
editImageFragment.resetControl()
|
||||
|
||||
brightnessFinal = BRIGHTNESS_START
|
||||
saturationFinal = SATURATION_START
|
||||
contrastFinal = CONTRAST_START
|
||||
|
||||
editImageFragment.resetControl()
|
||||
}
|
||||
|
||||
|
||||
//</editor-fold>
|
||||
//<editor-fold desc="EDITS">
|
||||
|
||||
private fun applyFilterAndShowImage(filter: Filter, image: Bitmap?) {
|
||||
future?.cancel(true)
|
||||
future = executor.submit {
|
||||
|
@ -255,8 +256,6 @@ class PhotoEditActivity : BaseActivity() {
|
|||
compressedImage = myFilter.processFilter(bitmap)
|
||||
}
|
||||
|
||||
//</editor-fold>
|
||||
//<editor-fold desc="CROPPING">
|
||||
|
||||
private fun startCrop() {
|
||||
val file = File.createTempFile("temp_crop_img", ".png", cacheDir)
|
||||
|
@ -314,8 +313,6 @@ class PhotoEditActivity : BaseActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
//</editor-fold>
|
||||
//<editor-fold desc="FLOW">
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<out String>,
|
||||
|
@ -325,10 +322,7 @@ class PhotoEditActivity : BaseActivity() {
|
|||
&& grantResults[0] == PackageManager.PERMISSION_GRANTED
|
||||
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
|
||||
// permission was granted
|
||||
when (requestCode) {
|
||||
REQUEST_CODE_PERMISSIONS_SAVE_PHOTO -> permissionsGrantedToSave(true)
|
||||
REQUEST_CODE_PERMISSIONS_SEND_PHOTO -> permissionsGrantedToSave(false)
|
||||
}
|
||||
permissionsGrantedToSave()
|
||||
} else {
|
||||
Snackbar.make(coordinator_edit, getString(R.string.permission_denied),
|
||||
Snackbar.LENGTH_LONG).show()
|
||||
|
@ -354,16 +348,16 @@ class PhotoEditActivity : BaseActivity() {
|
|||
finish()
|
||||
}
|
||||
|
||||
private fun saveImageToGallery(save: Boolean) {
|
||||
private fun saveImageToGallery() {
|
||||
// runtime permission and process
|
||||
if (!allPermissionsGranted()) {
|
||||
ActivityCompat.requestPermissions(
|
||||
this,
|
||||
REQUIRED_PERMISSIONS,
|
||||
if(save) REQUEST_CODE_PERMISSIONS_SAVE_PHOTO else REQUEST_CODE_PERMISSIONS_SEND_PHOTO
|
||||
REQUEST_CODE_PERMISSIONS_SEND_PHOTO
|
||||
)
|
||||
} else {
|
||||
permissionsGrantedToSave(save)
|
||||
permissionsGrantedToSave()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -375,32 +369,6 @@ class PhotoEditActivity : BaseActivity() {
|
|||
applicationContext, it) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
private fun getOutputFile(name: String): Pair<OutputStream, String> {
|
||||
val outputStream: OutputStream
|
||||
val path: String
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
val resolver: ContentResolver = contentResolver
|
||||
val contentValues = ContentValues()
|
||||
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, name)
|
||||
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/png")
|
||||
contentValues.put(
|
||||
MediaStore.MediaColumns.RELATIVE_PATH,
|
||||
Environment.DIRECTORY_PICTURES
|
||||
)
|
||||
val imageUri: Uri =
|
||||
resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)!!
|
||||
path = imageUri.toString()
|
||||
outputStream = resolver.openOutputStream(Objects.requireNonNull(imageUri))!!
|
||||
} else {
|
||||
val imagesDir =
|
||||
Environment.getExternalStoragePublicDirectory(getString(R.string.app_name))
|
||||
imagesDir.mkdir()
|
||||
val file = File(imagesDir, name)
|
||||
path = Uri.fromFile(file).toString()
|
||||
outputStream = file.outputStream()
|
||||
}
|
||||
return Pair(outputStream, path)
|
||||
}
|
||||
|
||||
private fun OutputStream.writeBitmap(bitmap: Bitmap) {
|
||||
use { out ->
|
||||
|
@ -410,7 +378,13 @@ class PhotoEditActivity : BaseActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun permissionsGrantedToSave(save: Boolean) {
|
||||
private fun noEdits(): Boolean =
|
||||
brightnessFinal == BRIGHTNESS_START
|
||||
&& contrastFinal == CONTRAST_START
|
||||
&& saturationFinal == SATURATION_START
|
||||
&& actualFilter?.let { it.name == getString(R.string.normal_filter)} ?: true
|
||||
|
||||
private fun permissionsGrantedToSave() {
|
||||
if (saving) {
|
||||
val builder = AlertDialog.Builder(this)
|
||||
builder.apply {
|
||||
|
@ -424,36 +398,24 @@ class PhotoEditActivity : BaseActivity() {
|
|||
saving = true
|
||||
progressBarSaveFile.visibility = VISIBLE
|
||||
saveFuture = saveExecutor.submit {
|
||||
val outputStream: OutputStream
|
||||
var path: String
|
||||
if (!save) {
|
||||
//put picture in cache
|
||||
try {
|
||||
val path: String
|
||||
if(!noEdits()) {
|
||||
// Save modified image in cache
|
||||
val tempFile = File.createTempFile("temp_edit_img", ".png", cacheDir)
|
||||
path = Uri.fromFile(tempFile).toString()
|
||||
outputStream = tempFile.outputStream()
|
||||
} else {
|
||||
// Save the picture to gallery
|
||||
val name = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS", Locale.US)
|
||||
.format(System.currentTimeMillis()) + ".png"
|
||||
val pair = getOutputFile(name)
|
||||
outputStream = pair.first
|
||||
path = pair.second
|
||||
}
|
||||
try {
|
||||
if(brightnessFinal != BRIGHTNESS_START || contrastFinal != CONTRAST_START
|
||||
|| saturationFinal != SATURATION_START
|
||||
|| (actualFilter != null && actualFilter!!.name != getString(R.string.normal_filter))) {
|
||||
outputStream.writeBitmap(applyFinalFilters(originalImage))
|
||||
tempFile.outputStream().writeBitmap(applyFinalFilters(originalImage))
|
||||
}
|
||||
else {
|
||||
if(save) {
|
||||
contentResolver.openInputStream(imageUri!!)!!.use { input ->
|
||||
outputStream.use { output ->
|
||||
input.copyTo(output)
|
||||
}
|
||||
}
|
||||
path = imageUri.toString()
|
||||
}
|
||||
|
||||
if(saving) {
|
||||
this.runOnUiThread {
|
||||
sendBackImage(path)
|
||||
progressBarSaveFile.visibility = GONE
|
||||
saving = false
|
||||
}
|
||||
else path = imageUri.toString()
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
this.runOnUiThread {
|
||||
|
@ -461,39 +423,10 @@ class PhotoEditActivity : BaseActivity() {
|
|||
coordinator_edit, getString(R.string.save_image_failed),
|
||||
Snackbar.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
}
|
||||
if(saving) {
|
||||
this.runOnUiThread {
|
||||
if(!save) {
|
||||
sendBackImage(path)
|
||||
} else {
|
||||
if(path.startsWith("file")) {
|
||||
MediaScannerConnection.scanFile(
|
||||
this,
|
||||
arrayOf(path.toUri().toFile().absolutePath),
|
||||
null
|
||||
|
||||
) { path, uri ->
|
||||
if (uri == null) {
|
||||
Log.e(
|
||||
"NEW IMAGE SCAN FAILED",
|
||||
"Tried to scan $path, but it failed"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Snackbar.make(
|
||||
coordinator_edit, getString(R.string.save_image_success),
|
||||
Snackbar.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
progressBarSaveFile.visibility = GONE
|
||||
saving = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//</editor-fold>
|
||||
}
|
||||
|
|
|
@ -18,6 +18,11 @@ class ThumbnailAdapter (private val context: Context,
|
|||
|
||||
private var selectedIndex = 0
|
||||
|
||||
fun resetSelected(){
|
||||
selectedIndex = 0
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
|
||||
val itemView = LayoutInflater.from(context).inflate(R.layout.thumbnail_list_item, parent, false)
|
||||
return MyViewHolder(itemView)
|
||||
|
|
|
@ -404,7 +404,7 @@ class StatusViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
|
|||
val builder = AlertDialog.Builder(holder.itemView.context)
|
||||
builder.apply {
|
||||
setMessage(R.string.delete_dialog)
|
||||
setPositiveButton(R.string.OK) { _, _ ->
|
||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
|
||||
lifecycleScope.launch {
|
||||
val user = db.userDao().getActiveUser()!!
|
||||
|
@ -420,7 +420,7 @@ class StatusViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
|
|||
}
|
||||
}
|
||||
}
|
||||
setNegativeButton(R.string.cancel) { _, _ -> }
|
||||
setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||
show()
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z"
|
||||
android:fillColor="@color/colorDrawing"/>
|
||||
</vector>
|
|
@ -2,9 +2,8 @@
|
|||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:fillColor="@color/colorDrawing"
|
||||
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
|
||||
</vector>
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.28,2.54 0.72,-1.21 -3.5,-2.08L13.5,8L12,8z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
</vector>
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
@ -46,24 +47,22 @@
|
|||
android:id="@+id/upload_completed_textview"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="@string/media_upload_completed"
|
||||
android:textColor="@android:color/holo_green_light"
|
||||
android:textSize="16sp"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:layout_constraintTop_toBottomOf="@+id/imageButton" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/image_grid"
|
||||
android:layout_width="0dp"
|
||||
<org.imaginativeworld.whynotimagecarousel.ImageCarousel
|
||||
android:id="@+id/carousel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:padding="16dp"
|
||||
app:layout_constraintBottom_toTopOf="@id/postTextInputLayout"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/upload_completed_textview" />
|
||||
app:layout_constraintTop_toBottomOf="@id/upload_completed_textview">
|
||||
|
||||
</org.imaginativeworld.whynotimagecarousel.ImageCarousel>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/buttonConstraints"
|
||||
|
@ -133,4 +132,43 @@
|
|||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/addPhotoButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:contentDescription="TODO"
|
||||
app:icon="@drawable/add_photo_alternate_black_24dp"
|
||||
app:iconGravity="textStart"
|
||||
app:iconPadding="0dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/savePhotoButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:contentDescription="TODO"
|
||||
app:iconGravity="textStart"
|
||||
app:iconPadding="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/addPhotoButton"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/addPhotoButton"
|
||||
app:icon="@drawable/download_file_24dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/editPhotoButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:contentDescription="TODO"
|
||||
app:iconGravity="textStart"
|
||||
app:iconPadding="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/addPhotoButton"
|
||||
app:layout_constraintEnd_toStartOf="@+id/addPhotoButton"
|
||||
app:layout_constraintTop_toTopOf="@+id/addPhotoButton"
|
||||
app:icon="@drawable/ic_baseline_edit_24" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,20 +1,20 @@
|
|||
<?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"
|
||||
>
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
|
||||
<item
|
||||
android:id="@+id/action_upload"
|
||||
android:id="@+id/action_reset"
|
||||
android:orderInCategory="100"
|
||||
android:title="CREATE POST"
|
||||
android:icon="@drawable/ic_file_upload_24dp"
|
||||
android:title="RESET"
|
||||
android:icon="@drawable/restore_24dp"
|
||||
app:showAsAction="ifRoom"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/action_save"
|
||||
android:orderInCategory="101"
|
||||
android:title="SAVE"
|
||||
android:icon="@drawable/ic_save_24dp"
|
||||
app:showAsAction="ifRoom"/>
|
||||
|
||||
</menu>
|
|
@ -149,12 +149,12 @@
|
|||
<string name="something_went_wrong">Something went wrong…</string>
|
||||
<string name="panda_pull_to_refresh_to_try_again">This panda is not happy. Pull to refresh to try again.</string>
|
||||
<string name="delete">Delete</string>
|
||||
<string name="OK">OK</string>
|
||||
<string name="delete_dialog">Delete this post?</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="language">Language</string>
|
||||
<string name="help_translate">Help translate PixelDroid to your language:</string>
|
||||
<string name="issues_contribute">Report issues or contribute to the application:</string>
|
||||
<string name="mascot_description">Image showing a red panda, Pixelfed\'s mascot, using a phone</string>
|
||||
<string name="save_before_returning">Save your edits?</string>
|
||||
<string name="no_cancel_edit">No, cancel edit</string>
|
||||
|
||||
</resources>
|
Loading…
Reference in New Issue