Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
1144fdb
change history entity added
Nikunjsharma0 Mar 12, 2026
a4d299c
data source added
Nikunjsharma0 Mar 15, 2026
631371f
commit
Nikunjsharma0 Mar 16, 2026
72988d6
Added test for change history
poojaustad Mar 16, 2026
2518430
Added test for change history
poojaustad Mar 16, 2026
6969254
commit
Nikunjsharma0 Mar 17, 2026
6a9ca60
update test with a name change from "TeacherA" to "TeacherB".
poojaustad Mar 17, 2026
bcc8ca9
Merge remote-tracking branch 'origin/change-history' into change-history
poojaustad Mar 17, 2026
b3632c3
commit
Nikunjsharma0 Mar 17, 2026
c51aff2
Merge remote-tracking branch 'origin/change-history' into change-history
Nikunjsharma0 Mar 17, 2026
34267a3
Updated first name placeholder text in Maestro flow
poojaustad Mar 18, 2026
9a46003
Merge branch 'refs/heads/main' into change-history
Nikunjsharma0 Mar 18, 2026
e78bbb2
Merge remote-tracking branch 'origin/change-history' into change-history
poojaustad Mar 18, 2026
fa95812
Merge remote-tracking branch 'origin/change-history' into change-history
Nikunjsharma0 Mar 18, 2026
52c1d6f
Update label to "First names*" in invite users Maestro test flow.
poojaustad Mar 23, 2026
c7adda4
Update Maestro test flow for inviting users to include verification o…
poojaustad Mar 23, 2026
836f221
commit
Nikunjsharma0 Mar 24, 2026
6bf73b2
Merge branch 'main' into change-history
Nikunjsharma0 Mar 24, 2026
0b76e18
commit
Nikunjsharma0 Mar 25, 2026
5636c41
commit
Nikunjsharma0 Mar 25, 2026
32d855e
commit
Nikunjsharma0 Mar 25, 2026
e422c2d
commit
Nikunjsharma0 Mar 25, 2026
f3cf255
commit
Nikunjsharma0 Mar 26, 2026
f98536e
commit
Nikunjsharma0 Mar 26, 2026
da0a66d
commit
Nikunjsharma0 Mar 27, 2026
f5dddb9
commit
Nikunjsharma0 Mar 31, 2026
8f655bf
Merge branch 'main' into change-history-backup
Nikunjsharma0 Apr 1, 2026
06031a5
Merge branch 'main' into change-history-backup
Nikunjsharma0 Apr 6, 2026
0336cc0
commit
Nikunjsharma0 Apr 6, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,28 @@ onFlowComplete:
text: "Apps"
- assertVisible: "Apps"
- assertVisible: "Assignments"
- assertVisible: "People"
- tapOn: "People"
- tapOn: "TeacherA User"
- tapOn:
id: "floating_action_button"
- tapOn: "First names*"
- runFlow:
file: "subflows/erase_text.yaml"
env:
TEXT: "First names*"
- inputText: "TeacherB"
- tapOn: "Date of birth"
- runScript:
file: "scripts/setDate.js"
- inputText: ${output.pastYearDateC}
- tapOn: "Save"
- tapOn: "Change History"
- assertVisible:
id: "app_title"
text: "Change History"
- assertVisible: 'Person name changed from "TeacherA User" to "TeacherB User"'
- runFlow:
file: "subflows/admin_add_class.yaml"
file: "subflows/add_class.yaml"
env:
CLASSNAME: "New Class"
- assertVisible:
Expand Down Expand Up @@ -199,6 +218,23 @@ onFlowComplete:
- assertVisible: "Pending requests.*"
- assertVisible: "Student User.*"
- tapOn: "Accept Invite"
- assertNotVisible: "Pending requests.*"
- tapOn: "Change History"
- assertVisible:
id: "app_title"
text: "Change History"
- assertVisible: 'Join request approved for "Student User"'
- tapOn: "People"
- tapOn: "TeacherB User"
- tapOn: "Change History"
- assertVisible:
id: "app_title"
text: "Change History"
- assertVisible: 'Person name changed from "TeacherA User" to "TeacherB User"'
- back
- back
- tapOn: "Classes"
- tapOn: "New Class"

# E) Teacher share invite link for parent device based signup
- tapOn: "Add student"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ import world.respect.credentials.passkey.request.GetPasskeyProviderInfoUseCase
import world.respect.credentials.password.SavePasswordUseCaseAndroidImpl
import world.respect.datalayer.AuthTokenProvider
import world.respect.datalayer.AuthenticatedUserPrincipalId
import world.respect.datalayer.ChangeHistoryProvider
import world.respect.datalayer.ChangeHistoryMarkSentToServer
import world.respect.datalayer.RespectAppDataSource
import world.respect.datalayer.SchoolDataSource
import world.respect.datalayer.SchoolDataSourceLocal
Expand All @@ -66,6 +68,8 @@ import world.respect.datalayer.db.RespectSchoolDatabase
import world.respect.datalayer.db.SchoolDataSourceDb
import world.respect.datalayer.db.addCommonMigrations
import world.respect.datalayer.db.networkvalidation.ExtendedDataSourceValidationHelperImpl
import world.respect.datalayer.db.school.ChangeHistoryProviderDb
import world.respect.datalayer.db.school.ChangeHistoryMarkSentToServerDb
import world.respect.datalayer.db.school.GetAuthenticatedPersonUseCase
import world.respect.datalayer.db.school.domain.CheckPersonPermissionUseCaseDbImpl
import world.respect.datalayer.db.school.writequeue.RemoteWriteQueueDbImpl
Expand Down Expand Up @@ -235,6 +239,7 @@ import world.respect.shared.viewmodel.person.setusernameandpassword.CreateAccoun
import world.respect.shared.viewmodel.person.setusernameandpassword.CreateAccountSetUserNameViewModel
import world.respect.shared.viewmodel.schooldirectory.edit.SchoolDirectoryEditViewModel
import world.respect.shared.viewmodel.schooldirectory.list.SchoolDirectoryListViewModel
import world.respect.shared.viewmodel.apps.changehistory.ChangeHistoryViewModel
import world.respect.shared.domain.sharelink.LaunchSendEmailUseCase
import world.respect.shared.domain.sharelink.LaunchShareLinkUseCase
import world.respect.shared.domain.sharelink.LaunchSendSmsUseCase
Expand Down Expand Up @@ -384,6 +389,7 @@ val appKoinModule = module {
viewModelOf(::EnrollmentEditViewModel)
viewModelOf(::InviteQrViewModel)
viewModelOf(::CreateAccountSetPasswordViewModel)
viewModelOf(::ChangeHistoryViewModel)


single<GetOfflineStorageOptionsUseCase> {
Expand Down Expand Up @@ -899,7 +905,17 @@ val appKoinModule = module {
defaultAppCatalogUrl = RespectBuildConfig.RESPECT_DEFAULT_APPLIST,
)
}

scoped<ChangeHistoryProvider> {
ChangeHistoryProviderDb(
schoolDb = get(),
)
}
scoped<ChangeHistoryMarkSentToServer> {
ChangeHistoryMarkSentToServerDb(
schoolDb = get(),
uidNumberMapper = get(),
)
}
scoped<SchoolDataSource> {
val schoolUrl = get<RespectAccountSchoolScopeLink>()
val localDs = get<SchoolDataSourceLocal>()
Expand All @@ -916,7 +932,9 @@ val appKoinModule = module {
defaultAppCatalogUrl = RespectBuildConfig.RESPECT_DEFAULT_APPLIST,
opdsFeedValidationHelper = localDs.opdsFeedDataSource,
opdsPublicationValidationHelper = localDs.opdsPublicationDataSource
.publicationNetworkValidationHelper
.publicationNetworkValidationHelper,
changeHistoryProvider = get(),
markSentToServer = get(),
),
validationHelper = get(),
remoteWriteQueue = get(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import world.respect.app.view.acknowledgement.AcknowledgementScreen
import world.respect.app.view.apps.changehistory.ChangeHistoryScreen
import world.respect.app.view.apps.detail.AppsDetailScreen
import world.respect.app.view.apps.enterlink.EnterLinkScreen
import world.respect.app.view.apps.launcher.AppLauncherScreen
Expand Down Expand Up @@ -73,6 +74,7 @@ import world.respect.shared.navigation.ClazzDetail
import world.respect.shared.navigation.ClazzEdit
import world.respect.shared.navigation.ClazzList
import world.respect.shared.navigation.AcceptInvite
import world.respect.shared.navigation.ChangeHistory
import world.respect.shared.navigation.CopyCode
import world.respect.shared.navigation.CreateAccount
import world.respect.shared.navigation.CreateAccountSetPassword
Expand Down Expand Up @@ -655,6 +657,15 @@ fun AppNavHost(
)
)
}

composable<ChangeHistory> {
ChangeHistoryScreen(
viewModel = respectViewModel(
onSetAppUiState = onSetAppUiState,
navController = respectNavController,
)
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package world.respect.app.view.apps.changehistory

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlinx.datetime.TimeZone
import org.jetbrains.compose.resources.stringResource
import world.respect.datalayer.db.school.ext.fullName
import world.respect.datalayer.school.model.ChangeHistoryFieldEnum
import world.respect.shared.generated.resources.Res
import world.respect.shared.generated.resources.change_format
import world.respect.shared.util.rememberFormattedDateTime
import world.respect.shared.viewmodel.apps.changehistory.ChangeHistoryUiState
import world.respect.shared.viewmodel.apps.changehistory.ChangeHistoryViewModel

@Composable
fun ChangeHistoryScreen(
viewModel: ChangeHistoryViewModel,
) {
val uiState by viewModel.uiState.collectAsState()

ChangeHistoryScreen(
uiState = uiState
)

}

@Composable
fun ChangeHistoryScreen(
uiState: ChangeHistoryUiState,
) {
val changeHistoryEntryWithWhoDid = uiState.changeHistoryEntryWithWhoDid ?: return

Column(
modifier = Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(16.dp)
) {

changeHistoryEntryWithWhoDid.forEach { group ->

group.changeHistoryEntry.forEach { entry ->

entry.changes.forEach { change ->

Text(
text = group.person.fullName(),
)
val createdAtStr = rememberFormattedDateTime(
timeInMillis = change.lastModified.toEpochMilliseconds(),
timeZoneId = TimeZone.currentSystemDefault().id,
)

Text(text = createdAtStr)
val text = when (change.field) {

ChangeHistoryFieldEnum.JOIN_REQUEST_APPROVED ->
"${change.field.displayName} \"${change.newVal}\""

ChangeHistoryFieldEnum.JOIN_REQUEST_REJECTED ->
"${change.field.displayName} \"${change.oldVal}\""

ChangeHistoryFieldEnum.CLASS_TEACHER_ADDED,
ChangeHistoryFieldEnum.CLASS_STUDENT_ADDED ->
"${change.field.displayName}: \"${change.newVal}\""

ChangeHistoryFieldEnum.CLASS_TEACHER_REMOVED,
ChangeHistoryFieldEnum.CLASS_STUDENT_REMOVED ->
"${change.field.displayName}: \"${change.newVal}\""

else ->
stringResource(
Res.string.change_format,
change.field.displayName,
change.oldVal ?: "",
change.newVal
)
}

Text(text = text)
Spacer(modifier = Modifier.height(16.dp))

}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,13 @@ import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.IconButton
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.Replay
import androidx.compose.material3.HorizontalDivider
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import world.respect.app.components.RespectQuickActionButton
import world.respect.shared.generated.resources.change_history
import world.respect.shared.generated.resources.manage_enrollments
import world.respect.shared.generated.resources.more_options
import world.respect.shared.generated.resources.remove_from_class
Expand All @@ -83,6 +87,7 @@ fun ClazzDetailScreen(
onTogglePendingSection = viewModel::onTogglePendingSection,
onToggleTeachersSection = viewModel::onToggleTeachersSection,
onToggleStudentsSection = viewModel::onToggleStudentsSection,
onClickChangeHistoryButton = viewModel::onClickChangeHistoryButton,
onClickRemovePersonFromClass = viewModel::onClickRemovePersonFromClass,
onClickManageEnrollments = viewModel::onClickManageEnrollments,
onClickPerson = viewModel::onClickPerson,
Expand All @@ -97,6 +102,7 @@ fun ClazzDetailScreen(
onSelectChip: (String) -> Unit,
onClickAcceptInvite: (Person) -> Unit,
onClickDismissInvite: (Person) -> Unit,
onClickChangeHistoryButton: () -> Unit,
onTogglePendingSection: () -> Unit,
onToggleTeachersSection: () -> Unit,
onToggleStudentsSection: () -> Unit,
Expand Down Expand Up @@ -141,6 +147,16 @@ fun ClazzDetailScreen(
}
)
}
item {
HorizontalDivider()
RespectQuickActionButton(
labelText = stringResource(Res.string.change_history),
imageVector = Icons.Default.Replay,
onClick = onClickChangeHistoryButton,
)
HorizontalDivider()
}


item {
RespectListSortHeader(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Key
import androidx.compose.material.icons.filled.Replay
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
Expand All @@ -30,6 +31,7 @@ import world.respect.shared.generated.resources.email
import world.respect.shared.generated.resources.family_members
import world.respect.shared.generated.resources.gender
import world.respect.shared.generated.resources.manage_account
import world.respect.shared.generated.resources.change_history
import world.respect.shared.generated.resources.phone_number
import world.respect.shared.generated.resources.role
import world.respect.shared.generated.resources.username_label
Expand All @@ -47,6 +49,7 @@ fun PersonDetailScreen(
onClickManageAccount = viewModel::navigateToManageAccount,
onClickCreateAccount = viewModel::onClickCreateAccount,
onClickPhoneNumber = viewModel::onClickPhoneNumber,
onClickChangeHistoryButton = viewModel::onClickChangeHistoryButton,
onClickFamilyMember = viewModel::onClickFamilyMember
)
}
Expand All @@ -56,6 +59,7 @@ fun PersonDetailScreen(
uiState: PersonDetailUiState,
onClickManageAccount:() -> Unit,
onClickCreateAccount: () -> Unit,
onClickChangeHistoryButton: () -> Unit,
onClickPhoneNumber: () -> Unit,
onClickFamilyMember: (String) -> Unit,
) {
Expand All @@ -80,6 +84,11 @@ fun PersonDetailScreen(
onClick = onClickCreateAccount,
)
}
RespectQuickActionButton(
labelText = stringResource(Res.string.change_history),
imageVector = Icons.Default.Replay,
onClick = onClickChangeHistoryButton,
)
}

HorizontalDivider()
Expand Down
2 changes: 2 additions & 0 deletions respect-datalayer-db/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ kotlin {
api(libs.androidx.paging.common)
api(libs.androidx.room.paging)
implementation(libs.napier)
implementation(libs.koin.core)
implementation(project.dependencies.platform(libs.koin.bom))

}

Expand Down
Loading