Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
140 commits
Select commit Hold shift + click to select a range
2a6f070
Add renovate.json
renovate[bot] May 18, 2025
01f7876
Merge pull request #1 from quran/renovate/configure
ahmedre May 18, 2025
79f9ade
Update agp to v8.10.1
renovate[bot] May 31, 2025
d25f249
Update dependency gradle to v8.14.2
renovate[bot] Jun 6, 2025
a8dc579
Update dependency androidx.compose:compose-bom to v2025.06.01
renovate[bot] Jun 22, 2025
dd1d9e6
Update dependency com.vanniktech.maven.publish to v0.33.0
renovate[bot] Jun 22, 2025
88950f3
Merge pull request #6 from quran/renovate/agp
ahmedre Jun 28, 2025
da08a41
Merge pull request #4 from quran/renovate/gradle-8.x
ahmedre Jun 28, 2025
cf6e62e
Merge pull request #3 from quran/renovate/compose
ahmedre Jun 28, 2025
29dca31
Merge pull request #7 from quran/renovate/maven.publish
ahmedre Jun 28, 2025
204aee6
Update kotlin monorepo to v2.2.0
renovate[bot] Jun 28, 2025
603db6b
Merge pull request #9 from quran/renovate/kotlin-monorepo
ahmedre Jun 28, 2025
0981702
Update agp to v8.11.0
renovate[bot] Jun 28, 2025
93ff893
Merge pull request #8 from quran/renovate/agp
ahmedre Jun 28, 2025
f4176fc
Bookmarks Repository (#5)
mohannad-hassan Jul 2, 2025
22f6061
CI Actions (#11)
mohannad-hassan Jul 3, 2025
badef71
Sync Library Interface & SyncAPIs (#12)
mohannad-hassan Jul 16, 2025
e44ebba
Factory for bookmarks repositories (#20)
mohannad-hassan Jul 17, 2025
55c5859
Integration Package (#22)
mohannad-hassan Aug 12, 2025
752542c
Update actions/checkout action to v5 (#24)
renovate[bot] Aug 13, 2025
2575156
SyncEngine – Bookmarks Conflict Resolution (#25)
mohannad-hassan Aug 23, 2025
2b07142
Update dependency co.touchlab:kermit to v2.0.8 (#10)
renovate[bot] Aug 23, 2025
2fff811
Update kotlin monorepo to v2.2.10 (#26)
renovate[bot] Aug 23, 2025
9664792
Update dependency org.jetbrains.kotlinx:kotlinx-datetime to v0.7.1-0.…
renovate[bot] Aug 23, 2025
f572069
Update actions/setup-java action to v5 (#28)
renovate[bot] Aug 23, 2025
9ebe5ad
Update kotlin monorepo to v2.2.20 (#30)
renovate[bot] Sep 10, 2025
1f9f603
Fix kotlinx.time.Instant deprecations (#31)
mohannad-hassan Sep 10, 2025
da33fff
Synchronization Scheduler (#29)
mohannad-hassan Sep 14, 2025
b62c89e
Update gradle/actions action to v5
renovate[bot] Oct 1, 2025
089b0d9
Update dependencies and modernize build scripts
ahmedre Oct 20, 2025
9d77b13
Merge pull request #33 from quran/bump_dependencies
ahmedre Oct 20, 2025
fbd17c5
Merge pull request #32 from quran/renovate/gradle-actions-5.x
ahmedre Oct 20, 2025
f7aab95
Support jvm
ahmedre Oct 20, 2025
6504f65
Merge pull request #34 from quran/jvm
ahmedre Oct 20, 2025
9414f30
Clean up some code in the networking layer
ahmedre Oct 21, 2025
f38393b
Merge pull request #35 from quran/minor_cleanup
ahmedre Oct 21, 2025
6f6c4bf
Update the iOS demo app
ahmedre Oct 22, 2025
02d7438
Merge pull request #36 from quran/update_ios_demo
mohamede1945 Oct 22, 2025
5cd52b5
Update dependency androidx.compose:compose-bom to v2025.10.01
renovate[bot] Oct 22, 2025
3c31190
Update kotlin monorepo to v2.2.21
renovate[bot] Oct 23, 2025
e54b7ce
Use kmp native coroutines and clean up visibility
ahmedre Oct 23, 2025
cfa83ae
Update iOS app to work with repository apis
ahmedre Oct 23, 2025
4b68245
Update GitHub workflow to display test summaries
ahmedre Oct 26, 2025
5004944
Address code review feedback
ahmedre Oct 26, 2025
c9ad83f
Merge pull request #40 from quran/test_summaries
ahmedre Oct 26, 2025
50ea0cd
Merge pull request #37 from quran/renovate/kotlin-monorepo
ahmedre Oct 26, 2025
ab96428
Merge pull request #19 from quran/renovate/compose
ahmedre Oct 26, 2025
5a9dd1f
Use kmp native coroutines and clean up visibility
ahmedre Oct 23, 2025
f528b8a
Update agp to v8.13.0
renovate[bot] Oct 26, 2025
c73b721
Merge pull request #38 from quran/update_kotlin
ahmedre Oct 26, 2025
484e89d
Update dependency com.rickclephas.kmp.nativecoroutines to v1.0.0-ALPH…
renovate[bot] Oct 26, 2025
15591b5
Merge pull request #41 from quran/renovate/native.coroutines
ahmedre Oct 26, 2025
93866ba
Merge branch 'main' into async_ios
ahmedre Oct 27, 2025
f298668
Merge pull request #39 from quran/async_ios
ahmedre Oct 27, 2025
599f491
Update Gradle to v9.2.0
renovate[bot] Oct 29, 2025
d155820
Merge pull request #42 from quran/renovate/gradle-9.x
ahmedre Oct 31, 2025
8d35e0e
Merge pull request #14 from quran/renovate/agp
ahmedre Oct 31, 2025
59efe4a
Add support for publishing a Swift package
ahmedre Nov 1, 2025
3d91610
Merge pull request #43 from quran/add_spm_support
ahmedre Nov 1, 2025
e0923fb
Remove ignored file from git
ahmedre Nov 1, 2025
1a59a75
Support macOS
ahmedre Nov 1, 2025
1b5010b
Bump version to 0.0.2
ahmedre Nov 1, 2025
414b896
Update dependency androidx.compose:compose-bom to v2025.11.00
renovate[bot] Nov 5, 2025
7970bc4
Update dependency com.google.devtools.ksp to v2.3.2
renovate[bot] Nov 6, 2025
9a6d8c0
Update agp to v8.13.1
renovate[bot] Nov 10, 2025
c05c4b4
Update dependency com.vanniktech.maven.publish to v0.35.0
renovate[bot] Nov 11, 2025
68dfa69
Merge pull request #48 from quran/renovate/maven.publish
ahmedre Nov 13, 2025
d0c23ae
Merge pull request #47 from quran/renovate/agp
ahmedre Nov 13, 2025
9b2fc96
Merge pull request #44 from quran/renovate/ksp-monorepo
ahmedre Nov 13, 2025
1b53503
Merge pull request #46 from quran/renovate/compose
ahmedre Nov 13, 2025
1e78ac7
Update ktor monorepo to v3.3.2
renovate[bot] Nov 13, 2025
d1429b0
Merge pull request #45 from quran/renovate/ktor-monorepo
ahmedre Nov 13, 2025
2224b86
Update sqldelight to v2.2.1
renovate[bot] Nov 14, 2025
f4074bc
Merge pull request #49 from quran/renovate/sqldelight
ahmedre Nov 16, 2025
5e316fc
Update Gradle to v9.2.1
renovate[bot] Nov 17, 2025
a9b0533
Merge pull request #50 from quran/renovate/gradle-9.x
ahmedre Nov 18, 2025
48ea48b
Rename page bookmarks queries
ahmedre Nov 18, 2025
3e7b8ed
Add initial ayah bookmarks tables
ahmedre Nov 18, 2025
2492b0f
Update dependency androidx.compose:compose-bom to v2025.11.01
renovate[bot] Nov 19, 2025
665e109
Merge pull request #51 from quran/rename_page_bookmarks
ahmedre Nov 19, 2025
e7cdc36
Merge pull request #52 from quran/ayah_bookmarks
ahmedre Nov 19, 2025
77e9df0
Merge pull request #53 from quran/renovate/compose
ahmedre Nov 19, 2025
6709aaf
Update actions/checkout action to v6
renovate[bot] Nov 20, 2025
fca2fe5
Merge pull request #54 from quran/renovate/actions-checkout-6.x
ahmedre Nov 20, 2025
ed33e20
Update dependency com.google.devtools.ksp to v2.3.3
renovate[bot] Nov 21, 2025
c87e846
Merge pull request #55 from quran/renovate/ksp-monorepo
ahmedre Nov 23, 2025
1f9ff33
Add table definitions for tags and recents
ahmedre Nov 23, 2025
32d452b
Update ktor monorepo to v3.3.3
renovate[bot] Nov 26, 2025
c5416c7
Merge pull request #56 from quran/tags_and_recents
ahmedre Nov 26, 2025
b31cfbe
Merge pull request #57 from quran/renovate/ktor-monorepo
ahmedre Nov 26, 2025
72c4e8b
Update dependency androidx.compose:compose-bom to v2025.12.00
renovate[bot] Dec 3, 2025
a8685d4
Merge pull request #58 from quran/renovate/compose
ahmedre Dec 11, 2025
2276c21
Update agp to v8.13.2
renovate[bot] Dec 12, 2025
4cb2007
Merge pull request #59 from quran/renovate/agp
ahmedre Dec 15, 2025
5aba68a
Update dependency com.google.devtools.ksp to v2.3.4
renovate[bot] Dec 16, 2025
cd9cf78
Add initial scaffolding for ayah bookmarks
ahmedre Dec 16, 2025
892b460
Update dependency androidx.compose:compose-bom to v2025.12.01
renovate[bot] Dec 17, 2025
866e7ff
Merge pull request #63 from quran/ayah_bookmarks
ahmedre Dec 17, 2025
3260e9e
Update deprecated jvmTarget in demo/android
ahmedre Dec 18, 2025
98bf1b4
Remove page from ayah bookmarks
ahmedre Dec 18, 2025
650b0fd
Merge pull request #66 from quran/update_deprecated_jvmtarget
ahmedre Dec 18, 2025
10661bc
Merge pull request #62 from quran/renovate/ksp-monorepo
ahmedre Dec 18, 2025
165d06d
Merge pull request #65 from quran/renovate/compose
ahmedre Dec 18, 2025
9a3790d
Merge pull request #67 from quran/remove_page_ayah_bookmarks
ahmedre Dec 18, 2025
7a4b394
Update dependency com.rickclephas.kmp.nativecoroutines to v1.0.0
renovate[bot] Dec 23, 2025
5cf00c1
Merge pull request #68 from quran/renovate/native.coroutines
ahmedre Dec 24, 2025
e8795e9
Update kotlin monorepo to v2.3.0
renovate[bot] Dec 24, 2025
58cdaed
Merge pull request #60 from quran/renovate/kotlin-monorepo
ahmedre Dec 24, 2025
6b8d743
Add notes table and improve table definitions
ahmedre Dec 28, 2025
97edd63
Merge pull request #69 from quran/fixes
ahmedre Dec 29, 2025
28ccdea
Combine page and ayah bookmarks into a single type
ahmedre Dec 28, 2025
b618ff1
Merge pull request #71 from quran/single_bookmark_repo
ahmedre Dec 29, 2025
bce6e69
Add methods for ayah bookmarks in persistence
ahmedre Dec 29, 2025
8bec168
Merge pull request #72 from quran/ayah_bookmarks
ahmedre Dec 29, 2025
648ee44
Organize and update sync call
ahmedre Jan 3, 2026
18f9acd
Merge pull request #73 from quran/reshape_sync
ahmedre Jan 3, 2026
6aba8e5
Use milliseconds instead of seconds
ahmedre Jan 3, 2026
2bbd8ab
Merge pull request #74 from quran/millis
ahmedre Jan 3, 2026
8452559
Respect the ordering of results from the backend
ahmedre Jan 3, 2026
3c7633a
Merge pull request #75 from quran/mutations_order
ahmedre Jan 3, 2026
1d7a3f0
Implement collections persistence and sync
ahmedre Jan 4, 2026
a447edc
Merge pull request #76 from quran/collections
ahmedre Jan 4, 2026
f377470
Separate input and general usage models
ahmedre Jan 4, 2026
353a6c8
Merge pull request #77 from quran/better_models
ahmedre Jan 4, 2026
4c56bd5
Implement sync of bookmarks within collections
ahmedre Jan 4, 2026
f783392
Merge pull request #78 from quran/collection_bookmarks
ahmedre Jan 4, 2026
21b8ccd
Implement notes syncing
ahmedre Jan 4, 2026
d796bec
Merge pull request #79 from quran/notes
ahmedre Jan 4, 2026
b40e6dc
Minor renaming for consistency
ahmedre Jan 11, 2026
2d0cf24
Merge pull request #80 from quran/rename
ahmedre Jan 11, 2026
e149edd
Minor performance improvements and fixes
ahmedre Jan 12, 2026
ded674e
Merge pull request #81 from quran/fixes
ahmedre Jan 12, 2026
cecf36a
Run fewer queries for collection bookmarks
ahmedre Jan 12, 2026
1beea90
Merge pull request #82 from quran/collection_bookmarks
ahmedre Jan 12, 2026
b63efee
auth logic based on kmp oidc lib
AhmedNMahran Jan 15, 2026
5d77bec
update AuthenticationManager.kt with correct url scheme, and use plat…
AhmedNMahran Jan 15, 2026
fc7eec2
fix: replace the invalid .filled button style with the standard Swift…
AhmedNMahran Jan 15, 2026
9e31ea5
fix import, concurrency, and Kotlin-to-Swift/Obj-C naming errors
AhmedNMahran Jan 15, 2026
525390e
update AuthViewModel.kt and MainActivity.kt wo use sharedPrefs
AhmedNMahran Jan 15, 2026
c88a6e3
update client id
AhmedNMahran Jan 15, 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
36 changes: 36 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Gradle CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
build:
runs-on: macos-latest

steps:
- uses: actions/checkout@v6

- name: Set up JDK 17
uses: actions/setup-java@v5
with:
java-version: "17"
distribution: "temurin"
cache: gradle

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v5

- name: Clean project
run: ./gradlew clean

- name: Run tests
run: ./gradlew allTests --stacktrace --continue

- name: Test Summary
uses: test-summary/action@v2
with:
paths: "**/build/test-results/**/TEST-*.xml"
if: always()
101 changes: 101 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
name: Publish Shared XCFramework

on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
ref:
description: "Git ref (branch or tag) to build from"
required: true
default: main

permissions:
contents: write

env:
XCF_NAME: Shared
XCF_GRADLE_TASK: umbrella:assembleSharedXCFramework
XCF_OUTPUT_DIR: umbrella/build/XCFrameworks/release

jobs:
build-and-release:
runs-on: macos-latest

steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.ref || github.ref }}

- name: Set up JDK 17
uses: actions/setup-java@v5
with:
java-version: "17"
distribution: "temurin"
cache: gradle

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v5

- name: Build XCFramework
run: ./gradlew $XCF_GRADLE_TASK --stacktrace

- name: Package XCFramework
id: package
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
run: |
set -euo pipefail

read_property_version() {
local prop
if [[ ! -f gradle.properties ]]; then
echo "gradle.properties not found" >&2
return 1
fi
prop=$(awk -F'=' '/^version[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); gsub(/^"|"$/, "", $2); print $2; exit}' gradle.properties)
if [[ -z "$prop" ]]; then
echo "version property missing in gradle.properties" >&2
return 1
fi
printf '%s' "$prop"
}

property_version=$(read_property_version)

if [[ "$EVENT_NAME" == "workflow_dispatch" ]]; then
version="$property_version"
tag_name="v${version}"
else
tag_name="${GITHUB_REF_NAME}"
version="$property_version"
if [[ "$tag_name" != "v${version}" ]]; then
echo "Tag ${tag_name} does not match gradle.properties version ${version}" >&2
exit 1
fi
fi

archive_name="${XCF_NAME}-${version}.xcframework.zip"
output_dir="$XCF_OUTPUT_DIR"
cd "$output_dir"
rm -f "${XCF_NAME}.xcframework.zip" "$archive_name"
zip -r "$archive_name" "${XCF_NAME}.xcframework"

echo "archive-path=$output_dir/$archive_name" >> "$GITHUB_OUTPUT"
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "tag-name=$tag_name" >> "$GITHUB_OUTPUT"

- name: Publish Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.package.outputs.tag-name }}
name: Shared XCFramework ${{ steps.package.outputs.version }}
draft: false
prerelease: ${{ contains(steps.package.outputs.version, '-') }}
make_latest: ${{ !contains(steps.package.outputs.version, '-') }}
files: ${{ steps.package.outputs.archive-path }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
32 changes: 32 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,35 @@ build

# Android
local.properties

# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore

## User settings
xcuserdata/

## Obj-C/Swift specific
*.hmap

## App packaging
*.ipa
*.dSYM.zip
*.dSYM

# Swift Package Manager
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
# Package.pins
# Package.resolved
# *.xcodeproj
#
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
# hence it is not needed unless you have added a package configuration file to your project
# .swiftpm

.build/

# macOS
.DS_Store
149 changes: 149 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Overview

The mobile-sync project (internally named "quransync") is a Kotlin Multiplatform Mobile (KMM) library for synchronizing Quran.com user data across Android and iOS. It implements bidirectional synchronization with conflict resolution for page bookmarks.

## Development Commands

### Building and Testing
```bash
# Clean and build entire project
./gradlew clean build

# Run all tests across all modules
./gradlew allTests

# Run tests for specific module
./gradlew :syncengine:test
./gradlew :persistence:test

# Build iOS framework
./gradlew :umbrella:assembleXCFramework

# Run Android demo
./gradlew :demo:android:installDebug
```

### Module-Specific Commands
```bash
# Test individual components
./gradlew :syncengine:testDebugUnitTest
./gradlew :syncengine:testReleaseUnitTest

# Check for dependency updates
./gradlew dependencyUpdates
```

## Architecture Overview

The project follows a layered architecture with clear separation of concerns:

### Module Dependencies
```
mutations-definitions (foundational)
┌────┴────┬────────────┐
│ │ │
persistence syncengine │
└────┬────┴────────┐ │
│ │ │
sync-pipelines │ │
↑ │ │
│ │ │
umbrella demo:android
```

### Core Modules

**mutations-definitions**: Foundation module defining `Mutation`, `LocalModelMutation<Model>`, and `RemoteModelMutation<Model>` types used across the entire sync system.

**persistence**: SQLDelight-based data layer with `PageBookmarksRepository` and change tracking. Handles cross-platform database operations and mutation state persistence.

**syncengine**: Pure business logic module containing `SynchronizationClient`, `PageBookmarksSynchronizationExecutor`, conflict resolution system, network layer (Ktor), and scheduling system. Contains no external dependencies in core executor logic.

**sync-pipelines**: Integration layer with `SyncEnginePipeline` that bridges syncengine and persistence. Provides the main high-level API via `RepositoryDataFetcher` and `ResultReceiver`.

**umbrella**: iOS framework packaging module that exports all public APIs as "Shared" framework.

**demo:android**: Sample Android app demonstrating library usage.

### Key Architectural Patterns

- **Dependency Inversion**: syncengine defines interfaces implemented by persistence
- **Adapter Pattern**: sync-pipelines acts as adapter between layers
- **Pure Business Logic**: Core sync logic has no external dependencies
- **Conflict Resolution Pipeline**: Sophisticated preprocessing and conflict handling

## Technology Stack

- **Language**: Kotlin Multiplatform (targeting iOS and Android)
- **Database**: SQLDelight for cross-platform SQL operations
- **Networking**: Ktor HTTP client with platform-specific implementations
- **Serialization**: kotlinx.serialization
- **Async**: kotlinx.coroutines
- **Testing**: kotlin.test with kotlinx.coroutines.test
- **Build**: Gradle with Kotlin DSL
- **iOS Distribution**: XCFramework via umbrella module

## Development Guidelines

### Module Boundaries
- Keep syncengine pure (no external persistence dependencies)
- Use sync-pipelines for integration between layers
- Maintain clear interfaces between modules

### Testing Strategy
- syncengine has comprehensive unit tests with timing-sensitive scheduling tests
- Use `kotlinx.coroutines.test` for coroutine testing
- Test timing with tolerance values (typically 100ms tolerance)

### Synchronization Architecture
The sync system implements a sophisticated bidirectional flow:

1. **Local Changes**: `PageBookmarksRepository` tracks mutations
2. **Sync Trigger**: Events fire through `SynchronizationClient`
3. **Pipeline Execution**: `PageBookmarksSynchronizationExecutor` orchestrates:
- Fetch local/remote mutations
- Conflict detection and resolution
- Push/pull data exchange
4. **Result Persistence**: Coordinated by sync-pipelines

### Scheduling System
The recently added `Scheduler` in syncengine manages sync timing with:
- `APP_START` trigger (30s delay)
- `LOCAL_DATA_MODIFIED` trigger (5s delay)
- `IMMEDIATE` trigger (0ms delay)
- Exponential backoff retry logic (200ms base, 2.5x multiplier, max 5 retries)
- State machine tracking scheduler lifecycle

**Error Handling**: The Scheduler uses exception-based error handling:
- Task functions should throw exceptions to indicate failure
- Scheduler catches exceptions and applies retry logic automatically
- After maximum retries, the final exception is reported to the failure callback
- Success is indicated by task function completing without throwing

### Platform-Specific Considerations
- HTTP clients: OkHttp (Android), Darwin (iOS)
- Database drivers: Android SQLite, iOS native
- Framework packaging: XCFramework for iOS consumption

## Common Development Tasks

### Adding New Mutation Types
1. Define in mutations-definitions module
2. Update persistence layer with SQL schema changes
3. Add syncengine business logic
4. Wire through sync-pipelines

### Extending Sync Logic
- Add new preprocessing steps to `LocalMutationsPreprocessor`/`RemoteMutationsPreprocessor`
- Extend conflict resolution in `ConflictDetector`/`ConflictResolver`
- Update `PageBookmarksSynchronizationExecutor` pipeline

### Testing Sync Behavior
- Use test timings in `SchedulerTest.kt` as reference
- Mock network layer for integration tests
- Test conflict scenarios with controlled data states
Loading