Finish implementing carousel+grid postcreation
This commit is contained in:
parent
4b8f47155c
commit
8bfbe2fbb5
@ -4,6 +4,7 @@ plugins {
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'jacoco'
|
||||
|
||||
@ -11,7 +12,7 @@ apply plugin: 'jacoco'
|
||||
android {
|
||||
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion '30.0.2'
|
||||
buildToolsVersion '30.0.3'
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
@ -56,6 +57,7 @@ android {
|
||||
}
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
dataBinding = true
|
||||
}
|
||||
|
||||
apply plugin: 'kotlin-kapt'
|
||||
@ -157,7 +159,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'
|
||||
implementation 'me.relex:circleindicator:2.1.4'
|
||||
|
||||
/**
|
||||
* Not in release, so not mentioned in licenses list
|
||||
|
@ -3,6 +3,7 @@ package com.h.pixeldroid.postCreation
|
||||
import android.app.Activity
|
||||
import android.content.ContentResolver
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.media.MediaScannerConnection
|
||||
import android.net.Uri
|
||||
@ -13,6 +14,8 @@ import android.provider.MediaStore
|
||||
import android.provider.OpenableColumns
|
||||
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
|
||||
@ -26,6 +29,8 @@ import com.h.pixeldroid.MainActivity
|
||||
import com.h.pixeldroid.R
|
||||
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.utils.api.objects.Attachment
|
||||
import com.h.pixeldroid.utils.api.objects.Instance
|
||||
@ -34,10 +39,9 @@ import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.android.synthetic.main.activity_post_creation.*
|
||||
import kotlinx.android.synthetic.main.activity_post_creation.view.*
|
||||
import kotlinx.android.synthetic.main.image_album_creation.view.*
|
||||
import okhttp3.MultipartBody
|
||||
import org.imaginativeworld.whynotimagecarousel.CarouselItem
|
||||
import org.imaginativeworld.whynotimagecarousel.ImageCarousel
|
||||
import retrofit2.HttpException
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
@ -100,6 +104,19 @@ class PostCreationActivity : BaseActivity() {
|
||||
|
||||
val carousel: ImageCarousel = findViewById(R.id.carousel)
|
||||
carousel.addData(photoData.map { CarouselItem(it.imageUri.toString()) })
|
||||
carousel.layoutCarouselCallback = {
|
||||
//TODO transition instead of at once
|
||||
if(it){
|
||||
// Became a carousel
|
||||
toolbar3.visibility = VISIBLE
|
||||
} else {
|
||||
// Became a grid
|
||||
toolbar3.visibility = INVISIBLE
|
||||
}
|
||||
}
|
||||
carousel.addPhotoButtonCallback = {
|
||||
addPhoto(applicationContext)
|
||||
}
|
||||
|
||||
// get the description and send the post
|
||||
findViewById<Button>(R.id.post_creation_send_button).setOnClickListener {
|
||||
@ -123,8 +140,7 @@ class PostCreationActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
findViewById<ImageButton>(R.id.addPhotoButton).setOnClickListener {
|
||||
val intent = Intent(it.context, CameraActivity::class.java)
|
||||
this@PostCreationActivity.startActivityForResult(intent, MORE_PICTURES_REQUEST_CODE)
|
||||
addPhoto(it.context)
|
||||
}
|
||||
|
||||
findViewById<ImageButton>(R.id.savePhotoButton).setOnClickListener {
|
||||
@ -139,10 +155,14 @@ class PostCreationActivity : BaseActivity() {
|
||||
photoData.removeAt(currentPosition)
|
||||
carousel.addData(photoData.map { CarouselItem(it.imageUri.toString()) })
|
||||
}
|
||||
//TODO("have to fix upload to allow deleting!")
|
||||
}
|
||||
}
|
||||
|
||||
private fun addPhoto(context: Context){
|
||||
val intent = Intent(context, CameraActivity::class.java)
|
||||
this@PostCreationActivity.startActivityForResult(intent, MORE_PICTURES_REQUEST_CODE)
|
||||
}
|
||||
|
||||
private fun savePicture(button: View, currentPosition: Int) {
|
||||
val name = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS", Locale.US)
|
||||
.format(System.currentTimeMillis()) + ".png"
|
||||
@ -375,58 +395,4 @@ class PostCreationActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
inner class PostCreationAdapter(private val posts: ArrayList<String>): RecyclerView.Adapter<PostCreationAdapter.ViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val view =
|
||||
if(viewType == 0) LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.image_album_creation, parent, false)
|
||||
else LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.add_more_album_creation, parent, false)
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
if(position == posts.size) return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
if(position != posts.size) {
|
||||
holder.bindImage()
|
||||
} else{
|
||||
holder.bindPlusButton()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = posts.size + 1
|
||||
|
||||
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
|
||||
fun bindImage() {
|
||||
val image = Uri.parse(
|
||||
posts[adapterPosition]
|
||||
)
|
||||
// load image
|
||||
Glide.with(itemView.context)
|
||||
.load(image)
|
||||
.centerCrop()
|
||||
.into(itemView.galleryImage)
|
||||
// adding click or tap handler for the image layout
|
||||
itemView.setOnClickListener {
|
||||
this@PostCreationActivity.onClick(adapterPosition)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun bindPlusButton() {
|
||||
itemView.setOnClickListener {
|
||||
val intent = Intent(itemView.context, CameraActivity::class.java)
|
||||
this@PostCreationActivity.startActivityForResult(intent, MORE_PICTURES_REQUEST_CODE)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
@ -169,7 +169,7 @@ class CameraFragment : Fragment() {
|
||||
}
|
||||
|
||||
/** Declare and bind preview, capture and analysis use cases */
|
||||
private fun bindCameraUseCases() {
|
||||
private fun bindCameraUseCases(forceRebind: Boolean = false) {
|
||||
|
||||
// Get screen metrics used to setup camera for full screen resolution
|
||||
val metrics = DisplayMetrics().also { viewFinder.display?.getRealMetrics(it) }
|
||||
@ -188,7 +188,7 @@ class CameraFragment : Fragment() {
|
||||
// CameraProvider
|
||||
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
|
||||
|
||||
if (camera == null || preview == null || imageCapture == null || !cameraProvider.isBound(preview!!) || !cameraProvider.isBound(imageCapture!!)) {
|
||||
if (forceRebind || camera == null || preview == null || imageCapture == null || !cameraProvider.isBound(preview!!) || !cameraProvider.isBound(imageCapture!!)) {
|
||||
|
||||
|
||||
// Preview
|
||||
@ -324,7 +324,7 @@ class CameraFragment : Fragment() {
|
||||
REQUEST_CODE_PERMISSIONS
|
||||
)
|
||||
} else {
|
||||
bindCameraUseCases()
|
||||
bindCameraUseCases(forceRebind = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,110 @@
|
||||
package com.h.pixeldroid.postCreation.carousel
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.h.pixeldroid.R
|
||||
|
||||
|
||||
class CarouselAdapter(
|
||||
@LayoutRes private val itemLayout: Int,
|
||||
@IdRes private val imageViewId: Int,
|
||||
var listener: OnItemClickListener? = null,
|
||||
private val imageScaleType: ImageView.ScaleType,
|
||||
private val imagePlaceholder: Drawable?,
|
||||
private val carousel: Boolean
|
||||
) : RecyclerView.Adapter<CarouselAdapter.MyViewHolder>() {
|
||||
|
||||
private val dataList: MutableList<CarouselItem> = mutableListOf()
|
||||
|
||||
|
||||
|
||||
class MyViewHolder(itemView: View, imageViewId: Int) : RecyclerView.ViewHolder(itemView) {
|
||||
var img: ImageView = itemView.findViewById(imageViewId)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
|
||||
return if(!carousel){
|
||||
if(viewType == 0) {
|
||||
val view =
|
||||
LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.image_album_creation, parent, false)
|
||||
MyViewHolder(view, R.id.galleryImage)
|
||||
} else {
|
||||
val view =
|
||||
LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.add_more_album_creation, parent, false)
|
||||
MyViewHolder(view, R.id.addPhotoSquare)
|
||||
}
|
||||
} else {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
.inflate(itemLayout, parent, false)
|
||||
MyViewHolder(view, imageViewId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return if(carousel) dataList.size
|
||||
else dataList.size + 1
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
if(position == dataList.size) return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
|
||||
if(carousel) {
|
||||
holder.img.scaleType = imageScaleType
|
||||
}
|
||||
|
||||
dataList.elementAtOrNull(position)?.let {
|
||||
Glide.with(holder.itemView.context)
|
||||
.load(it.imageUrl)
|
||||
.placeholder(imagePlaceholder)
|
||||
.into(holder.img)
|
||||
}
|
||||
|
||||
// Init listeners
|
||||
listener?.apply {
|
||||
|
||||
holder.itemView.setOnClickListener {
|
||||
this.onClick(position)
|
||||
}
|
||||
|
||||
holder.itemView.setOnLongClickListener {
|
||||
this.onLongClick(position)
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun getItem(position: Int): CarouselItem? {
|
||||
return if (position < dataList.size) {
|
||||
dataList[position]
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun addAll(dataList: List<CarouselItem>) {
|
||||
this.dataList.clear()
|
||||
|
||||
this.dataList.addAll(dataList)
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun add(item: CarouselItem) {
|
||||
this.dataList.add(item)
|
||||
notifyItemInserted(dataList.size - 1)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.h.pixeldroid.postCreation.carousel
|
||||
|
||||
data class CarouselItem constructor(
|
||||
val imageUrl: String? = null,
|
||||
val caption: String? = null
|
||||
) {
|
||||
constructor(imageUrl: String? = null) : this(imageUrl, null)
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.h.pixeldroid.postCreation.carousel
|
||||
|
||||
import android.content.Context
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
class CarouselLinearLayoutManager(
|
||||
context: Context,
|
||||
orientation: Int,
|
||||
reverseLayout: Boolean
|
||||
) : LinearLayoutManager(context, orientation, reverseLayout) {
|
||||
|
||||
override fun onLayoutChildren(recycler: RecyclerView.Recycler?, state: RecyclerView.State?) {
|
||||
super.onLayoutChildren(recycler, state)
|
||||
scrollHorizontallyBy(0, recycler, state)
|
||||
}
|
||||
}
|
@ -0,0 +1,615 @@
|
||||
package com.h.pixeldroid.postCreation.carousel
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
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 androidx.annotation.Dimension
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.*
|
||||
import com.h.pixeldroid.R
|
||||
import me.relex.circleindicator.CircleIndicator2
|
||||
import org.jetbrains.annotations.NotNull
|
||||
import org.jetbrains.annotations.Nullable
|
||||
|
||||
|
||||
class ImageCarousel(
|
||||
@NotNull context: Context,
|
||||
@Nullable private var attributeSet: AttributeSet?
|
||||
) : ConstraintLayout(context, attributeSet), OnItemClickListener {
|
||||
|
||||
private var adapter: CarouselAdapter? = null
|
||||
|
||||
private val scaleTypeArray = arrayOf(
|
||||
ImageView.ScaleType.MATRIX,
|
||||
ImageView.ScaleType.FIT_XY,
|
||||
ImageView.ScaleType.FIT_START,
|
||||
ImageView.ScaleType.FIT_CENTER,
|
||||
ImageView.ScaleType.FIT_END,
|
||||
ImageView.ScaleType.CENTER,
|
||||
ImageView.ScaleType.CENTER_CROP,
|
||||
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 var snapHelper: SnapHelper = PagerSnapHelper()
|
||||
|
||||
var indicator: CircleIndicator2? = null
|
||||
set(newIndicator) {
|
||||
indicator?.apply {
|
||||
// if we remove it form the view, then the caption textView constraint won't work.
|
||||
this.visibility = View.GONE
|
||||
|
||||
isBuiltInIndicator = false
|
||||
}
|
||||
|
||||
field = newIndicator
|
||||
|
||||
initIndicator()
|
||||
}
|
||||
|
||||
|
||||
private var btnPrevious: View? = null
|
||||
private var btnNext: View? = null
|
||||
|
||||
private var btnGrid: View? = null
|
||||
private var btnCarousel: View? = null
|
||||
|
||||
|
||||
private var isBuiltInIndicator = false
|
||||
private var data: List<CarouselItem>? = null
|
||||
|
||||
var onItemClickListener: OnItemClickListener? = this
|
||||
set(value) {
|
||||
field = value
|
||||
|
||||
adapter?.listener = onItemClickListener
|
||||
}
|
||||
|
||||
var onScrollListener: CarouselOnScrollListener? = null
|
||||
set(value) {
|
||||
field = value
|
||||
|
||||
initOnScrollStateChange()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set current item position
|
||||
*/
|
||||
var currentPosition = -1
|
||||
get() {
|
||||
return snapHelper.getSnapPosition(recyclerView.layoutManager)
|
||||
}
|
||||
set(value) {
|
||||
val position = when {
|
||||
value >= data?.size ?: 0 -> {
|
||||
-1
|
||||
}
|
||||
value < 0 -> {
|
||||
-1
|
||||
}
|
||||
else -> {
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
field = position
|
||||
|
||||
if (position != -1) {
|
||||
recyclerView.smoothScrollToPosition(position)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ****************************************************************
|
||||
* Attributes
|
||||
* ****************************************************************
|
||||
*/
|
||||
|
||||
var showCaption = false
|
||||
set(value) {
|
||||
field = value
|
||||
|
||||
tvCaption.visibility = if (showCaption) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
@Dimension(unit = Dimension.PX)
|
||||
var captionTextSize: Int = 0
|
||||
set(value) {
|
||||
field = value
|
||||
|
||||
tvCaption.setTextSize(TypedValue.COMPLEX_UNIT_PX, captionTextSize.toFloat())
|
||||
}
|
||||
|
||||
var showIndicator = false
|
||||
set(value) {
|
||||
field = value
|
||||
|
||||
when {
|
||||
indicator == null -> initIndicator()
|
||||
value -> indicator?.visibility = View.VISIBLE
|
||||
else -> indicator?.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
var showNavigationButtons = false
|
||||
set(value) {
|
||||
field = value
|
||||
|
||||
previousButtonContainer.visibility =
|
||||
if (showNavigationButtons) View.VISIBLE else View.GONE
|
||||
nextButtonContainer.visibility =
|
||||
if (showNavigationButtons) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
var imageScaleType: ImageView.ScaleType = ImageView.ScaleType.CENTER_INSIDE
|
||||
set(value) {
|
||||
field = value
|
||||
|
||||
initAdapter()
|
||||
}
|
||||
|
||||
var carouselBackground: Drawable? = null
|
||||
set(value) {
|
||||
field = value
|
||||
|
||||
recyclerView.background = carouselBackground
|
||||
}
|
||||
|
||||
var imagePlaceholder: Drawable? = null
|
||||
set(value) {
|
||||
field = value
|
||||
|
||||
initAdapter()
|
||||
}
|
||||
|
||||
@LayoutRes
|
||||
var itemLayout: Int = R.layout.item_carousel
|
||||
set(value) {
|
||||
field = value
|
||||
|
||||
initAdapter()
|
||||
}
|
||||
|
||||
@IdRes
|
||||
var imageViewId: Int = R.id.img
|
||||
set(value) {
|
||||
field = value
|
||||
|
||||
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
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
@Dimension(unit = Dimension.PX)
|
||||
var nextButtonMargin: Int = 0
|
||||
set(value) {
|
||||
field = value
|
||||
|
||||
val nextButtonParams = nextButtonContainer.layoutParams as LayoutParams
|
||||
nextButtonParams.setMargins(
|
||||
0,
|
||||
0,
|
||||
nextButtonMargin,
|
||||
0
|
||||
)
|
||||
nextButtonContainer.layoutParams = nextButtonParams
|
||||
}
|
||||
|
||||
var showLayoutSwitchButton: Boolean = true
|
||||
set(value) {
|
||||
field = value
|
||||
|
||||
btnGrid = findViewById<ImageButton>(R.id.switchToGridButton)
|
||||
btnCarousel = findViewById<ImageButton>(R.id.switchToCarouselButton)
|
||||
|
||||
btnGrid?.setOnClickListener {
|
||||
layoutCarousel = false
|
||||
}
|
||||
btnCarousel?.setOnClickListener {
|
||||
layoutCarousel = true
|
||||
}
|
||||
|
||||
if(value){
|
||||
if(layoutCarousel){
|
||||
btnGrid?.visibility = VISIBLE
|
||||
btnCarousel?.visibility = GONE
|
||||
} else {
|
||||
btnGrid?.visibility = GONE
|
||||
btnCarousel?.visibility = VISIBLE
|
||||
}
|
||||
} else {
|
||||
btnGrid?.visibility = GONE
|
||||
btnCarousel?.visibility = GONE
|
||||
}
|
||||
}
|
||||
|
||||
var layoutCarouselCallback: ((Boolean) -> Unit)? = null
|
||||
|
||||
var layoutCarousel: Boolean = true
|
||||
set(value) {
|
||||
field = value
|
||||
|
||||
if(value){
|
||||
recyclerView.layoutManager = CarouselLinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
||||
|
||||
btnNext?.visibility = VISIBLE
|
||||
btnPrevious?.visibility = VISIBLE
|
||||
} else {
|
||||
recyclerView.layoutManager = GridLayoutManager(context, 3)
|
||||
btnNext?.visibility = GONE
|
||||
btnPrevious?.visibility = GONE
|
||||
}
|
||||
showIndicator = value
|
||||
|
||||
layoutCarouselCallback?.let { it(value) }
|
||||
|
||||
//update layout switch button to make it take into account the change
|
||||
showLayoutSwitchButton = showLayoutSwitchButton
|
||||
|
||||
initAdapter()
|
||||
}
|
||||
|
||||
var addPhotoButtonCallback: (() -> Unit)? = null
|
||||
|
||||
|
||||
|
||||
init {
|
||||
initViews()
|
||||
initAttributes()
|
||||
initAdapter()
|
||||
initListeners()
|
||||
}
|
||||
|
||||
|
||||
private fun initViews() {
|
||||
carouselView = LayoutInflater.from(context).inflate(R.layout.image_carousel, this)
|
||||
|
||||
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.setHasFixedSize(true)
|
||||
|
||||
// For marquee effect
|
||||
tvCaption.isSelected = true
|
||||
}
|
||||
|
||||
|
||||
private fun initAttributes() {
|
||||
context.theme.obtainStyledAttributes(
|
||||
attributeSet,
|
||||
R.styleable.ImageCarousel,
|
||||
0,
|
||||
0
|
||||
).apply {
|
||||
|
||||
try {
|
||||
|
||||
showCaption = getBoolean(
|
||||
R.styleable.ImageCarousel_showCaption,
|
||||
true
|
||||
)
|
||||
|
||||
captionTextSize = getDimension(
|
||||
R.styleable.ImageCarousel_captionTextSize,
|
||||
14.spToPx(context).toFloat()
|
||||
).toInt()
|
||||
|
||||
showIndicator = getBoolean(
|
||||
R.styleable.ImageCarousel_showIndicator,
|
||||
true
|
||||
)
|
||||
|
||||
imageScaleType = scaleTypeArray[
|
||||
getInteger(
|
||||
R.styleable.ImageCarousel_imageScaleType,
|
||||
ImageView.ScaleType.CENTER_INSIDE.ordinal
|
||||
)
|
||||
]
|
||||
|
||||
carouselBackground = ColorDrawable(Color.parseColor("#333333"))
|
||||
|
||||
imagePlaceholder = getDrawable(
|
||||
R.styleable.ImageCarousel_imagePlaceholder
|
||||
) ?: ContextCompat.getDrawable(context, R.drawable.ic_picture_fallback)
|
||||
|
||||
itemLayout = getResourceId(
|
||||
R.styleable.ImageCarousel_itemLayout,
|
||||
R.layout.item_carousel
|
||||
)
|
||||
|
||||
imageViewId = getResourceId(
|
||||
R.styleable.ImageCarousel_imageViewId,
|
||||
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(
|
||||
R.styleable.ImageCarousel_showNavigationButtons,
|
||||
true
|
||||
)
|
||||
|
||||
layoutCarousel = getBoolean(
|
||||
R.styleable.ImageCarousel_layoutCarousel,
|
||||
true
|
||||
)
|
||||
|
||||
showLayoutSwitchButton = getBoolean(
|
||||
R.styleable.ImageCarousel_showLayoutSwitchButton,
|
||||
true
|
||||
)
|
||||
|
||||
} finally {
|
||||
recycle()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun initAdapter() {
|
||||
adapter = CarouselAdapter(
|
||||
itemLayout = itemLayout,
|
||||
imageViewId = imageViewId,
|
||||
listener = onItemClickListener,
|
||||
imageScaleType = imageScaleType,
|
||||
imagePlaceholder = imagePlaceholder,
|
||||
carousel = layoutCarousel
|
||||
)
|
||||
recyclerView.adapter = adapter
|
||||
|
||||
data?.apply {
|
||||
adapter?.addAll(this)
|
||||
}
|
||||
|
||||
indicator?.apply {
|
||||
try {
|
||||
adapter?.registerAdapterDataObserver(this.adapterDataObserver)
|
||||
} catch (e: IllegalStateException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun initListeners() {
|
||||
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
|
||||
if (showCaption) {
|
||||
val position = snapHelper.getSnapPosition(recyclerView.layoutManager)
|
||||
|
||||
if (position >= 0) {
|
||||
val dataItem = adapter?.getItem(position)
|
||||
|
||||
dataItem?.apply {
|
||||
tvCaption.text = this.caption
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onScrollListener?.onScrolled(recyclerView, dx, dy)
|
||||
|
||||
}
|
||||
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
|
||||
onScrollListener?.apply {
|
||||
val position = snapHelper.getSnapPosition(recyclerView.layoutManager)
|
||||
val carouselItem = data?.get(position)
|
||||
|
||||
onScrollStateChanged(
|
||||
recyclerView,
|
||||
newState,
|
||||
position,
|
||||
carouselItem
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun initIndicator() {
|
||||
// If no custom indicator added, then default indicator will be shown.
|
||||
if (indicator == null) {
|
||||
indicator = carouselView.findViewById(R.id.indicator)
|
||||
isBuiltInIndicator = true
|
||||
}
|
||||
|
||||
snapHelper.apply {
|
||||
try {
|
||||
attachToRecyclerView(recyclerView)
|
||||
} catch (e: IllegalStateException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
indicator?.apply {
|
||||
if (isBuiltInIndicator) {
|
||||
// Indicator visibility
|
||||
this.visibility = if (showIndicator) View.VISIBLE else View.INVISIBLE
|
||||
}
|
||||
|
||||
// Attach to recyclerview
|
||||
attachToRecyclerView(recyclerView, snapHelper)
|
||||
|
||||
// Observe the adapter
|
||||
adapter?.let { carouselAdapter ->
|
||||
try {
|
||||
carouselAdapter.registerAdapterDataObserver(this.adapterDataObserver)
|
||||
} catch (e: IllegalStateException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initOnScrollStateChange() {
|
||||
data?.apply {
|
||||
if (isNotEmpty()) {
|
||||
onScrollListener?.onScrollStateChanged(
|
||||
recyclerView,
|
||||
RecyclerView.SCROLL_STATE_IDLE,
|
||||
0,
|
||||
this[0]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add data to the carousel.
|
||||
*/
|
||||
fun addData(data: List<CarouselItem>) {
|
||||
adapter?.apply {
|
||||
addAll(data)
|
||||
|
||||
this@ImageCarousel.data = data
|
||||
|
||||
initOnScrollStateChange()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Goto previous item.
|
||||
*/
|
||||
fun previous() {
|
||||
currentPosition--
|
||||
}
|
||||
|
||||
/**
|
||||
* Goto next item.
|
||||
*/
|
||||
fun next() {
|
||||
currentPosition++
|
||||
}
|
||||
|
||||
override fun onClick(position: Int) {
|
||||
if(position == (data?.size ?: 0) ){
|
||||
addPhotoButtonCallback?.invoke()
|
||||
} else {
|
||||
if (!layoutCarousel) layoutCarousel = true
|
||||
currentPosition = position
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLongClick(position: Int) {
|
||||
//if(!layoutCarousel && position != (data?.size ?: 0) ) {
|
||||
//TODO Highlight selected, show toolbar?
|
||||
// Enable "long click mode?"
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
interface OnItemClickListener {
|
||||
|
||||
fun onClick(position: Int)
|
||||
|
||||
fun onLongClick(position: Int)
|
||||
|
||||
}
|
||||
|
||||
interface CarouselOnScrollListener {
|
||||
|
||||
fun onScrollStateChanged(
|
||||
recyclerView: RecyclerView,
|
||||
newState: Int,
|
||||
position: Int,
|
||||
carouselItem: CarouselItem?
|
||||
) {}
|
||||
|
||||
fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {}
|
||||
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package com.h.pixeldroid.postCreation.carousel
|
||||
|
||||
import android.content.Context
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.SnapHelper
|
||||
|
||||
|
||||
/**
|
||||
* This method converts device specific pixels to density independent pixels.
|
||||
*/
|
||||
fun Int.pxToDp(context: Context): Int {
|
||||
return (this / (context.resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)).toInt()
|
||||
}
|
||||
|
||||
/**
|
||||
* This method converts dp unit to equivalent pixels, depending on device density.
|
||||
*/
|
||||
fun Int.dpToPx(context: Context): Int {
|
||||
return TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
this.toFloat(),
|
||||
context.resources.displayMetrics
|
||||
).toInt()
|
||||
}
|
||||
|
||||
/**
|
||||
* This method converts sp unit to equivalent pixels, depending on device density.
|
||||
*/
|
||||
fun Int.spToPx(context: Context): Int {
|
||||
return TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
this.toFloat(),
|
||||
context.resources.displayMetrics
|
||||
).toInt()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current snap item position of a recyclerView.
|
||||
*
|
||||
* @param layoutManager Target recyclerView
|
||||
* @return Position of the item or RecyclerView.NO_POSITION (-1)
|
||||
*/
|
||||
fun SnapHelper.getSnapPosition(layoutManager: RecyclerView.LayoutManager?): Int {
|
||||
if (layoutManager == null) {
|
||||
return RecyclerView.NO_POSITION
|
||||
}
|
||||
val snapView: View = this.findSnapView(layoutManager) ?: return RecyclerView.NO_POSITION
|
||||
return layoutManager.getPosition(snapView)
|
||||
}
|
9
app/src/main/res/drawable/grid_on_black_24dp.xml
Normal file
9
app/src/main/res/drawable/grid_on_black_24dp.xml
Normal file
@ -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="M20,2L4,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM8,20L4,20v-4h4v4zM8,14L4,14v-4h4v4zM8,8L4,8L4,4h4v4zM14,20h-4v-4h4v4zM14,14h-4v-4h4v4zM14,8h-4L10,4h4v4zM20,20h-4v-4h4v4zM20,14h-4v-4h4v4zM20,8h-4L16,4h4v4z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_chevron_left_black_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_chevron_left_black_24dp.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M15.41,7.41L14,6l-6,6 6,6 1.41,-1.41L10.83,12z"/>
|
||||
</vector>
|
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z"/>
|
||||
</vector>
|
9
app/src/main/res/drawable/view_carousel_black_24dp.xml
Normal file
9
app/src/main/res/drawable/view_carousel_black_24dp.xml
Normal file
@ -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="M7,19h10L17,4L7,4v15zM2,17h4L6,6L2,6v11zM18,6v11h4L22,6h-4z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
@ -3,7 +3,8 @@
|
||||
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">
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".postCreation.PostCreationActivity">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/upload_error"
|
||||
@ -42,7 +43,7 @@
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<org.imaginativeworld.whynotimagecarousel.ImageCarousel
|
||||
<com.h.pixeldroid.postCreation.carousel.ImageCarousel
|
||||
android:id="@+id/carousel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
@ -59,7 +60,7 @@
|
||||
android:textSize="16sp"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/toolbar3" />
|
||||
app:layout_constraintBottom_toTopOf="@id/postTextInputLayout"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/buttonConstraints"
|
||||
@ -142,50 +143,54 @@
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageButton
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/savePhotoButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="30dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="TODO"
|
||||
android:contentDescription="@string/save_to_gallery"
|
||||
android:tooltipText='@string/save_to_gallery'
|
||||
android:src="@drawable/download_file_30dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageButton
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/removePhotoButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="30dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="TODO"
|
||||
android:contentDescription="@string/delete"
|
||||
android:tooltipText='@string/delete'
|
||||
android:src="@drawable/delete_30dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/savePhotoButton"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageButton
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/editPhotoButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="30dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="TODO"
|
||||
android:contentDescription="@string/edit"
|
||||
android:tooltipText='@string/edit'
|
||||
android:src="@drawable/ic_baseline_edit_30"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/removePhotoButton"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
<ImageButton
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/addPhotoButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="30dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="TODO"
|
||||
android:contentDescription="@string/add_photo"
|
||||
android:tooltipText='@string/add_photo'
|
||||
android:src="@drawable/add_photo_alternate_white_30dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
@ -7,6 +7,7 @@
|
||||
android:focusable="true">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/addPhotoSquare"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_centerInParent="true"
|
||||
|
@ -7,10 +7,6 @@
|
||||
android:foreground="?selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/galleryImage"
|
||||
android:layout_width="match_parent"
|
||||
@ -18,19 +14,4 @@
|
||||
android:padding="8dp"
|
||||
android:scaleType="centerCrop"
|
||||
android:contentDescription="@string/post_image" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@drawable/circle_black_24dp"
|
||||
android:backgroundTint="#7A3E3C3C"
|
||||
android:foreground="@drawable/ic_baseline_edit_30"
|
||||
android:foregroundGravity="center"
|
||||
android:foregroundTint="#FFFFFF"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:contentDescription="@string/click_image_edit" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.h.pixeldroid.postCreation.SquareLayout>
|
93
app/src/main/res/layout/image_carousel.xml
Normal file
93
app/src/main/res/layout/image_carousel.xml
Normal file
@ -0,0 +1,93 @@
|
||||
<?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"
|
||||
android:foregroundTint="#FFFFFF">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:itemCount="5"
|
||||
tools:listitem="@layout/item_carousel" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_caption"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:ellipsize="marquee"
|
||||
android:gravity="center"
|
||||
android:marqueeRepeatLimit="marquee_forever"
|
||||
android:singleLine="true"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@+id/indicator"
|
||||
app:layout_goneMarginBottom="8dp"
|
||||
tools:text="@tools:sample/lorem[5]" />
|
||||
|
||||
<me.relex.circleindicator.CircleIndicator2
|
||||
android:id="@+id/indicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="32dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/recyclerView"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/previous_button_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/recyclerView"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/recyclerView" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/next_button_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/recyclerView"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/recyclerView" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/switchToGridButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="TODO"
|
||||
android:src="@drawable/grid_on_black_24dp"
|
||||
android:tint="@color/white"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/indicator"
|
||||
app:layout_constraintEnd_toStartOf="@+id/indicator"
|
||||
app:layout_constraintTop_toTopOf="@+id/indicator" />
|
||||
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/switchToCarouselButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="TODO"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
android:src="@drawable/view_carousel_black_24dp"
|
||||
android:tint="@color/white"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/indicator"
|
||||
app:layout_constraintTop_toTopOf="@+id/indicator" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
9
app/src/main/res/layout/item_carousel.xml
Normal file
9
app/src/main/res/layout/item_carousel.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/img"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="centerInside"
|
||||
tools:ignore="ContentDescription"
|
||||
tools:src="@tools:sample/backgrounds/scenic" />
|
19
app/src/main/res/layout/next_button_layout.xml
Normal file
19
app/src/main/res/layout/next_button_layout.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.button.MaterialButton xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/btn_next"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton.Icon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:insetLeft="0dp"
|
||||
android:insetTop="0dp"
|
||||
android:insetRight="0dp"
|
||||
android:insetBottom="0dp"
|
||||
android:padding="0dp"
|
||||
app:backgroundTint="#22000000"
|
||||
app:cornerRadius="48dp"
|
||||
app:icon="@drawable/ic_chevron_right_black_24dp"
|
||||
app:iconGravity="textEnd"
|
||||
app:iconSize="48dp"
|
||||
app:iconTint="@color/white"
|
||||
app:rippleColor="@color/white" />
|
19
app/src/main/res/layout/previous_button_layout.xml
Normal file
19
app/src/main/res/layout/previous_button_layout.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.button.MaterialButton xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/btn_previous"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton.Icon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:insetLeft="0dp"
|
||||
android:insetTop="0dp"
|
||||
android:insetRight="0dp"
|
||||
android:insetBottom="0dp"
|
||||
android:padding="0dp"
|
||||
app:backgroundTint="#22000000"
|
||||
app:cornerRadius="48dp"
|
||||
app:icon="@drawable/ic_chevron_left_black_24dp"
|
||||
app:iconGravity="textStart"
|
||||
app:iconSize="48dp"
|
||||
app:iconTint="@color/white"
|
||||
app:rippleColor="@color/white" />
|
@ -19,7 +19,7 @@
|
||||
<string name="whats_an_instance">ماذا نعني بمثيل الخادم؟</string>
|
||||
<string name="logout">الخروج</string>
|
||||
<string name="tab_filters">الفلاتر</string>
|
||||
<string name="tab_edit">تعديل</string>
|
||||
<string name="edit">تعديل</string>
|
||||
<string name="save_to_gallery">احتفظ بها في المعرض…</string>
|
||||
<string name="image_download_downloading">التنزيل جارٍ…</string>
|
||||
<string name="image_download_success">تم التنزيل بنجاح</string>
|
||||
|
@ -30,7 +30,7 @@
|
||||
<string name="lbl_contrast">CONTRAST</string>
|
||||
<string name="lbl_saturation">SATURACIÓ</string>
|
||||
<string name="tab_filters">FILTRES</string>
|
||||
<string name="tab_edit">EDITAR</string>
|
||||
<string name="edit">EDITAR</string>
|
||||
<string name="capture_button_alt">Captura</string>
|
||||
<string name="gallery_button_alt">Galeria</string>
|
||||
<string name="NoCommentsToShow">No hi ha comentaris en aquesta publicació …</string>
|
||||
|
@ -22,7 +22,7 @@
|
||||
<string name="logout">Abmelden</string>
|
||||
<string name="lbl_brightness">Helligkeit</string>
|
||||
<string name="tab_filters">Filter</string>
|
||||
<string name="tab_edit">bearbeiten</string>
|
||||
<string name="edit">bearbeiten</string>
|
||||
<string name="lbl_contrast">Kontrast</string>
|
||||
<string name="lbl_saturation">Sättigung</string>
|
||||
<string name="NoCommentsToShow">Keine Kommentare zu diesem Beitrag…</string>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<string name="lbl_contrast">CONTRASTE</string>
|
||||
<string name="lbl_saturation">SATURACIÓN</string>
|
||||
<string name="tab_filters">FILTROS</string>
|
||||
<string name="tab_edit">EDITAR</string>
|
||||
<string name="edit">EDITAR</string>
|
||||
<string name="capture_button_alt">Capturar</string>
|
||||
<string name="gallery_button_alt">Galería</string>
|
||||
<string name="NoCommentsToShow">No hay comentarios en esta publicación…</string>
|
||||
|
@ -25,7 +25,7 @@
|
||||
<string name="gallery_button_alt">Galeria</string>
|
||||
<string name="NoCommentsToShow">Iruzkinik gabeko argitalpena…</string>
|
||||
<string name="theme_title">Aplikazioaren gaia</string>
|
||||
<string name="tab_edit">EDITATU</string>
|
||||
<string name="edit">EDITATU</string>
|
||||
<string name="switch_camera_button_alt">Aldatu kamera</string>
|
||||
<string name="capture_button_alt">Atera</string>
|
||||
<string name="theme_header">Gaia</string>
|
||||
|
@ -23,7 +23,7 @@
|
||||
<string name="lbl_contrast">تضاد</string>
|
||||
<string name="lbl_saturation">اشباع</string>
|
||||
<string name="tab_filters">پالایهها</string>
|
||||
<string name="tab_edit">ویرایش</string>
|
||||
<string name="edit">ویرایش</string>
|
||||
<string name="save_to_gallery">ذخیره در نگارخانه…</string>
|
||||
<string name="image_download_failed">بارگیری شکست خورد، دوباره تلاش کنید</string>
|
||||
<string name="image_download_downloading">در حال بارگیری…</string>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<string name="lbl_contrast">CONTRASTE</string>
|
||||
<string name="lbl_saturation">SATURATION</string>
|
||||
<string name="tab_filters">FILTRES</string>
|
||||
<string name="tab_edit">MODIFIER</string>
|
||||
<string name="edit">MODIFIER</string>
|
||||
<string name="capture_button_alt">Prendre une photo</string>
|
||||
<string name="switch_camera_button_alt">Changer de caméra</string>
|
||||
<string name="gallery_button_alt">Galerie</string>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<string name="lbl_contrast">CONTRASTE</string>
|
||||
<string name="lbl_saturation">SATURACIÓN</string>
|
||||
<string name="tab_filters">FILTROS</string>
|
||||
<string name="tab_edit">EDITAR</string>
|
||||
<string name="edit">EDITAR</string>
|
||||
<string name="save_to_gallery">Gardar na Galería…</string>
|
||||
<string name="image_download_downloading">Descargando…</string>
|
||||
<string name="image_download_success">Imaxe descargada correctamente</string>
|
||||
|
@ -37,7 +37,7 @@
|
||||
<string name="domain_of_your_instance">Dominio della tua istanza</string>
|
||||
<string name="login_connection_required_once">Devi essere online per poter aggiungere il primo account e utilizzare PixelDroid :(</string>
|
||||
<string name="invalid_domain">Dominio non valido</string>
|
||||
<string name="tab_edit">MODIFICA</string>
|
||||
<string name="edit">MODIFICA</string>
|
||||
<string name="permission_denied">Permesso negato</string>
|
||||
<string name="instance_error">Impossibile ottenere informazioni sull\'istanza</string>
|
||||
<string name="save_image_failed">Impossibile salvare l\'immagine</string>
|
||||
|
@ -35,7 +35,7 @@
|
||||
<string name="browser_launch_failed">ブラウザが起動できませんでした。インストールされているか確認してください。</string>
|
||||
<string name="mention_notification">%1$s さんがあなたにメンションしました</string>
|
||||
<string name="shared_notification">%1$s さんがあなたの投稿を再共有しました</string>
|
||||
<string name="tab_edit">編集</string>
|
||||
<string name="edit">編集</string>
|
||||
<string name="image_download_failed">ダウンロードに失敗しました、もう一度実行してください</string>
|
||||
<string name="NoCommentsToShow">この投稿にはコメントがありません</string>
|
||||
<string name="add_account_description">他のPixelfedアカウントを追加</string>
|
||||
|
@ -30,7 +30,7 @@
|
||||
<string name="lbl_contrast">CONTRAST</string>
|
||||
<string name="lbl_saturation">VERZADIGING</string>
|
||||
<string name="tab_filters">FILTERS</string>
|
||||
<string name="tab_edit">BEWERKEN</string>
|
||||
<string name="edit">BEWERKEN</string>
|
||||
<string name="capture_button_alt">Vastleggen</string>
|
||||
<string name="switch_camera_button_alt">Van camera wisselen</string>
|
||||
<string name="gallery_button_alt">Gallerij</string>
|
||||
|
@ -33,7 +33,7 @@
|
||||
<string name="lbl_contrast">KONTRAST</string>
|
||||
<string name="lbl_saturation">NASYCENIE</string>
|
||||
<string name="tab_filters">FILTRY</string>
|
||||
<string name="tab_edit">EDYCJA</string>
|
||||
<string name="edit">EDYCJA</string>
|
||||
<string name="normal_filter">Zwykły</string>
|
||||
<string name="busy_dialog_ok_button">OK, zaczekam.</string>
|
||||
<string name="crop_result_error">Nie udało się pobrać obrazka po przycięciu</string>
|
||||
|
@ -22,7 +22,7 @@
|
||||
<string name="image_download_downloading">Baixando o arquivo…</string>
|
||||
<string name="image_download_failed">O download não deu certo, por favor, tente novamente</string>
|
||||
<string name="save_to_gallery">Salvar na Galeria…</string>
|
||||
<string name="tab_edit">EDITAR</string>
|
||||
<string name="edit">EDITAR</string>
|
||||
<string name="tab_filters">FILTROS</string>
|
||||
<string name="lbl_saturation">SATURAÇÃO</string>
|
||||
<string name="lbl_contrast">CONTRASTE</string>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<string name="lbl_contrast">КОНТРАСТ</string>
|
||||
<string name="lbl_saturation">НАСЫЩЕННОСТЬ</string>
|
||||
<string name="tab_filters">ФИЛЬТРЫ</string>
|
||||
<string name="tab_edit">РЕДАКТИРОВАТЬ</string>
|
||||
<string name="edit">РЕДАКТИРОВАТЬ</string>
|
||||
<string name="save_to_gallery">Сохранить в Галерею…</string>
|
||||
<string name="image_download_downloading">Сохранение…</string>
|
||||
<string name="image_download_success">Изображение успешно сохранено</string>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<string name="lbl_contrast">KONTRAST</string>
|
||||
<string name="lbl_saturation">FÄRGMÄTTNAD</string>
|
||||
<string name="tab_filters">FILTER</string>
|
||||
<string name="tab_edit">REDIGERA</string>
|
||||
<string name="edit">REDIGERA</string>
|
||||
<string name="capture_button_alt">Lagra</string>
|
||||
<string name="switch_camera_button_alt">Byt kamera</string>
|
||||
<string name="gallery_button_alt">Galleri</string>
|
||||
|
@ -22,7 +22,7 @@
|
||||
<string name="share_picture">Поділитися фотографією…</string>
|
||||
<string name="logout">Вийти</string>
|
||||
<string name="NoCommentsToShow">Немає коментарів до цієї публікації…</string>
|
||||
<string name="tab_edit">Редагувати</string>
|
||||
<string name="edit">Редагувати</string>
|
||||
<string name="app_name">PixelDroid</string>
|
||||
<string name="menu_settings">Налаштування</string>
|
||||
</resources>
|
@ -24,7 +24,7 @@
|
||||
<string name="lbl_contrast">对比度</string>
|
||||
<string name="lbl_saturation">饱和度</string>
|
||||
<string name="tab_filters">滤镜</string>
|
||||
<string name="tab_edit">编辑</string>
|
||||
<string name="edit">编辑</string>
|
||||
<string name="save_to_gallery">保存到相册……</string>
|
||||
<string name="image_download_failed">下载失败,请重试</string>
|
||||
<string name="image_download_downloading">下载中……</string>
|
||||
|
24
app/src/main/res/values/attrs.xml
Normal file
24
app/src/main/res/values/attrs.xml
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<declare-styleable name="ImageCarousel">
|
||||
<attr name="showCaption" format="boolean" />
|
||||
<attr name="captionTextSize" format="dimension" />
|
||||
<attr name="showIndicator" format="boolean" />
|
||||
<attr name="showNavigationButtons" format="boolean" />
|
||||
<attr name="imageScaleType" format="enum">
|
||||
<enum name="matrix" value="0" />
|
||||
<enum name="fitXY" value="1" />
|
||||
<enum name="fitStart" value="2" />
|
||||
<enum name="fitCenter" value="3" />
|
||||
<enum name="fitEnd" value="4" />
|
||||
<enum name="center" value="5" />
|
||||
<enum name="centerCrop" value="6" />
|
||||
<enum name="centerInside" value="7" />
|
||||
</attr>
|
||||
<attr name="imagePlaceholder" format="reference|color" />
|
||||
<attr name="itemLayout" format="reference" />
|
||||
<attr name="imageViewId" format="reference" />
|
||||
<attr name="showLayoutSwitchButton" format="boolean" />
|
||||
<attr name="layoutCarousel" format="boolean" />
|
||||
</declare-styleable>
|
||||
</resources>
|
@ -14,5 +14,6 @@
|
||||
<color name="filterLabelSelected">#221F20</color>
|
||||
<color name="colorPrimaryError">#FF0000</color>
|
||||
<color name="colorText">#FFFFFF</color>
|
||||
<color name="white">#FFFFFF</color>
|
||||
<color name="colorDrawing">#000000</color>
|
||||
</resources>
|
||||
|
@ -56,7 +56,7 @@
|
||||
<string name="lbl_contrast">CONTRAST</string>
|
||||
<string name="lbl_saturation">SATURATION</string>
|
||||
<string name="tab_filters">FILTERS</string>
|
||||
<string name="tab_edit">EDIT</string>
|
||||
<string name="edit">Edit</string>
|
||||
<string name="filter_thumbnail">Thumbnail of filter</string>
|
||||
<string name="normal_filter">Normal</string>
|
||||
<string name="busy_dialog_text">Still processing image, wait for that to finish first!</string>
|
||||
|
@ -27,6 +27,6 @@
|
||||
app:icon="@drawable/info_black_24dp">
|
||||
<intent
|
||||
android:targetPackage="com.h.pixeldroid"
|
||||
android:targetClass="com.h.pixeldroid.AboutActivity"/>
|
||||
android:targetClass="com.h.pixeldroid.settings.AboutActivity"/>
|
||||
</Preference>
|
||||
</PreferenceScreen>
|
||||
|
Loading…
x
Reference in New Issue
Block a user