Skip to content

Commit

Permalink
Merge pull request #4 from kareemradwan/cutom-icons
Browse files Browse the repository at this point in the history
finish user can add custom icon for 'checked - unChecked' status
  • Loading branch information
kareemradwan authored Jul 3, 2020
2 parents abbd5f7 + e355777 commit 4139ef6
Show file tree
Hide file tree
Showing 13 changed files with 139 additions and 86 deletions.
2 changes: 1 addition & 1 deletion app/src/main/java/com/kareemradwan/stepeer/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class MainActivity : AppCompatActivity(), SteeperView.SteeperHandler {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

val order1 = Order(1, "Step1")
val order1 = Order(1, "Step1" , true)
order1.setChecked(true)
val adapter = OrderAdapter(
this, listOf(
Expand Down
10 changes: 7 additions & 3 deletions app/src/main/java/com/kareemradwan/stepeer/Order.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,19 @@ import kotlinx.android.parcel.Parcelize
@Parcelize
class Order(
val id: Int,
val title: String
) : IStep() {
val title: String,
private var status: Boolean = false
) : IStep {

/**
* You Can Override this Method to Add Some Code
*/
override fun isChecked(): Boolean {
// You can put some code here
return super.isChecked()
return status
}

override fun setChecked(isChecked: Boolean) {
status = isChecked
}
}
3 changes: 1 addition & 2 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
app:checked_color="#342987"
app:unchecked_color="#909090" />
/>


<Button
Expand Down
8 changes: 3 additions & 5 deletions stepeer/src/main/java/com/kradwan/stepeer/model/IStep.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,17 @@ import android.os.Parcelable
* The Class you need To Create Must be Annotated with
* `@Parcelize` Annotation to be save state when Device Rotate for example
*/
abstract class IStep(private var isChecked: Boolean = false) : Parcelable {
interface IStep : Parcelable {

/**
* Getter Method for Checked Variable
* you can Override this Method to run custom code
*/
open fun isChecked(): Boolean = isChecked
fun isChecked(): Boolean

/**
* Setter Method For Checked Variable
* you can Override this Method to run custom code
*/
open fun setChecked(isChecked: Boolean) {
this.isChecked = isChecked
}
fun setChecked(isChecked: Boolean)
}
11 changes: 11 additions & 0 deletions stepeer/src/main/java/com/kradwan/stepeer/model/StepColor.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.kradwan.stepeer.model

import android.graphics.Color

/**
* This Class is Deal with Library Colors
* TODO We Need More Method to Deal with Advance Color
Expand All @@ -12,5 +14,14 @@ data class StepColor(var color: Int) {
companion object {
const val COLOR_CHECKED = "checked_color"
const val COLOR_UNCHECKED = "unchecked_color"

val defaultColor = Color.parseColor("#1C8AFF")

fun default(): HashMap<String, StepColor> {
return hashMapOf(
Pair(COLOR_CHECKED, StepColor(defaultColor)),
Pair(COLOR_CHECKED, StepColor(defaultColor))
)
}
}
}
24 changes: 24 additions & 0 deletions stepeer/src/main/java/com/kradwan/stepeer/model/StepDrawable.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.kradwan.stepeer.model

import android.content.Context
import android.graphics.drawable.Drawable
import androidx.core.content.ContextCompat
import com.kradwan.stepeer.R

class StepDrawable(var drawable: Drawable) {

companion object {
const val DRAWABLE_CHECKED = "checked_drawable"
const val DRAWABLE_UNCHECKED = "unchecked_drawable"

private val defaultIconId = R.drawable.ic_star_black_24dp

fun default(context: Context): HashMap<String, StepDrawable> {
val drawable = ContextCompat.getDrawable(context, defaultIconId)!!
return hashMapOf(
Pair(DRAWABLE_CHECKED, StepDrawable(drawable)),
Pair(DRAWABLE_UNCHECKED, StepDrawable(drawable))
)
}
}
}
95 changes: 40 additions & 55 deletions stepeer/src/main/java/com/kradwan/stepeer/view/SingleStepView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ import android.graphics.Color
import android.util.Log
import android.view.View
import android.view.animation.AnimationUtils
import android.widget.CheckBox
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import androidx.appcompat.content.res.AppCompatResources.getDrawable
import androidx.core.graphics.drawable.DrawableCompat
import com.kradwan.stepeer.R
import com.kradwan.stepeer.model.IStep
import com.kradwan.stepeer.model.StepColor
import com.kradwan.stepeer.model.StepDrawable

/**
* This Class Represent Each Step as View
Expand All @@ -23,15 +22,16 @@ import com.kradwan.stepeer.model.StepColor
@SuppressLint("ViewConstructor")
class SingleStepView(
context: Context,
private var colors: HashMap<String, StepColor>?
private var colors: HashMap<String, StepColor>,
private var icons: HashMap<String, StepDrawable>
) :
FrameLayout(context) {

// Setup All Require Views in Layout
private lateinit var view: View
private lateinit var rootView: LinearLayout
private lateinit var stepInfo: LinearLayout
private lateinit var stepCheckBox: CheckBox
private lateinit var stepCheckBox: ImageView
private lateinit var stepDivider: View
private lateinit var stepDividerSolid: View
private lateinit var stepContentContainer: LinearLayout
Expand All @@ -58,35 +58,30 @@ class SingleStepView(
stepDividerSolid = view.findViewById(R.id.stepDividerSolid)
stepContentContainer = view.findViewById(R.id.stepContentContainer)


if (icons[StepDrawable.DRAWABLE_UNCHECKED] != null) {
stepCheckBox.setImageDrawable(icons[StepDrawable.DRAWABLE_UNCHECKED]?.drawable)
}
/**
* Check if you Override Default Colors
*/
if (colors != null) {
// Check if you override `Checked` state Color
if (colors?.contains(StepColor.COLOR_CHECKED)!!) {
// Change Default Color to your Custom Color
checkBoxSelectedColor = colors?.get(StepColor.COLOR_CHECKED)!!
}
// Check if you override `Checked` state Color
// Change Default Color to your Custom Color
checkBoxSelectedColor = colors[StepColor.COLOR_CHECKED]!!

/**
* Check if you override `unChecked` state Color
* because UnCheck Color is Default and initial State you need Override View Color
*/
checkBoxUnSelectedColor = colors[StepColor.COLOR_UNCHECKED]!!
stepDivider.setBackgroundColor(checkBoxUnSelectedColor.color)
stepDividerSolid.setBackgroundColor(checkBoxUnSelectedColor.color)

/**
* Support sdk 15 and higher than it
* Change Tint of Checkbox to checkBoxUnSelectedColor
*/

/**
* Check if you override `unChecked` state Color
* because UnCheck Color is Default and initial State you need Override View Color
*/
if (colors?.contains(StepColor.COLOR_UNCHECKED)!!) {
checkBoxUnSelectedColor = colors?.get(StepColor.COLOR_UNCHECKED)!!
stepDivider.setBackgroundColor(checkBoxUnSelectedColor.color)
stepDividerSolid.setBackgroundColor(checkBoxUnSelectedColor.color)

/**
* Support sdk 15 and higher than it
* Change Tint of Checkbox to checkBoxUnSelectedColor
*/
val checkDrawable =
DrawableCompat.wrap(getDrawable(context, R.drawable.custom_checkbox)!!)
DrawableCompat.setTint(checkDrawable, checkBoxUnSelectedColor.color)
stepCheckBox.buttonDrawable = checkDrawable
}
}
}

/**
Expand All @@ -95,9 +90,9 @@ class SingleStepView(
* @param view Generate View from Adapter
* @param last to hide last Divider
*/
fun <T : IStep> setModel(model: T, view: View, last: Boolean) {
fun <T : IStep> setModel(model: T, view: View, last: Boolean, animated: Boolean) {
// Set Init State of Checkbox
stepCheckBox.isChecked = model.isChecked()
// stepCheckBox.isChecked = model.isChecked()
stepDivider.visibility = if (last) View.GONE else View.VISIBLE

/**
Expand All @@ -121,7 +116,7 @@ class SingleStepView(
*/
if (model.isChecked()) {
// We Pass here if This Model is Last or Not
selectAsDone()
selectAsDone(animated)
}

if (last) {
Expand All @@ -132,37 +127,27 @@ class SingleStepView(
}
}

/**
* this private method called when step is be Done
* @param last to check if
*
* Deprecated in 2 Jue 2020
* No We Make one if Condition
*/
@Deprecated("You Can Use `SelectAsDone() without parameters`", ReplaceWith("selectAsDone()"))
fun selectAsDone(last: Boolean) {
selectAsDone()
}

/**
* This Method Change UI State From UnChecked to Checked
*/
fun selectAsDone() {

stepCheckBox.isChecked = true
fun selectAsDone(animated: Boolean) {
stepCheckBox.setImageDrawable(icons[StepDrawable.DRAWABLE_CHECKED]?.drawable)

/**
* Support sdk 15 and higher than it
* Change Tint of Checkbox to checkBoxSelectedColor
*/
val checkDrawable = DrawableCompat.wrap(getDrawable(context, R.drawable.custom_checkbox)!!)
DrawableCompat.setTint(checkDrawable, checkBoxSelectedColor.color)
stepCheckBox.buttonDrawable = checkDrawable

stepDividerSolid.setBackgroundColor(checkBoxSelectedColor.color)
stepDividerSolid.visibility = View.VISIBLE
val move = AnimationUtils.loadAnimation(context, R.anim.move)
stepDividerSolid.animation = move

if (animated) {
stepDividerSolid.setBackgroundColor(colors[StepColor.COLOR_CHECKED]!!.color)
stepDividerSolid.visibility = View.VISIBLE
val move = AnimationUtils.loadAnimation(context, R.anim.move)
stepDividerSolid.animation = move
} else {
stepDividerSolid.setBackgroundColor(checkBoxSelectedColor.color)
stepDividerSolid.visibility = View.VISIBLE
}
}

}
47 changes: 32 additions & 15 deletions stepeer/src/main/java/com/kradwan/stepeer/view/SteeperView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.content.Context
import android.graphics.Color
import android.os.Parcelable
import android.util.AttributeSet
import android.util.Log
import android.view.View
import android.widget.FrameLayout
import android.widget.LinearLayout
Expand All @@ -14,6 +15,8 @@ import com.kradwan.stepeer.StepperState
import com.kradwan.stepeer.adapter.StepAdapter
import com.kradwan.stepeer.model.IStep
import com.kradwan.stepeer.model.StepColor
import com.kradwan.stepeer.model.StepDrawable
import kotlinx.android.synthetic.main.item_step.view.*
import java.lang.Exception

/**
Expand All @@ -33,7 +36,8 @@ class SteeperView(context: Context, private val attrs: AttributeSet?) :
// Index to Current Step to Save State
private var currentStep: Int = 0
// Colors of `unChecked` and `Checked` state
private var colors = HashMap<String, StepColor>()
private var colors = StepColor.default()
private var icons = StepDrawable.default(context)
// Adapter of Stepper
private lateinit var mAdapter: StepAdapter<IStep>

Expand Down Expand Up @@ -61,7 +65,7 @@ class SteeperView(context: Context, private val attrs: AttributeSet?) :
// Get The List Of Steps if null [ First Time Open] Assign Empty List
mAdapter.models = myState?.steps ?: listOf()
// Pass Adapter to Build UI
setAdapter(mAdapter)
setAdapter(mAdapter , false)
//redraw
}

Expand All @@ -75,23 +79,36 @@ class SteeperView(context: Context, private val attrs: AttributeSet?) :
if (attrs != null) {
// Declare Default Color if The Developer Not Override the
// 'unchecked_color' , 'checked_color';
val defaultColor = StepColor(Color.parseColor("#1C8AFF"))
// Get the xml style attribute form view
val style = context.theme.obtainStyledAttributes(attrs, R.styleable.SteeperView, 0, 0)
/**
* get First Value [ First from attr file not in XML Order ]
* In our Example the First attr is `check`
*/
val checkColor = style.getColor(0, -1)
// In our Example the First attr is `uncheck`
val unCheckColor = style.getColor(1, -1)
/**
* Short IF To Check if Override Values of [checked , unchecked color]
*/
val checkColor = style.getColor(R.styleable.SteeperView_checked_color, -1)
val unCheckColor = style.getColor(R.styleable.SteeperView_unchecked_color, -1)
val checkIcon = style.getDrawable(R.styleable.SteeperView_checked_icon)
val unCheckIcon = style.getDrawable(R.styleable.SteeperView_unchecked_icon)


colors[StepColor.COLOR_CHECKED] =
if (checkColor != -1) StepColor(checkColor) else defaultColor
if (checkColor != -1) StepColor(checkColor) else StepColor(StepColor.defaultColor)
colors[StepColor.COLOR_UNCHECKED] =
if (unCheckColor != -1) StepColor(unCheckColor) else defaultColor
if (unCheckColor != -1) StepColor(unCheckColor) else StepColor(StepColor.defaultColor)


/**
* Extract Drawable for [ Checked and unChecked]
*/
if (checkIcon != null) {
icons[StepDrawable.DRAWABLE_CHECKED] = StepDrawable(checkIcon)
}

if (unCheckIcon != null) {
icons[StepDrawable.DRAWABLE_UNCHECKED] = StepDrawable(unCheckIcon)
}


}
}

Expand All @@ -100,7 +117,7 @@ class SteeperView(context: Context, private val attrs: AttributeSet?) :
* and Show in screen
* @param adapter Any Class Inherited [StepAdapter]
*/
fun <T : IStep> setAdapter(adapter: StepAdapter<T>) {
fun <T : IStep> setAdapter(adapter: StepAdapter<T> , animated: Boolean = true) {
try {
// because we need assign adapter to global variable
// we need Cast generic Type to IStep
Expand All @@ -119,9 +136,9 @@ class SteeperView(context: Context, private val attrs: AttributeSet?) :
currentStep++
}
// View of Single Step Without Any Actual Data
val step = SingleStepView(view.context, colors)
val step = SingleStepView(view.context, colors, icons)
// Assign Actual Data to Step View
step.setModel(it, adapter.onCreateView(it), adapter.models.last() == it)
step.setModel(it, adapter.onCreateView(it), adapter.models.last() == it , animated)
// Add Step in Container of Steps
containerSteeper.addView(step)
}
Expand All @@ -144,7 +161,7 @@ class SteeperView(context: Context, private val attrs: AttributeSet?) :
*/
private fun selectAsDone(index: Int) {
val stepView = containerSteeper[index] as SingleStepView
stepView.selectAsDone()
stepView.selectAsDone(true)
}

fun nextStep() {
Expand Down
5 changes: 5 additions & 0 deletions stepeer/src/main/res/drawable/ic_star_black_24dp.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#E98500"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/>
</vector>
Loading

0 comments on commit 4139ef6

Please sign in to comment.