1 /* <lambda>null2 * Copyright 2019 Google LLC 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * https://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.mobileer.androidfxlab 18 19 import android.view.LayoutInflater 20 import android.view.MotionEvent 21 import android.view.View 22 import android.view.ViewGroup 23 import android.widget.LinearLayout 24 import android.widget.SeekBar 25 import android.widget.TextView 26 import androidx.recyclerview.widget.ItemTouchHelper 27 import androidx.recyclerview.widget.RecyclerView 28 import com.google.android.material.switchmaterial.SwitchMaterial 29 import com.mobileer.androidfxlab.datatype.Effect 30 import java.util.* 31 import kotlin.concurrent.timerTask 32 import kotlin.math.max 33 import kotlin.math.min 34 35 object EffectsAdapter : 36 RecyclerView.Adapter<EffectsAdapter.EffectsHolder>() { 37 val effectList = arrayListOf<Effect>() 38 lateinit var mRecyclerView: RecyclerView 39 40 // This class adapts view in effect_view.xml for Effect class 41 class EffectsHolder(val parentView: ViewGroup) : RecyclerView.ViewHolder(parentView) { 42 private val layoutContainer: LinearLayout = parentView.findViewById(R.id.effectContainer) 43 lateinit var effect: Effect 44 private val floatFormat = "%4.2f" 45 private var index: Int = -1 46 fun bindEffect(bindedEffect: Effect, position: Int) { 47 effect = bindedEffect 48 index = position 49 // Clear all views 50 layoutContainer.removeAllViews() 51 View.inflate(layoutContainer.context, 52 R.layout.effect_header, layoutContainer) 53 val header: LinearLayout = layoutContainer.findViewById(R.id.effectHeader) 54 val dragHandleView: View = header.findViewById(R.id.cat_card_list_item_drag_handle) 55 val checkBoxView: SwitchMaterial = header.findViewById(R.id.effectEnabled) 56 val label: TextView = header.findViewById(R.id.effectLabel) 57 // Bind header views 58 label.text = effect.name 59 checkBoxView.isChecked = effectList[index].enable 60 checkBoxView.setOnCheckedChangeListener { _, checked -> 61 effectList[index].enable = checked 62 NativeInterface.enableEffectAt(checked, index) 63 } 64 dragHandleView.setOnTouchListener { _, event -> 65 if (event.action == MotionEvent.ACTION_DOWN) { 66 itemTouchHelper.startDrag(this@EffectsHolder) 67 return@setOnTouchListener true 68 } 69 false 70 } 71 header.setOnTouchListener { _, event -> 72 if (event.action == MotionEvent.ACTION_DOWN) { 73 itemTouchHelper.startSwipe(this@EffectsHolder) 74 return@setOnTouchListener true 75 } 76 false 77 } 78 // Add correct number of SeekBars based on effect 79 for (ind in effect.effectDescription.paramValues.withIndex()) { 80 val param = ind.value 81 val counter = ind.index 82 val view = View.inflate(layoutContainer.context, 83 R.layout.param_seek, null) 84 layoutContainer.addView(view) 85 val paramWrapper: LinearLayout = view.findViewById(R.id.paramWrapper) 86 val paramLabelView: TextView = paramWrapper.findViewById(R.id.paramLabel) 87 val minLabelView: TextView = paramWrapper.findViewById(R.id.minLabel) 88 val maxLabelView: TextView = paramWrapper.findViewById(R.id.maxLabel) 89 val curLabelView: TextView = paramWrapper.findViewById(R.id.curLabel) 90 val seekBar: SeekBar = paramWrapper.findViewById(R.id.seekBar) 91 paramLabelView.text = param.paramName 92 minLabelView.text = floatFormat.format(param.minValue) 93 maxLabelView.text = floatFormat.format(param.maxValue) 94 seekBar.progress = 95 ((effectList[index].paramValues[counter] - param.minValue) * 100 / (param.maxValue 96 - param.minValue)).toInt() 97 curLabelView.text = floatFormat.format(effectList[index].paramValues[counter]) 98 // Bind param listeners to effects 99 seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { 100 val paramInd = counter 101 var timer : Timer? = null 102 103 override fun onStartTrackingTouch(p0: SeekBar?) {} 104 105 override fun onStopTrackingTouch(seekbar: SeekBar?) {} 106 107 override fun onProgressChanged( 108 seekBar: SeekBar?, progress: Int, fromUser: Boolean 109 ) { 110 val fracprogress = 111 ((seekBar!!.progress / 100f) * (param.maxValue - param.minValue) + param.minValue) 112 curLabelView.text = floatFormat.format(fracprogress) 113 114 timer?.cancel() 115 timer = Timer() 116 timer?.schedule(timerTask { updateEffectParam(fracprogress) }, 100) 117 } 118 119 fun updateEffectParam(fracprogress : Float){ 120 effectList[index].paramValues[paramInd] = fracprogress 121 NativeInterface.updateParamsAt(effect, index) 122 } 123 }) 124 } 125 } 126 127 } 128 129 override fun onCreateViewHolder( 130 parent: ViewGroup, 131 viewType: Int 132 ): EffectsHolder { 133 val myView = LayoutInflater.from(parent.context) 134 .inflate(R.layout.effect_view, parent, false) 135 return EffectsHolder(myView as ViewGroup) 136 } 137 138 override fun onBindViewHolder(holder: EffectsHolder, position: Int) { 139 holder.bindEffect(effectList[position], position) 140 } 141 142 override fun getItemCount() = effectList.size 143 144 override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { 145 super.onAttachedToRecyclerView(recyclerView) 146 mRecyclerView = recyclerView 147 itemTouchHelper.attachToRecyclerView(mRecyclerView) 148 } 149 150 private val itemTouchHelper = ItemTouchHelper(object : ItemTouchHelper.SimpleCallback( 151 ItemTouchHelper.UP or ItemTouchHelper.DOWN, ItemTouchHelper.RIGHT or ItemTouchHelper.LEFT 152 ) { 153 154 var dragFrom = -1 155 var dragTo = -1 156 override fun onMove( 157 recyclerView: RecyclerView, 158 viewHolder: RecyclerView.ViewHolder, 159 target: RecyclerView.ViewHolder 160 ): Boolean { 161 162 val fromPos = viewHolder.adapterPosition 163 val toPos = target.adapterPosition 164 if (dragFrom == -1) { 165 dragFrom = fromPos 166 } 167 dragTo = toPos 168 effectList.add(toPos, effectList.removeAt(fromPos)) 169 recyclerView.adapter?.notifyItemMoved(fromPos, toPos) 170 return true 171 } 172 173 override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { 174 val position = viewHolder.adapterPosition 175 effectList.removeAt(position) 176 mRecyclerView.adapter?.notifyItemRemoved(position) 177 NativeInterface.removeEffectAt(position) 178 for (i in position until effectList.size) { 179 var holder = mRecyclerView.findViewHolderForAdapterPosition(i) as EffectsHolder 180 holder.bindEffect(holder.effect, i) 181 } 182 } 183 184 override fun clearView( 185 recyclerView: RecyclerView, 186 viewHolder: RecyclerView.ViewHolder 187 ) { 188 super.clearView(recyclerView, viewHolder) 189 if (dragFrom != -1 && dragTo != -1 && dragFrom != dragTo) { 190 rotateItems(dragFrom, dragTo) 191 } 192 dragFrom = -1 193 dragTo = -1 194 } 195 196 override fun isLongPressDragEnabled(): Boolean = false 197 override fun isItemViewSwipeEnabled(): Boolean = false 198 199 fun rotateItems(fromPos: Int, toPos: Int) { 200 val a = min(fromPos, toPos) 201 val b = max(fromPos, toPos) 202 for (i in a..b) { 203 var holder = mRecyclerView.findViewHolderForAdapterPosition(i) as EffectsHolder 204 holder.bindEffect(holder.effect, i) 205 } 206 NativeInterface.rotateEffectAt(fromPos, toPos) 207 } 208 }) 209 210 } 211