ref: ac22ab61a7e71bcae8ff03cfbcc55952c074b7c9
app/src/main/java/xyz/apiote/bimba/czwek/repo/OfflineRepository.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
// SPDX-FileCopyrightText: Adam Evyčędo // // SPDX-License-Identifier: GPL-3.0-or-later package xyz.apiote.bimba.czwek.repo import android.content.Context import android.database.sqlite.SQLiteDatabase import androidx.core.content.edit import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import xyz.apiote.bimba.czwek.api.Server import xyz.apiote.fruchtfleisch.Reader import xyz.apiote.fruchtfleisch.Writer import java.io.File import java.net.URLEncoder import java.time.LocalDate class OfflineRepository(context: Context) : Repository { private val db = SQLiteDatabase.openOrCreateDatabase(context.getDatabasePath("favourites").path, null) fun saveFeedCache(context: Context, feedInfos: Map<String, FeedInfo>) { val file = File( context.filesDir, URLEncoder.encode(Server.get(context).apiPath, "utf-8") ) context.getSharedPreferences("offlineFeeds", Context.MODE_PRIVATE).edit { putInt("version", FeedInfo.VERSION.toInt()) } val stream = file.outputStream() val writer = Writer(stream) writer.writeUInt(feedInfos.size.toULong()) feedInfos.forEach { it.value.marshal(stream) } stream.flush() stream.close() } override suspend fun getFavourite(stopCode: String): Favourite? { val cursor = db.rawQuery( "select stop_name, feed_id, feed_name, lines from favourites where stop_code = ?", listOf(stopCode).toTypedArray() ) if (cursor.count == 0) { return null } cursor.moveToNext() val f = Favourite( cursor.getString(1), cursor.getString(2), stopCode, cursor.getString(0), cursor.getString(2).split("||").filter { it != "" } ) cursor.close() return f } override suspend fun getFavourites(feedIDs: Set<String>): List<Favourite> { val whereClause = if (feedIDs.isNotEmpty()) { feedIDs.indices.joinToString(prefix = "where feed_id in (", postfix = ")") { "?" } } else { "" } val cursor = db.rawQuery( "select stop_name, feed_id, feed_name, stop_code, lines from favourites $whereClause", feedIDs.toTypedArray() ) val l = mutableListOf<Favourite>() while (cursor.moveToNext()) { l.add( Favourite( cursor.getString(1), cursor.getString(2), cursor.getString(3), cursor.getString(0), cursor.getString(4).split("||").filter { it != "" } ) ) } cursor.close() return l } override suspend fun saveFavourite(favourite: Favourite) { db.execSQL( "insert into favourites(feed_id, feed_name, stop_code, stop_name, lines) values (?,?,?,?,?) on conflict(feed_id, stop_code) do update set stop_name = ?, lines = ?", arrayOf( favourite.feedID, favourite.feedName, favourite.stopCode, favourite.stopName, favourite.lines.joinToString(separator = "||"), favourite.stopName, favourite.lines.joinToString(separator = "||") ) ) } @Suppress("RedundantNullableReturnType") override suspend fun getFeeds( context: Context, server: Server ): Map<String, FeedInfo>? { val file = File( context.filesDir, withContext(Dispatchers.IO) { URLEncoder.encode(server.apiPath, "utf-8") } ) if (!file.exists()) { return emptyMap() } val version = context.getSharedPreferences("offlineFeeds", Context.MODE_PRIVATE).getInt("version", -1) if (version < 0) { return emptyMap() } val unmarshaller = if (version.toUInt() == FeedInfo.VERSION) FeedInfo::unmarshal else FeedInfoPrev::unmarshal val stream = file.inputStream() val feeds = mutableMapOf<String, FeedInfo>() val n = Reader(stream).readUInt().toULong().toInt() repeat(n) { val feed = unmarshaller(stream) feeds[feed.id] = feed if (version.toUInt() != FeedInfo.VERSION) { saveFeedCache(context, feeds) } } return feeds } override suspend fun getDepartures( feedID: String, stop: String, date: LocalDate?, context: Context, limit: Int? ): StopDepartures? { TODO("Not yet implemented") } override suspend fun getLocatablesIn( context: Context, bl: Position, tr: Position, ): List<Locatable>? { TODO("Not yet implemented") } override suspend fun getLine( context: Context, feedID: String, lineName: String, lineID: String, ): Line? { TODO("Not yet implemented") } override suspend fun queryQueryables( query: String, context: Context ): List<Queryable>? { TODO("Not yet implemented") } override suspend fun locateQueryables( position: Position, context: Context ): List<Queryable>? { TODO("Not yet implemented") } } fun migrateDB(context: Context) { val db = SQLiteDatabase.openOrCreateDatabase(context.getDatabasePath("favourites").path, null) db.execSQL("create table if not exists favourites(feed_id text, feed_name text, stop_code text, stop_name text, lines text, primary key(feed_id, stop_code))") } |