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
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import com.quran.shared.persistence.Bookmark_collection
import com.quran.shared.persistence.Collection
import com.quran.shared.persistence.Note
import com.quran.shared.persistence.Page_bookmark
import com.quran.shared.persistence.Recent_page

internal typealias DatabasePageBookmark = Page_bookmark
internal typealias DatabaseAyahBookmark = Ayah_bookmark
internal typealias DatabaseCollection = Collection
internal typealias DatabaseBookmarkCollection = Bookmark_collection
internal typealias DatabaseNote = Note
internal typealias DatabaseRecentPage = Recent_page
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.quran.shared.persistence.model

import com.quran.shared.persistence.util.PlatformDateTime

data class RecentPage(
val page: Int,
val lastUpdated: PlatformDateTime,
val localId: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.quran.shared.persistence.repository.recentpage

import com.quran.shared.persistence.DriverFactory
import com.quran.shared.persistence.makeDatabase
import com.quran.shared.persistence.repository.recentpage.repository.RecentPagesRepository
import com.quran.shared.persistence.repository.recentpage.repository.RecentPagesRepositoryImpl

/**
* Factory for creating RecentPagesRepository instances.
* This factory hides the details of database creation and provides a clean interface
* for obtaining repository instances.
*/
object RecentPagesRepositoryFactory {
/**
* Creates a new instance of RecentPagesRepository.
* The repository is backed by a SQLite database created using the provided driver factory.
*
* @param driverFactory The driver factory to use for database creation
* @return RecentPagesRepository A new repository instance
*/
fun createRepository(driverFactory: DriverFactory): RecentPagesRepository {
val database = makeDatabase(driverFactory)
return RecentPagesRepositoryImpl(database)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@file:OptIn(ExperimentalTime::class)

package com.quran.shared.persistence.repository.recentpage.extension

import com.quran.shared.persistence.model.DatabaseRecentPage
import com.quran.shared.persistence.model.RecentPage
import com.quran.shared.persistence.util.toPlatform
import kotlin.time.ExperimentalTime
import kotlin.time.Instant

internal fun DatabaseRecentPage.toRecentPage(): RecentPage {
return RecentPage(
page = page.toInt(),
lastUpdated = Instant.fromEpochMilliseconds(modified_at).toPlatform(),
localId = local_id.toString()
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.quran.shared.persistence.repository.recentpage.repository

import com.quran.shared.persistence.model.RecentPage
import com.rickclephas.kmp.nativecoroutines.NativeCoroutines

interface RecentPagesRepository {
/**
* Fetch and returns all recent pages.
*
* @return List<RecentPage> the current list of recent pages
*/
@NativeCoroutines
suspend fun getRecentPages(): List<RecentPage>

/**
* Add a page to the recent pages list.
*
* @return the [RecentPage]
*/
@NativeCoroutines
suspend fun addRecentPage(page: Int): RecentPage

/**
* Delete a page from the recent pages list.
*
* @return a boolean denoting success
*/
@NativeCoroutines
suspend fun deleteRecentPage(page: Int): Boolean
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.quran.shared.persistence.repository.recentpage.repository

import co.touchlab.kermit.Logger
import com.quran.shared.persistence.QuranDatabase
import com.quran.shared.persistence.model.RecentPage
import com.quran.shared.persistence.repository.recentpage.extension.toRecentPage
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.withContext

class RecentPagesRepositoryImpl(
private val database: QuranDatabase
) : RecentPagesRepository {

private val logger = Logger.withTag("RecentPagesRepository")
private val recentPagesQueries = lazy { database.recent_pagesQueries }

override suspend fun getRecentPages(): List<RecentPage> {
return withContext(Dispatchers.IO) {
recentPagesQueries.value.getRecentPages()
.executeAsList()
.map { it.toRecentPage() }
}
}

override suspend fun addRecentPage(page: Int): RecentPage {
logger.i { "Adding recent page $page" }
return withContext(Dispatchers.IO) {
recentPagesQueries.value.addRecentPage(page.toLong())
val record = recentPagesQueries.value.getRecentPageForPage(page.toLong())
.executeAsOneOrNull()
requireNotNull(record) { "Expected recent page for page $page after insert." }
record.toRecentPage()
}
}

override suspend fun deleteRecentPage(page: Int): Boolean {
logger.i { "Deleting recent page for page $page" }
withContext(Dispatchers.IO) {
recentPagesQueries.value.deleteRecentPage(page.toLong())
}
return true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,37 @@ CREATE TABLE IF NOT EXISTS recent_page(
local_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
remote_id TEXT,
page INTEGER NOT NULL UNIQUE,
created_at INTEGER DEFAULT (strftime('%s', 'now')) NOT NULL,
modified_at INTEGER DEFAULT (strftime('%s', 'now')) NOT NULL,
created_at INTEGER DEFAULT (CAST(strftime('%s', 'now') AS INTEGER) * 1000) NOT NULL,
modified_at INTEGER DEFAULT (CAST(strftime('%s', 'now') AS INTEGER) * 1000) NOT NULL,
deleted INTEGER NOT NULL DEFAULT 0,
CHECK (deleted IN (0, 1))
);
);

CREATE INDEX IF NOT EXISTS recent_page_remote_id_idx ON recent_page(remote_id);

getRecentPages:
SELECT * FROM recent_page WHERE deleted = 0 ORDER BY modified_at DESC;

getRecentPageForPage:
SELECT * FROM recent_page WHERE page = ? LIMIT 1;

getRecentPageByLocalId:
SELECT * FROM recent_page WHERE local_id = ? LIMIT 1;

addRecentPage {
INSERT OR IGNORE INTO recent_page (remote_id, page, deleted)
VALUES (NULL, :page, 0);
UPDATE recent_page
SET deleted = 0,
created_at = CAST(strftime('%s', 'now') AS INTEGER) * 1000,
modified_at = CAST(strftime('%s', 'now') AS INTEGER) * 1000
WHERE page = :page;
}

deleteRecentPage {
DELETE FROM recent_page WHERE page = :page AND remote_id IS NULL;
UPDATE recent_page
SET deleted = 1,
modified_at = CAST(strftime('%s', 'now') AS INTEGER) * 1000
WHERE page = :page AND remote_id IS NOT NULL;
}