Skip to content

Commit

Permalink
feature: simplified apk installation
Browse files Browse the repository at this point in the history
  • Loading branch information
popovanton0 committed Feb 27, 2024
1 parent ddacd35 commit f40229d
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 68 deletions.
27 changes: 8 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,7 @@ You can read more about it [here](https://www.jetbrains.com/help/idea/managing-p
"functionSimpleNamePrefix": "Ds",
"appPackageName": "com.your.designsystem.package.demo",
"componentDeeplink": "yourscheme://component/DS_COMPONENT_FQN_DEEPLINK_PLACEHOLDER",
"apkInstalling": {
"latestVersion": {
"file": "/gradle/libs.versions.toml",
"regex": "demoApp=\"(?<version>[a-zA-Z0-9.-]+)\""
}
}
"apkInstallation": true
}
}
```
Expand Down Expand Up @@ -248,7 +243,7 @@ You can read more about it [here](https://www.jetbrains.com/help/idea/managing-p
// package name of the demo app
"appPackageName": "com.your.designsystem.package.demo",
// deeplink that will be used to open a component page in the demo app.
// DS_COMPONENT_FQN_DEEPLINK_PLACEHOLDER will bw replaced with
// DS_COMPONENT_FQN_DEEPLINK_PLACEHOLDER will be replaced with
// the fully qualified name of the
// composable function, e.g. com.your.designsystem.package.components.Badge
"componentDeeplink": "yourscheme://component/DS_COMPONENT_FQN_DEEPLINK_PLACEHOLDER",
Expand All @@ -257,18 +252,12 @@ You can read more about it [here](https://www.jetbrains.com/help/idea/managing-p
// Installing (if not installed) the apk file
// of the demo app (showcase app) on an Android device.

// Demo app apk must be placed here: /.idea/kelp/demoApp-0.12.0.apk
// Plugin will acquire the latest version from apkInstalling.latestVersion.file (for example, 0.12.0)
// and install an apk file with that version (from a path above) on the device.
"apkInstalling": {
"latestVersion": {
// looks in this file
"file": "/gradle/libs.versions.toml",
// for this regex. Text in the named group "version"
// MUST contain "versionName" of the demo apk
"regex": "demoApp=\"(?<version>[a-zA-Z0-9.-]+)\""
},
}
// Demo app apk must be placed here with this name: /.idea/kelp/demoApp-VERSION_NAME.apk
// For example: /.idea/kelp/demoApp-0.12.0.apk
// The plugin will acquire the latest version from the apk file name (for example, 0.12.0).
// If the app is not installed OR installed, but has a lower
// version, the plugin will install the apk on the device.
"apkInstallation": true
}
}
```
Expand Down
14 changes: 2 additions & 12 deletions src/main/kotlin/ru/ozon/ideplugin/kelp/KelpConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import com.intellij.openapi.vfs.AsyncFileListener.ChangeApplier
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.openapi.vfs.readText
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import ru.ozon.ideplugin.kelp.codeCompletion.DsColorLookupElement
import ru.ozon.ideplugin.kelp.codeCompletion.DsComponentFunLookupElement
Expand Down Expand Up @@ -82,17 +81,8 @@ class KelpConfig(
val appPackageName: String,
val componentDeeplink: String,
val intentionName: String = KelpBundle.message("openInDemoAppIntentionName"),
val apkInstalling: ApkInstalling? = null,
) {
@Serializable
class ApkInstalling(val latestVersion: LatestVersion) {
@Serializable
class LatestVersion(
val file: String,
val regex: String,
)
}
}
val apkInstallation: Boolean? = null,
)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import com.intellij.openapi.ui.popup.ListPopupStep
import com.intellij.openapi.ui.popup.PopupStep
import com.intellij.openapi.ui.popup.util.BaseListPopupStep
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.openapi.vfs.readText
import com.intellij.openapi.wm.ToolWindowManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
Expand All @@ -36,7 +35,6 @@ import java.nio.file.Path
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.io.path.Path
import kotlin.io.path.div

/**
Expand All @@ -48,11 +46,10 @@ import kotlin.io.path.div
* selecting the Android device on which you'd like to open the demo app. If there is only one Android device,
* it is selected by default.
* - Turns on the screen of the Android device
* - Acquires the intended latest version of the demo app from [KelpConfig.DemoApp.ApkInstalling.LatestVersion.file].
* - Acquires the intended latest version of the demo app from name of the demo app apk file.
* - Checks whether the demo app is installed on the Android device, and if so, whether it is the latest
* version. If not, the apk file is installed on the Android device from the predefined path: [apkPath].
* - Next, an intent is launched with a deeplink leading to the component
* page in demo app.
* - Next, an intent is launched with a deeplink leading to the component page in demo app.
*/
@Suppress("IntentionDescriptionNotFoundInspection")
internal class OpenDsComponentInDemoAppIntention : PsiElementBaseIntentionAction(), IntentionAction, PriorityAction {
Expand All @@ -70,7 +67,7 @@ internal class OpenDsComponentInDemoAppIntention : PsiElementBaseIntentionAction
}

val isAvailable = element.parent.reference?.resolve()?.isDsComponentFunction(config) == true ||
(element.parent as? KtNamedFunction)?.isDsComponentFunction(config) == true
(element.parent as? KtNamedFunction)?.isDsComponentFunction(config) == true
if (isAvailable) text = config.intentionName
return isAvailable
}
Expand Down Expand Up @@ -158,10 +155,10 @@ internal class OpenDsComponentInDemoAppIntention : PsiElementBaseIntentionAction
progressIndicator: ProgressIndicator,
device: IDevice,
) {
if (config.apkInstalling == null) return
if (config.apkInstallation != true) return

progressIndicator.text = KelpBundle.message("checkingInstalledAppVersionMessage")
val latestVersion = getLatestVersion(project, config.apkInstalling)
val latestVersion = getLatestVersion(project)
val isLatestVersionInstalled = isLatestVersionInstalled(device, latestVersion, config.appPackageName)

if (isLatestVersionInstalled) return
Expand All @@ -170,42 +167,30 @@ internal class OpenDsComponentInDemoAppIntention : PsiElementBaseIntentionAction
device.uninstallPackage(config.appPackageName)

progressIndicator.text = KelpBundle.message("installingAppMessage")
val apkPath = apkPath(project, latestVersion)
val apkPath = apkPath(project)
device.installPackage(apkPath.toString(), true)
}

private fun getLatestVersion(
project: Project,
apkInstalling: KelpConfig.DemoApp.ApkInstalling,
): String {
val latestVersionFilePath = Path(project.basePath!!) / apkInstalling.latestVersion.file.removePrefix("/")
val fileContent: String = runReadAction {
VirtualFileManager.getInstance()
.findFileByNioPath(latestVersionFilePath)
?.readText()
?: error(
KelpBundle.message("demoAppLatestVersionInfoFileNotFoundErrorMessage", latestVersionFilePath),
)
}

val regex = apkInstalling.latestVersion.regex
return regex.toRegex()
.find(fileContent)
?.groups?.get("version")?.value
?: error(
KelpBundle.message("demoAppLatestVersionNotFoundErrorMessage", regex, latestVersionFilePath),
)
private fun getLatestVersion(project: Project): String {
val apkFileName = apkPath(project).toFile().name
return apkFileNameRegex.matchEntire(apkFileName)?.groups?.get("version")?.value
?: error(KelpBundle.message("demoAppLatestVersionNotFoundErrorMessage", apkFileName))
}

private fun apkPath(project: Project, latestVersion: String): Path {
val apkPath = pluginConfigDirPath(project) / "apk" / "demoApp-$latestVersion.apk"
private fun apkPath(project: Project): Path {
val apkFolderPath = pluginConfigDirPath(project) / "apk"
return runReadAction {
VirtualFileManager.getInstance()
.findFileByNioPath(apkPath)
?.toNioPath() ?: error(KelpBundle.message("apkFileNotFoundErrorMessage", apkPath))
.findFileByNioPath(apkFolderPath)
?.children
?.find { it.name.matches(apkFileNameRegex) }
?.toNioPath()
?: error(KelpBundle.message("apkFileNotFoundErrorMessage", apkFolderPath))
}
}

private val apkFileNameRegex = "demoApp-(?<version>.+?).apk".toRegex()

private fun isLatestVersionInstalled(device: IDevice, latestVersion: String, demoAppPackageName: String): Boolean {
val isLatestVersionInstalled = AtomicBoolean(false)
val latch = CountDownLatch(1)
Expand Down Expand Up @@ -295,6 +280,6 @@ internal class OpenDsComponentInDemoAppIntention : PsiElementBaseIntentionAction
private companion object {
private const val DS_COMPONENT_FQN_DEEPLINK_PLACEHOLDER = "DS_COMPONENT_FQN_DEEPLINK_PLACEHOLDER"
private const val UNLOCK_SCREEN_COMMAND = "input keyevent 82"
private const val SHELL_TIMEOUT_MS = 3000L
private const val SHELL_TIMEOUT_MS = 6000L
}
}
3 changes: 1 addition & 2 deletions src/main/resources/messages/KelpBundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ chooseDevicePopupTitle=Choose a Device
checkingInstalledAppVersionMessage=Checking installed demo app version
uninstallingPreviousAppMessage=Uninstalling previous demo app version
installingAppMessage=Installing demo app apk
demoAppLatestVersionInfoFileNotFoundErrorMessage=File that contains info about latest version of the demo app wasn't found: {0}
demoAppLatestVersionNotFoundErrorMessage=Latest version of the demo app wasn't found by this regex '{0}' in this file {1}
demoAppLatestVersionNotFoundErrorMessage=Latest version of the demo app wasn't found in the filename of this apk: {0}
apkFileNotFoundErrorMessage=Demo apk file was not found here: {0}
openedNotificationContent={0} opened in demo app
componentOpeningErrorTitle=Error While Opening DS Component
Expand Down

0 comments on commit f40229d

Please sign in to comment.