Skip to content

Commit

Permalink
Add a Stop button to the addiction card.
Browse files Browse the repository at this point in the history
It should have the functionality as described in upstream issue KiARC#25.
  • Loading branch information
unbiaseduser committed Oct 19, 2022
1 parent dc978b9 commit b844b92
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 10 deletions.
Expand Up @@ -8,13 +8,18 @@ import java.time.Instant
class Addiction(
val name: String,
var lastRelapse: Instant,
var relapses: CircularBuffer<Long> = CircularBuffer(3) //Default is a new one, but you can provide your own (from a cache)
var isStopped: Boolean,
var timeStopped: Long, //in milliseconds
private val relapses: CircularBuffer<Long> = CircularBuffer(3) //Default is a new one, but you can provide your own (from a cache)
) : Serializable {
var averageRelapseDuration = if (relapses.get(0) == null) -1 else calculateAverageRelapseDuration()
private set

fun relapse() {
relapses.update(lastRelapse.secondsFromNow())
if (!isStopped)
relapses.update(lastRelapse.secondsFromNow())
else
relapses.update(Instant.ofEpochMilli(timeStopped).epochSecond - lastRelapse.epochSecond)
averageRelapseDuration = calculateAverageRelapseDuration()
lastRelapse = Instant.now()
}
Expand All @@ -27,13 +32,21 @@ class Addiction(
val map = HashMap<Int, Any>()
map[0] = name
map[1] = lastRelapse
map[2] = relapses
map[2] = isStopped
map[3] = timeStopped
map[4] = relapses
return map
}

companion object {
fun fromCacheable(map: HashMap<Int, Any>): Addiction {
return Addiction(map[0] as String, map[1] as Instant, map[2] as CircularBuffer<Long>)
return Addiction(
map[0] as String,
map[1] as Instant,
map[2] as Boolean,
map[3] as Long,
map[4] as CircularBuffer<Long>
)
}
}
}
Expand Up @@ -11,12 +11,16 @@ import androidx.recyclerview.widget.RecyclerView
import com.sixtyninefourtwenty.imdefinitelysober.activities.Main
import com.sixtyninefourtwenty.imdefinitelysober.utils.convertSecondsToString
import com.sixtyninefourtwenty.imdefinitelysober.utils.secondsFromNow
import java.text.DateFormat
import java.util.*

class AddictionCardAdapter(private val context: Context) :
RecyclerView.Adapter<AddictionCardAdapter.AddictionCardViewHolder>() {

private lateinit var onButtonDeleteClickListener: OnClickListener
private lateinit var onButtonRelapseClickListener: OnClickListener
private lateinit var onButtonStopClickListener: OnClickListener
private val dateFormat = DateFormat.getDateTimeInstance()

fun setOnButtonDeleteClickListener(onButtonDeleteClickListener: OnClickListener) {
this.onButtonDeleteClickListener = onButtonDeleteClickListener
Expand All @@ -26,13 +30,18 @@ class AddictionCardAdapter(private val context: Context) :
this.onButtonRelapseClickListener = onButtonRelapseClickListener
}

fun setOnButtonStopClickListener(onButtonStopClickListener: OnClickListener) {
this.onButtonStopClickListener = onButtonStopClickListener
}

override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): AddictionCardViewHolder {
val itemView =
LayoutInflater.from(parent.context).inflate(R.layout.card_addiction, parent, false)
return AddictionCardViewHolder(itemView, onButtonDeleteClickListener, onButtonRelapseClickListener)
return AddictionCardViewHolder(itemView, onButtonDeleteClickListener, onButtonRelapseClickListener,
onButtonStopClickListener)
}

override fun onBindViewHolder(
Expand All @@ -42,8 +51,10 @@ class AddictionCardAdapter(private val context: Context) :
val addiction = Main.addictions[position]

holder.textViewName.text = addiction.name
holder.textViewTime.text =
context.convertSecondsToString(addiction.lastRelapse.secondsFromNow())
holder.textViewTime.text = if (!addiction.isStopped) context.convertSecondsToString(addiction.lastRelapse.secondsFromNow())
else context.getString(R.string.stop_notice,
dateFormat.format(Date(addiction.timeStopped)),
context.convertSecondsToString((addiction.timeStopped - addiction.lastRelapse.toEpochMilli()) / 1000))
holder.textViewAverage.visibility = if (addiction.averageRelapseDuration == -1L) View.GONE else View.VISIBLE
holder.textViewAverage.text =
context.getString(R.string.recent_avg, context.convertSecondsToString(addiction.averageRelapseDuration))
Expand All @@ -52,7 +63,8 @@ class AddictionCardAdapter(private val context: Context) :
override fun getItemCount() = Main.addictions.size

class AddictionCardViewHolder(itemView: View, onButtonDeleteClickListener: OnClickListener,
onButtonRelapseClickListener: OnClickListener) : RecyclerView.ViewHolder(itemView) {
onButtonRelapseClickListener: OnClickListener,
onButtonStopClickListener: OnClickListener) : RecyclerView.ViewHolder(itemView) {
val textViewName: TextView = itemView.findViewById(R.id.textViewAddictionName)
val textViewTime: TextView = itemView.findViewById(R.id.textViewTime)
val textViewAverage: TextView = itemView.findViewById(R.id.textViewAverage)
Expand All @@ -66,6 +78,10 @@ class AddictionCardAdapter(private val context: Context) :
tag = this@AddictionCardViewHolder
setOnClickListener(onButtonRelapseClickListener)
}
itemView.findViewById<ImageView>(R.id.imageStop).apply {
tag = this@AddictionCardViewHolder
setOnClickListener(onButtonStopClickListener)
}
}
}
}
Expand Up @@ -5,11 +5,14 @@ import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.google.android.material.snackbar.BaseTransientBottomBar
import com.google.android.material.snackbar.Snackbar
import com.sixtyninefourtwenty.imdefinitelysober.Addiction
import com.sixtyninefourtwenty.imdefinitelysober.AddictionCardAdapter
import com.sixtyninefourtwenty.imdefinitelysober.R
Expand Down Expand Up @@ -40,11 +43,11 @@ class Main : AppCompatActivity() {
private val addNewAddiction = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == RESULT_OK) {
val name = it.data?.extras?.getString("name") as String
val instant =
@Suppress("DEPRECATION") val instant =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
it.data?.extras?.getSerializable("instant", Instant::class.java) as Instant
else it.data?.extras?.getSerializable("instant") as Instant
val addiction = Addiction(name, instant)
val addiction = Addiction(name, instant, false, 0)
addictions.add(addiction)
cacheHandler.writeCache()
adapterAddictions.notifyDataSetChanged()
Expand Down Expand Up @@ -88,11 +91,27 @@ class Main : AppCompatActivity() {
val pos = viewHolder.adapterPosition
val action: () -> Unit = {
addictions[pos].relapse()
addictions[pos].isStopped = false
this.notifyItemChanged(pos)
cacheHandler.writeCache()
}
showConfirmDialog(getString(R.string.relapse), getString(R.string.relapse_confirm, addictions[pos].name), action)
}
setOnButtonStopClickListener {
val viewHolder = it.tag as ViewHolder
val pos = viewHolder.adapterPosition
if (addictions[pos].isStopped)
Snackbar.make(binding.root, getString(R.string.already_stopped, addictions[pos].name), BaseTransientBottomBar.LENGTH_SHORT).show()
else {
val action: () -> Unit = {
addictions[pos].isStopped = true
addictions[pos].timeStopped = System.currentTimeMillis()
this.notifyItemChanged(pos)
cacheHandler.writeCache()
}
showConfirmDialog(getString(R.string.stop), getString(R.string.stop_confirm, addictions[pos].name), action)
}
}
}
val recyclerAddictions = findViewById<RecyclerView>(R.id.recyclerAddictions)
val layoutManager = LinearLayoutManager(this)
Expand Down
9 changes: 9 additions & 0 deletions app/src/main/res/drawable/ic_baseline_stop_24.xml
@@ -0,0 +1,9 @@
<vector android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android"
android:tint="?attr/colorControlNormal">
<path android:fillColor="@android:color/white"
android:pathData="M6,6h12v12H6z"/>
</vector>
13 changes: 13 additions & 0 deletions app/src/main/res/layout/card_addiction.xml
Expand Up @@ -76,6 +76,19 @@
app:layout_constraintTop_toTopOf="@+id/imageDelete"
app:tint="?attr/colorIconOnCard" />

<ImageView
android:id="@+id/imageStop"
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="12dp"
android:foreground="@drawable/ripple"
android:src="@drawable/ic_baseline_stop_24"
android:contentDescription="@string/stop"
android:tooltipText="@string/stop"
app:layout_constraintEnd_toStartOf="@id/imageReset"
app:layout_constraintTop_toTopOf="@+id/imageDelete"
app:tint="?attr/colorIconOnCard" />

</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.cardview.widget.CardView>
4 changes: 4 additions & 0 deletions app/src/main/res/values/strings.xml
Expand Up @@ -25,4 +25,8 @@
<string name="delete_confirm">Do you really want to delete entry \"%s\"?\nThis action cannot be undone.</string>
<string name="relapse">Relapse</string>
<string name="relapse_confirm">Log relapse of \"%s\"?</string>
<string name="stop">Stop</string>
<string name="stop_confirm">Stop abstaining from \"%s\"?</string>
<string name="stop_notice">Stopped at: %s\nYour attempt lasted %s</string>
<string name="already_stopped">You have already stopped abstaining from \"%s\".\nPress the Relapse button to start over.</string>
</resources>

0 comments on commit b844b92

Please sign in to comment.