Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 0 additions & 49 deletions .codeclimate.yml

This file was deleted.

7 changes: 7 additions & 0 deletions .qlty/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
*
!configs
!configs/**
!hooks
!hooks/**
!qlty.toml
!.gitignore
1 change: 1 addition & 0 deletions .qlty/configs/.shellcheckrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
source-path=SCRIPTDIR
8 changes: 8 additions & 0 deletions .qlty/configs/.yamllint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
rules:
document-start: disable
quoted-strings:
required: only-when-needed
extra-allowed: ["{|}"]
key-duplicates: {}
octal-values:
forbid-implicit-octal: true
88 changes: 88 additions & 0 deletions .qlty/qlty.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# This file was automatically generated by `qlty init`.
# You can modify it to suit your needs.
# We recommend you to commit this file to your repository.
#
# This configuration is used by both Qlty CLI and Qlty Cloud.
#
# Qlty CLI -- Code quality toolkit for developers
# Qlty Cloud -- Fully automated Code Health Platform
#
# Try Qlty Cloud: https://qlty.sh
#
# For a guide to configuration, visit https://qlty.sh/d/config
# Or for a full reference, visit https://qlty.sh/d/qlty-toml
config_version = "0"

exclude_patterns = [
"*_min.*",
"*-min.*",
"*.min.*",
"**/.yarn/**",
"**/*.d.ts",
"**/assets/**",
"**/bower_components/**",
"**/build/**",
"**/cache/**",
"**/config/**",
"**/db/**",
"**/deps/**",
"**/dist/**",
"**/extern/**",
"**/external/**",
"**/generated/**",
"**/Godeps/**",
"**/gradlew/**",
"**/mvnw/**",
"**/node_modules/**",
"**/protos/**",
"**/seed/**",
"**/target/**",
"**/templates/**",
"**/testdata/**",
"**/vendor/**", "**/androidTest/", "**/test/", "**/sharedTest/", "**/src/main/java/org/simple/clinic/storage/migrations/Migration_*.kt", "**/build/", "router/",
]

test_patterns = [
"**/test/**",
"**/spec/**",
"**/*.test.*",
"**/*.spec.*",
"**/*_test.*",
"**/*_spec.*",
"**/test_*.*",
"**/spec_*.*",
]

[smells]
mode = "block"

[smells.boolean_logic]
threshold = 1
enabled = true

[smells.file_complexity]
threshold = 55
enabled = false

[smells.return_statements]
threshold = 2
enabled = true

[smells.nested_control_flow]
threshold = 2
enabled = true

[smells.function_parameters]
threshold = 6
enabled = true

[smells.function_complexity]
threshold = 11
enabled = true

[smells.duplication]
enabled = false

[[source]]
name = "default"
default = true
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
- Handle window insets when displaying app content in edge-to-edge
- Enable edge-to-edge support on all versions of Android
- Handle nullable inputs when removing last chip in the `ChipInputAutoCompleteTextView`
- Migrate `PatientSummaryScreen` toolbar to Jetpack Compose
- Add Compose components for Overdue screen
- Migrate medicines summary view to Jetpack Compose
- Migrate codeclimate config to qlty.sh config
- Migrate `OverdueScreen` patient list to Jetpack Compose

## 2025.05.20

Expand Down
93 changes: 50 additions & 43 deletions app/src/main/java/org/simple/clinic/home/overdue/OverdueScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.ViewCompositionStrategy
import com.f2prateek.rx.preferences2.Preference
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.jakewharton.rxbinding3.view.clicks
Expand All @@ -17,25 +20,23 @@ import io.reactivex.Observable
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.cast
import io.reactivex.rxkotlin.ofType
import io.reactivex.subjects.PublishSubject
import kotlinx.parcelize.Parcelize
import org.simple.clinic.R
import org.simple.clinic.ReportAnalyticsEvents
import org.simple.clinic.activity.permissions.RequestPermissions
import org.simple.clinic.activity.permissions.RuntimePermissions
import org.simple.clinic.appconfig.Country
import org.simple.clinic.contactpatient.ContactPatientBottomSheet
import org.simple.clinic.databinding.ListItemDividerBinding
import org.simple.clinic.databinding.ListItemNoPendingPatientsBinding
import org.simple.clinic.databinding.ListItemOverdueListSectionHeaderBinding
import org.simple.clinic.databinding.ListItemOverduePatientBinding
import org.simple.clinic.databinding.ListItemOverduePendingListFooterBinding
import org.simple.clinic.databinding.ListItemSearchOverduePatientButtonBinding
import org.simple.clinic.databinding.ScreenOverdueBinding
import org.simple.clinic.di.injector
import org.simple.clinic.feature.Feature.OverdueInstantSearch
import org.simple.clinic.feature.Feature.PatientReassignment
import org.simple.clinic.feature.Features
import org.simple.clinic.home.HomeScreen
import org.simple.clinic.home.overdue.compose.OverdueAppointmentListItem
import org.simple.clinic.home.overdue.compose.OverdueUiModel
import org.simple.clinic.home.overdue.compose.OverdueUiModelMapper
import org.simple.clinic.home.overdue.search.OverdueSearchScreen
import org.simple.clinic.navigation.v2.Router
import org.simple.clinic.navigation.v2.ScreenKey
Expand All @@ -54,7 +55,6 @@ import org.simple.clinic.util.UserClock
import org.simple.clinic.util.UtcClock
import org.simple.clinic.util.applyInsetsBottomPadding
import org.simple.clinic.util.unsafeLazy
import org.simple.clinic.widgets.ItemAdapter
import org.simple.clinic.widgets.UiEvent
import java.time.Instant
import java.time.LocalDate
Expand Down Expand Up @@ -115,37 +115,13 @@ class OverdueScreen : BaseScreen<
@Inject
lateinit var locale: Locale

private val overdueListAdapter = ItemAdapter(
diffCallback = OverdueAppointmentListItem.DiffCallback(),
bindings = mapOf(
R.layout.list_item_overdue_patient to { layoutInflater, parent ->
ListItemOverduePatientBinding.inflate(layoutInflater, parent, false)
},
R.layout.list_item_overdue_list_section_header to { layoutInflater, parent ->
ListItemOverdueListSectionHeaderBinding.inflate(layoutInflater, parent, false)
},
R.layout.list_item_overdue_pending_list_footer to { layoutInflater, parent ->
ListItemOverduePendingListFooterBinding.inflate(layoutInflater, parent, false)
},
R.layout.list_item_no_pending_patients to { layoutInflater, parent ->
ListItemNoPendingPatientsBinding.inflate(layoutInflater, parent, false)
},
R.layout.list_item_divider to { layoutInflater, parent ->
ListItemDividerBinding.inflate(layoutInflater, parent, false)
},
R.layout.list_item_search_overdue_patient_button to { layoutInflater, parent ->
ListItemSearchOverduePatientButtonBinding.inflate(layoutInflater, parent, false)
}
)
)

private val disposable = CompositeDisposable()

private val viewForEmptyList
get() = binding.viewForEmptyList

private val overdueRecyclerView
get() = binding.overdueRecyclerView
private val composeView
get() = binding.composeView

private val overdueProgressBar
get() = binding.overdueProgressBar
Expand All @@ -172,18 +148,22 @@ class OverdueScreen : BaseScreen<
country.isoCountryCode == Country.INDIA
}

private var uiModelsState by mutableStateOf<List<OverdueUiModel>>(emptyList())

override fun defaultModel() = OverdueModel.create()

override fun bindView(layoutInflater: LayoutInflater, container: ViewGroup?) =
ScreenOverdueBinding.inflate(layoutInflater, container, false)

override fun uiRenderer() = OverdueUiRenderer(ui = this)

private val composeUiEvents = PublishSubject.create<OverdueEvent>()

override fun events() = Observable.mergeArray(
overdueListAdapter.itemEvents,
downloadOverdueListClicks(),
shareOverdueListClicks(),
clearSelectedOverdueAppointmentClicks()
clearSelectedOverdueAppointmentClicks(),
composeUiEvents,
)
.compose(RequestPermissions(runtimePermissions, screenResults.streamResults().ofType()))
.compose(runtimeNetworkStatus::apply)
Expand Down Expand Up @@ -218,12 +198,38 @@ class OverdueScreen : BaseScreen<

buttonsFrame.applyInsetsBottomPadding()

overdueRecyclerView.adapter = overdueListAdapter
overdueRecyclerView.layoutManager = LinearLayoutManager(context)
composeView.apply {
setViewCompositionStrategy(
ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
)
setContent {
OverdueAppointmentListItem(
uiModels = uiModelsState,
onCallClicked = { patientId ->
composeUiEvents.onNext(CallPatientClicked(patientId))
},
onRowClicked = { patientId ->
composeUiEvents.onNext(OverduePatientClicked(patientId))
},
onCheckboxClicked = { appointmentUuid ->
composeUiEvents.onNext(OverdueAppointmentCheckBoxClicked(appointmentUuid))
},
onSearch = {
composeUiEvents.onNext(OverdueSearchButtonClicked)
},
onSectionHeaderClick = { overdueAppointmentSectionTitle ->
composeUiEvents.onNext(ChevronClicked(overdueAppointmentSectionTitle))
},
onSectionFooterClick = {
composeUiEvents.onNext(PendingListFooterClicked)
}
)
}
}
}


override fun onDestroyView() {
overdueRecyclerView.adapter = null
disposable.clear()
super.onDestroyView()
}
Expand Down Expand Up @@ -267,7 +273,7 @@ class OverdueScreen : BaseScreen<
selectedOverdueAppointments: Set<UUID>,
overdueListSectionStates: OverdueListSectionStates
) {
overdueListAdapter.submitList(OverdueAppointmentListItem.from(
uiModelsState = OverdueUiModelMapper.from(
overdueAppointmentSections = overdueAppointmentSections,
clock = userClock,
pendingListDefaultStateSize = pendingAppointmentsConfig.pendingListDefaultStateSize,
Expand All @@ -277,7 +283,8 @@ class OverdueScreen : BaseScreen<
selectedOverdueAppointments = selectedOverdueAppointments,
isPatientReassignmentFeatureEnabled = features.isEnabled(PatientReassignment),
locale = locale,
))
)

if (isOverdueListDownloadAndShareEnabled) {
buttonsFrame.visibility = View.VISIBLE
}
Expand Down Expand Up @@ -316,11 +323,11 @@ class OverdueScreen : BaseScreen<
}

override fun showOverdueRecyclerView() {
overdueRecyclerView.visibility = View.VISIBLE
composeView.visibility = View.VISIBLE
}

override fun hideOverdueRecyclerView() {
overdueRecyclerView.visibility = View.GONE
composeView.visibility = View.GONE
}

override fun openOverdueSearch() {
Expand Down
Loading
Loading