Convert SatsPrice to a Skip multiplatform app
64
Android/app/build.gradle.kts
Normal file
@@ -0,0 +1,64 @@
|
||||
import java.util.Properties
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.kotlin.android)
|
||||
alias(libs.plugins.kotlin.compose)
|
||||
alias(libs.plugins.android.application)
|
||||
id("skip-build-plugin")
|
||||
}
|
||||
|
||||
skip {
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = group as String
|
||||
compileSdk = libs.versions.android.sdk.compile.get().toInt()
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.toVersion(libs.versions.jvm.get())
|
||||
targetCompatibility = JavaVersion.toVersion(libs.versions.jvm.get())
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = libs.versions.jvm.get().toString()
|
||||
}
|
||||
packaging {
|
||||
jniLibs.keepDebugSymbols.add("**/*.so")
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
minSdk = libs.versions.android.sdk.min.get().toInt()
|
||||
targetSdk = libs.versions.android.sdk.compile.get().toInt()
|
||||
// skip.tools.skip-build-plugin will automatically use Skip.env properties for:
|
||||
// applicationId = PRODUCT_BUNDLE_IDENTIFIER
|
||||
// versionCode = CURRENT_PROJECT_VERSION
|
||||
// versionName = MARKETING_VERSION
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
}
|
||||
|
||||
// default signing configuration tries to load from keystore.properties
|
||||
signingConfigs {
|
||||
val keystorePropertiesFile = file("keystore.properties")
|
||||
if (keystorePropertiesFile.isFile) {
|
||||
create("release") {
|
||||
val keystoreProperties = Properties()
|
||||
keystoreProperties.load(keystorePropertiesFile.inputStream())
|
||||
keyAlias = keystoreProperties.getProperty("keyAlias")
|
||||
keyPassword = keystoreProperties.getProperty("keyPassword")
|
||||
storeFile = file(keystoreProperties.getProperty("storeFile"))
|
||||
storePassword = keystoreProperties.getProperty("storePassword")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
signingConfig = signingConfigs.findByName("release")
|
||||
isMinifyEnabled = true
|
||||
isShrinkResources = true
|
||||
isDebuggable = false // can be set to true for debugging release build, but needs to be false when uploading to store
|
||||
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
|
||||
}
|
||||
}
|
||||
}
|
||||
4
Android/app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
-keeppackagenames **
|
||||
-keep class skip.** { *; }
|
||||
-keep class com.sun.jna.Pointer { *; }
|
||||
-keep class sats.price.** { *; }
|
||||
30
Android/app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This AndroidManifest.xml template was generated by Skip -->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- example permissions for using device location -->
|
||||
<!-- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> -->
|
||||
<!-- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> -->
|
||||
|
||||
<!-- permissions needed for using the internet or an embedded WebKit browser -->
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<!-- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> -->
|
||||
|
||||
<application
|
||||
android:label="${PRODUCT_NAME}"
|
||||
android:name=".AndroidAppMain"
|
||||
android:supportsRtl="true"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|mnc|colorMode|density|fontScale|fontWeightAdjustment|keyboard|layoutDirection|locale|mcc|navigation|smallestScreenSize|touchscreen|uiMode"
|
||||
android:theme="@style/Theme.AppCompat.DayNight.NoActionBar"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
BIN
Android/app/src/main/ic_launcher-playstore.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
125
Android/app/src/main/kotlin/sats/price/Main.kt
Normal file
@@ -0,0 +1,125 @@
|
||||
package sats.price
|
||||
|
||||
import skip.lib.*
|
||||
import skip.model.*
|
||||
import skip.foundation.*
|
||||
import skip.ui.*
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Application
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.saveable.rememberSaveableStateHolder
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.core.app.ActivityCompat
|
||||
|
||||
internal val logger: SkipLogger = SkipLogger(subsystem = "sats.price", category = "SatsPrice")
|
||||
|
||||
/// AndroidAppMain is the `android.app.Application` entry point, and must match `application android:name` in the AndroidMainfest.xml file.
|
||||
open class AndroidAppMain: Application {
|
||||
constructor() {
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
logger.info("starting app")
|
||||
ProcessInfo.launch(applicationContext)
|
||||
}
|
||||
|
||||
companion object {
|
||||
}
|
||||
}
|
||||
|
||||
/// AndroidAppMain is initial `androidx.appcompat.app.AppCompatActivity`, and must match `activity android:name` in the AndroidMainfest.xml file.
|
||||
open class MainActivity: AppCompatActivity {
|
||||
constructor() {
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: android.os.Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
logger.info("starting activity")
|
||||
UIApplication.launch(this)
|
||||
enableEdgeToEdge()
|
||||
|
||||
setContent {
|
||||
val saveableStateHolder = rememberSaveableStateHolder()
|
||||
saveableStateHolder.SaveableStateProvider(true) {
|
||||
PresentationRootView(ComposeContext())
|
||||
}
|
||||
}
|
||||
|
||||
// Example of requesting permissions on startup.
|
||||
// These must match the permissions in the AndroidManifest.xml file.
|
||||
//let permissions = listOf(
|
||||
// Manifest.permission.ACCESS_COARSE_LOCATION,
|
||||
// Manifest.permission.ACCESS_FINE_LOCATION
|
||||
// Manifest.permission.CAMERA,
|
||||
// Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
//)
|
||||
//let requestTag = 1
|
||||
//ActivityCompat.requestPermissions(self, permissions.toTypedArray(), requestTag)
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(bundle: android.os.Bundle): Unit = super.onSaveInstanceState(bundle)
|
||||
|
||||
override fun onRestoreInstanceState(bundle: android.os.Bundle) {
|
||||
// Usually you restore your state in onCreate(). It is possible to restore it in onRestoreInstanceState() as well, but not very common. (onRestoreInstanceState() is called after onStart(), whereas onCreate() is called before onStart().
|
||||
logger.info("onRestoreInstanceState")
|
||||
super.onRestoreInstanceState(bundle)
|
||||
}
|
||||
|
||||
override fun onRestart() {
|
||||
logger.info("onRestart")
|
||||
super.onRestart()
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
logger.info("onStart")
|
||||
super.onStart()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
logger.info("onResume")
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
logger.info("onPause")
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
logger.info("onStop")
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
logger.info("onDestroy")
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: kotlin.Array<String>, grantResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
logger.info("onRequestPermissionsResult: ${requestCode}")
|
||||
}
|
||||
|
||||
companion object {
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun PresentationRootView(context: ComposeContext) {
|
||||
val colorScheme = if (isSystemInDarkTheme()) ColorScheme.dark else ColorScheme.light
|
||||
PresentationRoot(defaultColorScheme = colorScheme, context = context) { ctx ->
|
||||
val contentContext = ctx.content()
|
||||
Box(modifier = ctx.modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
RootView().Compose(context = contentContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
BIN
Android/app/src/main/res/mipmap-hdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
Android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
Android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
Android/app/src/main/res/mipmap-mdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
Android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
Android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
BIN
Android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
Android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
BIN
Android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
BIN
Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#FFFFFF</color>
|
||||
</resources>
|
||||