From 9dd6f3f1a8c6ef4b1462f6bb46fa045cc3462ce8 Mon Sep 17 00:00:00 2001 From: Matthieu <24-artectrex@users.noreply.shinice.net> Date: Mon, 25 Jan 2021 00:02:03 +0100 Subject: [PATCH] Add image description functionality --- .../postCreation/PostCreationActivity.kt | 27 +-- .../postCreation/carousel/CarouselAdapter.kt | 5 + .../postCreation/carousel/CarouselItem.kt | 8 +- .../postCreation/carousel/ImageCarousel.kt | 158 +++++++++--------- .../com/h/pixeldroid/utils/api/PixelfedAPI.kt | 1 + app/src/main/res/drawable/check_circle_24.xml | 12 ++ .../res/layout/activity_post_creation.xml | 1 + app/src/main/res/layout/image_carousel.xml | 103 ++++++++++-- .../main/res/layout/next_button_layout.xml | 19 --- .../res/layout/previous_button_layout.xml | 19 --- app/src/main/res/values-de/strings.xml | 1 - app/src/main/res/values-fa/strings.xml | 1 - app/src/main/res/values-fr/strings.xml | 1 - app/src/main/res/values-it/strings.xml | 1 - app/src/main/res/values-nl/strings.xml | 1 - app/src/main/res/values/strings.xml | 9 +- 16 files changed, 209 insertions(+), 158 deletions(-) create mode 100644 app/src/main/res/drawable/check_circle_24.xml delete mode 100644 app/src/main/res/layout/next_button_layout.xml delete mode 100644 app/src/main/res/layout/previous_button_layout.xml diff --git a/app/src/main/java/com/h/pixeldroid/postCreation/PostCreationActivity.kt b/app/src/main/java/com/h/pixeldroid/postCreation/PostCreationActivity.kt index 11839d03..7319bb58 100644 --- a/app/src/main/java/com/h/pixeldroid/postCreation/PostCreationActivity.kt +++ b/app/src/main/java/com/h/pixeldroid/postCreation/PostCreationActivity.kt @@ -16,26 +16,23 @@ import android.util.Log import android.view.View import android.view.View.INVISIBLE import android.view.View.VISIBLE -import android.widget.Button -import android.widget.ImageButton import android.widget.Toast import androidx.core.net.toFile import androidx.core.net.toUri import androidx.lifecycle.lifecycleScope 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 import com.h.pixeldroid.R import com.h.pixeldroid.databinding.ActivityPostCreationBinding -import com.h.pixeldroid.utils.api.PixelfedAPI import com.h.pixeldroid.postCreation.camera.CameraActivity import com.h.pixeldroid.postCreation.carousel.CarouselItem import com.h.pixeldroid.postCreation.carousel.ImageCarousel -import com.h.pixeldroid.utils.db.entities.UserDatabaseEntity +import com.h.pixeldroid.postCreation.photoEdit.PhotoEditActivity +import com.h.pixeldroid.utils.BaseActivity +import com.h.pixeldroid.utils.api.PixelfedAPI import com.h.pixeldroid.utils.api.objects.Attachment import com.h.pixeldroid.utils.api.objects.Instance -import com.h.pixeldroid.postCreation.photoEdit.PhotoEditActivity +import com.h.pixeldroid.utils.db.entities.UserDatabaseEntity import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers @@ -54,7 +51,8 @@ private const val MORE_PICTURES_REQUEST_CODE = 0xffff data class PhotoData( var imageUri: Uri, var uploadId: String? = null, - var progress: Int? = null + var progress: Int? = null, + var imageDescription: String? = null ) class PostCreationActivity : BaseActivity() { @@ -102,7 +100,7 @@ class PostCreationActivity : BaseActivity() { pixelfedAPI = apiHolder.api ?: apiHolder.setDomainToCurrentUser(db) val carousel: ImageCarousel = binding.carousel - carousel.addData(photoData.map { CarouselItem(it.imageUri.toString()) }) + carousel.addData(photoData.map { CarouselItem(it.imageUri) }) carousel.layoutCarouselCallback = { //TODO transition instead of at once if(it){ @@ -116,6 +114,9 @@ class PostCreationActivity : BaseActivity() { carousel.addPhotoButtonCallback = { addPhoto(applicationContext) } + carousel.updateDescriptionCallback = { position: Int, description: String -> + photoData[position].imageDescription = description + } // get the description and send the post binding.postCreationSendButton.setOnClickListener { @@ -152,7 +153,7 @@ class PostCreationActivity : BaseActivity() { binding.removePhotoButton.setOnClickListener { carousel.currentPosition.takeIf { it != -1 }?.let { currentPosition -> photoData.removeAt(currentPosition) - carousel.addData(photoData.map { CarouselItem(it.imageUri.toString()) }) + carousel.addData(photoData.map { CarouselItem(it.imageUri, it.imageDescription) }) } } } @@ -283,7 +284,7 @@ class PostCreationActivity : BaseActivity() { } var postSub: Disposable? = null - val inter = pixelfedAPI.mediaUpload("Bearer $accessToken", requestBody.parts[0]) + val inter = pixelfedAPI.mediaUpload("Bearer $accessToken", data.imageDescription, requestBody.parts[0]) postSub = inter .subscribeOn(Schedulers.io()) @@ -369,7 +370,7 @@ class PostCreationActivity : BaseActivity() { if (resultCode == Activity.RESULT_OK && data != null) { photoData[positionResult].imageUri = data.getStringExtra("result")!!.toUri() - binding.carousel.addData(photoData.map { CarouselItem(it.imageUri.toString()) }) + binding.carousel.addData(photoData.map { CarouselItem(it.imageUri, it.imageDescription) }) photoData[positionResult].progress = null photoData[positionResult].uploadId = null @@ -385,7 +386,7 @@ class PostCreationActivity : BaseActivity() { photoData.add(PhotoData(imageUri)) } - binding.carousel.addData(photoData.map { CarouselItem(it.imageUri.toString()) }) + 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() } diff --git a/app/src/main/java/com/h/pixeldroid/postCreation/carousel/CarouselAdapter.kt b/app/src/main/java/com/h/pixeldroid/postCreation/carousel/CarouselAdapter.kt index 1062abbb..b2ecb451 100644 --- a/app/src/main/java/com/h/pixeldroid/postCreation/carousel/CarouselAdapter.kt +++ b/app/src/main/java/com/h/pixeldroid/postCreation/carousel/CarouselAdapter.kt @@ -95,6 +95,11 @@ class CarouselAdapter( } } + fun updateDescription(position: Int, description: String) { + dataList[position] = dataList[position].copy(caption = description) + notifyItemChanged(position) + } + fun addAll(dataList: List) { this.dataList.clear() diff --git a/app/src/main/java/com/h/pixeldroid/postCreation/carousel/CarouselItem.kt b/app/src/main/java/com/h/pixeldroid/postCreation/carousel/CarouselItem.kt index a50326c0..8b3ef70e 100644 --- a/app/src/main/java/com/h/pixeldroid/postCreation/carousel/CarouselItem.kt +++ b/app/src/main/java/com/h/pixeldroid/postCreation/carousel/CarouselItem.kt @@ -1,8 +1,10 @@ package com.h.pixeldroid.postCreation.carousel +import android.net.Uri + data class CarouselItem constructor( - val imageUrl: String? = null, - val caption: String? = null + val imageUrl: Uri, + val caption: String? = null ) { - constructor(imageUrl: String? = null) : this(imageUrl, null) + constructor(imageUrl: Uri) : this(imageUrl, null) } \ No newline at end of file diff --git a/app/src/main/java/com/h/pixeldroid/postCreation/carousel/ImageCarousel.kt b/app/src/main/java/com/h/pixeldroid/postCreation/carousel/ImageCarousel.kt index 3185dc89..6c7e51b2 100644 --- a/app/src/main/java/com/h/pixeldroid/postCreation/carousel/ImageCarousel.kt +++ b/app/src/main/java/com/h/pixeldroid/postCreation/carousel/ImageCarousel.kt @@ -8,10 +8,7 @@ import android.util.AttributeSet import android.util.TypedValue import android.view.LayoutInflater import android.view.View -import android.widget.FrameLayout -import android.widget.ImageButton -import android.widget.ImageView -import android.widget.TextView +import android.widget.* import androidx.annotation.Dimension import androidx.annotation.IdRes import androidx.annotation.LayoutRes @@ -19,6 +16,7 @@ import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.ContextCompat import androidx.recyclerview.widget.* import com.h.pixeldroid.R +import com.h.pixeldroid.databinding.ImageCarouselBinding import me.relex.circleindicator.CircleIndicator2 import org.jetbrains.annotations.NotNull import org.jetbrains.annotations.Nullable @@ -31,6 +29,8 @@ class ImageCarousel( private var adapter: CarouselAdapter? = null + private lateinit var binding: ImageCarouselBinding + private val scaleTypeArray = arrayOf( ImageView.ScaleType.MATRIX, ImageView.ScaleType.FIT_XY, @@ -42,11 +42,9 @@ class ImageCarousel( ImageView.ScaleType.CENTER_INSIDE ) - private lateinit var carouselView: View private lateinit var recyclerView: RecyclerView private lateinit var tvCaption: TextView - private lateinit var previousButtonContainer: FrameLayout - private lateinit var nextButtonContainer: FrameLayout + private lateinit var editTextMediaDescription: EditText private var snapHelper: SnapHelper = PagerSnapHelper() var indicator: CircleIndicator2? = null @@ -151,9 +149,9 @@ class ImageCarousel( set(value) { field = value - previousButtonContainer.visibility = + binding.btnPrevious.visibility = if (showNavigationButtons) View.VISIBLE else View.GONE - nextButtonContainer.visibility = + binding.btnNext.visibility = if (showNavigationButtons) View.VISIBLE else View.GONE } @@ -194,69 +192,19 @@ class ImageCarousel( initAdapter() } - @LayoutRes - var previousButtonLayout: Int = R.layout.previous_button_layout - set(value) { - field = value - - btnPrevious = null - - previousButtonContainer.removeAllViews() - LayoutInflater.from(context).apply { - inflate(previousButtonLayout, previousButtonContainer, true) - } - } - - @IdRes - var previousButtonId: Int = R.id.btn_next - set(value) { - field = value - - btnPrevious = carouselView.findViewById(previousButtonId) - - btnPrevious?.setOnClickListener { - previous() - } - } - @Dimension(unit = Dimension.PX) var previousButtonMargin: Int = 0 set(value) { field = value - val previousButtonParams = previousButtonContainer.layoutParams as LayoutParams + val previousButtonParams = binding.btnPrevious.layoutParams as LayoutParams previousButtonParams.setMargins( previousButtonMargin, 0, 0, 0 ) - previousButtonContainer.layoutParams = previousButtonParams - } - - @LayoutRes - var nextButtonLayout: Int = R.layout.next_button_layout - set(value) { - field = value - - btnNext = null - - nextButtonContainer.removeAllViews() - LayoutInflater.from(context).apply { - inflate(nextButtonLayout, nextButtonContainer, true) - } - } - - @IdRes - var nextButtonId: Int = R.id.btn_previous - set(value) { - field = value - - btnNext = carouselView.findViewById(nextButtonId) - - btnNext?.setOnClickListener { - next() - } + binding.btnPrevious.layoutParams = previousButtonParams } @Dimension(unit = Dimension.PX) @@ -264,22 +212,22 @@ class ImageCarousel( set(value) { field = value - val nextButtonParams = nextButtonContainer.layoutParams as LayoutParams + val nextButtonParams = binding.btnNext.layoutParams as LayoutParams nextButtonParams.setMargins( 0, 0, nextButtonMargin, 0 ) - nextButtonContainer.layoutParams = nextButtonParams + binding.btnNext.layoutParams = nextButtonParams } var showLayoutSwitchButton: Boolean = true set(value) { field = value - btnGrid = findViewById(R.id.switchToGridButton) - btnCarousel = findViewById(R.id.switchToCarouselButton) + btnGrid = binding.switchToGridButton + btnCarousel = binding.switchToCarouselButton btnGrid?.setOnClickListener { layoutCarousel = false @@ -304,6 +252,9 @@ class ImageCarousel( var layoutCarouselCallback: ((Boolean) -> Unit)? = null + var updateDescriptionCallback: ((position: Int, description: String) -> Unit)? = null + + var layoutCarousel: Boolean = true set(value) { field = value @@ -313,10 +264,16 @@ class ImageCarousel( btnNext?.visibility = VISIBLE btnPrevious?.visibility = VISIBLE + + binding.editMediaDescriptionLayout.visibility = if(editingMediaDescription) VISIBLE else INVISIBLE + tvCaption.visibility = if(editingMediaDescription) INVISIBLE else VISIBLE } else { recyclerView.layoutManager = GridLayoutManager(context, 3) btnNext?.visibility = GONE btnPrevious?.visibility = GONE + + binding.editMediaDescriptionLayout.visibility = INVISIBLE + tvCaption.visibility = INVISIBLE } showIndicator = value @@ -330,6 +287,37 @@ class ImageCarousel( var addPhotoButtonCallback: (() -> Unit)? = null + var editingMediaDescription: Boolean = false + set(value){ + + if(layoutCarousel){ + field = value + if(value) editTextMediaDescription.setText(currentDescription) + else { + val description = editTextMediaDescription.text.toString() + currentDescription = description + adapter?.updateDescription(currentPosition, description) + updateDescriptionCallback?.invoke(currentPosition, description) + } + binding.editMediaDescriptionLayout.visibility = if(value) VISIBLE else INVISIBLE + tvCaption.visibility = if(value) INVISIBLE else VISIBLE + + } + + } + + var currentDescription: String? = null + set(value) { + if(!value.isNullOrEmpty()) { + field = value + tvCaption.text = value + } else { + field = null + tvCaption.text = context.getText(R.string.no_media_description) + } + + } + init { @@ -341,12 +329,11 @@ class ImageCarousel( private fun initViews() { - carouselView = LayoutInflater.from(context).inflate(R.layout.image_carousel, this) + binding = ImageCarouselBinding.inflate(LayoutInflater.from(context),this, true) - recyclerView = carouselView.findViewById(R.id.recyclerView) - tvCaption = carouselView.findViewById(R.id.tv_caption) - previousButtonContainer = carouselView.findViewById(R.id.previous_button_container) - nextButtonContainer = carouselView.findViewById(R.id.next_button_container) + recyclerView = binding.recyclerView + tvCaption = binding.tvCaption + editTextMediaDescription = binding.editTextMediaDescription recyclerView.setHasFixedSize(true) @@ -403,16 +390,8 @@ class ImageCarousel( R.id.img ) - previousButtonLayout = R.layout.previous_button_layout - - previousButtonId = R.id.btn_previous - previousButtonMargin = 4.dpToPx(context) - nextButtonLayout = R.layout.next_button_layout - - nextButtonId = R.id.btn_next - nextButtonMargin = 4.dpToPx(context) showNavigationButtons = getBoolean( @@ -474,7 +453,11 @@ class ImageCarousel( val dataItem = adapter?.getItem(position) dataItem?.apply { - tvCaption.text = this.caption + caption.apply { + binding.editMediaDescriptionLayout.visibility = INVISIBLE + tvCaption.visibility = VISIBLE + currentDescription = this + } } } } @@ -499,12 +482,27 @@ class ImageCarousel( } }) + + tvCaption.setOnClickListener { + editingMediaDescription = true + } + + binding.btnNext.setOnClickListener { + next() + } + + binding.btnPrevious.setOnClickListener { + previous() + } + binding.imageDescriptionButton.setOnClickListener { + editingMediaDescription = false + } } private fun initIndicator() { // If no custom indicator added, then default indicator will be shown. if (indicator == null) { - indicator = carouselView.findViewById(R.id.indicator) + indicator = binding.indicator isBuiltInIndicator = true } diff --git a/app/src/main/java/com/h/pixeldroid/utils/api/PixelfedAPI.kt b/app/src/main/java/com/h/pixeldroid/utils/api/PixelfedAPI.kt index 7718a9a4..d79392b8 100644 --- a/app/src/main/java/com/h/pixeldroid/utils/api/PixelfedAPI.kt +++ b/app/src/main/java/com/h/pixeldroid/utils/api/PixelfedAPI.kt @@ -256,6 +256,7 @@ interface PixelfedAPI { fun mediaUpload( //The authorization header needs to be of the form "Bearer " @Header("Authorization") authorization: String, + @Part("description") description: String?, @Part file: MultipartBody.Part ): Observable diff --git a/app/src/main/res/drawable/check_circle_24.xml b/app/src/main/res/drawable/check_circle_24.xml new file mode 100644 index 00000000..3cb7dd9a --- /dev/null +++ b/app/src/main/res/drawable/check_circle_24.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/app/src/main/res/layout/activity_post_creation.xml b/app/src/main/res/layout/activity_post_creation.xml index a99418c2..362bad7b 100644 --- a/app/src/main/res/layout/activity_post_creation.xml +++ b/app/src/main/res/layout/activity_post_creation.xml @@ -47,6 +47,7 @@ android:id="@+id/carousel" android:layout_width="match_parent" android:layout_height="0dp" + app:showCaption="true" app:layout_constraintBottom_toBottomOf="@+id/uploadProgressBar" app:layout_constraintTop_toTopOf="parent"/> diff --git a/app/src/main/res/layout/image_carousel.xml b/app/src/main/res/layout/image_carousel.xml index c7e16eea..52500e18 100644 --- a/app/src/main/res/layout/image_carousel.xml +++ b/app/src/main/res/layout/image_carousel.xml @@ -4,7 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:foregroundTint="#FFFFFF"> + android:foregroundTint="#000000"> + + + + + + + + + - + app:layout_constraintTop_toTopOf="@+id/recyclerView"/> - + app:layout_constraintTop_toTopOf="@+id/recyclerView"/> + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="@+id/indicator" + tools:visibility="visible" /> \ No newline at end of file diff --git a/app/src/main/res/layout/next_button_layout.xml b/app/src/main/res/layout/next_button_layout.xml deleted file mode 100644 index 652b23cf..00000000 --- a/app/src/main/res/layout/next_button_layout.xml +++ /dev/null @@ -1,19 +0,0 @@ - - \ No newline at end of file diff --git a/app/src/main/res/layout/previous_button_layout.xml b/app/src/main/res/layout/previous_button_layout.xml deleted file mode 100644 index 862ff299..00000000 --- a/app/src/main/res/layout/previous_button_layout.xml +++ /dev/null @@ -1,19 +0,0 @@ - - \ No newline at end of file diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 79bfb65f..a2ec06c4 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -146,7 +146,6 @@ Schaltfläche zum ausschneiden oder rotieren des Bildes Vorschau des bearbeiteten Bildes Vorschaubild des Filters - Klicke auf das Bild um es zu ändern Eines der Bilder im Beitrag Benutzerdaten konnten nicht geladen werden \ No newline at end of file diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 6ac71f3a..ac76e247 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -141,7 +141,6 @@ دکمه برش یا چرخش تصویر پیش‌نمایش تصویری که در حال ویرایش است تصویر بندانگشتی پالایه - برای ویرایش تصویر، روی آن کلیک کنید یکی از تصاویر در فرسته ناتوانی در دریافت اطلاعات کاربر \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 1d0c3dec..400f4f58 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -108,7 +108,6 @@ Rapporter Aperçu de l\'image en cours de modification Vignette d\'un filtre - Appuyez sur l\'image pour la modifier Image montrant un panda rouge (la mascotte de Pixelfed) qui utilise un téléphone Aidez pour traduire PixelDroid dans votre langue : Langue diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 4e0bf7cc..35abbd56 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -142,7 +142,6 @@ Pulsante per ritagliare o ruotare l\'immagine Anteprima dell\'immagine in fase di modifica Miniatura del filtro - Clicca sull\'immagine per modificarla Una delle immagini nel post Impossibile ottenere le informazioni sull\'utente Passa alla visualizzazione a griglia diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 9130b533..58db999c 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -130,7 +130,6 @@ Commentaar versturen Commentaar toevoegen %1$s commentaren - Klik op de afbeelding om het te bewerken Foto toevoegen Aanmelding annuleren OK, toch verdergaan diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index be252cfc..6fa92f97 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -50,7 +50,11 @@ post Add a photo One of the images in the post - Click the image to edit it + Switch to grid view + Switch to carousel + Save image description + Add a media description here… + BRIGHTNESS CONTRAST @@ -64,6 +68,7 @@ "Couldn't retrieve image after crop" Preview of the image being edited Button to crop or rotate the image + Capture Switch camera @@ -156,7 +161,5 @@ Image showing a red panda, Pixelfed\'s mascot, using a phone Save your edits? No, cancel edit - Switch to grid view - Switch to carousel \ No newline at end of file