From bc3ad75328b8a745ec899b29f18f41ac3e0c8a2d Mon Sep 17 00:00:00 2001 From: Aria Moradi Date: Mon, 29 Mar 2021 02:47:51 +0430 Subject: [PATCH] finished Update support: webUI side --- .../ir/armor/tachidesk/impl/Extension.kt | 19 ++++---- .../ir/armor/tachidesk/impl/ExtensionsList.kt | 6 ++- .../model/dataclass/ExtensionDataClass.kt | 4 +- .../ir/armor/tachidesk/server/JavalinSetup.kt | 4 +- webUI/react/src/components/ExtensionCard.tsx | 48 ++++++++++++++++--- webUI/react/src/screens/Extensions.tsx | 11 +++-- webUI/react/src/typings.d.ts | 6 +-- webUI/react/src/util/language.tsx | 1 + 8 files changed, 72 insertions(+), 27 deletions(-) diff --git a/server/src/main/kotlin/ir/armor/tachidesk/impl/Extension.kt b/server/src/main/kotlin/ir/armor/tachidesk/impl/Extension.kt index ed5ab89..78c9ecb 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/impl/Extension.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/impl/Extension.kt @@ -168,19 +168,22 @@ private fun downloadAPKFile(url: String, apkPath: String) { sink.close() } -fun removeExtension(pkgName: String) { +fun uninstallExtension(pkgName: String) { logger.debug("Uninstalling $pkgName") - val extensionRecord = extensionTableAsDataClass().first { it.pkgName == pkgName } - val fileNameWithoutType = extensionRecord.apkName.substringBefore(".apk") + val extensionRecord = transaction { ExtensionTable.select { ExtensionTable.pkgName eq pkgName }.firstOrNull()!! } + val fileNameWithoutType = extensionRecord[ExtensionTable.apkName].substringBefore(".apk") val jarPath = "${applicationDirs.extensionsRoot}/$fileNameWithoutType.jar" transaction { - val extensionId = ExtensionTable.select { ExtensionTable.name eq extensionRecord.name }.first()[ExtensionTable.id] + val extensionId = extensionRecord[ExtensionTable.id].value SourceTable.deleteWhere { SourceTable.extension eq extensionId } - ExtensionTable.update({ ExtensionTable.name eq extensionRecord.name }) { - it[isInstalled] = false - } + if (extensionRecord[ExtensionTable.isObsolete]) + ExtensionTable.deleteWhere { ExtensionTable.pkgName eq pkgName } + else + ExtensionTable.update({ ExtensionTable.pkgName eq pkgName }) { + it[isInstalled] = false + } } if (File(jarPath).exists()) { @@ -190,7 +193,7 @@ fun removeExtension(pkgName: String) { fun updateExtension(pkgName: String): Int { val targetExtension = ExtensionListData.updateMap.remove(pkgName)!! - removeExtension(pkgName) + uninstallExtension(pkgName) transaction { ExtensionTable.update({ ExtensionTable.pkgName eq pkgName }) { it[name] = targetExtension.name diff --git a/server/src/main/kotlin/ir/armor/tachidesk/impl/ExtensionsList.kt b/server/src/main/kotlin/ir/armor/tachidesk/impl/ExtensionsList.kt index 7ea4491..0a34ad5 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/impl/ExtensionsList.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/impl/ExtensionsList.kt @@ -28,9 +28,11 @@ object ExtensionListData { var updateMap = ConcurrentHashMap() } +const val ExtensionUpdateDelayTime = 0 // 60 seconds + fun getExtensionList(): List { - // update if 60 seconds has passed or requested offline and database is empty - if (ExtensionListData.lastUpdateCheck + 60 * 1000 < System.currentTimeMillis()) { + // update if {ExtensionUpdateDelayTime} seconds has passed or requested offline and database is empty + if (ExtensionListData.lastUpdateCheck + ExtensionUpdateDelayTime < System.currentTimeMillis()) { logger.debug("Getting extensions list from the internet") ExtensionListData.lastUpdateCheck = System.currentTimeMillis() runBlocking { diff --git a/server/src/main/kotlin/ir/armor/tachidesk/model/dataclass/ExtensionDataClass.kt b/server/src/main/kotlin/ir/armor/tachidesk/model/dataclass/ExtensionDataClass.kt index de0eb6c..41af672 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/model/dataclass/ExtensionDataClass.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/model/dataclass/ExtensionDataClass.kt @@ -16,7 +16,7 @@ data class ExtensionDataClass( val isNsfw: Boolean, val apkName: String, val iconUrl: String, - val isInstalled: Boolean, + val installed: Boolean, val hasUpdate: Boolean, - val isObsolete: Boolean, + val obsolete: Boolean, ) diff --git a/server/src/main/kotlin/ir/armor/tachidesk/server/JavalinSetup.kt b/server/src/main/kotlin/ir/armor/tachidesk/server/JavalinSetup.kt index 0e77ad2..12d45d5 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/server/JavalinSetup.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/server/JavalinSetup.kt @@ -21,13 +21,13 @@ import ir.armor.tachidesk.impl.getSourceList import ir.armor.tachidesk.impl.getThumbnail import ir.armor.tachidesk.impl.installExtension import ir.armor.tachidesk.impl.removeCategory -import ir.armor.tachidesk.impl.removeExtension import ir.armor.tachidesk.impl.removeMangaFromCategory import ir.armor.tachidesk.impl.removeMangaFromLibrary import ir.armor.tachidesk.impl.reorderCategory import ir.armor.tachidesk.impl.sourceFilters import ir.armor.tachidesk.impl.sourceGlobalSearch import ir.armor.tachidesk.impl.sourceSearch +import ir.armor.tachidesk.impl.uninstallExtension import ir.armor.tachidesk.impl.updateCategory import ir.armor.tachidesk.impl.updateExtension import ir.armor.tachidesk.server.util.openInBrowser @@ -89,7 +89,7 @@ fun javalinSetup() { app.get("/api/v1/extension/uninstall/:pkgName") { ctx -> val pkgName = ctx.pathParam("pkgName") - removeExtension(pkgName) + uninstallExtension(pkgName) ctx.status(200) } diff --git a/webUI/react/src/components/ExtensionCard.tsx b/webUI/react/src/components/ExtensionCard.tsx index 5ff5b4c..5b334cb 100644 --- a/webUI/react/src/components/ExtensionCard.tsx +++ b/webUI/react/src/components/ExtensionCard.tsx @@ -49,11 +49,17 @@ interface IProps { export default function ExtensionCard(props: IProps) { const { extension: { - name, lang, versionName, installed, pkgName, iconUrl, + name, lang, versionName, installed, hasUpdate, obsolete, pkgName, iconUrl, }, notifyInstall, } = props; - const [installedState, setInstalledState] = useState((installed ? 'uninstall' : 'install')); + const [installedState, setInstalledState] = useState( + () => { + if (obsolete) { return 'obsolete'; } + if (hasUpdate) { return 'update'; } + return (installed ? 'uninstall' : 'install'); + }, + ); const [serverAddress] = useLocalStorage('serverBaseURL', ''); @@ -69,6 +75,15 @@ export default function ExtensionCard(props: IProps) { }); } + function update() { + setInstalledState('updating'); + client.get(`/api/v1/extension/update/${pkgName}`) + .then(() => { + setInstalledState('uninstall'); + notifyInstall(); + }); + } + function uninstall() { setInstalledState('uninstalling'); client.get(`/api/v1/extension/uninstall/${pkgName}`) @@ -79,10 +94,22 @@ export default function ExtensionCard(props: IProps) { } function handleButtonClick() { - if (installedState === 'install') { - install(); - } else { - uninstall(); + switch (installedState) { + case 'install': + install(); + break; + case 'update': + update(); + break; + case 'obsolete': + uninstall(); + setTimeout(() => window.location.reload(), 3000); + break; + case 'uninstall': + uninstall(); + break; + default: + break; } } @@ -108,7 +135,14 @@ export default function ExtensionCard(props: IProps) { - + ); diff --git a/webUI/react/src/screens/Extensions.tsx b/webUI/react/src/screens/Extensions.tsx index 9e6124b..968d9fd 100644 --- a/webUI/react/src/screens/Extensions.tsx +++ b/webUI/react/src/screens/Extensions.tsx @@ -17,7 +17,7 @@ const allLangs: string[] = []; function groupExtensions(extensions: IExtension[]) { allLangs.length = 0; // empty the array - const result = { installed: [] } as any; + const result = { installed: [], 'updates pending': [] } as any; extensions.sort((a, b) => ((a.apkName > b.apkName) ? 1 : -1)); extensions.forEach((extension) => { @@ -26,7 +26,11 @@ function groupExtensions(extensions: IExtension[]) { if (extension.lang !== 'all') { allLangs.push(extension.lang); } } if (extension.installed) { - result.installed.push(extension); + if (extension.hasUpdate) { + result['updates pending'].push(extension); + } else { + result.installed.push(extension); + } } else { result[extension.lang].push(extension); } @@ -79,11 +83,12 @@ export default function Extensions() { if (Object.entries(extensions).length === 0) { return

loading...

; } + const groupsToShow = ['updates pending', 'installed', ...shownLangs]; return ( <> { Object.entries(extensions).map(([lang, list]) => ( - ((['installed', ...shownLangs].indexOf(lang) !== -1 && (list as []).length > 0) + ((groupsToShow.indexOf(lang) !== -1 && (list as []).length > 0) && (

diff --git a/webUI/react/src/typings.d.ts b/webUI/react/src/typings.d.ts index 80725e8..747f267 100644 --- a/webUI/react/src/typings.d.ts +++ b/webUI/react/src/typings.d.ts @@ -14,9 +14,9 @@ interface IExtension { isNsfw: boolean apkName: string iconUrl: string - isInstalled: boolean + installed: boolean hasUpdate: boolean - isObsolete: boolean + obsolete: boolean } interface ISource { @@ -81,4 +81,4 @@ interface ICategory { interface INavbarOverride { status: boolean value: any -} \ No newline at end of file +} diff --git a/webUI/react/src/util/language.tsx b/webUI/react/src/util/language.tsx index 920f6c9..14d589f 100644 --- a/webUI/react/src/util/language.tsx +++ b/webUI/react/src/util/language.tsx @@ -8,6 +8,7 @@ export const ISOLanguages = [ { code: 'all', name: 'All', nativeName: 'All' }, { code: 'installed', name: 'Installed', nativeName: 'Installed' }, + { code: 'updates pending', name: 'Updates pending', nativeName: 'Updates pending' }, // full list: https://github.com/meikidd/iso-639-1/blob/master/src/data.js { code: 'en', name: 'English', nativeName: 'English' },