@@ -12,6 +12,7 @@ import com.apurebase.kgraphql.schema.dsl.SchemaBuilder
1212import com.apurebase.kgraphql.schema.dsl.SchemaConfigurationDSL
1313import com.apurebase.kgraphql.schema.execution.Execution
1414import com.apurebase.kgraphql.schema.execution.Executor
15+ import com.ismartcoding.lib.apk.ApkParsers
1516import com.ismartcoding.lib.channel.sendEvent
1617import com.ismartcoding.lib.extensions.cut
1718import com.ismartcoding.lib.extensions.getFinalPath
@@ -44,20 +45,22 @@ import com.ismartcoding.plain.db.DMessageType
4445import com.ismartcoding.plain.enums.AppFeatureType
4546import com.ismartcoding.plain.enums.DataType
4647import com.ismartcoding.plain.enums.MediaPlayMode
47- import com.ismartcoding.plain.extensions.newPath
48- import com.ismartcoding.plain.extensions.sorted
49- import com.ismartcoding.plain.features.AudioPlayer
5048import com.ismartcoding.plain.events.CancelNotificationsEvent
51- import com.ismartcoding.plain.features.ChatHelper
5249import com.ismartcoding.plain.events.ClearAudioPlaylistEvent
5350import com.ismartcoding.plain.events.DeleteChatItemViewEvent
51+ import com.ismartcoding.plain.events.EventType
52+ import com.ismartcoding.plain.events.FetchLinkPreviewsEvent
5453import com.ismartcoding.plain.events.HttpApiEvents
55- import com.ismartcoding.plain.features.LinkPreviewHelper
54+ import com.ismartcoding.plain.events.StartScreenMirrorEvent
55+ import com.ismartcoding.plain.events.WebSocketEvent
56+ import com.ismartcoding.plain.extensions.newPath
57+ import com.ismartcoding.plain.extensions.sorted
58+ import com.ismartcoding.plain.features.AudioPlayer
59+ import com.ismartcoding.plain.features.ChatHelper
5660import com.ismartcoding.plain.features.NoteHelper
5761import com.ismartcoding.plain.features.PackageHelper
5862import com.ismartcoding.plain.features.Permission
5963import com.ismartcoding.plain.features.Permissions
60- import com.ismartcoding.plain.events.StartScreenMirrorEvent
6164import com.ismartcoding.plain.features.TagHelper
6265import com.ismartcoding.plain.features.call.SimHelper
6366import com.ismartcoding.plain.features.contact.GroupHelper
@@ -79,6 +82,7 @@ import com.ismartcoding.plain.helpers.DeviceInfoHelper
7982import com.ismartcoding.plain.helpers.FileHelper
8083import com.ismartcoding.plain.helpers.QueryHelper
8184import com.ismartcoding.plain.helpers.TempHelper
85+ import com.ismartcoding.plain.packageManager
8286import com.ismartcoding.plain.preference.ApiPermissionsPreference
8387import com.ismartcoding.plain.preference.AudioPlayModePreference
8488import com.ismartcoding.plain.preference.AudioPlayingPreference
@@ -112,16 +116,14 @@ import com.ismartcoding.plain.web.models.MediaFileInfo
112116import com.ismartcoding.plain.web.models.Message
113117import com.ismartcoding.plain.web.models.Note
114118import com.ismartcoding.plain.web.models.NoteInput
119+ import com.ismartcoding.plain.web.models.PackageInstallPending
115120import com.ismartcoding.plain.web.models.PackageStatus
116121import com.ismartcoding.plain.web.models.StorageStats
117122import com.ismartcoding.plain.web.models.Tag
118123import com.ismartcoding.plain.web.models.TempValue
119124import com.ismartcoding.plain.web.models.Video
120125import com.ismartcoding.plain.web.models.toExportModel
121126import com.ismartcoding.plain.web.models.toModel
122- import com.ismartcoding.plain.events.EventType
123- import com.ismartcoding.plain.events.FetchLinkPreviewsEvent
124- import com.ismartcoding.plain.events.WebSocketEvent
125127import com.ismartcoding.plain.workers.FeedFetchWorker
126128import io.ktor.http.ContentType
127129import io.ktor.http.HttpStatusCode
@@ -149,7 +151,6 @@ import kotlinx.serialization.json.put
149151import java.io.File
150152import java.io.StringReader
151153import java.io.StringWriter
152- import kotlin.collections.set
153154import kotlin.io.path.Path
154155import kotlin.io.path.moveTo
155156
@@ -435,7 +436,11 @@ class SXGraphQL(val schema: Schema) {
435436 }
436437 query(" packageStatuses" ) {
437438 resolver { ids: List <ID > ->
438- PackageHelper .getPackageStatuses(ids.map { it.value }).map { PackageStatus (ID (it.key), it.value) }
439+ PackageHelper .getPackageInfoMap(ids.map { it.value }).map {
440+ val pkg = it.value
441+ val updatedAt = if (pkg != null ) Instant .fromEpochMilliseconds(pkg.lastUpdateTime) else null
442+ PackageStatus (ID (it.key), pkg != null , updatedAt)
443+ }
439444 }
440445 }
441446 query(" packageCount" ) {
@@ -682,6 +687,38 @@ class SXGraphQL(val schema: Schema) {
682687 true
683688 }
684689 }
690+ mutation(" installPackage" ) {
691+ resolver { path: String ->
692+ val file = File (path)
693+ if (! file.exists()) {
694+ throw GraphQLError (" File does not exist" )
695+ }
696+
697+ try {
698+ val context = MainActivity .instance.get()!!
699+ if (file.name.endsWith(" .apk" , ignoreCase = true )) {
700+ LogCat .d(" Installing APK file: ${file.name} " )
701+ val apkMeta = ApkParsers .getMetaInfo(file)
702+ ? : throw GraphQLError (" Failed to parse APK package ID" )
703+
704+ PackageHelper .install(context, file)
705+ val packageName = apkMeta.packageName ? : " "
706+ try {
707+ val pkg = packageManager.getPackageInfo(packageName, 0 )
708+ PackageInstallPending (packageName, Instant .fromEpochMilliseconds(pkg.lastUpdateTime), isNew = false )
709+ } catch (e: Exception ) {
710+ PackageInstallPending (packageName, null , isNew = true )
711+ }
712+ } else {
713+ throw GraphQLError (" Unsupported file format. Only APK files are supported." )
714+ }
715+ } catch (e: Exception ) {
716+ LogCat .e(" Installation failed: ${e.message} " , e)
717+ throw GraphQLError (" Installation failed: ${e.message} " )
718+ }
719+ }
720+ }
721+
685722 mutation(" cancelNotifications" ) {
686723 resolver { ids: List <ID > ->
687724 sendEvent(CancelNotificationsEvent (ids.map { it.value }.toSet()))
0 commit comments