diff --git a/app/src/androidTest/java/it/diab/viewmodels/glucose/OverviewViewModelTest.kt b/app/src/androidTest/java/it/diab/viewmodels/glucose/OverviewViewModelTest.kt index aae3bdbdc88e223b423635abc719590086facf4b..e9c3d551a2bdb8bdf5f636770c0931bc5b290ef0 100644 --- a/app/src/androidTest/java/it/diab/viewmodels/glucose/OverviewViewModelTest.kt +++ b/app/src/androidTest/java/it/diab/viewmodels/glucose/OverviewViewModelTest.kt @@ -15,6 +15,7 @@ import it.diab.core.data.AppDatabase import it.diab.core.data.entities.TimeFrame import it.diab.core.data.repositories.GlucoseRepository import it.diab.core.util.extensions.glucose +import it.diab.viewmodels.overview.OverviewViewModel import kotlinx.coroutines.runBlocking import org.junit.Assert.assertEquals import org.junit.Before diff --git a/app/src/main/java/it/diab/MainActivity.kt b/app/src/main/java/it/diab/MainActivity.kt index a746b8960be6042d83c1706cd57edebdf9408a99..fc4b1ddf0f2736d4302608163df8220d9950dd58 100644 --- a/app/src/main/java/it/diab/MainActivity.kt +++ b/app/src/main/java/it/diab/MainActivity.kt @@ -12,14 +12,13 @@ import android.os.Build import android.os.Bundle import android.view.View import androidx.appcompat.app.AppCompatActivity -import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.app.ActivityOptionsCompat import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentPagerAdapter import androidx.viewpager.widget.ViewPager import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.tabs.TabLayout +import it.diab.adapters.FragmentsPagerAdapter import it.diab.core.util.Activities import it.diab.core.util.event.EventObserver import it.diab.core.util.intentTo @@ -29,16 +28,8 @@ import it.diab.fragments.OverviewFragment import it.diab.util.ShortcutUtils class MainActivity : AppCompatActivity() { - private lateinit var coordinator: CoordinatorLayout - private lateinit var tabLayout: TabLayout - private lateinit var viewPager: ViewPager - private lateinit var adapter: ViewPagerAdapter private lateinit var fab: FloatingActionButton - private lateinit var overviewFragment: OverviewFragment - private lateinit var glucoseFragment: GlucoseListFragment - private lateinit var insulinFragment: InsulinFragment - private val fragmentsLifeCycleCallback = object : FragmentManager.FragmentLifecycleCallbacks() { override fun onFragmentViewCreated( fm: FragmentManager, @@ -62,19 +53,18 @@ class MainActivity : AppCompatActivity() { super.onCreate(savedInstance) setContentView(R.layout.activity_main) - overviewFragment = OverviewFragment() - glucoseFragment = GlucoseListFragment() - insulinFragment = InsulinFragment() - - coordinator = findViewById(R.id.coordinator) - tabLayout = findViewById(R.id.tabs) - viewPager = findViewById(R.id.viewpager) + val tabLayout = findViewById(R.id.tabs) + val viewPager = findViewById(R.id.viewpager) fab = findViewById(R.id.fab) supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentsLifeCycleCallback, false) - - adapter = ViewPagerAdapter(supportFragmentManager) - viewPager.adapter = adapter + viewPager.adapter = FragmentsPagerAdapter( + supportFragmentManager, + resources, + OverviewFragment(), + GlucoseListFragment(), + InsulinFragment() + ) tabLayout.setupWithViewPager(viewPager) fab.setOnClickListener { onGlucoseClick(-1) } @@ -102,12 +92,4 @@ class MainActivity : AppCompatActivity() { ShortcutUtils.setupShortcuts(this) } } - - inner class ViewPagerAdapter(manager: FragmentManager) : FragmentPagerAdapter(manager) { - private val fragments = arrayOf(overviewFragment, glucoseFragment, insulinFragment) - - override fun getCount() = fragments.size - override fun getItem(position: Int) = fragments[position] - override fun getPageTitle(position: Int): String = getString(fragments[position].getTitle()) - } } diff --git a/app/src/main/java/it/diab/adapters/FragmentsPagerAdapter.kt b/app/src/main/java/it/diab/adapters/FragmentsPagerAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..b7e519309a693ee1c25257a00c6c693f976e5b08 --- /dev/null +++ b/app/src/main/java/it/diab/adapters/FragmentsPagerAdapter.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2019 Bevilacqua Joey + * + * Licensed under the GNU GPLv3 license + * + * The text of the license can be found in the LICENSE file + * or at https://www.gnu.org/licenses/gpl.txt + */ +package it.diab.adapters + +import android.content.res.Resources +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentPagerAdapter +import it.diab.fragments.BaseFragment + +class FragmentsPagerAdapter( + manager: FragmentManager, + private val resources: Resources, + vararg fragment: BaseFragment +) : FragmentPagerAdapter(manager) { + + private val fragments: Array = fragment + + override fun getCount() = fragments.size + + override fun getItem(position: Int) = fragments[position] + + override fun getPageTitle(position: Int): String = fragments[position].getTitle(resources) +} \ No newline at end of file diff --git a/app/src/main/java/it/diab/adapters/GlucoseListAdapter.kt b/app/src/main/java/it/diab/adapters/GlucoseListAdapter.kt index 8ab4e9c311fb801cee661accd07e281678813211..03e2e9d9bd94db3a574d948e3956b67aa1b59f17 100644 --- a/app/src/main/java/it/diab/adapters/GlucoseListAdapter.kt +++ b/app/src/main/java/it/diab/adapters/GlucoseListAdapter.kt @@ -11,26 +11,23 @@ package it.diab.adapters import android.content.Context import android.graphics.drawable.Drawable import android.view.LayoutInflater -import android.view.View import android.view.ViewGroup -import android.widget.ImageView -import android.widget.TextView import androidx.annotation.ColorRes -import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.paging.PagedListAdapter import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.RecyclerView import it.diab.R import it.diab.core.data.entities.Glucose import it.diab.core.util.PreferencesUtil import it.diab.core.util.event.Event -import it.diab.core.util.extensions.setPrecomputedText +import it.diab.holders.GlucoseHolder +import it.diab.holders.GlucoseHolderCallbacks import it.diab.util.UIUtils import it.diab.util.extensions.diff import it.diab.viewmodels.glucose.GlucoseListViewModel +import kotlinx.coroutines.CoroutineScope import java.text.SimpleDateFormat import java.util.Date import java.util.Locale @@ -38,14 +35,14 @@ import java.util.Locale class GlucoseListAdapter( val context: Context, private val viewModel: GlucoseListViewModel -) : PagedListAdapter(CALLBACK) { +) : PagedListAdapter(CALLBACK), GlucoseHolderCallbacks { private val _openGlucose = MutableLiveData>() val openGlucose: LiveData> = _openGlucose // Store the these for better performance - private val lowIndicator by lazy { getIndicator(R.color.glucose_indicator_low) } - private val highIndicator by lazy { getIndicator(R.color.glucose_indicator_high) } + private val lowIndicator by lazy { buildIndicator(R.color.glucose_indicator_low) } + private val highIndicator by lazy { buildIndicator(R.color.glucose_indicator_high) } private val highThreshold by lazy { PreferencesUtil.getGlucoseHighThreshold(context) } private val lowThreshold by lazy { PreferencesUtil.getGlucoseLowThreshold(context) } @@ -57,20 +54,42 @@ class GlucoseListAdapter( override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = GlucoseHolder( - LayoutInflater.from(parent.context) - .inflate(R.layout.item_glucose, parent, false) + LayoutInflater.from(parent.context).inflate(R.layout.item_glucose, parent, false), + this ) override fun onBindViewHolder(holder: GlucoseHolder, position: Int) { val item = getItem(position) if (item == null) { - holder.clear() + holder.onLoading() } else { holder.onBind(item) } } - private fun shouldInsertHeader(position: Int): Boolean { + override fun fetchHeaderText(date: Date, onFetch: (String, CoroutineScope) -> Unit) { + viewModel.setHeader(date, dateFormat, onFetch) + } + + override fun fetchHourText(date: Date, onFetch: (String, CoroutineScope) -> Unit) { + val text = hourFormat.format(date) + onFetch(text, viewModel.viewModelScope) + } + + override fun getIndicator(value: Int) = when { + value < lowThreshold -> lowIndicator + value > highThreshold -> highIndicator + else -> null + } + + override fun getInsulinName(uid: Long) = + viewModel.getInsulin(uid).name + + override fun onClick(uid: Long) { + _openGlucose.value = Event(uid) + } + + override fun shouldInsertHeader(position: Int): Boolean { if (position == 0) { return true } @@ -83,103 +102,13 @@ class GlucoseListAdapter( return b.diff(Date()) != 0 && a.diff(b) > 0 } - private fun getIndicator(@ColorRes colorId: Int): Drawable? { + private fun buildIndicator(@ColorRes colorId: Int): Drawable? { val resources = context.resources val color = ContextCompat.getColor(context, colorId) val size = resources.getDimensionPixelSize(R.dimen.item_glucose_indicator) return UIUtils.createRoundDrawable(resources, size, color) } - inner class GlucoseHolder(view: View) : RecyclerView.ViewHolder(view) { - private val icon = view.findViewById(R.id.item_glucose_timezone) - private val title = view.findViewById(R.id.item_glucose_value) - private val summary = view.findViewById(R.id.item_glucose_insulin) - private val indicator = view.findViewById(R.id.item_glucose_status) - - private val header = view.findViewById(R.id.item_glucose_header) - private val headerTitle = view.findViewById(R.id.item_glucose_header_title) - - fun onBind(glucose: Glucose) { - itemView.visibility = View.VISIBLE - - bindHeader(glucose) - bindValue(glucose) - - icon.setImageResource(glucose.timeFrame.icon) - - itemView.setOnClickListener { _openGlucose.value = Event(glucose.uid) } - - bindInsulins(glucose) - } - - fun clear() { - itemView.visibility = View.INVISIBLE - } - - private fun bindHeader(glucose: Glucose) { - val shouldShowHeader = shouldInsertHeader(adapterPosition) - header.visibility = if (shouldShowHeader) View.VISIBLE else View.GONE - - if (shouldShowHeader) { - viewModel.setHeader(glucose.date, dateFormat) { date -> - headerTitle.setPrecomputedText(date, viewModel.viewModelScope) - } - } - } - - private fun bindValue(glucose: Glucose) { - title.setPrecomputedText( - "%1\$d (%2\$s)".format(glucose.value, hourFormat.format(glucose.date)), - viewModel.viewModelScope - ) - - // High / low indicator - val indicatorDrawable = when { - glucose.value > highThreshold -> highIndicator - glucose.value < lowThreshold -> lowIndicator - else -> null - } - - if (indicatorDrawable == null) { - indicator.visibility = View.GONE - } else { - indicator.setImageDrawable(indicatorDrawable) - indicator.visibility = View.VISIBLE - } - } - - private fun bindInsulins(glucose: Glucose) { - val builder = StringBuilder() - - val insulinId = glucose.insulinId0 - val basalId = glucose.insulinId1 - - if (insulinId >= 0) { - builder.append(glucose.insulinValue0) - .append(" ") - .append(viewModel.getInsulin(insulinId).name) - - if (basalId >= 0) { - builder.append(", ") - } - } - - if (basalId >= 0) { - builder.append(glucose.insulinValue1) - .append(" ") - .append(viewModel.getInsulin(basalId).name) - } - - if (builder.isEmpty()) { - summary.visibility = View.GONE - return - } - - summary.setPrecomputedText(builder.toString(), viewModel.viewModelScope) - summary.visibility = View.VISIBLE - } - } - companion object { private val CALLBACK = object : DiffUtil.ItemCallback() { override fun areContentsTheSame(oldItem: Glucose, newItem: Glucose) = diff --git a/app/src/main/java/it/diab/adapters/InsulinAdapter.kt b/app/src/main/java/it/diab/adapters/InsulinAdapter.kt index 745ef32c280e6d15844394759a49993245e8594c..0f3a47157f2f1b4885e573b3c49245aac5287d8a 100644 --- a/app/src/main/java/it/diab/adapters/InsulinAdapter.kt +++ b/app/src/main/java/it/diab/adapters/InsulinAdapter.kt @@ -9,20 +9,18 @@ package it.diab.adapters import android.view.LayoutInflater -import android.view.View import android.view.ViewGroup -import android.widget.ImageView -import android.widget.TextView import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.paging.PagedListAdapter import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.RecyclerView import it.diab.R import it.diab.core.data.entities.Insulin import it.diab.core.util.event.Event +import it.diab.holders.InsulinHolderCallbacks +import it.diab.holders.InsulinHolder -class InsulinAdapter : PagedListAdapter(CALLBACK) { +class InsulinAdapter : PagedListAdapter(CALLBACK), InsulinHolderCallbacks { private val _editInsulin = MutableLiveData>() internal val editInsulin: LiveData> = _editInsulin @@ -30,7 +28,8 @@ class InsulinAdapter : PagedListAdapter(C override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): InsulinHolder { return InsulinHolder( LayoutInflater.from(parent.context) - .inflate(R.layout.item_insulin, parent, false) + .inflate(R.layout.item_insulin, parent, false), + this ) } @@ -45,34 +44,14 @@ class InsulinAdapter : PagedListAdapter(C val item = getItem(position) if (item == null) { - holder.clear() + holder.onLoading() } else { holder.onBind(item) } } - inner class InsulinHolder(view: View) : RecyclerView.ViewHolder(view) { - private val title: TextView = view.findViewById(R.id.item_insulin_name) - private val icon: ImageView = view.findViewById(R.id.item_insulin_icon) - - fun onBind(insulin: Insulin) { - title.text = insulin.name - icon.setImageResource(insulin.timeFrame.icon) - - itemView.setOnClickListener { _editInsulin.value = Event(insulin.uid) } - } - - fun onBind() { - val res = itemView.resources - title.text = res.getString(R.string.insulin_add_item) - icon.setImageResource(R.drawable.ic_add) - - itemView.setOnClickListener { _editInsulin.value = Event(-1) } - } - - fun clear() { - itemView.visibility = View.GONE - } + override fun onClick(uid: Long) { + _editInsulin.value = Event(uid) } companion object { diff --git a/app/src/main/java/it/diab/fragments/MainFragment.kt b/app/src/main/java/it/diab/fragments/BaseFragment.kt similarity index 56% rename from app/src/main/java/it/diab/fragments/MainFragment.kt rename to app/src/main/java/it/diab/fragments/BaseFragment.kt index 7c85ff499d0cf4a1dcbcbf35245d701ae54b1d5f..7b7d8afae0785377d0b33b6033c2327e46c3808c 100644 --- a/app/src/main/java/it/diab/fragments/MainFragment.kt +++ b/app/src/main/java/it/diab/fragments/BaseFragment.kt @@ -8,10 +8,11 @@ */ package it.diab.fragments -import androidx.annotation.StringRes +import android.content.res.Resources import androidx.fragment.app.Fragment -abstract class MainFragment : Fragment() { - @StringRes - abstract fun getTitle(): Int +abstract class BaseFragment : Fragment() { + protected abstract val titleRes: Int + + fun getTitle(resources: Resources): String = resources.getString(titleRes) } \ No newline at end of file diff --git a/app/src/main/java/it/diab/fragments/GlucoseListFragment.kt b/app/src/main/java/it/diab/fragments/GlucoseListFragment.kt index ac903e6817239c112381d148338cab4c2bcd4baa..a28d2196fcd8a910a065c775c6e17ce7bea6e435 100644 --- a/app/src/main/java/it/diab/fragments/GlucoseListFragment.kt +++ b/app/src/main/java/it/diab/fragments/GlucoseListFragment.kt @@ -29,7 +29,9 @@ import it.diab.core.util.event.EventObserver import it.diab.viewmodels.glucose.GlucoseListViewModel import it.diab.viewmodels.glucose.GlucoseListViewModelFactory -class GlucoseListFragment : MainFragment() { +class GlucoseListFragment : BaseFragment() { + override val titleRes = R.string.fragment_glucose + private lateinit var recyclerView: RecyclerView private lateinit var viewModel: GlucoseListViewModel @@ -84,8 +86,6 @@ class GlucoseListFragment : MainFragment() { setViewModelStrings() } - override fun getTitle() = R.string.fragment_glucose - private fun update(data: PagedList?) { adapter.submitList(data) } diff --git a/app/src/main/java/it/diab/fragments/InsulinFragment.kt b/app/src/main/java/it/diab/fragments/InsulinFragment.kt index da1cdc75f4f418e57e8c40ada24f6d9aa7d37dc5..3c634e8ff5f07de9751d283f441ddb4ca617bdbf 100644 --- a/app/src/main/java/it/diab/fragments/InsulinFragment.kt +++ b/app/src/main/java/it/diab/fragments/InsulinFragment.kt @@ -26,7 +26,9 @@ import it.diab.core.util.intentTo import it.diab.viewmodels.insulin.InsulinViewModel import it.diab.viewmodels.insulin.InsulinViewModelFactory -class InsulinFragment : MainFragment() { +class InsulinFragment : BaseFragment() { + override val titleRes = R.string.fragment_insulin + private lateinit var recyclerView: RecyclerView private lateinit var viewModel: InsulinViewModel @@ -56,8 +58,6 @@ class InsulinFragment : MainFragment() { return view } - override fun getTitle() = R.string.fragment_insulin - private fun onItemClick(uid: Long) { val intent = intentTo(Activities.Insulin.Editor).apply { putExtra(Activities.Insulin.Editor.EXTRA_UID, uid) diff --git a/app/src/main/java/it/diab/fragments/OverviewFragment.kt b/app/src/main/java/it/diab/fragments/OverviewFragment.kt index 667c32efd31b4d69334ebc8de22a9e5896cd262a..e01edcf47426a834cec0ac747a54d66d14e45c1a 100644 --- a/app/src/main/java/it/diab/fragments/OverviewFragment.kt +++ b/app/src/main/java/it/diab/fragments/OverviewFragment.kt @@ -37,12 +37,14 @@ import it.diab.core.util.SystemUtil import it.diab.core.util.intentTo import it.diab.ui.graph.OverviewGraphView import it.diab.util.extensions.isToday -import it.diab.viewmodels.glucose.OverviewViewModel -import it.diab.viewmodels.glucose.OverviewViewModelFactory +import it.diab.viewmodels.overview.OverviewViewModel +import it.diab.viewmodels.overview.OverviewViewModelFactory import java.text.SimpleDateFormat import java.util.Locale -class OverviewFragment : MainFragment() { +class OverviewFragment : BaseFragment() { + override val titleRes = R.string.fragment_overview + private lateinit var lastValueView: TextView private lateinit var lastDescView: TextView private lateinit var chart: OverviewGraphView @@ -91,8 +93,6 @@ class OverviewFragment : MainFragment() { setupMenu() } - override fun getTitle() = R.string.fragment_overview - private fun updateChart(data: List?) { if (data == null || data.isEmpty()) { return diff --git a/app/src/main/java/it/diab/holders/GlucoseHolder.kt b/app/src/main/java/it/diab/holders/GlucoseHolder.kt new file mode 100644 index 0000000000000000000000000000000000000000..43213b484fa3d900951d57b400f265fd96454fdd --- /dev/null +++ b/app/src/main/java/it/diab/holders/GlucoseHolder.kt @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2019 Bevilacqua Joey + * + * Licensed under the GNU GPLv3 license + * + * The text of the license can be found in the LICENSE file + * or at https://www.gnu.org/licenses/gpl.txt + */ +package it.diab.holders + +import android.view.View +import android.widget.ImageView +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import it.diab.R +import it.diab.core.data.entities.Glucose +import it.diab.core.util.extensions.setPrecomputedText + +class GlucoseHolder( + view: View, + private val callbacks: GlucoseHolderCallbacks +) : RecyclerView.ViewHolder(view) { + private val headerView = view.findViewById(R.id.item_glucose_header) + private val headerTitleView = view.findViewById(R.id.item_glucose_header_title) + private val iconView = view.findViewById(R.id.item_glucose_timezone) + private val titleView = view.findViewById(R.id.item_glucose_value) + private val summaryView = view.findViewById(R.id.item_glucose_insulin) + private val indicatorView = view.findViewById(R.id.item_glucose_status) + + fun onBind(glucose: Glucose) { + itemView.visibility = View.VISIBLE + + bindHeader(glucose) + bindValue(glucose) + bindInsulin(glucose) + + iconView.setImageResource(glucose.timeFrame.icon) + itemView.setOnClickListener { callbacks.onClick(glucose.uid) } + } + + fun onLoading() { + itemView.visibility = View.INVISIBLE + } + + private fun bindHeader(glucose: Glucose) { + val shouldShowHeader = callbacks.shouldInsertHeader(adapterPosition) + headerView.visibility = if (shouldShowHeader) View.VISIBLE else View.GONE + + if (shouldShowHeader) { + callbacks.fetchHeaderText(glucose.date, headerTitleView::setPrecomputedText) + } + } + + private fun bindValue(glucose: Glucose) { + val title = "${glucose.value} (%1\$s)" + + callbacks.fetchHourText(glucose.date) { text, scope -> + titleView.setPrecomputedText(title.format(text), scope) + } + + val indicatorDrawable = callbacks.getIndicator(glucose.value) + if (indicatorDrawable == null) { + indicatorView.visibility = View.GONE + } else { + indicatorView.visibility = View.VISIBLE + indicatorView.setImageDrawable(indicatorDrawable) + } + } + + private fun bindInsulin(glucose: Glucose) { + val builder = StringBuilder() + val insulinId = glucose.insulinId0 + val basalId = glucose.insulinId1 + + builder.apply { + if (insulinId >= 0) { + append(glucose.insulinValue0) + append(" ") + append(callbacks.getInsulinName(insulinId)) + } + + if (basalId >= 0) { + if (insulinId >= 0) { + append(", ") + } + + append(glucose.insulinValue1) + append(" ") + append(callbacks.getInsulinName(basalId)) + } + } + + if (builder.isEmpty()) { + summaryView.visibility = View.GONE + } else { + summaryView.visibility = View.VISIBLE + summaryView.text = builder.toString() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/it/diab/holders/GlucoseHolderCallbacks.kt b/app/src/main/java/it/diab/holders/GlucoseHolderCallbacks.kt new file mode 100644 index 0000000000000000000000000000000000000000..eaac3dee102e2b96da30714d0b1e1de3e92dec56 --- /dev/null +++ b/app/src/main/java/it/diab/holders/GlucoseHolderCallbacks.kt @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019 Bevilacqua Joey + * + * Licensed under the GNU GPLv3 license + * + * The text of the license can be found in the LICENSE file + * or at https://www.gnu.org/licenses/gpl.txt + */ +package it.diab.holders + +import android.graphics.drawable.Drawable +import kotlinx.coroutines.CoroutineScope +import java.util.Date + +interface GlucoseHolderCallbacks { + + /** + * Fetch a String that for the header + * + * @param date date to be put in the string + * @param onFetch callback for fetch completion + */ + fun fetchHeaderText( + date: Date, + onFetch: (String, CoroutineScope) -> Unit + ) + + /** + * Fetch a String that represents hours of a given [Date] + * + * @param date date to be put in the string + * @param onFetch callback for fetch completion + */ + fun fetchHourText( + date: Date, + onFetch: (String, CoroutineScope) -> Unit + ) + + /** + * Get the indicator drawable for + * a given glucose value + */ + fun getIndicator(value: Int): Drawable? + + /** + * Get the name of an insulin + * + * @param uid uid of the insulin + */ + fun getInsulinName(uid: Long): String + + /** + * OnClick event callback + */ + fun onClick(uid: Long) + + /** + * Whether the header should be shown + * + * @param position position of the glucose in the list + */ + fun shouldInsertHeader(position: Int): Boolean +} diff --git a/app/src/main/java/it/diab/holders/InsulinHolder.kt b/app/src/main/java/it/diab/holders/InsulinHolder.kt new file mode 100644 index 0000000000000000000000000000000000000000..d603d352762324440bbcf56b18705d5046e1f858 --- /dev/null +++ b/app/src/main/java/it/diab/holders/InsulinHolder.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019 Bevilacqua Joey + * + * Licensed under the GNU GPLv3 license + * + * The text of the license can be found in the LICENSE file + * or at https://www.gnu.org/licenses/gpl.txt + */ +package it.diab.holders + +import android.view.View +import android.widget.ImageView +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import it.diab.R +import it.diab.core.data.entities.Insulin + +class InsulinHolder( + view: View, + private val callbacks: InsulinHolderCallbacks +) : RecyclerView.ViewHolder(view) { + private val titleView = view.findViewById(R.id.item_insulin_name) + private val iconView = view.findViewById(R.id.item_insulin_icon) + + fun onBind(insulin: Insulin) { + titleView.text = insulin.name + iconView.setImageResource(insulin.timeFrame.icon) + + itemView.setOnClickListener { callbacks.onClick(insulin.uid) } + } + + fun onBind() { + val res = itemView.resources + titleView.text = res.getString(R.string.insulin_add_item) + iconView.setImageResource(R.drawable.ic_add) + + itemView.setOnClickListener { callbacks.onClick(-1) } + } + + fun onLoading() { + itemView.visibility = View.GONE + } +} \ No newline at end of file diff --git a/app/src/main/java/it/diab/holders/InsulinHolderCallbacks.kt b/app/src/main/java/it/diab/holders/InsulinHolderCallbacks.kt new file mode 100644 index 0000000000000000000000000000000000000000..b029392b28af30ab5a8ada1a91296c58dd9b4289 --- /dev/null +++ b/app/src/main/java/it/diab/holders/InsulinHolderCallbacks.kt @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2019 Bevilacqua Joey + * + * Licensed under the GNU GPLv3 license + * + * The text of the license can be found in the LICENSE file + * or at https://www.gnu.org/licenses/gpl.txt + */ +package it.diab.holders + +interface InsulinHolderCallbacks { + + /** + * On item click callback + * + * @param uid insulin uid + */ + fun onClick(uid: Long) +} \ No newline at end of file diff --git a/app/src/main/java/it/diab/viewmodels/glucose/GlucoseListViewModel.kt b/app/src/main/java/it/diab/viewmodels/glucose/GlucoseListViewModel.kt index d4fe2fdd5bcaac0d360f1b801cf460d470fc1b6b..5086f0202ce6be8659e9bd9733e2fe17c909a6fd 100644 --- a/app/src/main/java/it/diab/viewmodels/glucose/GlucoseListViewModel.kt +++ b/app/src/main/java/it/diab/viewmodels/glucose/GlucoseListViewModel.kt @@ -16,8 +16,8 @@ import it.diab.core.data.repositories.InsulinRepository import it.diab.core.viewmodels.ScopedViewModel import it.diab.util.extensions.diff import it.diab.util.extensions.getWeekDay +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import java.text.SimpleDateFormat import java.util.Date @@ -37,7 +37,7 @@ class GlucoseListViewModel internal constructor( fun prepare(block: () -> Unit) { viewModelScope.launch { runPrepare() - GlobalScope.launch(Dispatchers.Main) { block() } + launch(Dispatchers.Main) { block() } } } @@ -46,11 +46,11 @@ class GlucoseListViewModel internal constructor( fun setHeader( date: Date, format: SimpleDateFormat, - block: (String) -> Unit + block: (String, CoroutineScope) -> Unit ) { viewModelScope.launch { val text = runSetHeader(date, format) - GlobalScope.launch(Dispatchers.Main) { block(text) } + block(text, viewModelScope) } } diff --git a/app/src/main/java/it/diab/viewmodels/glucose/OverviewViewModel.kt b/app/src/main/java/it/diab/viewmodels/overview/OverviewViewModel.kt similarity index 87% rename from app/src/main/java/it/diab/viewmodels/glucose/OverviewViewModel.kt rename to app/src/main/java/it/diab/viewmodels/overview/OverviewViewModel.kt index 93c6e0255571e5c63ee3ee425a91bd4c460b807d..ef5e5c00748e56698e28af97a80e9f981c1c852c 100644 --- a/app/src/main/java/it/diab/viewmodels/glucose/OverviewViewModel.kt +++ b/app/src/main/java/it/diab/viewmodels/overview/OverviewViewModel.kt @@ -6,8 +6,9 @@ * The text of the license can be found in the LICENSE file * or at https://www.gnu.org/licenses/gpl.txt */ -package it.diab.viewmodels.glucose +package it.diab.viewmodels.overview +import android.annotation.SuppressLint import androidx.annotation.VisibleForTesting import com.github.mikephil.charting.data.Entry import it.diab.core.data.entities.Glucose @@ -21,7 +22,6 @@ import it.diab.util.extensions.getAsMinutes import it.diab.util.extensions.isToday import it.diab.util.extensions.isZeroOrNan import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.async import kotlinx.coroutines.launch import kotlin.collections.set @@ -44,17 +44,22 @@ class OverviewViewModel internal constructor( val end = System.currentTimeMillis() val start = end - DateUtils.WEEK val data = glucoseRepository.getInDateRange(start, end) - val pair = runGetDataSets(data) - GlobalScope.launch(Dispatchers.Main) { block(pair.first, pair.second) } + val result = runGetDataSets(data) + + launch(Dispatchers.Main) { + block(result.first, result.second) + } } } + @SuppressLint("UseSparseArrays") @VisibleForTesting suspend fun runGetDataSets(data: List): Pair, List> { val averageDef = async { val avg = HashMap() - val size = TimeFrame.values().size - 2 // -1 for the iterator and -1 for "EXTRA" + val size = TimeFrame.values().size - 2 // -1 because we start at 0 and -1 for "EXTRA" + for (i in 0..size) { val tf = i.toTimeFrame() diff --git a/app/src/main/java/it/diab/viewmodels/glucose/OverviewViewModelFactory.kt b/app/src/main/java/it/diab/viewmodels/overview/OverviewViewModelFactory.kt similarity index 88% rename from app/src/main/java/it/diab/viewmodels/glucose/OverviewViewModelFactory.kt rename to app/src/main/java/it/diab/viewmodels/overview/OverviewViewModelFactory.kt index 734bc43acaca9af93553520804e68a0315f78c98..d32bb3445829f3dccfa4b7a1f6fd02717bae10b3 100644 --- a/app/src/main/java/it/diab/viewmodels/glucose/OverviewViewModelFactory.kt +++ b/app/src/main/java/it/diab/viewmodels/overview/OverviewViewModelFactory.kt @@ -1,12 +1,12 @@ /* - * Copyright (c) 2018 Bevilacqua Joey + * Copyright (c) 2019 Bevilacqua Joey * * Licensed under the GNU GPLv3 license * * The text of the license can be found in the LICENSE file * or at https://www.gnu.org/licenses/gpl.txt */ -package it.diab.viewmodels.glucose +package it.diab.viewmodels.overview import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider diff --git a/core/src/main/java/it/diab/core/util/extensions/TextView.kt b/core/src/main/java/it/diab/core/util/extensions/TextView.kt index 8cfc6ea029177e328d12cead9e7129a8ae900b61..6d1460e44771a80990cf48a687f17677c3228b26 100644 --- a/core/src/main/java/it/diab/core/util/extensions/TextView.kt +++ b/core/src/main/java/it/diab/core/util/extensions/TextView.kt @@ -13,7 +13,6 @@ import androidx.core.text.PrecomputedTextCompat import androidx.core.widget.TextViewCompat import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.async import kotlinx.coroutines.launch @@ -22,6 +21,6 @@ fun TextView.setPrecomputedText(text: CharSequence, coroutineScope: CoroutineSco coroutineScope.launch(Dispatchers.IO) { val textDef = async { PrecomputedTextCompat.getTextFuture(text, params, null).get() } - GlobalScope.launch(Dispatchers.Main) { this@setPrecomputedText.text = textDef.await() } + launch(Dispatchers.Main) { this@setPrecomputedText.text = textDef.await() } } }