diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 0ce3222..2821bf7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -80,6 +80,7 @@ dependencies { // Misc implementation(Dependencies.Misc.appIntro) implementation(Dependencies.Misc.materialSpinner) + implementation(Dependencies.Misc.materialProgressBar) // Testing testImplementation(Dependencies.Testing.junit) diff --git a/app/src/main/java/net/underdesk/circolapp/adapters/AttachmentAdapter.kt b/app/src/main/java/net/underdesk/circolapp/adapters/AttachmentAdapter.kt index b76a197..9232c06 100644 --- a/app/src/main/java/net/underdesk/circolapp/adapters/AttachmentAdapter.kt +++ b/app/src/main/java/net/underdesk/circolapp/adapters/AttachmentAdapter.kt @@ -23,19 +23,27 @@ import android.view.LayoutInflater import android.view.ViewGroup import android.widget.ImageButton import android.widget.TextView +import androidx.lifecycle.Observer import androidx.recyclerview.widget.RecyclerView +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch import net.underdesk.circolapp.MainActivity +import net.underdesk.circolapp.data.AndroidCircularRepository import net.underdesk.circolapp.databinding.ItemAttachmentBinding +import net.underdesk.circolapp.shared.data.Circular +import net.underdesk.circolapp.shared.data.CircularRepository import net.underdesk.circolapp.utils.DownloadableFile import net.underdesk.circolapp.utils.FileUtils class AttachmentAdapter( - private val attachmentsNames: List, - private val attachmentsUrls: List, + private val circular: Circular, private val mainActivity: MainActivity, + private val adapterScope: CoroutineScope, + private val circularHolder: CircularLetterAdapter.CircularLetterViewHolder ) : RecyclerView.Adapter() { private val adapterCallback: CircularLetterAdapter.AdapterCallback = mainActivity + private lateinit var circularRepository: CircularRepository private lateinit var context: Context inner class AttachmentViewHolder(binding: ItemAttachmentBinding) : RecyclerView.ViewHolder(binding.root) { @@ -48,26 +56,74 @@ class AttachmentAdapter( override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AttachmentViewHolder { val binding = ItemAttachmentBinding.inflate(LayoutInflater.from(parent.context), parent, false) context = parent.context + circularRepository = AndroidCircularRepository.getInstance(context) return AttachmentViewHolder(binding) } override fun onBindViewHolder(holder: AttachmentViewHolder, position: Int) { - holder.title.text = attachmentsNames[position] + holder.title.text = circular.attachmentsNames[position] + + val observer = Observer { + if (it) { + holder.viewButton.isEnabled = false + holder.downloadButton.isEnabled = false + holder.shareButton.isEnabled = false + } else { + holder.viewButton.isEnabled = true + holder.downloadButton.isEnabled = true + holder.shareButton.isEnabled = true + } + } + + circularHolder.loading.observe(mainActivity, observer) + circularHolder.observer.add(observer) holder.viewButton.setOnClickListener { - FileUtils.viewFile(attachmentsUrls[position], context, mainActivity.customTabsSession) + runWhenUrlIsAvailable(position) { url -> + FileUtils.viewFile(url, context, mainActivity.customTabsSession) + } } holder.shareButton.setOnClickListener { - FileUtils.shareFile(attachmentsUrls[position], context) + runWhenUrlIsAvailable(position) { url -> FileUtils.shareFile(url, context) } } holder.downloadButton.setOnClickListener { - val file = DownloadableFile(attachmentsNames[position], attachmentsUrls[position]) - FileUtils.downloadFile(file, adapterCallback, context) + runWhenUrlIsAvailable(position) { url -> + val file = DownloadableFile(circular.attachmentsNames[position], url) + FileUtils.downloadFile(file, adapterCallback, context) + } } } - override fun getItemCount() = attachmentsNames.size + private fun runWhenUrlIsAvailable(position: Int, code: (url: String) -> Unit) { + if (circular.realAttachmentsUrls.size != circular.attachmentsUrls.size || circular.realAttachmentsUrls[position] == "") { + circularHolder.loading.postValue(true) + + adapterScope.launch { + val realUrls = circularRepository.getRealUrlForAttachment( + position, + circular.attachmentsUrls, + circular.realAttachmentsUrls, + circular.id, + circular.school + ) + circularHolder.loading.postValue(false) + + if (circular.realAttachmentsUrls.size != circular.attachmentsUrls.size) { + circular.realAttachmentsUrls.clear() + repeat(circular.attachmentsUrls.size) { circular.realAttachmentsUrls.add("") } + } + + circular.realAttachmentsUrls[position] = realUrls[position] + code(realUrls[position]) + } + return + } + + code(circular.realAttachmentsUrls[position]) + } + + override fun getItemCount() = circular.attachmentsNames.size } diff --git a/app/src/main/java/net/underdesk/circolapp/adapters/CircularLetterAdapter.kt b/app/src/main/java/net/underdesk/circolapp/adapters/CircularLetterAdapter.kt index 29a829c..3e20865 100644 --- a/app/src/main/java/net/underdesk/circolapp/adapters/CircularLetterAdapter.kt +++ b/app/src/main/java/net/underdesk/circolapp/adapters/CircularLetterAdapter.kt @@ -26,10 +26,13 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ImageButton +import android.widget.ProgressBar import android.widget.TextView import androidx.cardview.widget.CardView import androidx.core.content.ContextCompat.getDrawable import androidx.fragment.app.FragmentActivity +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import kotlinx.coroutines.CoroutineScope @@ -37,10 +40,12 @@ import kotlinx.coroutines.launch import net.underdesk.circolapp.AlarmBroadcastReceiver import net.underdesk.circolapp.MainActivity import net.underdesk.circolapp.R +import net.underdesk.circolapp.data.AndroidCircularRepository import net.underdesk.circolapp.data.AndroidDatabase import net.underdesk.circolapp.databinding.ItemCircularBinding import net.underdesk.circolapp.fragments.NewReminderFragment import net.underdesk.circolapp.shared.data.Circular +import net.underdesk.circolapp.shared.data.CircularRepository import net.underdesk.circolapp.utils.DownloadableFile import net.underdesk.circolapp.utils.FileUtils @@ -51,6 +56,7 @@ class CircularLetterAdapter( ) : RecyclerView.Adapter() { private lateinit var context: Context + private lateinit var circularRepository: CircularRepository private val adapterCallback: AdapterCallback = mainActivity private var collapsedItems = -1 @@ -60,6 +66,7 @@ class CircularLetterAdapter( inner class CircularLetterViewHolder(binding: ItemCircularBinding) : RecyclerView.ViewHolder(binding.root) { var card: CardView = binding.circularCard + var progressBar: ProgressBar = binding.circularProgressBar var title: TextView = binding.circularTitleTextview var number: TextView = binding.circularNumberTextview var date: TextView = binding.circularDateTextview @@ -71,6 +78,9 @@ class CircularLetterAdapter( var reminderButton: ImageButton = binding.circularReminderButton var attachmentsList: RecyclerView = binding.circularsAttachmentsList + val loading = MutableLiveData(false) + var observer: MutableList> = mutableListOf() + init { attachmentsList.layoutManager = LinearLayoutManager(context) } @@ -79,6 +89,7 @@ class CircularLetterAdapter( override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CircularLetterViewHolder { val binding = ItemCircularBinding.inflate(LayoutInflater.from(parent.context), parent, false) context = parent.context + circularRepository = AndroidCircularRepository.getInstance(context) return CircularLetterViewHolder(binding) } @@ -88,6 +99,23 @@ class CircularLetterAdapter( holder.title.text = circulars[position].name holder.date.text = circulars[position].date + val observer = Observer { + if (it) { + holder.progressBar.visibility = View.VISIBLE + holder.viewButton.isEnabled = false + holder.downloadButton.isEnabled = false + holder.shareButton.isEnabled = false + } else { + holder.progressBar.visibility = View.GONE + holder.viewButton.isEnabled = true + holder.downloadButton.isEnabled = true + holder.shareButton.isEnabled = true + } + } + + holder.loading.observe(mainActivity, observer) + holder.observer.add(observer) + if (circulars[position].read) { holder.number.typeface = Typeface.DEFAULT holder.date.typeface = Typeface.DEFAULT @@ -139,7 +167,7 @@ class CircularLetterAdapter( holder.attachmentsList.adapter = null } else { FileUtils.preloadFiles( - circulars[position].url, + circulars[position].realUrl, circulars[position].attachmentsUrls, mainActivity.customTabsSession ) @@ -161,9 +189,10 @@ class CircularLetterAdapter( if (circulars[position].attachmentsNames.isNotEmpty()) { holder.attachmentsList.visibility = View.VISIBLE holder.attachmentsList.adapter = AttachmentAdapter( - circulars[position].attachmentsNames, - circulars[position].attachmentsUrls, - mainActivity + circulars[position], + mainActivity, + adapterScope, + holder ) } else { holder.attachmentsList.adapter = null @@ -181,16 +210,29 @@ class CircularLetterAdapter( } } - FileUtils.viewFile(circulars[position].url, context, mainActivity.customTabsSession) + runWhenUrlIsAvailable(holder, circulars[position]) { url -> + FileUtils.viewFile( + url, + context, + mainActivity.customTabsSession + ) + } } holder.shareButton.setOnClickListener { - FileUtils.shareFile(circulars[position].url, context) + runWhenUrlIsAvailable(holder, circulars[position]) { url -> + FileUtils.shareFile( + url, + context + ) + } } holder.downloadButton.setOnClickListener { - val file = DownloadableFile(circulars[position].name, circulars[position].url) - FileUtils.downloadFile(file, adapterCallback, context) + runWhenUrlIsAvailable(holder, circulars[position]) { url -> + val file = DownloadableFile(circulars[position].name, url) + FileUtils.downloadFile(file, adapterCallback, context) + } } holder.favouriteButton.setOnClickListener { @@ -254,6 +296,32 @@ class CircularLetterAdapter( } } + override fun onViewRecycled(holder: CircularLetterViewHolder) { + holder.observer.forEach { holder.loading.removeObserver(it) } + holder.observer.clear() + super.onViewRecycled(holder) + } + + private fun runWhenUrlIsAvailable( + holder: CircularLetterViewHolder, + circular: Circular, + code: (url: String) -> Unit + ) { + if (circular.realUrl == null) { + holder.loading.postValue(true) + + adapterScope.launch { + val realUrl = + circularRepository.getRealUrl(circular.url, circular.id, circular.school) + holder.loading.postValue(false) + code(realUrl) + } + return + } + + code(circular.realUrl!!) + } + fun changeDataSet(newCirculars: List) { if (circulars.size != newCirculars.size) collapsedItems = -1 diff --git a/app/src/main/java/net/underdesk/circolapp/push/CircolappFirebaseMessagingService.kt b/app/src/main/java/net/underdesk/circolapp/push/CircolappFirebaseMessagingService.kt index 7716c18..7b2821b 100644 --- a/app/src/main/java/net/underdesk/circolapp/push/CircolappFirebaseMessagingService.kt +++ b/app/src/main/java/net/underdesk/circolapp/push/CircolappFirebaseMessagingService.kt @@ -33,7 +33,7 @@ class CircolappFirebaseMessagingService : FirebaseMessagingService() { val url = remoteMessage.data["url"] ?: "" val circular = Circular( - id, -1, name, url, "", + id, -1, name, url, null, "", favourite = false, reminder = false, attachmentsNames = mutableListOf(), diff --git a/app/src/main/java/net/underdesk/circolapp/utils/FileUtils.kt b/app/src/main/java/net/underdesk/circolapp/utils/FileUtils.kt index 6010899..222a4c4 100644 --- a/app/src/main/java/net/underdesk/circolapp/utils/FileUtils.kt +++ b/app/src/main/java/net/underdesk/circolapp/utils/FileUtils.kt @@ -78,7 +78,10 @@ object FileUtils { } } - fun preloadFiles(url: String, otherUrls: List, session: CustomTabsSession?) { + fun preloadFiles(url: String?, otherUrls: List, session: CustomTabsSession?) { + if (url == null) + return + if (!url.endsWith(".pdf")) { val bundles = arrayListOf() diff --git a/app/src/main/res/layout/item_circular.xml b/app/src/main/res/layout/item_circular.xml index a972fed..68caa50 100644 --- a/app/src/main/res/layout/item_circular.xml +++ b/app/src/main/res/layout/item_circular.xml @@ -14,6 +14,19 @@ android:layout_width="match_parent" android:layout_height="match_parent"> + + currentVer) { + AppDatabase.Schema.migrate(it, currentVer, schemaVer) + DatabaseFactory.setVersion(it, schemaVer) + } + } } } diff --git a/shared/src/androidMain/kotlin/net/underdesk/circolapp/shared/server/curie/SpecificCurieServer.kt b/shared/src/androidMain/kotlin/net/underdesk/circolapp/shared/server/curie/SpecificCurieServer.kt index c75f216..e3567b3 100644 --- a/shared/src/androidMain/kotlin/net/underdesk/circolapp/shared/server/curie/SpecificCurieServer.kt +++ b/shared/src/androidMain/kotlin/net/underdesk/circolapp/shared/server/curie/SpecificCurieServer.kt @@ -29,14 +29,26 @@ actual class SpecificCurieServer actual constructor(private val curieServer: Cur val list = ArrayList() htmlList.forEach { element -> + val url = element.attr("href") if (element.parents().size == 6) { list.last().attachmentsNames.add(element.text()) - list.last().attachmentsUrls.add(element.attr("href")) + list.last().attachmentsUrls.add(url) + + if (url.endsWith(".pdf")) { + list.last().realAttachmentsUrls.add(url) + } else { + list.last().realAttachmentsUrls.add("") + } } else if (element.parents().size == 4) { - list.add(curieServer.generateFromString(element.text(), element.attr("href"))) + list.add(curieServer.generateFromString(element.text(), url)) } } return list } + + actual fun parseFileUrl(string: String): String { + val document = Jsoup.parseBodyFragment(string) + return document.getElementsByClass("mtli_attachment")[0].attr("href") + } } diff --git a/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/data/Circular.kt b/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/data/Circular.kt index a621b14..d1e44f2 100644 --- a/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/data/Circular.kt +++ b/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/data/Circular.kt @@ -23,10 +23,12 @@ data class Circular( val school: Int, val name: String, val url: String, + val realUrl: String?, val date: String, var favourite: Boolean = false, var reminder: Boolean = false, var read: Boolean = false, val attachmentsNames: MutableList = mutableListOf(), - val attachmentsUrls: MutableList = mutableListOf() + val attachmentsUrls: MutableList = mutableListOf(), + val realAttachmentsUrls: MutableList = mutableListOf() ) diff --git a/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/data/CircularDao.kt b/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/data/CircularDao.kt index 97b8668..7c4b822 100644 --- a/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/data/CircularDao.kt +++ b/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/data/CircularDao.kt @@ -34,18 +34,20 @@ class CircularDao( private val appDatabaseQueries = database.appDatabaseQueries private val circularMapper = - { id: Long, school: Long, name: String, url: String, date: String, favourite: Long, reminder: Long, read: Long, attachmentsNames: String, attachmentsUrls: String -> + { id: Long, school: Long, name: String, url: String, date: String, favourite: Long, reminder: Long, read: Long, attachmentsNames: String, attachmentsUrls: String, realAttachmentsUrls: String, realUrl: String? -> Circular( id, school.toInt(), name, url, + realUrl, date, favourite.toBoolean(), reminder.toBoolean(), read.toBoolean(), attachmentsNames.toList(), - attachmentsUrls.toList() + attachmentsUrls.toList(), + realAttachmentsUrls.toList() ) } @@ -61,7 +63,9 @@ class CircularDao( it.reminder.toLong(), it.read.toLong(), it.attachmentsNames.joinToString(), - it.attachmentsUrls.joinToString() + it.attachmentsUrls.joinToString(), + it.realAttachmentsUrls.joinToString(), + it.realUrl ) } } @@ -76,6 +80,24 @@ class CircularDao( ) } + suspend fun setRealUrl(id: Long, school: Int, url: String?) = + withContext(PlatformDispatcher.IO) { + appDatabaseQueries.setRealUrl( + url, + id, + school.toLong() + ) + } + + suspend fun setRealAttachmentsUrls(id: Long, school: Int, urls: List) = + withContext(PlatformDispatcher.IO) { + appDatabaseQueries.setRealAttachmentsUrls( + urls.joinToString(), + id, + school.toLong() + ) + } + suspend fun markRead(id: Long, school: Int, read: Boolean) = withContext(PlatformDispatcher.IO) { appDatabaseQueries.markCircularRead( diff --git a/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/data/CircularRepository.kt b/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/data/CircularRepository.kt index b470363..a3eaa12 100644 --- a/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/data/CircularRepository.kt +++ b/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/data/CircularRepository.kt @@ -57,4 +57,34 @@ class CircularRepository( } return Pair(onlyNewCirculars, errorCode) } + + suspend fun getRealUrl(rawUrl: String, id: Long, school: Int): String { + val result = serverAPI.getRealUrl(rawUrl) + + if (result.second != ServerAPI.Companion.Result.SUCCESS) + return rawUrl + + circularDao.setRealUrl(id, school, result.first) + return result.first + } + + suspend fun getRealUrlForAttachment( + index: Int, + rawUrls: List, + realUrls: List, + id: Long, + school: Int + ): List { + val result = serverAPI.getRealUrl(rawUrls[index]) + + if (result.second != ServerAPI.Companion.Result.SUCCESS) + return realUrls + + val newList = + if (realUrls.size != rawUrls.size) MutableList(rawUrls.size) { "" } else realUrls.toMutableList() + newList[index] = result.first + + circularDao.setRealAttachmentsUrls(id, school, newList) + return newList + } } diff --git a/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/data/DatabaseFactory.kt b/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/data/DatabaseFactory.kt index fa3ab6e..ec8998e 100644 --- a/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/data/DatabaseFactory.kt +++ b/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/data/DatabaseFactory.kt @@ -22,4 +22,16 @@ import com.squareup.sqldelight.db.SqlDriver object DatabaseFactory { fun createDatabase(sqlDriver: SqlDriver) = AppDatabase(sqlDriver) + + fun getVersion(driver: SqlDriver): Int { + val sqlCursor = driver.executeQuery(null, "PRAGMA user_version;", 0, null) + if (!sqlCursor.next()) + return 0 + + return sqlCursor.getLong(0)?.toInt() ?: 0 + } + + fun setVersion(driver: SqlDriver, version: Int) { + driver.execute(null, "PRAGMA user_version = $version;", 0, null) + } } diff --git a/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/server/Server.kt b/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/server/Server.kt index 504928e..d399da2 100644 --- a/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/server/Server.kt +++ b/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/server/Server.kt @@ -26,5 +26,6 @@ abstract class Server( ) { abstract val serverID: Int abstract suspend fun getCircularsFromServer(): Pair, ServerAPI.Companion.Result> + abstract suspend fun getRealUrl(rawUrl: String): Pair abstract suspend fun newCircularsAvailable(): Pair } diff --git a/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/server/ServerAPI.kt b/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/server/ServerAPI.kt index c93d408..8d68cc5 100644 --- a/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/server/ServerAPI.kt +++ b/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/server/ServerAPI.kt @@ -50,6 +50,11 @@ class ServerAPI(serverName: Servers) { server.getCircularsFromServer() } + suspend fun getRealUrl(rawUrl: String): Pair = + withContext(PlatformDispatcher.IO) { + server.getRealUrl(rawUrl) + } + fun changeServer(serverName: Servers) { server = createServer(serverName, ktorClient) } diff --git a/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/server/curie/CurieServer.kt b/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/server/curie/CurieServer.kt index 9c8ec73..70b1e89 100644 --- a/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/server/curie/CurieServer.kt +++ b/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/server/curie/CurieServer.kt @@ -46,6 +46,23 @@ class CurieServer(ktorClient: HttpClient) : Server(ktorClient) { } } + override suspend fun getRealUrl(rawUrl: String): Pair { + if (rawUrl.endsWith(".pdf")) + return Pair(rawUrl, ServerAPI.Companion.Result.SUCCESS) + + return try { + withContext(Dispatchers.Default) { + val html: String = ktorClient.get(rawUrl) + val realUrl = SpecificCurieServer(this@CurieServer).parseFileUrl(html) + Pair(realUrl, ServerAPI.Companion.Result.SUCCESS) + } + } catch (exception: IOException) { + Pair(rawUrl, ServerAPI.Companion.Result.NETWORK_ERROR) + } catch (exception: Exception) { + Pair(rawUrl, ServerAPI.Companion.Result.GENERIC_ERROR) + } + } + override suspend fun newCircularsAvailable(): Pair { return Pair(true, ServerAPI.Companion.Result.SUCCESS) } @@ -61,6 +78,8 @@ class CurieServer(ktorClient: HttpClient) : Server(ktorClient) { """(\d+)""".toRegex() val idMatcher = idRegex.find(string) + val realUrl = if (url.endsWith(".pdf")) url else null + val id = idMatcher?.value?.toLong() ?: -1L val dateRegex = @@ -75,9 +94,9 @@ class CurieServer(ktorClient: HttpClient) : Server(ktorClient) { .removePrefix("_") .removePrefix(" ") - Circular(id, serverID, title, url, dateMatcher.value) + Circular(id, serverID, title, url, realUrl, dateMatcher.value) } else { - Circular(id, serverID, title, url, "") + Circular(id, serverID, title, url, realUrl, "") } } @@ -88,4 +107,5 @@ class CurieServer(ktorClient: HttpClient) : Server(ktorClient) { expect class SpecificCurieServer(curieServer: CurieServer) { fun parseHtml(string: String): List + fun parseFileUrl(string: String): String } diff --git a/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/server/porporato/PorporatoServer.kt b/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/server/porporato/PorporatoServer.kt index 9df6df8..8324155 100644 --- a/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/server/porporato/PorporatoServer.kt +++ b/shared/src/commonMain/kotlin/net/underdesk/circolapp/shared/server/porporato/PorporatoServer.kt @@ -67,6 +67,10 @@ class PorporatoServer(ktorClient: HttpClient) : Server(ktorClient) { } } + override suspend fun getRealUrl(rawUrl: String): Pair { + return Pair(rawUrl, ServerAPI.Companion.Result.SUCCESS) + } + override suspend fun newCircularsAvailable(): Pair { return Pair(true, ServerAPI.Companion.Result.SUCCESS) } @@ -85,6 +89,7 @@ class PorporatoServer(ktorClient: HttpClient) : Server(ktorClient) { val parent = list.find { it.id == attachment.id && !it.name.startsWith("All") } parent?.attachmentsNames?.add(attachment.name) parent?.attachmentsUrls?.add(attachment.url) + parent?.realAttachmentsUrls?.add(attachment.url) return@removeAll true } @@ -101,6 +106,7 @@ class PorporatoServer(ktorClient: HttpClient) : Server(ktorClient) { val parent = list[lastIndex] parent.attachmentsNames.add(attachment.name) parent.attachmentsUrls.add(attachment.url) + parent.realAttachmentsUrls.add(attachment.url) return@removeAll true } @@ -146,9 +152,9 @@ class PorporatoServer(ktorClient: HttpClient) : Server(ktorClient) { title = title.removeRange(dateMatcher.range) .removeSuffix(" (pubb.: )") - Circular(id, serverID, title, fullUrl, dateMatcher.value.replace("-", "/")) + Circular(id, serverID, title, fullUrl, fullUrl, dateMatcher.value.replace("-", "/")) } else { - Circular(id, serverID, title, fullUrl, "") + Circular(id, serverID, title, fullUrl, fullUrl, "") } } } diff --git a/shared/src/commonMain/sqldelight/net.underdesk.circolapp.shared.data/1.sqm b/shared/src/commonMain/sqldelight/net.underdesk.circolapp.shared.data/1.sqm new file mode 100644 index 0000000..7e56e5e --- /dev/null +++ b/shared/src/commonMain/sqldelight/net.underdesk.circolapp.shared.data/1.sqm @@ -0,0 +1,2 @@ +ALTER TABLE Circulars ADD COLUMN realAttachmentsUrls TEXT NOT NULL DEFAULT ""; +ALTER TABLE Circulars ADD COLUMN realUrl TEXT; \ No newline at end of file diff --git a/shared/src/commonMain/sqldelight/net.underdesk.circolapp.shared.data/AppDatabase.sq b/shared/src/commonMain/sqldelight/net.underdesk.circolapp.shared.data/AppDatabase.sq index b5b4303..9d72dc0 100644 --- a/shared/src/commonMain/sqldelight/net.underdesk.circolapp.shared.data/AppDatabase.sq +++ b/shared/src/commonMain/sqldelight/net.underdesk.circolapp.shared.data/AppDatabase.sq @@ -9,18 +9,30 @@ CREATE TABLE Circulars ( read INTEGER NOT NULL DEFAULT 0, attachmentsNames TEXT NOT NULL, attachmentsUrls TEXT NOT NULL, + realAttachmentsUrls TEXT NOT NULL, + realUrl TEXT, PRIMARY KEY (id, school) ); insertCircular: -INSERT OR IGNORE INTO Circulars(id, school, name, url, date, favourite, reminder, read, attachmentsNames, attachmentsUrls) -VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?); +INSERT OR IGNORE INTO Circulars(id, school, name, url, date, favourite, reminder, read, attachmentsNames, attachmentsUrls, realAttachmentsUrls, realUrl) +VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); updateCircular: UPDATE Circulars SET favourite = ?, reminder = ? WHERE id = ? AND school = ?; +setRealUrl: +UPDATE Circulars +SET realUrl = ? +WHERE id = ? AND school = ?; + +setRealAttachmentsUrls: +UPDATE Circulars +SET realAttachmentsUrls = ? +WHERE id = ? AND school = ?; + markCircularRead: UPDATE Circulars SET read = ? diff --git a/shared/src/iosMain/kotlin/net/underdesk/circolapp/shared/data/DatabaseDriverFactory.kt b/shared/src/iosMain/kotlin/net/underdesk/circolapp/shared/data/DatabaseDriverFactory.kt index ea77f97..561605c 100644 --- a/shared/src/iosMain/kotlin/net/underdesk/circolapp/shared/data/DatabaseDriverFactory.kt +++ b/shared/src/iosMain/kotlin/net/underdesk/circolapp/shared/data/DatabaseDriverFactory.kt @@ -24,5 +24,18 @@ import com.squareup.sqldelight.drivers.native.NativeSqliteDriver actual class DatabaseDriverFactory { actual fun createDriver(): SqlDriver { return NativeSqliteDriver(AppDatabase.Schema, "circolapp.db") + .also { + var currentVer = DatabaseFactory.getVersion(it) + val schemaVer: Int = AppDatabase.Schema.version + + if (currentVer == 0) { + currentVer = 1 + } + + if (schemaVer > currentVer) { + AppDatabase.Schema.migrate(it, currentVer, schemaVer) + DatabaseFactory.setVersion(it, schemaVer) + } + } } } diff --git a/shared/src/iosMain/kotlin/net/underdesk/circolapp/shared/server/curie/SpecificCurieServer.kt b/shared/src/iosMain/kotlin/net/underdesk/circolapp/shared/server/curie/SpecificCurieServer.kt index 65fbd04..f30fa38 100644 --- a/shared/src/iosMain/kotlin/net/underdesk/circolapp/shared/server/curie/SpecificCurieServer.kt +++ b/shared/src/iosMain/kotlin/net/underdesk/circolapp/shared/server/curie/SpecificCurieServer.kt @@ -30,14 +30,25 @@ actual class SpecificCurieServer actual constructor(private val curieServer: Cur val list = ArrayList() htmlList?.forEach { element -> + val url = element.attributes.objectForKey("href").toString() if (element.parentElement?.parentElement?.parentElement?.tagName == "li") { list.last().attachmentsNames.add(element.textContent) - list.last().attachmentsUrls.add(element.attributes.objectForKey("href").toString()) + list.last().attachmentsUrls.add(url) + + if (url.endsWith(".pdf")) { + list.last().realAttachmentsUrls.add(url) + } else { + list.last().realAttachmentsUrls.add("") + } } else { - list.add(curieServer.generateFromString(element.textContent, element.attributes.objectForKey("href").toString())) + list.add(curieServer.generateFromString(element.textContent, url)) } } return list } + + actual fun parseFileUrl(string: String): String { + TODO("Not yet implemented") + } } diff --git a/shared/src/jvmMain/kotlin/net/underdesk/circolapp/shared/data/DatabaseDriverFactory.kt b/shared/src/jvmMain/kotlin/net/underdesk/circolapp/shared/data/DatabaseDriverFactory.kt index eef7035..08af893 100644 --- a/shared/src/jvmMain/kotlin/net/underdesk/circolapp/shared/data/DatabaseDriverFactory.kt +++ b/shared/src/jvmMain/kotlin/net/underdesk/circolapp/shared/data/DatabaseDriverFactory.kt @@ -25,27 +25,18 @@ actual class DatabaseDriverFactory(private val path: String) { actual fun createDriver(): SqlDriver { return JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY + path) .also { - val currentVer = getVersion(it) + val currentVer = DatabaseFactory.getVersion(it) if (currentVer == 0) { AppDatabase.Schema.create(it) - setVersion(it, 1) + DatabaseFactory.setVersion(it, 1) } else { val schemaVer: Int = AppDatabase.Schema.version if (schemaVer > currentVer) { AppDatabase.Schema.migrate(it, currentVer, schemaVer) - setVersion(it, schemaVer) + DatabaseFactory.setVersion(it, schemaVer) println("init: migrated from $currentVer to $schemaVer") } } } } - - private fun getVersion(driver: SqlDriver): Int { - val sqlCursor = driver.executeQuery(null, "PRAGMA user_version;", 0, null) - return sqlCursor.getLong(0)!!.toInt() - } - - private fun setVersion(driver: SqlDriver, version: Int) { - driver.execute(null, String.format("PRAGMA user_version = %d;", version), 0, null) - } }