Merge branch 'edit_fixes' into 'master'
Fix upload of edited images See merge request pixeldroid/PixelDroid!317
This commit is contained in:
commit
bfb5d93f01
|
@ -110,6 +110,7 @@ dependencies {
|
||||||
implementation "androidx.lifecycle:lifecycle-common-java8:2.3.0"
|
implementation "androidx.lifecycle:lifecycle-common-java8:2.3.0"
|
||||||
implementation "androidx.annotation:annotation:1.1.0"
|
implementation "androidx.annotation:annotation:1.1.0"
|
||||||
implementation 'androidx.gridlayout:gridlayout:1.0.0'
|
implementation 'androidx.gridlayout:gridlayout:1.0.0'
|
||||||
|
implementation "androidx.activity:activity-ktx:1.2.1"
|
||||||
|
|
||||||
// Use the most recent version of CameraX
|
// Use the most recent version of CameraX
|
||||||
def cameraX_version = '1.0.0-rc03'
|
def cameraX_version = '1.0.0-rc03'
|
||||||
|
|
|
@ -782,4 +782,15 @@
|
||||||
license: The Apache Software License, Version 2.0
|
license: The Apache Software License, Version 2.0
|
||||||
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
|
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
url: http://developer.android.com/tools/extras/support-library.html
|
url: http://developer.android.com/tools/extras/support-library.html
|
||||||
|
- artifact: androidx.savedstate:savedstate-ktx:+
|
||||||
|
name: savedstate-ktx
|
||||||
|
copyrightHolder: Google Inc
|
||||||
|
license: The Apache Software License, Version 2.0
|
||||||
|
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
url: https://developer.android.com/jetpack/androidx/releases/savedstate#1.1.0
|
||||||
|
- artifact: androidx.tracing:tracing:+
|
||||||
|
name: tracing
|
||||||
|
copyrightHolder: Google Inc
|
||||||
|
license: The Apache Software License, Version 2.0
|
||||||
|
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
url: https://developer.android.com/jetpack/androidx/releases/tracing#1.0.0
|
File diff suppressed because it is too large
Load Diff
|
@ -15,6 +15,8 @@ import android.view.View
|
||||||
import android.view.View.INVISIBLE
|
import android.view.View.INVISIBLE
|
||||||
import android.view.View.VISIBLE
|
import android.view.View.VISIBLE
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.activity.result.ActivityResult
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.core.net.toFile
|
import androidx.core.net.toFile
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
@ -43,10 +45,8 @@ import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
import kotlin.properties.Delegates
|
|
||||||
|
|
||||||
private const val TAG = "Post Creation Activity"
|
private const val TAG = "Post Creation Activity"
|
||||||
private const val MORE_PICTURES_REQUEST_CODE = 0xffff
|
|
||||||
|
|
||||||
data class PhotoData(
|
data class PhotoData(
|
||||||
var imageUri: Uri,
|
var imageUri: Uri,
|
||||||
|
@ -61,7 +61,6 @@ class PostCreationActivity : BaseActivity() {
|
||||||
private lateinit var accessToken: String
|
private lateinit var accessToken: String
|
||||||
private lateinit var pixelfedAPI: PixelfedAPI
|
private lateinit var pixelfedAPI: PixelfedAPI
|
||||||
|
|
||||||
private var positionResult = 0
|
|
||||||
private var user: UserDatabaseEntity? = null
|
private var user: UserDatabaseEntity? = null
|
||||||
private lateinit var instance: InstanceDatabaseEntity
|
private lateinit var instance: InstanceDatabaseEntity
|
||||||
|
|
||||||
|
@ -103,7 +102,7 @@ class PostCreationActivity : BaseActivity() {
|
||||||
}
|
}
|
||||||
carousel.maxEntries = instance.albumLimit
|
carousel.maxEntries = instance.albumLimit
|
||||||
carousel.addPhotoButtonCallback = {
|
carousel.addPhotoButtonCallback = {
|
||||||
addPhoto(applicationContext)
|
addPhoto()
|
||||||
}
|
}
|
||||||
carousel.updateDescriptionCallback = { position: Int, description: String ->
|
carousel.updateDescriptionCallback = { position: Int, description: String ->
|
||||||
photoData[position].imageDescription = description
|
photoData[position].imageDescription = description
|
||||||
|
@ -131,7 +130,7 @@ class PostCreationActivity : BaseActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.addPhotoButton.setOnClickListener {
|
binding.addPhotoButton.setOnClickListener {
|
||||||
addPhoto(it.context)
|
addPhoto()
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.savePhotoButton.setOnClickListener {
|
binding.savePhotoButton.setOnClickListener {
|
||||||
|
@ -170,45 +169,66 @@ class PostCreationActivity : BaseActivity() {
|
||||||
}
|
}
|
||||||
for (i in 0 until count) {
|
for (i in 0 until count) {
|
||||||
clipData.getItemAt(i).uri.let {
|
clipData.getItemAt(i).uri.let {
|
||||||
val size: Long =
|
val size = it.getSize()
|
||||||
if (it.toString().startsWith("content")) {
|
|
||||||
contentResolver.query(it, null, null, null, null)
|
|
||||||
?.use { cursor ->
|
|
||||||
/* Get the column indexes of the data in the Cursor,
|
|
||||||
* move to the first row in the Cursor, get the data,
|
|
||||||
* and display it.
|
|
||||||
*/
|
|
||||||
val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE)
|
|
||||||
cursor.moveToFirst()
|
|
||||||
cursor.getLong(sizeIndex)
|
|
||||||
} ?: 0
|
|
||||||
} else {
|
|
||||||
it.toFile().length()
|
|
||||||
}
|
|
||||||
val sizeInkBytes = ceil(size.toDouble() / 1000).toLong()
|
|
||||||
if(sizeInkBytes > instance.maxPhotoSize || sizeInkBytes > instance.maxVideoSize){
|
|
||||||
val maxSize = when {
|
|
||||||
instance.maxPhotoSize != instance.maxVideoSize -> {
|
|
||||||
val type = contentResolver.getType(it)
|
|
||||||
if(type?.startsWith("video/") == true){
|
|
||||||
instance.maxVideoSize
|
|
||||||
} else instance.maxPhotoSize
|
|
||||||
}
|
|
||||||
else -> instance.maxPhotoSize
|
|
||||||
}
|
|
||||||
AlertDialog.Builder(this).apply {
|
|
||||||
setMessage(getString(R.string.size_exceeds_instance_limit).format(photoData.size + 1, sizeInkBytes, maxSize))
|
|
||||||
setNegativeButton(android.R.string.ok) { _, _ -> }
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
photoData.add(PhotoData(imageUri = it, size = size))
|
photoData.add(PhotoData(imageUri = it, size = size))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addPhoto(context: Context){
|
/**
|
||||||
val intent = Intent(context, CameraActivity::class.java)
|
* Returns the size of the file of the Uri, and opens a dialog in case it is too big.
|
||||||
this@PostCreationActivity.startActivityForResult(intent, MORE_PICTURES_REQUEST_CODE)
|
*/
|
||||||
|
private fun Uri.getSize(): Long {
|
||||||
|
val size: Long =
|
||||||
|
if (toString().startsWith("content")) {
|
||||||
|
contentResolver.query(this, null, null, null, null)
|
||||||
|
?.use { cursor ->
|
||||||
|
/* Get the column indexes of the data in the Cursor,
|
||||||
|
* move to the first row in the Cursor, get the data,
|
||||||
|
* and display it.
|
||||||
|
*/
|
||||||
|
val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE)
|
||||||
|
cursor.moveToFirst()
|
||||||
|
cursor.getLong(sizeIndex)
|
||||||
|
} ?: 0
|
||||||
|
} else {
|
||||||
|
toFile().length()
|
||||||
|
}
|
||||||
|
|
||||||
|
val sizeInkBytes = ceil(size.toDouble() / 1000).toLong()
|
||||||
|
if (sizeInkBytes > instance.maxPhotoSize || sizeInkBytes > instance.maxVideoSize) {
|
||||||
|
val maxSize = when {
|
||||||
|
instance.maxPhotoSize != instance.maxVideoSize -> {
|
||||||
|
val type = contentResolver.getType(this)
|
||||||
|
if (type?.startsWith("video/") == true) {
|
||||||
|
instance.maxVideoSize
|
||||||
|
} else instance.maxPhotoSize
|
||||||
|
}
|
||||||
|
else -> instance.maxPhotoSize
|
||||||
|
}
|
||||||
|
AlertDialog.Builder(this@PostCreationActivity).apply {
|
||||||
|
setMessage(getString(R.string.size_exceeds_instance_limit, photoData.size + 1, sizeInkBytes, maxSize))
|
||||||
|
setNegativeButton(android.R.string.ok) { _, _ -> }
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
|
||||||
|
private val addPhotoResultContract = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||||
|
if (result.resultCode == Activity.RESULT_OK && result.data?.clipData != null) {
|
||||||
|
result.data?.clipData?.let {
|
||||||
|
addPossibleImages(it)
|
||||||
|
}
|
||||||
|
binding.carousel.addData(photoData.map { CarouselItem(it.imageUri, it.imageDescription) })
|
||||||
|
} else if (result.resultCode != Activity.RESULT_CANCELED) {
|
||||||
|
Toast.makeText(applicationContext, "Error while adding images", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addPhoto(){
|
||||||
|
addPhotoResultContract.launch(
|
||||||
|
Intent(this, CameraActivity::class.java)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun savePicture(button: View, currentPosition: Int) {
|
private fun savePicture(button: View, currentPosition: Int) {
|
||||||
|
@ -334,7 +354,7 @@ class PostCreationActivity : BaseActivity() {
|
||||||
binding.uploadError.visibility = View.VISIBLE
|
binding.uploadError.visibility = View.VISIBLE
|
||||||
if(e is HttpException){
|
if(e is HttpException){
|
||||||
binding.uploadErrorTextExplanation.text =
|
binding.uploadErrorTextExplanation.text =
|
||||||
getString(R.string.upload_error).format(e.code())
|
getString(R.string.upload_error, e.code())
|
||||||
binding.uploadErrorTextExplanation.visibility= VISIBLE
|
binding.uploadErrorTextExplanation.visibility= VISIBLE
|
||||||
} else {
|
} else {
|
||||||
binding.uploadErrorTextExplanation.visibility= View.GONE
|
binding.uploadErrorTextExplanation.visibility= View.GONE
|
||||||
|
@ -398,39 +418,27 @@ class PostCreationActivity : BaseActivity() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun edit(position: Int) {
|
private fun editResultContract(position: Int) = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){
|
||||||
positionResult = position
|
result: ActivityResult? ->
|
||||||
|
if (result?.resultCode == Activity.RESULT_OK && result.data != null) {
|
||||||
|
photoData[position].apply {
|
||||||
|
imageUri = result.data!!.getStringExtra("result")!!.toUri()
|
||||||
|
size = imageUri.getSize()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.carousel.addData(photoData.map { CarouselItem(it.imageUri, it.imageDescription) })
|
||||||
|
|
||||||
|
photoData[position].progress = null
|
||||||
|
photoData[position].uploadId = null
|
||||||
|
} else if(result?.resultCode != Activity.RESULT_CANCELED){
|
||||||
|
Toast.makeText(applicationContext, "Error while editing", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun edit(position: Int) {
|
||||||
val intent = Intent(this, PhotoEditActivity::class.java)
|
val intent = Intent(this, PhotoEditActivity::class.java)
|
||||||
.putExtra("picture_uri", photoData[position].imageUri)
|
.putExtra("picture_uri", photoData[position].imageUri)
|
||||||
.putExtra("no upload", false)
|
.putExtra("no upload", false)
|
||||||
startActivityForResult(intent, positionResult)
|
editResultContract(position).launch(intent)
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
|
||||||
if (requestCode == positionResult) {
|
|
||||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
|
||||||
photoData[positionResult].imageUri = data.getStringExtra("result")!!.toUri()
|
|
||||||
|
|
||||||
binding.carousel.addData(photoData.map { CarouselItem(it.imageUri, it.imageDescription) })
|
|
||||||
|
|
||||||
photoData[positionResult].progress = null
|
|
||||||
photoData[positionResult].uploadId = null
|
|
||||||
} else if(resultCode != Activity.RESULT_CANCELED){
|
|
||||||
Toast.makeText(applicationContext, "Error while editing", Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
} else if (requestCode == MORE_PICTURES_REQUEST_CODE) {
|
|
||||||
|
|
||||||
if (resultCode == Activity.RESULT_OK && data?.clipData != null) {
|
|
||||||
data.clipData?.let {
|
|
||||||
addPossibleImages(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.carousel.addData(photoData.map { CarouselItem(it.imageUri, it.imageDescription) })
|
|
||||||
} else if(resultCode != Activity.RESULT_CANCELED){
|
|
||||||
Toast.makeText(applicationContext, "Error while adding images", Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -280,12 +280,12 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold
|
||||||
//Update shown share count
|
//Update shown share count
|
||||||
binding.nshares.text = resp.getNShares(binding.root.context)
|
binding.nshares.text = resp.getNShares(binding.root.context)
|
||||||
binding.reblogger.isChecked = resp.reblogged!!
|
binding.reblogger.isChecked = resp.reblogged!!
|
||||||
} catch (exception: IOException) {
|
|
||||||
Log.e("REBLOG ERROR", exception.toString())
|
|
||||||
binding.reblogger.isChecked = false
|
|
||||||
} catch (exception: HttpException) {
|
} catch (exception: HttpException) {
|
||||||
Log.e("RESPONSE_CODE", exception.code().toString())
|
Log.e("RESPONSE_CODE", exception.code().toString())
|
||||||
binding.reblogger.isChecked = false
|
binding.reblogger.isChecked = false
|
||||||
|
} catch (exception: IOException) {
|
||||||
|
Log.e("REBLOG ERROR", exception.toString())
|
||||||
|
binding.reblogger.isChecked = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -302,12 +302,12 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold
|
||||||
//Update shown share count
|
//Update shown share count
|
||||||
binding.nshares.text = resp.getNShares(binding.root.context)
|
binding.nshares.text = resp.getNShares(binding.root.context)
|
||||||
binding.reblogger.isChecked = resp.reblogged!!
|
binding.reblogger.isChecked = resp.reblogged!!
|
||||||
} catch (exception: IOException) {
|
|
||||||
Log.e("REBLOG ERROR", exception.toString())
|
|
||||||
binding.reblogger.isChecked = true
|
|
||||||
} catch (exception: HttpException) {
|
} catch (exception: HttpException) {
|
||||||
Log.e("RESPONSE_CODE", exception.code().toString())
|
Log.e("RESPONSE_CODE", exception.code().toString())
|
||||||
binding.reblogger.isChecked = true
|
binding.reblogger.isChecked = true
|
||||||
|
} catch (exception: IOException) {
|
||||||
|
Log.e("REBLOG ERROR", exception.toString())
|
||||||
|
binding.reblogger.isChecked = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -397,8 +397,18 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold
|
||||||
try {
|
try {
|
||||||
api.deleteStatus("Bearer ${user.accessToken}", id)
|
api.deleteStatus("Bearer ${user.accessToken}", id)
|
||||||
binding.root.visibility = View.GONE
|
binding.root.visibility = View.GONE
|
||||||
} catch (exception: IOException) {
|
|
||||||
} catch (exception: HttpException) {
|
} catch (exception: HttpException) {
|
||||||
|
Toast.makeText(
|
||||||
|
binding.root.context,
|
||||||
|
binding.root.context.getString(R.string.delete_post_failed_error, exception.code()),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
} catch (exception: IOException) {
|
||||||
|
Toast.makeText(
|
||||||
|
binding.root.context,
|
||||||
|
binding.root.context.getString(R.string.delete_post_failed_io_except),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,10 +39,10 @@ class SearchPagingSource<T: FeedContent>(
|
||||||
prevKey = null,
|
prevKey = null,
|
||||||
nextKey = if (repos.isEmpty()) null else (position ?: 0) + repos.size
|
nextKey = if (repos.isEmpty()) null else (position ?: 0) + repos.size
|
||||||
)
|
)
|
||||||
} catch (exception: IOException) {
|
|
||||||
LoadResult.Error(exception)
|
|
||||||
} catch (exception: HttpException) {
|
} catch (exception: HttpException) {
|
||||||
LoadResult.Error(exception)
|
LoadResult.Error(exception)
|
||||||
|
} catch (exception: IOException) {
|
||||||
|
LoadResult.Error(exception)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,8 +66,8 @@ For more info about Pixelfed, you can check here: https://pixelfed.org"</string>
|
||||||
<string name="save_image_description">Save image description</string>
|
<string name="save_image_description">Save image description</string>
|
||||||
<string name="no_media_description">Add a media description here…</string>
|
<string name="no_media_description">Add a media description here…</string>
|
||||||
<string name="total_exceeds_album_limit">You chose more images than the maximum your server allows (%1$s). Images beyond the limit have been ignored.</string>
|
<string name="total_exceeds_album_limit">You chose more images than the maximum your server allows (%1$s). Images beyond the limit have been ignored.</string>
|
||||||
<string name="size_exceeds_instance_limit">Size of image number %1$s in the album exceeds the maximum size allowed by the instance (%2$s kB but the limit is %3$s kB). You might not be able to upload it.</string>
|
<string name="size_exceeds_instance_limit">Size of image number %1$d in the album exceeds the maximum size allowed by the instance (%2$d kB but the limit is %3$d kB). You might not be able to upload it.</string>
|
||||||
<string name="upload_error">Error code returned by server: %1$s</string>
|
<string name="upload_error">Error code returned by server: %1$d</string>
|
||||||
|
|
||||||
|
|
||||||
<!-- Post editing -->
|
<!-- Post editing -->
|
||||||
|
@ -200,4 +200,6 @@ Following"</item>
|
||||||
<string name="help_translate">Help translate PixelDroid to your 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="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="mascot_description">Image showing a red panda, Pixelfed\'s mascot, using a phone</string>
|
||||||
|
<string name="delete_post_failed_error">Could not delete the post, error %1$d</string>
|
||||||
|
<string name="delete_post_failed_io_except">Could not delete the post, check your connection?</string>
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in New Issue