{
  "_class" : "hudson.model.FreeStyleBuild",
  "actions" : [
    {
      "_class" : "hudson.model.CauseAction",
      "causes" : [
        {
          "_class" : "hudson.triggers.TimerTrigger$TimerTriggerCause",
          "shortDescription" : "Started by timer"
        }
      ]
    },
    {
      
    },
    {
      "_class" : "hudson.plugins.git.util.BuildData",
      "buildsByBranchName" : {
        "refs/remotes/origin/main" : {
          "_class" : "hudson.plugins.git.util.Build",
          "buildNumber" : 45,
          "buildResult" : None,
          "marked" : {
            "SHA1" : "beec082677ecfe343236c083f1545d158453e63f",
            "branch" : [
              {
                "SHA1" : "beec082677ecfe343236c083f1545d158453e63f",
                "name" : "refs/remotes/origin/main"
              }
            ]
          },
          "revision" : {
            "SHA1" : "beec082677ecfe343236c083f1545d158453e63f",
            "branch" : [
              {
                "SHA1" : "beec082677ecfe343236c083f1545d158453e63f",
                "name" : "refs/remotes/origin/main"
              }
            ]
          }
        },
        "refs/remotes/origin/dev-xapi-ipc" : {
          "_class" : "hudson.plugins.git.util.Build",
          "buildNumber" : 9,
          "buildResult" : None,
          "marked" : {
            "SHA1" : "35548db75de85c0441a83620284c3f99155699c1",
            "branch" : [
              {
                "SHA1" : "35548db75de85c0441a83620284c3f99155699c1",
                "name" : "refs/remotes/origin/dev-xapi-ipc"
              }
            ]
          },
          "revision" : {
            "SHA1" : "35548db75de85c0441a83620284c3f99155699c1",
            "branch" : [
              {
                "SHA1" : "35548db75de85c0441a83620284c3f99155699c1",
                "name" : "refs/remotes/origin/dev-xapi-ipc"
              }
            ]
          }
        }
      },
      "lastBuiltRevision" : {
        "SHA1" : "beec082677ecfe343236c083f1545d158453e63f",
        "branch" : [
          {
            "SHA1" : "beec082677ecfe343236c083f1545d158453e63f",
            "name" : "refs/remotes/origin/main"
          }
        ]
      },
      "remoteUrls" : [
        "https://github.com/UstadMobile/Respect.git"
      ],
      "scmName" : ""
    },
    {
      
    },
    {
      
    },
    {
      
    },
    {
      
    },
    {
      
    },
    {
      "_class" : "org.jenkinsci.plugins.displayurlapi.actions.RunDisplayAction"
    }
  ],
  "artifacts" : [
    {
      "displayPath" : "respect-cli-1.0.34a.zip",
      "fileName" : "respect-cli-1.0.34a.zip",
      "relativePath" : "respect-cli/build/distributions/respect-cli-1.0.34a.zip"
    },
    {
      "displayPath" : "respect-server-1.0.34a.zip",
      "fileName" : "respect-server-1.0.34a.zip",
      "relativePath" : "respect-server/build/distributions/respect-server-1.0.34a.zip"
    },
    {
      "displayPath" : "respect-server-shadow-1.0.34a.zip",
      "fileName" : "respect-server-shadow-1.0.34a.zip",
      "relativePath" : "respect-server/build/distributions/respect-server-shadow-1.0.34a.zip"
    }
  ],
  "building" : False,
  "description" : None,
  "displayName" : "#45",
  "duration" : 156065,
  "estimatedDuration" : 159136,
  "executor" : None,
  "fullDisplayName" : "RESPECT-Primary-MavenPublish #45",
  "id" : "45",
  "inProgress" : False,
  "keepLog" : False,
  "number" : 45,
  "queueId" : 10861,
  "result" : "SUCCESS",
  "timestamp" : 1785481320420,
  "url" : "https://devserver3.ustadmobile.com/jenkins/job/RESPECT-Primary-MavenPublish/45/",
  "builtOn" : "",
  "changeSet" : {
    "_class" : "hudson.plugins.git.GitChangeSetList",
    "items" : [
      {
        "_class" : "hudson.plugins.git.GitChangeSet",
        "affectedPaths" : [
          "README.md"
        ],
        "commitId" : "97ac20242d7390216f788048a1b7854592ce390c",
        "timestamp" : 1785405360000,
        "author" : {
          "absoluteUrl" : "https://devserver3.ustadmobile.com/jenkins/user/noreply",
          "fullName" : "noreply"
        },
        "authorEmail" : "noreply@github.com",
        "comment" : "Update README.md\u000a\u000aUpdate README.md to specify using the latest stable channel version of Android Studio\u000a",
        "date" : "2026-07-30 13:56:00 +0400",
        "id" : "97ac20242d7390216f788048a1b7854592ce390c",
        "msg" : "Update README.md",
        "paths" : [
          {
            "editType" : "edit",
            "file" : "README.md"
          }
        ]
      },
      {
        "_class" : "hudson.plugins.git.GitChangeSet",
        "affectedPaths" : [
          "respect-lib-shared/src/commonMain/composeResources/values/strings.xml",
          "app-android/src/main/kotlin/world/respect/AppKoinModule.kt",
          "respect-datalayer-db/schemas/world.respect.datalayer.db.RespectAppDatabase/6.json",
          "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/viewmodel/apps/detail/AppsDetailViewModel.kt",
          ".maestro/flows/002_001_browse_lessons_test.yaml",
          ".maestro/flows/001_002_add_user_direct_test.yaml",
          "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/viewmodel/apps/launcher/AppLauncherViewModel.kt",
          ".maestro/flows/003_admin_user_assigns_assignment_to_a_class_test.yaml",
          ".maestro/flows/002_002_browse_demo_app_test.yaml",
          "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/domain/geticonforxapiactivity/GetPublicationForXapiActivityUseCase.kt",
          "respect-lib-xapi-core/src/commonMain/kotlin/world/respect/lib/xapi/model/XapiVerb.kt",
          "respect-app-compose/src/androidMain/kotlin/world/respect/shared/domain/license/GetLicenseLabelUseCaseAndroid.kt",
          "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/navigation/AppRoutes.kt",
          "respect-lib-shared/src/androidMain/kotlin/world/respect/shared/domain/launchapp/LaunchAppUseCaseAndroid.kt",
          "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/util/CommonSortOptions.kt",
          "respect-datalayer-db/schemas/world.respect.datalayer.db.RespectAppDatabase/5.json",
          "respect-server/src/main/kotlin/world/respect/server/demoapp/DemoLaunchableAppManifestRoute.kt",
          ".maestro/flows/001_001_invite_users_using_qr_code_or_link_test.yaml",
          "respect-lib-shared/src/commonMain/composeResources/drawable/no_bookmark.xml",
          "respect-server/src/main/resources/http/respect-ds/case_valid/js/xapi_statement_maker.js",
          "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/domain/bookmark/AddBookmarkUseCase.kt",
          "respect-app-compose/src/commonMain/kotlin/world/respect/app/app/AppNavHost.kt",
          "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/domain/license/GetLicenseLabelUseCase.kt",
          "respect-app-compose/src/commonMain/kotlin/world/respect/app/view/bookmark/BookmarkListScreen.kt",
          "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/viewmodel/learningunit/detail/LearningUnitDetailViewModel.kt",
          "respect-app-compose/src/commonMain/kotlin/world/respect/app/view/learningunit/list/LearningUnitListScreen.kt",
          "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/domain/bookmark/RemoveBookmarkUseCase.kt",
          "respect-lib-xapi-core/src/commonMain/kotlin/world/respect/lib/xapi/OpenEelXapiConstants.kt",
          "respect-server/src/main/resources/http/respect-ds/case_valid/examples/statementmaker/index.html",
          "respect-app-compose/src/commonMain/kotlin/world/respect/app/view/learningunit/detail/LearningUnitDetailScreen.kt",
          ".maestro/flows/001_003_login_using_school_link_test.yaml",
          "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/viewmodel/app/appstate/Snack.kt",
          ".maestro/flows/subflows/admin_add_app.yaml",
          "respect-app-compose/src/commonMain/kotlin/world/respect/app/app/App.kt",
          "respect-app-compose/src/androidMain/kotlin/world/respect/WebViewActivity.kt",
          "respect-app-compose/src/commonMain/kotlin/world/respect/app/view/learningunit/list/PublicationListItem.kt",
          "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/viewmodel/bookmark/BookmarkListViewModel.kt",
          "respect-app-compose/src/commonMain/kotlin/world/respect/app/view/home/HomeScreen.kt"
        ],
        "commitId" : "beec082677ecfe343236c083f1545d158453e63f",
        "timestamp" : 1785408254000,
        "author" : {
          "absoluteUrl" : "https://devserver3.ustadmobile.com/jenkins/user/noreply",
          "fullName" : "noreply"
        },
        "authorEmail" : "noreply@github.com",
        "comment" : "Dev bookmark xapi (#272)\u000a\u000a* Add bookmark button to lesson details\u000a\u000a* Add bookmark functionality for learning units\u000a\u000aKey changes include:\u000a- Updating the `OpdsDataSource` interface and its implementations (`OpdsDataSourceRepository`, `OpdsDataSourceDb`) to handle observing and setting bookmark status.\u000a- Adding a `BookmarkEntity` and `BookmarkDao` to the database schema to persist bookmark state.\u000a- Implementing the bookmark logic in the `LearningUnitDetailViewModel`, which now observes and updates the bookmark status.\u000a- The bookmark button in `LearningUnitDetailScreen` now dynamically changes its icon based on whether the unit is bookmarked.\u000a\u000a* feat: Add bookmark data layer\u000a\u000aIntroduced the data layer components required for managing publication bookmarks.\u000a\u000aThis includes:\u000a- A `BookmarkEntity` to store bookmark status and timestamp.\u000a- A `BookmarkDao` with functions to insert/update bookmarks, observe a single bookmark's status, and retrieve all bookmarked publications.\u000a- An implementation in `OpdsDataSourceDb` to get a flow of bookmarked `OpdsPublication` objects.\u000a- An update to `ReadiumLinkEntityDao` to find all links associated with a publication UID.\u000a\u000a* feat: Implement fetching of bookmarked publications\u000a\u000aThis commit introduces the functionality to retrieve a list of all bookmarked publications from the local database.\u000a\u000aKey changes:\u000a\u000a-   Added `getBookmarkedPublications()` to the `OpdsDataSource` interface.\u000a-   Implemented the new function in `OpdsDataSourceRepository` to delegate the call to the local data source.\u000a-   In `OpdsDataSourceDb`, the implementation now fetches bookmarked publication entities from `BookmarkDao` and maps them to `OpdsPublication` models.\u000a-   Updated the `OpdsDataSourceHttp` stub to include the new interface method.\u000a\u000a* feat: Store title and timestamp for bookmarks\u000a\u000aThis change enhances the bookmarking functionality by storing the title of the bookmarked item and implicitly tracking when it was last updated.\u000a\u000aKey changes include:\u000a- Updating the `setBookmarkStatus` function across the `OpdsDataSource` interface and its implementations (`OpdsDataSourceDb`, `OpdsDataSourceRepository`, `OpdsDataSourceHttp`) to accept a `title` parameter.\u000a- Modifying the `BookmarkDao` to no longer retrieve `OpdsPublicationEntity` objects directly. Instead, a new `observeAllBookmarks` function returns a flow of `BookmarkEntity` objects, ordered by their update timestamp.\u000a- The `LearningUnitDetailViewModel` now passes the lesson title when setting the bookmark status.\u000a- The `OpdsDataSourceDb` was updated to implement these DAO changes and now provides a `getAllBookmarks` function.\u000a\u000a* Implement fetching of all bookmarks\u000aThis commit introduces the functionality to retrieve a list of all bookmarks.\u000a\u000a* Display app name and icon on learning unit detail screen\u000a\u000a* Store subtitle and app icon for bookmarks\u000a\u000a* Store subtitle and app icon for bookmarks\u000a\u000a* Improve code formatting in OpdsDataSourceDb\u000a\u000a* Improve code formatting in OpdsDataSourceDb\u000a\u000a* Implement bookmark list screen\u000a\u000a* Implement bookmark list screen\u000a\u000a* Implement bookmark list screen\u000a\u000a* Implement bookmark list screen\u000a\u000a* Implement bookmark list screen\u000a\u000a* Implement bookmark list screen\u000a\u000a* Refactor bookmarking logic to toggle status\u000a\u000aThis commit refactors the bookmarking functionality. Instead of explicitly passing a boolean to set the bookmark status, the `setBookmarkStatus` function now toggles the state. If a bookmark exists, it's removed; otherwise, a new one is created.\u000a\u000aThis change simplifies the bookmarking logic across the data layers and the view model. Additionally, the bookmark list screen now allows for the removal of bookmarks.\u000a\u000a* Refactor bookmarking logic to toggle status\u000a\u000aThis commit refactors the bookmarking functionality. Instead of explicitly passing a boolean to set the bookmark status, the `setBookmarkStatus` function now toggles the state. If a bookmark exists, it's removed; otherwise, a new one is created.\u000a\u000aThis change simplifies the bookmarking logic across the data layers and the view model. Additionally, the bookmark list screen now allows for the removal of bookmarks.\u000a\u000a* Delete respect-datalayer-db/schemas/world.respect.datalayer.db.RespectAppDatabase/2.json\u000a\u000a* Refactor bookmarking logic to toggle status\u000a\u000aThis commit refactors the bookmarking functionality. Instead of explicitly passing a boolean to set the bookmark status, the `setBookmarkStatus` function now toggles the state. If a bookmark exists, it's removed; otherwise, a new one is created.\u000a\u000aThis change simplifies the bookmarking logic across the data layers and the view model. Additionally, the bookmark list screen now allows for the removal of bookmarks.\u000a\u000a* Refactor bookmarking logic to toggle status\u000a\u000a* Refactor: Enhance bookmark data and enable navigation\u000a\u000a* Seperation of bookmark implementation\u000a\u000a* Seperation of bookmark implementation\u000a\u000a* Update bookmark data model to include learning unit URL\u000a\u000a* Update bookmark\u000a\u000a* Move bookmarking logic from respect app data source to school data source\u000a\u000a* Update bookmark logic to use enum to delete\u000a\u000a* Rename bookmark observation methods to getBookmarkStatus and getAllBookmarks\u000a\u000a* Rename bookmark observation methods to getBookmarkStatus and getAllBookmarks\u000a\u000a* Refactor bookmarking logic to use Bookmark model and toggle status\u000a\u000a* Refactor bookmarking logic to use Bookmark model and toggle status\u000a\u000a* Refactor bookmarking logic to use Bookmark model and toggle status\u000a\u000a* Refactor bookmarking logic to use Bookmark model and toggle status\u000a\u000a* Rename Bookmark field learningUnitUrl to learningUnitManifestUrl\u000a\u000aThis commit renames the `learningUnitUrl` property in the `Bookmark` data class to `learningUnitManifestUrl` for better clarity and consistency with other parts of the codebase.\u000a\u000aThe changes include:\u000a- Updating the `Bookmark` model definition.\u000a- Updating the `BookmarkAdapter` mapping logic to reflect the rename.\u000a- Adjusting usages in `LearningUnitDetailViewModel` and `BookmarkListViewModel`.\u000a- Updating the database access logic in `BookmarkDataSourceDb`.\u000a- Cleaning up unused imports.\u000a\u000a* Rename Bookmark field learningUnitUrl to learningUnitManifestUrl\u000a\u000a* Added playlist test\u000a\u000a* Move bookmark-related database components to the school package\u000a\u000a* Move bookmark-related database components to the school package\u000a\u000a* Added bookmark test\u000a\u000a* Add user identification to bookmark database components\u000a\u000a* Add user identification to bookmark database components\u000a\u000a* Add user identification to bookmark database components\u000a\u000a* Update bookmark storage logic\u000a\u000a* Implement bookmark toggling and update database components\u000a\u000a* Refactor bookmark data layer to use unique identifiers and timestamps\u000a\u000a* Refactor bookmark data layer to use composite primary keys and remove UID generation logic\u000a\u000a* Refactor bookmark data layer to use composite primary keys and remove UID generation logic\u000a\u000a* Clean up code and refactor bookmark icon logic\u000a\u000a* Implement bookmark data layer including HTTP, DB, and Repository components\u000a\u000a* Update Bookmark model and data layer to support titles, subtitles, and images.\u000a\u000a- Add `title`, `subtitle`, and `imageUrl` properties to the `Bookmark` model.\u000a- Implement `BookmarkEntities` and `PublicationWithDetails` in the DB layer to handle relational data for bookmarks and OPDS publications.\u000a- Update `BookmarkDao` and `BookmarkDataSourceDb` to return bookmarks with their associated publication details.\u000a- Refactor `BookmarkListScreen` to display bookmark images and text content.\u000a- Add navigation logic to `AppLauncherViewModel` for navigating to the bookmark list.\u000a- Minor clean up and documentation updates in OPDS and Bookmark entities.\u000a\u000a* Remove title, subtitle, and image fields from Bookmark model and DAO logic\u000a\u000a* Add localized title support to bookmarks and update database relations\u000a\u000a* Refactor LearningUnitDetailViewModel and clean up unused imports and whitespace.\u000a\u000a* Update Bookmark model and data layer to include subtitles and improve app detail handling in LearningUnitDetailScreen.\u000a\u000a* Remove properties\u000a\u000a* Update BookmarkListViewModel to use LoadingUiState and clean up imports\u000a\u000a* Update BookmarkListViewModel to use LoadingUiState and clean up imports\u000a\u000a* Update BookmarkListViewModel to use LoadingUiState and clean up imports\u000a\u000a* Update BookmarkListViewModel to use LoadingUiState and clean up imports\u000a\u000a* Clean up formatting in BookmarkDao\u000a\u000a* Clean up formatting in BookmarkAdapter.kt\u000a\u000a* Clean up\u000a\u000a* Clean up\u000a\u000a* Clean up\u000a\u000a* Clean up LearningUnitDetailViewModel constructor and improve code formatting\u000a\u000a* Add image URL support to Bookmark model and UI components\u000a\u000a* Add BookmarkEntity to database schema and implement navigation to bookmark list from app launcher.\u000a\u000a* Add BookmarkEntity to database schema and implement navigation to bookmark list from app launcher.\u000a\u000a* Add BookmarkEntity to database schema and implement navigation to bookmark list from app launcher.\u000a\u000a* Added lesson002 and updated test\u000a\u000a* Implement bookmark navigation and fix data synchronization in BookmarkListViewModel\u000a\u000a* Update bookmark implementation to include application manifest URLs and app metadata.\u000a\u000a* commented bookmark code for playlist screen\u000a\u000a* commented bookmark code for playlist screen\u000a\u000a* Update bookmark implementation to include application manifest URLs and app metadata.\u000a\u000a* Update bookmark data layer, database entities, and cleanup ViewModel logic\u000a\u000a* Rename findBookmarks to findBookmarksWithMissingPublication and update loading logic in BookmarkListViewModel\u000a\u000a* Implement getBookmarkLastModified and findByUidList in BookmarkDao and BookmarkDataSourceDb\u000a\u000a* Register Bookmark components in RespectSchoolDatabase and update OPDS package imports\u000a\u000a* Register Bookmark components in RespectSchoolDatabase and update OPDS package imports\u000a\u000a* Add language, grade, and type fields to Bookmark model and display them in BookmarkListScreen\u000a\u000a* Update navigation labels to \"Home\" and integrate BookmarkListScreen into HomeScreen\u000a\u000a- Rename \"Apps\" navigation label to \"Home\" across `App.kt`, `AppLauncherViewModel`, and `BookmarkListViewModel`.\u000a- Update `HomeScreen` to include a new \"Bookmarks\" tab alongside the existing \"Apps\" tab.\u000a- Refactor `BookmarkListScreen` UI: remove redundant styling boxes/borders around icons and adjust icon sizing.\u000a- Update `strings.xml` to include new \"home\" and \"bookmarks\" resources and update the bookmark empty state message.\u000a- Update Maestro flow test to reflect UI text changes.\u000a\u000a* Update navigation labels to \"Home\" and integrate BookmarkListScreen into HomeScreen\u000a\u000a* Add NO_BOOKMARK to RespectImage and update EmptyBookmarkState UI in BookmarkListScreen\u000a\u000a* Add NO_BOOKMARK to RespectImage and update EmptyBookmarkState UI in BookmarkListScreen\u000a\u000a* Add NO_BOOKMARK to RespectImage and update EmptyBookmarkState UI in BookmarkListScreen\u000a\u000a* Add NO_BOOKMARK to RespectImage and update EmptyBookmarkState UI in BookmarkListScreen\u000a\u000a* Update UI layout and styling in BookmarkListScreen.kt\u000a\u000a* Update UI layout and styling in BookmarkListScreen.kt\u000a\u000a* Move no_bookmark image to shared resources and update BookmarkListScreen usage\u000a\u000a* Implement `listAsFlow` in `BookmarkDataSource` and update `BookmarkListViewModel` to reactive flow\u000a\u000aInstead Of using Paging Source I am using List as Flow because-App loading per item getting messy with paging\u000a\u000a* Implement paging support for BookmarkDataSource across DB, HTTP, and Repository layers\u000a\u000a* Remove redundant comments in BookmarkListViewModel\u000a\u000a* Introduce `BookmarkDetails` to associate bookmarks with their corresponding application data and refactor `BookmarkListViewModel` to load these details concurrently.\u000a\u000a* Update Maestro flows\u000a\u000a* test - update Maestro flow for lesson browsing\u000a\u000a* Update Maestro test flows\u000a\u000a*   **002_browse_lessons_test.yaml**: Updated the \"Bookmark\" tap index from 1 to 0 and commented out several assertion and undo steps.\u000a\u000a* Update Maestro test flows\u000a\u000a* Update Maestro test flows\u000a\u000a* Update BookmarkDataSource and related components to support includeDeleted parameter and fix BookmarkDao query\u000a\u000a* Update SnackBar implementation to support actions and implement undo functionality for bookmark removal\u000a\u000a*   Modify `App.kt` to handle `SnackbarResult` and trigger the snackbar's `onAction` callback.\u000a*   Update `BookmarkListViewModel` to use `SnackBarDispatcher` and provide an \"Undo\" action when removing a bookmark.\u000a*   Add `remove_bookmark` and `undo` string resources.\u000a\u000a* Implement `UiText.asString()` extension and update `Snack` to support `UiText` actions\u000a\u000a* Use default snackbar duration in App.kt\u000a\u000a* test is failing as Snack bar appears but due to duration by the time tapOn Undo is triggered it disappears\u000a\u000a* test: Update browse lessons Maestro flow with additional assertions\u000a\u000a* test: update browse lessons Maestro flow\u000a\u000a* Updated `002_browse_lessons_test.yaml` Maestro flow\u000a\u000a* test: update Maestro browse lessons flow\u000a\u000a* test is failing as Snack bar appears but due to duration by the time tapOn Undo is triggered it disappears\u000a\u000a* Format code and apply style improvements across bookmark and data layer components\u000a\u000a* Update icon URI handling in Bookmark and LearningUnit detail screens and resolve publication URLs in ViewModels\u000a\u000a* Update snackbar message handling to support StringUiText and StringResourceUiText in App.kt\u000a\u000a* Update snackbar message handling to support StringUiText and StringResourceUiText in App.kt\u000a\u000a* Update bookmark query field and remote sync logic.\u000a\u000a* Refactor data loading state and clean up bookmark-related logic.\u000a\u000a- Move `DataLoadState`, `DataLoadParams`, and related extensions from `world.respect.datalayer` to `world.respect.lib.dataloadstate`.\u000a- Remove `UiText.asString()` extension in favor of explicit `when` branches in the `App` composable.\u000a- Remove `AssignmentDataSource` and related references across the data layer and server routes.\u000a- Replace `getTitle()` with `langMapString()` for title resolution in `BookmarkListScreen` and `LearningUnitDetailScreen`.\u000a- Fix parameter mapping in `LearningUnitDetailViewModel` to use `learningUnitManifestUrl` and update bookmark storage logic.\u000a- Clean up unused imports and duplicate string resources.\u000a\u000a* Add `gradle-daemon-jvm.properties` to specify Java 21 for the Gradle daemon.\u000a\u000a* Add `gradle-daemon-jvm.properties` to specify Java 21 for the Gradle daemon.\u000a\u000a* Add `gradle-daemon-jvm.properties` to specify Java 21 for the Gradle daemon.\u000a\u000a* removed bookmark data source\u000a\u000a* Refactor bookmark management to use xapi statements instead of a dedicated `BookmarkDataSource`.\u000a\u000a- Remove `BookmarkDataSourceRepository` and its associated server-side route.\u000a- Update `LearningUnitDetailViewModel` to fetch and store bookmark status using `xapiResource.statements` with the `ID_BOOKMARKED` verb.\u000a- Update `BookmarkListViewModel` and `BookmarkListScreen` to display and manage bookmarks based on xapi statements and linked `OpdsPublication` data.\u000a- Add `ID_BOOKMARKED` constant to `XapiVerb`.\u000a- Update Maestro UI tests to reflect changes in sample data names and bookmark behavior.\u000a\u000a* Sort bookmark statements by timestamp in `BookmarkListViewModel` and remove unused imports and test steps.\u000a\u000a* Remove redundant newline in `002_browse_lessons_test.yaml`.\u000a\u000a* Update Maestro flow assertions to use \"Home\" instead of \"Apps\".\u000a\u000a* Update Maestro flow assertions to use \"Home\" instead of \"Apps\".\u000a\u000a* Reorganize Maestro YAML files between flows and test directories.\u000a\u000a* Update lesson visibility assertion in `002_browse_lessons_test.yaml`.\u000a\u000a* Add `BookmarkEntity` table to `RespectSchoolDatabase` schema and move Maestro test files to the `flows` directory.\u000a\u000a* Update school self-registration test and remove unused admin subflow.\u000a\u000a* Update school self-registration test and remove unused admin subflow.\u000a\u000a* Update `002_browse_lessons_test.yaml` to use `${output.TEST_APP_URL}` variable.\u000a\u000a* Update `002_browse_lessons_test.yaml` to use `${output.TEST_APP_URL}` variable.\u000a\u000a* Update `002_browse_lessons_test.yaml` to use `${output.TEST_APP_URL}` variable.\u000a\u000a* Add database schema files for versions 1 through 8 of `RespectAppDatabase`.\u000a\u000a* Add database schema files for versions 1 through 8 of `RespectAppDatabase`.\u000a\u000a* Refine code formatting and whitespace.\u000a\u000a* Refine code formatting and whitespace.\u000a\u000a* Refine imports in `SchoolDataSourceDb.kt` and remove trailing whitespace in `OpdsPublicationEntityAdapter.kt`.\u000a\u000a* Remove extraneous blank lines from documentation comments in `OpdsPublicationEntity.kt`.\u000a\u000a* Introduce `AddBookmarkUseCase` and `RemoveBookmarkUseCase` to centralize bookmarking logic and refactor view models to use these use cases.\u000a\u000a- Deleted legacy `Bookmark` model from `datalayer`.\u000a- Added `AddBookmarkUseCase` and `RemoveBookmarkUseCase` in `respect-lib-shared`.\u000a- Refactored `LearningUnitDetailViewModel` and `BookmarkListViewModel` to use the new use cases and improve error handling via snackbars.\u000a- Updated `AppKoinModule.kt` to provide the new use cases within the account scope.\u000a- Refined UI styles and string resources in `BookmarkListScreen`, `LearningUnitDetailScreen`, and `strings.xml`.\u000a- Fixed typo from `accountMananger` to `accountManager` in `LearningUnitDetailViewModel`.\u000a\u000a* Remove unused `FontWeight` import in `LearningUnitDetailScreen`.\u000a\u000a* Include `appManifestUrl` in `LearningUnitDetail` route and xAPI bookmark statements.\u000a\u000a- Update `LearningUnitDetail` route to include and persist `appManifestUrl`.\u000a- Pass `appManifestUrl` through `AddBookmarkUseCase` and store it within the xAPI statement's `context.contextActivities.parent` field.\u000a- Update `LearningUnitDetailViewModel` to fetch application data using `appManifestUrl` from the route.\u000a- Enhance `BookmarkListViewModel` to extract `appManifestUrl` from bookmark statements when navigating to unit details.\u000a- Simplify UI in `LearningUnitDetailScreen` by removing the subtitle from the supporting content row.\u000a\u000a* Refactor `BookmarkListScreen` to use `PublicationListItem` and add `trailingContent` support to `PublicationListItem`.\u000a\u000a* Remove `grade1` test case data, including `lesson002` HTML, JSON, and media assets.\u000a\u000a* Replace duplicated getString code with new getUiTextString function\u000a\u000a* Move PublicationListItem into its own file\u000a\u000a* Update `.maestro/flows/002_browse_lessons_test.yaml` to include a test flow for downloading a lesson and verifying its functionality in offline mode.\u000a\u000a* Refactor bookmark handling to utilize new XAPI constants and improve context management\u000a\u000a* Refactor AddBookmarkUseCase and LearningUnitDetailViewModel to remove appManifestUrl handling\u000a\u000a* Refactor AddBookmarkUseCase and LearningUnitDetailViewModel to remove appManifestUrl handling\u000a\u000a* Enhance AddBookmarkUseCase to include title in bookmark xAPI statement\u000a\u000a* Refactor BookmarkListViewModel and LearningUnitDetailViewModel to remove appManifestUrl handling and improve bookmark state management\u000a\u000a* Add sorting functionality to BookmarkListViewModel and UI for bookmarks\u000a\u000a* Add sorting functionality to BookmarkListViewModel and UI for bookmarks\u000a\u000a* Refactor LearningUnitDetailScreen to use Column layout for improved UI structure and add app icon\u000a\u000a* Add error handling and user feedback for bookmark operations\u000a\u000a* Add test tags to top navigation items for improved UI testing\u000a\u000a* Update `.maestro/flows/002_browse_lessons_test.yaml` to use element IDs instead of text-based indexing for navigating to the home screen and asserting home visibility.\u000a\u000a* Update Maestro test flows to use resource IDs for home navigation visibility assertions.\u000a\u000a* Update `admin_add_app.yaml` to use the resource ID `nav_home` for the home navigation tap action instead of the \"Home\" text label.\u000a\u000a* Tidyup of bookmark saving to/from xAPI.\u000a\u000a* Update `.maestro/flows/002_browse_lessons_test.yaml` to refine the navigation flow. Replace the back button action with specific navigation to the home screen and \"Apps\" section to access the \"Statement Maker\" feature.\u000a\u000a* Refactored\u000aThe screen now:\u000aExtracts the activityId\u000aPasses it as Url(activityId)to uiState.taskInfoFlow()\u000aCollects the returned flow\u000aRenders the PublicationListItem\u000a\u000a* Minor tidyup on homescreen.kt\u000a\u000a* Add bookmark button back to learning unit detail screen.\u000a\u000a* Bookmark cleanup\u000a\u000a1) Use remember on bookmarklistscreen when collecting flow\u000a2) bookmarklistviewmodel to filter current active user.\u000a\u000a* Fix 002_001 browse lessons test flow.\u000a\u000a* Tidyup bookmarks\u000a\u000a1) Learning detail screen updated to use a shared flow to avoid unnecessarily reloading app detail\u000a2) Use separate buttons enabled setting for bookmark button on learning unit detail to avoid potential end to end test flakiness: it is a separate load/API call.\u000a\u000a* Resolve OpdsPublication in BookmarkListViewModel to ensure icon will display as expected if it is a relative href.\u000a\u000a* Update demo app test to reflect navigation changes from \"Apps\" to \"Home\"\u000a\u000a* Correct license link on DemoLaunchableAppManifestRoute.kt\u000a\u000a* Update demo app test to use navigation ID for \"Home\"\u000a\u000a* Replace tapOn home with using test tag\u000a\u000a* Add additional logging to WebViewActivity and lesson launch to attempt to diagnose learning unit not opening flakey results on Maestro testing.\u000a\u000a* Add more logging on xapi_statement_maker.js .\u000a\u000a* Revert database JSON schema change: BookmarkEntity was not added when using xapi so no change.\u000a\u000a---------\u000a\u000aCo-authored-by: pooja <pooja@ustadmobile.com>\u000aCo-authored-by: Mike Dawson <mike@ustadmobile.com>\u000a",
        "date" : "2026-07-30 14:44:14 +0400",
        "id" : "beec082677ecfe343236c083f1545d158453e63f",
        "msg" : "Dev bookmark xapi (#272)",
        "paths" : [
          {
            "editType" : "edit",
            "file" : "respect-app-compose/src/commonMain/kotlin/world/respect/app/view/learningunit/detail/LearningUnitDetailScreen.kt"
          },
          {
            "editType" : "edit",
            "file" : "respect-app-compose/src/androidMain/kotlin/world/respect/WebViewActivity.kt"
          },
          {
            "editType" : "delete",
            "file" : "respect-datalayer-db/schemas/world.respect.datalayer.db.RespectAppDatabase/6.json"
          },
          {
            "editType" : "edit",
            "file" : "respect-app-compose/src/commonMain/kotlin/world/respect/app/view/learningunit/list/LearningUnitListScreen.kt"
          },
          {
            "editType" : "add",
            "file" : "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/domain/bookmark/AddBookmarkUseCase.kt"
          },
          {
            "editType" : "edit",
            "file" : ".maestro/flows/002_001_browse_lessons_test.yaml"
          },
          {
            "editType" : "edit",
            "file" : "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/navigation/AppRoutes.kt"
          },
          {
            "editType" : "edit",
            "file" : ".maestro/flows/002_002_browse_demo_app_test.yaml"
          },
          {
            "editType" : "edit",
            "file" : ".maestro/flows/001_003_login_using_school_link_test.yaml"
          },
          {
            "editType" : "edit",
            "file" : "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/domain/geticonforxapiactivity/GetPublicationForXapiActivityUseCase.kt"
          },
          {
            "editType" : "edit",
            "file" : ".maestro/flows/subflows/admin_add_app.yaml"
          },
          {
            "editType" : "add",
            "file" : "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/viewmodel/bookmark/BookmarkListViewModel.kt"
          },
          {
            "editType" : "edit",
            "file" : "respect-lib-xapi-core/src/commonMain/kotlin/world/respect/lib/xapi/model/XapiVerb.kt"
          },
          {
            "editType" : "edit",
            "file" : "respect-lib-xapi-core/src/commonMain/kotlin/world/respect/lib/xapi/OpenEelXapiConstants.kt"
          },
          {
            "editType" : "edit",
            "file" : "respect-lib-shared/src/commonMain/composeResources/values/strings.xml"
          },
          {
            "editType" : "edit",
            "file" : ".maestro/flows/001_002_add_user_direct_test.yaml"
          },
          {
            "editType" : "edit",
            "file" : "respect-app-compose/src/commonMain/kotlin/world/respect/app/app/AppNavHost.kt"
          },
          {
            "editType" : "add",
            "file" : "respect-app-compose/src/commonMain/kotlin/world/respect/app/view/bookmark/BookmarkListScreen.kt"
          },
          {
            "editType" : "add",
            "file" : "respect-app-compose/src/commonMain/kotlin/world/respect/app/view/learningunit/list/PublicationListItem.kt"
          },
          {
            "editType" : "add",
            "file" : "respect-lib-shared/src/commonMain/composeResources/drawable/no_bookmark.xml"
          },
          {
            "editType" : "edit",
            "file" : "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/viewmodel/apps/detail/AppsDetailViewModel.kt"
          },
          {
            "editType" : "edit",
            "file" : "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/viewmodel/apps/launcher/AppLauncherViewModel.kt"
          },
          {
            "editType" : "edit",
            "file" : "app-android/src/main/kotlin/world/respect/AppKoinModule.kt"
          },
          {
            "editType" : "edit",
            "file" : "respect-app-compose/src/androidMain/kotlin/world/respect/shared/domain/license/GetLicenseLabelUseCaseAndroid.kt"
          },
          {
            "editType" : "edit",
            "file" : "respect-lib-shared/src/androidMain/kotlin/world/respect/shared/domain/launchapp/LaunchAppUseCaseAndroid.kt"
          },
          {
            "editType" : "add",
            "file" : "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/domain/bookmark/RemoveBookmarkUseCase.kt"
          },
          {
            "editType" : "edit",
            "file" : "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/viewmodel/learningunit/detail/LearningUnitDetailViewModel.kt"
          },
          {
            "editType" : "delete",
            "file" : "respect-datalayer-db/schemas/world.respect.datalayer.db.RespectAppDatabase/5.json"
          },
          {
            "editType" : "edit",
            "file" : "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/viewmodel/app/appstate/Snack.kt"
          },
          {
            "editType" : "edit",
            "file" : "respect-server/src/main/resources/http/respect-ds/case_valid/examples/statementmaker/index.html"
          },
          {
            "editType" : "add",
            "file" : "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/util/CommonSortOptions.kt"
          },
          {
            "editType" : "edit",
            "file" : ".maestro/flows/001_001_invite_users_using_qr_code_or_link_test.yaml"
          },
          {
            "editType" : "edit",
            "file" : "respect-server/src/main/resources/http/respect-ds/case_valid/js/xapi_statement_maker.js"
          },
          {
            "editType" : "edit",
            "file" : ".maestro/flows/003_admin_user_assigns_assignment_to_a_class_test.yaml"
          },
          {
            "editType" : "edit",
            "file" : "respect-app-compose/src/commonMain/kotlin/world/respect/app/app/App.kt"
          },
          {
            "editType" : "edit",
            "file" : "respect-server/src/main/kotlin/world/respect/server/demoapp/DemoLaunchableAppManifestRoute.kt"
          },
          {
            "editType" : "edit",
            "file" : "respect-lib-shared/src/commonMain/kotlin/world/respect/shared/domain/license/GetLicenseLabelUseCase.kt"
          },
          {
            "editType" : "edit",
            "file" : "respect-app-compose/src/commonMain/kotlin/world/respect/app/view/home/HomeScreen.kt"
          }
        ]
      }
    ],
    "kind" : "git"
  },
  "culprits" : [
    {
      "absoluteUrl" : "https://devserver3.ustadmobile.com/jenkins/user/noreply",
      "fullName" : "noreply"
    }
  ]
}