MrOzOn преди 5 години
родител
ревизия
8b4af8fb41

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

@@ -27,4 +27,9 @@ interface MeasureDao {
         insertAllMeasure(measures)
     }
 
+    @Query("DELETE FROM measure_table WHERE measure_id=:id")
+    suspend fun deleteMeasure(id: Long)
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    suspend fun insertMeasure(measureDb: MeasureDb)
 }

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

@@ -14,6 +14,9 @@ interface UserDao {
     @Query("SELECT * FROM user_table LIMIT 1")
     fun getLiveUser(): LiveData<UserDb>
 
+    @Query("SELECT * FROM user_table LIMIT 1")
+    suspend fun getSuspendUser(): UserDb
+
     @Insert(onConflict = OnConflictStrategy.REPLACE)
     suspend fun insertUser(userDb: UserDb)
 

+ 9 - 13
core_api/src/main/java/com/mrozon/core_api/network/HealthDiaryService.kt

@@ -39,17 +39,13 @@ interface HealthDiaryService {
     suspend fun getMeasure(@Query("type") type: Long,
                            @Query("patient") patient: Long): Response<List<MeasureResponse>>
 
-//    @GET("lego/themes/")
-//    suspend fun getThemes(@Query("page") page: Int? = null,
-//                          @Query("page_size") pageSize: Int? = null,
-//                          @Query("ordering") order: String? = null): Response<ResultsResponse<LegoTheme>>
-//
-//    @GET("lego/sets/")
-//    suspend fun getSets(@Query("page") page: Int? = null,
-//                        @Query("page_size") pageSize: Int? = null,
-//                        @Query("theme_id") themeId: Int? = null,
-//                        @Query("ordering") order: String? = null): Response<ResultsResponse<LegoSet>>
-//
-//    @GET("lego/sets/{id}/")
-//    suspend fun getSet(@Path("id") id: String): Response<LegoSet>
+    @DELETE("indicators/{id}/")
+    suspend fun deleteMeasure(@Path("id") id: String): Response<Unit>
+
+    @POST("indicators/")
+    suspend fun addMeasure(@Body body: MeasureRequest): Response<MeasureResponse>
+
+    @PUT("indicators/{id}/")
+    suspend fun editMeasure(@Path("id") id: String,
+                           @Body body: MeasureRequest): Response<MeasureResponse>
 }

+ 11 - 0
core_api/src/main/java/com/mrozon/core_api/network/model/MeasureRequest.kt

@@ -0,0 +1,11 @@
+package com.mrozon.core_api.network.model
+
+data class MeasureRequest(
+    val value1: String,
+    val value2: String,
+    val value_added: String,
+    val comments: String,
+    val type: Long,
+    val patient: Long,
+    val observing: Long
+)

+ 17 - 0
feature_measure/src/main/java/com/mrozon/feature_measure/data/MeasureRemoteDataSource.kt

@@ -1,6 +1,8 @@
 package com.mrozon.feature_measure.data
 
 import com.mrozon.core_api.network.HealthDiaryService
+import com.mrozon.core_api.network.model.MeasureRequest
+import com.mrozon.core_api.network.model.PersonRequest
 import com.mrozon.utils.base.BaseDataSource
 import javax.inject.Inject
 
@@ -11,4 +13,19 @@ class MeasureRemoteDataSource @Inject constructor(private val service: HealthDia
         service.getMeasure(measureTypeId, personId)
     }
 
+    suspend fun deleteMeasure(id: Long)
+            = getResult {
+        service.deleteMeasure(id.toString())
+    }
+
+    suspend fun addMeasure(request: MeasureRequest)
+            = getResult {
+        service.addMeasure(request)
+    }
+
+    suspend fun editMeasure(id: Long, request: MeasureRequest)
+            = getResult {
+        service.editMeasure(id.toString(), request)
+    }
+
 }

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

@@ -19,4 +19,10 @@ interface MeasureRepository {
 
     fun loadSelectedMeasure(id: Long): Flow<Result<Measure>>
 
+    fun deleteMeasure(id: Long): Flow<Result<Unit>>
+
+    fun addMeasure(measure: Measure): Flow<Result<Unit>>
+
+    fun editMeasure(measure: Measure): Flow<Result<Unit>>
+
 }

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

@@ -8,7 +8,10 @@ import com.mrozon.core_api.entity.Person
 import com.mrozon.core_api.mapper.MeasureToMeasureDbMapper
 import com.mrozon.core_api.mapper.MeasureTypeToMeasureTypeDbMapper
 import com.mrozon.core_api.mapper.PersonToPersonDbMapper
+import com.mrozon.core_api.network.model.MeasureRequest
 import com.mrozon.core_api.network.model.toMeasure
+import com.mrozon.core_api.network.model.toPerson
+import com.mrozon.utils.extension.toDateString
 import com.mrozon.utils.network.Result
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.flow
@@ -119,5 +122,68 @@ class MeasureRepositoryImpl @Inject constructor(
         }
     }
 
+    override fun deleteMeasure(id: Long): Flow<Result<Unit>> {
+        return flow {
+            emit(Result.loading())
+            val response = dataSource.deleteMeasure(id)
+            if (response.status == Result.Status.SUCCESS) {
+                dao.deleteMeasure(id)
+                emit(Result.success())
+            } else if (response.status == Result.Status.ERROR) {
+                emit(Result.error(response.message!!))
+            }
+        }
+    }
+
+    override fun addMeasure(measure: Measure): Flow<Result<Unit>> {
+        return flow {
+            emit(Result.loading())
+            val observing = dao.getSuspendUser().id
+            val request = MeasureRequest (
+                value1 = measure.value1,
+                value2 = measure.value2,
+                value_added = measure.valueAdded.toDateString(format = "yyyy-MM-dd'T'HH:mm:ss"),
+                comments = measure.comment,
+                type = measure.measureTypeId,
+                patient = measure.personId,
+                observing = observing
+            )
+            val response = dataSource.addMeasure(request)
+            if (response.status == Result.Status.SUCCESS) {
+                val measureDb = mapperMeasure.map(response.data?.toMeasure())
+                dao.insertMeasure(measureDb!!)
+                emit(Result.success())
+            } else if (response.status == Result.Status.ERROR) {
+                emit(Result.error(response.message!!))
+            }
+        }
+    }
+
+    override fun editMeasure(measure: Measure): Flow<Result<Unit>> {
+        return flow {
+            emit(Result.loading())
+            val observing = dao.getSuspendUser().id
+            val request = MeasureRequest (
+                value1 = measure.value1,
+                value2 = measure.value2,
+                value_added = measure.valueAdded.toDateString(format = "yyyy-MM-dd'T'HH:mm:ss"),
+                comments = measure.comment,
+                type = measure.measureTypeId,
+                patient = measure.personId,
+                observing = observing
+            )
+            val response = dataSource.editMeasure(measure.id, request)
+            if (response.status == Result.Status.SUCCESS) {
+                val measureDb = mapperMeasure.map(response.data?.toMeasure())
+                dao.insertMeasure(measureDb!!)
+                emit(Result.success())
+            } else if (response.status == Result.Status.ERROR) {
+                emit(Result.error(response.message!!))
+            }
+        }
+    }
+
+
+
 
 }

+ 58 - 3
feature_measure/src/main/java/com/mrozon/feature_measure/presentation/EditMeasureFragment.kt

@@ -3,6 +3,7 @@ package com.mrozon.feature_measure.presentation
 import android.content.Context
 import android.os.Bundle
 import android.view.*
+import androidx.core.app.ActivityCompat
 import androidx.fragment.app.viewModels
 import androidx.lifecycle.Observer
 import androidx.lifecycle.ViewModelProvider
@@ -14,9 +15,8 @@ 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 com.mrozon.utils.extension.*
+import com.mrozon.utils.network.Result
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.FlowPreview
 import timber.log.Timber
@@ -45,6 +45,7 @@ class EditMeasureFragment: BaseFragment<FragmentEditMeasureBinding>() {
         return super.onCreateView(inflater, container, savedInstanceState)
     }
 
+    @ExperimentalCoroutinesApi
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
         arguments?.let {
@@ -90,12 +91,20 @@ class EditMeasureFragment: BaseFragment<FragmentEditMeasureBinding>() {
                 showError(e.message!!)
             }
         }
+
+        binding?.tilComment?.editText?.offer(viewModel.commentChannel)
+        binding?.tilMeasureValue?.editText?.offer(viewModel.measureValueChannel)
     }
 
     @ExperimentalCoroutinesApi
     @FlowPreview
     override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
         inflater.inflate(R.menu.add_measure_menu, menu)
+        val currentId = requireArguments().getLong("id", 0)
+        val deleteMenuItem = menu.findItem(R.id.deleteMeasure)
+        deleteMenuItem.isVisible = currentId>0
+        val saveMenuItem = menu.findItem(R.id.saveMeasure)
+        saveMenuItem.isVisible = binding?.tilMeasureValue?.error == null && binding?.tilMeasureValue?.editText?.text?.isNotEmpty()!!
         return super.onCreateOptionsMenu(menu, inflater)
     }
 
@@ -106,10 +115,21 @@ class EditMeasureFragment: BaseFragment<FragmentEditMeasureBinding>() {
             showError(getString(R.string.network_inactive))
             return false
         }
+        when(item.itemId){
+            R.id.saveMeasure -> {
+                val currentId = requireArguments().getLong("id", 0)
+                viewModel.saveMeasure(currentId)
+            }
+            R.id.deleteMeasure -> {
+                viewModel.deleteMeasure()
+            }
+        }
         return false
     }
 
 
+    @FlowPreview
+    @ExperimentalCoroutinesApi
     override fun subscribeUi() {
         viewModel.measureType.observe(viewLifecycleOwner, Observer { measureType ->
             measureType?.let {
@@ -125,5 +145,40 @@ class EditMeasureFragment: BaseFragment<FragmentEditMeasureBinding>() {
                 binding?.tvMeasureAddedDate?.text = it.toDateString("EEE, d MMM YY HH:mm:ss")
             }
         })
+        viewModel.measure.observe(viewLifecycleOwner, Observer { event ->
+            event.peekContent().let { result ->
+                when (result.status) {
+                    Result.Status.LOADING -> {
+                        binding?.progressBar?.visible(true)
+                    }
+                    Result.Status.SUCCESS -> {
+                        binding?.progressBar?.visible(false)
+                        val measure = result.data
+                        measure?.let {
+                            binding?.tilComment?.editText?.setText(measure.comment)
+                            var measureValue = measure.value1
+                            if(measure.value2.isNotEmpty()) {
+                                measureValue +="/"+measure.value2
+                            }
+                            binding?.tilMeasureValue?.editText?.setText(measureValue)
+                        }
+                    }
+                    Result.Status.ERROR -> {
+                        binding?.progressBar?.visible(false)
+                        showError(result.message!!)
+                    }
+                }
+            }
+        })
+        viewModel.correctMeasureValue.observe(viewLifecycleOwner, Observer {correct ->
+            correct?.let {
+                if(correct) {
+                    binding?.tilMeasureValue?.error = null
+                } else {
+                    binding?.tilMeasureValue?.error = getString(R.string.error_value, viewModel.measureType.value?.hint)
+                }
+                ActivityCompat.invalidateOptionsMenu(activity)
+            }
+        })
     }
 }

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

@@ -11,11 +11,14 @@ import com.mrozon.feature_measure.data.MeasureRepository
 import com.mrozon.utils.Event
 import com.mrozon.utils.base.BaseViewModel
 import com.mrozon.utils.network.Result
+import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.ConflatedBroadcastChannel
+import kotlinx.coroutines.flow.asFlow
 import kotlinx.coroutines.flow.collect
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
+import kotlinx.coroutines.flow.combine
 import java.time.Year
 import java.util.*
+import java.util.regex.Pattern
 import javax.inject.Inject
 
 class EditMeasureFragmentViewModel @Inject constructor(
@@ -39,6 +42,10 @@ class EditMeasureFragmentViewModel @Inject constructor(
     val currentDatetime: LiveData<Date>
         get() = _currentDatetime
 
+    private var _goToListMeasure = MutableLiveData<Event<Result<Unit>>>()
+    val goToListMeasure: LiveData<Event<Result<Unit>>>
+        get() = _goToListMeasure
+
     val currentHour: Int
         get() {
             val currentCalendar = Calendar.getInstance()
@@ -53,6 +60,33 @@ class EditMeasureFragmentViewModel @Inject constructor(
             return currentCalendar.get(Calendar.MINUTE)
         }
 
+    @ExperimentalCoroutinesApi
+    val commentChannel = ConflatedBroadcastChannel<String>()
+
+    @ExperimentalCoroutinesApi
+    val measureValueChannel = ConflatedBroadcastChannel<String>()
+
+    @ExperimentalCoroutinesApi
+    @FlowPreview
+    val correctMeasureValue = object: MutableLiveData<Boolean>() {
+
+        override fun onActive() {
+            value?.let { return }
+            viewModelScope.launch {
+                var job: Deferred<Unit>? = null
+                measureValueChannel.asFlow()
+                    .collect {
+                        job?.cancel()
+                        job = async(Dispatchers.Main) {
+                            val pattern = Pattern.compile(measureType.value?.regexp?:"")
+                            val matcher = pattern.matcher(it)
+                            value = matcher.matches()
+                        }
+                    }
+            }
+        }
+    }
+
     fun initialLoadData(id: Long, personId: Long, measureTypeId: Long) {
         if(_measureType.value==null){
 //            _measure.value = Event(Result.loading())
@@ -106,5 +140,55 @@ class EditMeasureFragmentViewModel @Inject constructor(
         _currentDatetime.value = currentCalendar.time
     }
 
+    fun deleteMeasure() {
+        _measure.value?.let {
+            viewModelScope.launch(coroutineContextProvider.IO) {
+                val id = _measure.value?.peekContent()?.data?.id?:0
+                repository.deleteMeasure(id).collect {
+                    withContext(Dispatchers.Main) {
+                        _goToListMeasure.value = Event(it)
+                    }
+                }
+            }
+        }
+    }
+
+    @ExperimentalCoroutinesApi
+    fun saveMeasure(id: Long) {
+        val newMeasureValue = measureValueChannel.value
+        var value1 = newMeasureValue
+        var value2 = ""
+        if(newMeasureValue.contains('/')) {
+            val splits = newMeasureValue.split('/')
+            if(splits.size>1){
+                value1 = splits[0]
+                value2 = splits[1]
+            }
+        }
+
+        viewModelScope.launch(coroutineContextProvider.IO) {
+            val personId = _person.value?.id?:0
+            val measureTypeId = _measureType.value?.id?:0
+            val measure = Measure(id = id, personId = personId, measureTypeId = measureTypeId,
+                comment = commentChannel.value, valueAdded = _currentDatetime.value!!,
+                value1 = value1, value2 = value2
+            )
+            if(id>0) {
+                repository.editMeasure(measure).collect {
+                    withContext(Dispatchers.Main) {
+                        _goToListMeasure.value = Event(it)
+                    }
+                }
+            } else {
+                repository.addMeasure(measure).collect {
+                    withContext(Dispatchers.Main) {
+                        _goToListMeasure.value = Event(it)
+                    }
+                }
+            }
+        }
+
+    }
+
 
 }

+ 16 - 1
feature_measure/src/main/res/layout/fragment_edit_measure.xml

@@ -94,10 +94,25 @@
                 <com.google.android.material.textfield.TextInputEditText
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:inputType="textMultiLine" />
+                    android:inputType="textMultiLine"
+                    android:maxLength="150" />
 
             </com.google.android.material.textfield.TextInputLayout>
 
+
+            <ProgressBar
+                android:id="@+id/progressBar"
+                style="?android:attr/progressBarStyle"
+                android:layout_width="128dp"
+                android:layout_height="128dp"
+                android:indeterminate="true"
+                android:visibility="invisible"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toTopOf="parent"
+                tools:visibility="visible" />
+
         </androidx.constraintlayout.widget.ConstraintLayout>
 
     </ScrollView>

+ 2 - 2
feature_measure/src/main/res/menu/add_measure_menu.xml

@@ -2,14 +2,14 @@
 <menu xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:android="http://schemas.android.com/apk/res/android">
     <item
-        android:id="@+id/deletePerson"
+        android:id="@+id/deleteMeasure"
         android:icon="@drawable/ic_baseline_delete_outline_24"
         android:title="@string/delete_measure"
         android:visible="false"
         app:showAsAction="ifRoom" />
 
     <item
-        android:id="@+id/addPerson"
+        android:id="@+id/saveMeasure"
         android:icon="@drawable/ic_check_white_24dp"
         android:title="@string/save_measure"
         app:showAsAction="always" />

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

@@ -10,4 +10,5 @@
     <string name="choose_time">Choose Time</string>
     <string name="measure_added">Measure added</string>
     <string name="hint_value_added">%s ( in %s)</string>
+    <string name="error_value">Incorrect value, needed %s</string>
 </resources>