Prechádzať zdrojové kódy

create layout for edit measure
add material dialog for date, time
add interactive for its

MrOzOn 5 rokov pred
rodič
commit
c22189e860

+ 8 - 2
app/src/main/java/com/mrozon/healthdiary/navigation/ListMeasureNavigatorImpl.kt

@@ -11,8 +11,14 @@ import javax.inject.Inject
 class ListMeasureNavigatorImpl @Inject constructor()
     : ListMeasureNavigator {
 
-    override fun navigateToEditMeasure(navController: NavController, title: String, id: Long) {
-        val bundle = bundleOf("title" to title, "id" to id)
+    override fun navigateToEditMeasure(
+        navController: NavController,
+        title: String,
+        id: Long,
+        personId: Long,
+        measureTypeId: Long
+    ) {
+        val bundle = bundleOf("title" to title, "id" to id, "personId" to personId, "measureTypeId" to measureTypeId)
         navController.navigate(R.id.action_tabMeasureFragment_to_editMeasureFragment, bundle)
     }
 }

+ 6 - 0
app/src/main/res/navigation/nav_graph.xml

@@ -170,6 +170,12 @@
         <argument
             android:name="id"
             app:argType="long" />
+        <argument
+            android:name="personId"
+            app:argType="long" />
+        <argument
+            android:name="measureTypeId"
+            app:argType="long" />
         <action
             android:id="@+id/action_editMeasureFragment_to_listMeasureFragment"
             app:destination="@id/listMeasureFragment"

+ 1 - 1
app/src/main/res/values/styles.xml

@@ -1,7 +1,7 @@
 <resources>
 
     <!-- Base application theme. -->
-    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
+    <style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
         <!-- Customize your theme here. -->
         <item name="colorPrimary">@color/colorPrimary</item>
         <item name="colorPrimaryDark">@color/colorPrimaryDark</item>

+ 3 - 0
core_api/src/main/java/com/mrozon/core_api/db/dao/MeasureDao.kt

@@ -12,6 +12,9 @@ interface MeasureDao {
     @Query("SELECT * FROM measure_table WHERE measure_person=:personId AND measure_mtype=:measureTypeId ORDER BY measure_value_added LIMIT 100")
     fun getMeasures(personId: Long, measureTypeId: Long): List<MeasureDb>
 
+    @Query("SELECT * FROM measure_table WHERE measure_id=:id LIMIT 1")
+    fun getMeasure(id: Long): MeasureDb
+
     @Insert(onConflict = OnConflictStrategy.REPLACE)
     suspend fun insertAllMeasure(measures: List<MeasureDb>)
 

+ 1 - 1
core_api/src/main/java/com/mrozon/core_api/navigation/ListMeasureNavigator.kt

@@ -4,6 +4,6 @@ import androidx.navigation.NavController
 
 interface ListMeasureNavigator {
 
-    fun navigateToEditMeasure(navController: NavController, title: String, id: Long)
+    fun navigateToEditMeasure(navController: NavController, title: String, id: Long, personId: Long, measureTypeId: Long )
 
 }

+ 5 - 0
feature_measure/src/main/java/com/mrozon/feature_measure/data/MeasureRepository.kt

@@ -14,4 +14,9 @@ interface MeasureRepository {
     fun loadMeasure(personId: Long, measureTypeId: Long): Flow<Result<MeasureHistory>>
 
     fun loadMeasureOnlyNetwork(personId: Long, measureTypeId: Long): Flow<Result<List<Measure>>>
+
+    fun loadSelectedPersonAndMeasureTypes(personId: Long, measureTypeId: Long): Flow<Result<Pair<Person,MeasureType>>>
+
+    fun loadSelectedMeasure(id: Long): Flow<Result<Measure>>
+
 }

+ 30 - 0
feature_measure/src/main/java/com/mrozon/feature_measure/data/MeasureRepositoryImpl.kt

@@ -89,5 +89,35 @@ class MeasureRepositoryImpl @Inject constructor(
         }
     }
 
+    override fun loadSelectedPersonAndMeasureTypes(
+        personId: Long,
+        measureTypeId: Long
+    ): Flow<Result<Pair<Person, MeasureType>>> {
+        return  flow {
+            emit(Result.loading())
+            try {
+                val personDb = dao.getPerson(personId)
+                val measureTypeDb = dao.getMeasureType(measureTypeId)
+                emit(Result.success(Pair(mapperPerson.reverseMap(personDb)!!, mapperMeasureType.reverseMap(measureTypeDb)!!)))
+            }
+            catch (e: Exception){
+                emit(Result.error(e.message!!))
+            }
+        }
+    }
+
+    override fun loadSelectedMeasure(id: Long): Flow<Result<Measure>> {
+        return  flow {
+            emit(Result.loading())
+            try {
+                val measureDb = dao.getMeasure(id)
+                emit(Result.success(mapperMeasure.reverseMap(measureDb)!!))
+            }
+            catch (e: Exception){
+                emit(Result.error(e.message!!))
+            }
+        }
+    }
+
 
 }

+ 67 - 1
feature_measure/src/main/java/com/mrozon/feature_measure/presentation/EditMeasureFragment.kt

@@ -4,13 +4,19 @@ import android.content.Context
 import android.os.Bundle
 import android.view.*
 import androidx.fragment.app.viewModels
+import androidx.lifecycle.Observer
 import androidx.lifecycle.ViewModelProvider
+import com.google.android.material.datepicker.MaterialDatePicker
+import com.google.android.material.timepicker.MaterialTimePicker
+import com.google.android.material.timepicker.MaterialTimePicker.INPUT_MODE_CLOCK
+import com.google.android.material.timepicker.TimeFormat
 import com.mrozon.feature_measure.R
 import com.mrozon.feature_measure.databinding.FragmentEditMeasureBinding
 import com.mrozon.feature_measure.di.TabMeasureFragmentComponent
 import com.mrozon.utils.base.BaseFragment
 import com.mrozon.utils.extension.hideKeyboard
 import com.mrozon.utils.extension.isActiveNetwork
+import com.mrozon.utils.extension.toDateString
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.FlowPreview
 import timber.log.Timber
@@ -39,6 +45,53 @@ class EditMeasureFragment: BaseFragment<FragmentEditMeasureBinding>() {
         return super.onCreateView(inflater, container, savedInstanceState)
     }
 
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        arguments?.let {
+            val id = requireArguments().getLong("id", 0)
+            val personId = requireArguments().getLong("personId", 0)
+            val measureTypeId = requireArguments().getLong("measureTypeId", 0)
+
+            viewModel.initialLoadData(id, personId, measureTypeId)
+        }
+
+        binding?.buttonChooseDate?.setOnClickListener {
+            try {
+                val builder = MaterialDatePicker.Builder.datePicker()
+                    .apply {
+                        setInputMode(MaterialDatePicker.INPUT_MODE_CALENDAR)
+                        setSelection(viewModel.currentDatetime.value?.time)
+                    }
+                val picker = builder.build()
+                picker.addOnPositiveButtonClickListener {
+                    viewModel.changeDate(it)
+                }
+                picker.show(childFragmentManager, picker.toString())
+            } catch (e: IllegalArgumentException) {
+                Timber.e(e)
+                showError(e.message!!)
+            }
+        }
+
+        binding?.buttonChooseTime?.setOnClickListener {
+            try {
+                val picker = MaterialTimePicker.Builder()
+                    .setTimeFormat(TimeFormat.CLOCK_24H)
+                    .setInputMode(INPUT_MODE_CLOCK)
+                    .setHour(viewModel.currentHour)
+                    .setMinute(viewModel.currentMinute)
+                    .build()
+                picker.addOnPositiveButtonClickListener {
+                    viewModel.changeTime(picker.hour, picker.minute)
+                }
+                picker.show(childFragmentManager, picker.toString())
+            } catch (e: IllegalArgumentException) {
+                Timber.e(e)
+                showError(e.message!!)
+            }
+        }
+    }
+
     @ExperimentalCoroutinesApi
     @FlowPreview
     override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@@ -58,6 +111,19 @@ class EditMeasureFragment: BaseFragment<FragmentEditMeasureBinding>() {
 
 
     override fun subscribeUi() {
-
+        viewModel.measureType.observe(viewLifecycleOwner, Observer { measureType ->
+            measureType?.let {
+                binding?.tilMeasureValue?.hint = getString(
+                    R.string.hint_value_added,
+                    it.name,
+                    it.mark
+                )
+            }
+        })
+        viewModel.currentDatetime.observe(viewLifecycleOwner, Observer { datetime ->
+            datetime?.let {
+                binding?.tvMeasureAddedDate?.text = it.toDateString("EEE, d MMM YY HH:mm:ss")
+            }
+        })
     }
 }

+ 86 - 0
feature_measure/src/main/java/com/mrozon/feature_measure/presentation/EditMeasureFragmentViewModel.kt

@@ -3,6 +3,7 @@ package com.mrozon.feature_measure.presentation
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.viewModelScope
+import com.mrozon.core_api.entity.Measure
 import com.mrozon.core_api.entity.MeasureType
 import com.mrozon.core_api.entity.Person
 import com.mrozon.core_api.providers.CoroutineContextProvider
@@ -13,6 +14,8 @@ import com.mrozon.utils.network.Result
 import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
+import java.time.Year
+import java.util.*
 import javax.inject.Inject
 
 class EditMeasureFragmentViewModel @Inject constructor(
@@ -20,5 +23,88 @@ class EditMeasureFragmentViewModel @Inject constructor(
     private val coroutineContextProvider: CoroutineContextProvider
 ): BaseViewModel() {
 
+    private var _measureType = MutableLiveData<MeasureType>()
+    val measureType: LiveData<MeasureType>
+        get() = _measureType
+
+    private var _person = MutableLiveData<Person>()
+    val person: LiveData<Person>
+        get() = _person
+
+    private var _measure = MutableLiveData<Event<Result<Measure>>>()
+    val measure: LiveData<Event<Result<Measure>>>
+        get() = _measure
+
+    private var _currentDatetime = MutableLiveData<Date>()
+    val currentDatetime: LiveData<Date>
+        get() = _currentDatetime
+
+    val currentHour: Int
+        get() {
+            val currentCalendar = Calendar.getInstance()
+            currentCalendar.time = _currentDatetime.value!!
+            return currentCalendar.get(Calendar.HOUR_OF_DAY)
+        }
+
+    val currentMinute: Int
+        get() {
+            val currentCalendar = Calendar.getInstance()
+            currentCalendar.time = _currentDatetime.value!!
+            return currentCalendar.get(Calendar.MINUTE)
+        }
+
+    fun initialLoadData(id: Long, personId: Long, measureTypeId: Long) {
+        if(_measureType.value==null){
+//            _measure.value = Event(Result.loading())
+            viewModelScope.launch(coroutineContextProvider.IO) {
+                repository.loadSelectedPersonAndMeasureTypes(personId, measureTypeId).collect {
+                    withContext(coroutineContextProvider.Main) {
+                        if(it.status== Result.Status.SUCCESS) {
+                            _measureType.value = it.data?.second!!
+                            _person.value = it.data?.first!!
+                        }
+                    }
+                }
+                if (id>0){
+                    repository.loadSelectedMeasure(id).collect {
+                        withContext(coroutineContextProvider.Main) {
+                            _measure.value = Event(it)
+                            if (it.status == Result.Status.SUCCESS) {
+                                _currentDatetime.value = it.data?.valueAdded
+                            }
+                        }
+                    }
+                } else {
+                    withContext(coroutineContextProvider.Main) {
+                        _currentDatetime.value = Date()
+                    }
+                }
+            }
+//            _measure.value = Event(Result.success())
+        }
+    }
+
+    fun changeDate(value: Long?) {
+        value?.let {
+            val currentCalendar = Calendar.getInstance()
+            currentCalendar.time = _currentDatetime.value!!
+            val newDate = Calendar.getInstance()
+            newDate.time = Date(value)
+            currentCalendar.set(Calendar.YEAR,newDate.get(Calendar.YEAR))
+            currentCalendar.set(Calendar.MONTH,newDate.get(Calendar.MONTH))
+            currentCalendar.set(Calendar.DAY_OF_YEAR,newDate.get(Calendar.DAY_OF_YEAR))
+            _currentDatetime.value = currentCalendar.time
+        }
+    }
+
+    fun changeTime(hour: Int, minute: Int) {
+        val currentCalendar = Calendar.getInstance()
+        currentCalendar.time = _currentDatetime.value!!
+        currentCalendar.set(Calendar.HOUR_OF_DAY,hour)
+        currentCalendar.set(Calendar.MINUTE,minute)
+        currentCalendar.set(Calendar.SECOND,0)
+        _currentDatetime.value = currentCalendar.time
+    }
+
 
 }

+ 11 - 3
feature_measure/src/main/java/com/mrozon/feature_measure/presentation/ListMeasureFragment.kt

@@ -62,8 +62,12 @@ class ListMeasureFragment : BaseFragment<FragmentListMeasureBinding>() {
             layoutManager = manager
             addItemDecoration(DividerItemDecoration(requireContext(),DividerItemDecoration.VERTICAL))
         }
-        binding?.fabAddMeasure?.setOnClickListener {
-            navigator.navigateToEditMeasure(findNavController(),getString(R.string.add_measure),0)
+        binding?.fabAddMeasure?.setOnClickListener { _ ->
+            arguments?.let {
+                val personId = requireArguments().getLong(ARG_PERSON_ID, 0)
+                val measureTypeId = requireArguments().getLong(ARG_MEASURE_TYPE_ID, 0)
+                navigator.navigateToEditMeasure(findNavController(),getString(R.string.add_measure),0, personId, measureTypeId)
+            }
         }
     }
 
@@ -123,7 +127,11 @@ class ListMeasureFragment : BaseFragment<FragmentListMeasureBinding>() {
                         adapter = ListMeasureAdapter(measureType!!, object:
                             ListMeasureAdapter.ListMeasureClickListener {
                             override fun onClick(measure: Measure) {
-                                //edit measure
+                                arguments?.let {
+                                    val personId = requireArguments().getLong(ARG_PERSON_ID, 0)
+                                    val measureTypeId = requireArguments().getLong(ARG_MEASURE_TYPE_ID, 0)
+                                    navigator.navigateToEditMeasure(findNavController(),getString(R.string.add_measure),measure.id, personId, measureTypeId)
+                                }
                             }
                         })
                         binding?.rvMeasure?.adapter = adapter

+ 82 - 0
feature_measure/src/main/res/layout/fragment_edit_measure.xml

@@ -15,6 +15,88 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content">
 
+            <com.google.android.material.button.MaterialButton
+                android:id="@+id/buttonChooseDate"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="16dp"
+                android:layout_marginTop="32dp"
+                android:layout_marginEnd="8dp"
+                android:text="@string/choose_date"
+                app:layout_constraintEnd_toStartOf="@+id/buttonChooseTime"
+                app:layout_constraintHorizontal_bias="0.5"
+                app:layout_constraintHorizontal_chainStyle="spread"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toTopOf="parent" />
+
+            <com.google.android.material.button.MaterialButton
+                android:id="@+id/buttonChooseTime"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="8dp"
+                android:layout_marginTop="32dp"
+                android:layout_marginEnd="16dp"
+                android:text="@string/choose_time"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintHorizontal_bias="0.5"
+                app:layout_constraintStart_toEndOf="@+id/buttonChooseDate"
+                app:layout_constraintTop_toTopOf="parent" />
+
+            <TextView
+                android:id="@+id/tvMeasureAddedDate"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="8dp"
+                android:layout_marginTop="8dp"
+                android:layout_marginEnd="8dp"
+                android:text="пн, 30 нояб. 2020 22:11:29"
+                android:textAlignment="center"
+                android:textAppearance="@style/TextAppearance.AppCompat.Large"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/buttonChooseDate" />
+
+            <com.google.android.material.textfield.TextInputLayout
+                android:id="@+id/tilMeasureValue"
+                style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="16dp"
+                android:layout_marginTop="16dp"
+                android:layout_marginEnd="16dp"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/tvMeasureAddedDate">
+
+                <com.google.android.material.textfield.TextInputEditText
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:inputType="numberDecimal"
+                    android:singleLine="true" />
+
+            </com.google.android.material.textfield.TextInputLayout>
+
+
+            <com.google.android.material.textfield.TextInputLayout
+                android:id="@+id/tilComment"
+                style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="16dp"
+                android:layout_marginTop="32dp"
+                android:layout_marginEnd="16dp"
+                app:endIconMode="clear_text"
+                android:hint="@string/ivMeasureComment"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/tilMeasureValue">
+
+                <com.google.android.material.textfield.TextInputEditText
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:inputType="textMultiLine" />
+
+            </com.google.android.material.textfield.TextInputLayout>
 
         </androidx.constraintlayout.widget.ConstraintLayout>
 

+ 5 - 1
feature_measure/src/main/res/values/strings.xml

@@ -1,9 +1,13 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
     <string name="ivTimeOfDay">Time of day</string>
-    <string name="ivMeasureComment">comment</string>
+    <string name="ivMeasureComment">Comment</string>
     <string name="refresh">Refresh</string>
     <string name="add_measure">Add measure</string>
     <string name="delete_measure">Delete measure</string>
     <string name="save_measure">Save measure</string>
+    <string name="choose_date">Choose date</string>
+    <string name="choose_time">Choose Time</string>
+    <string name="measure_added">Measure added</string>
+    <string name="hint_value_added">%s ( in %s)</string>
 </resources>

+ 1 - 1
scripts/deps_versions.gradle

@@ -11,7 +11,7 @@ ext {
     constraintlayoutVersion = '1.1.3'
     cardviewVersion = '1.0.0'
     recyclerviewViersion = '1.2.0-alpha05'
-    materialVersion = '1.2.1'
+    materialVersion = '1.3.0-alpha04'
     lifecycleVersion = '2.3.0-alpha07'
     junitVersion = "4.12"
     mockitoCoreVersion = "2.28.2"