diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a42c540
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,104 @@
+## User settings
+xcuserdata/
+
+xcodebuild*.log
+
+.gradle/
+.idea/
+.*.swp
+.*.swo
+.DS_Store
+Android/app/keystore.jks
+Android/app/keystore.properties
+
+## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
+*.xcscmblueprint
+*.xccheckout
+
+## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
+build/
+DerivedData/
+.android/
+.kotlin/
+*.moved-aside
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+
+## Obj-C/Swift specific
+*.hmap
+
+## App packaging
+*.ipa
+*.dSYM.zip
+*.dSYM
+
+## Playgrounds
+timeline.xctimeline
+playground.xcworkspace
+
+# Swift Package Manager
+#
+# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
+Packages/
+Package.pins
+Package.resolved
+#*.xcodeproj
+
+# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
+# hence it is not needed unless you have added a package configuration file to your project
+.swiftpm
+.build/
+
+# CocoaPods
+#
+# We recommend against adding the Pods directory to your .gitignore. However
+# you should judge for yourself, the pros and cons are mentioned at:
+# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
+#
+# Pods/
+#
+# Add this line if you want to avoid checking in source code from the Xcode workspace
+# *.xcworkspace
+
+# Carthage
+#
+# Add this line if you want to avoid checking in source code from Carthage dependencies.
+# Carthage/Checkouts
+
+Carthage/Build/
+
+# Accio dependency management
+Dependencies/
+.accio/
+
+# fastlane
+#
+# It is recommended to not store the screenshots in the git repo.
+# Instead, use fastlane to re-generate the screenshots whenever they are needed.
+# For more information about the recommended setup visit:
+# https://docs.fastlane.tools/best-practices/source-control/#source-control
+
+**/fastlane/apikey.json
+**/fastlane/report.xml
+**/fastlane/README.md
+**/fastlane/Preview.html
+**/fastlane/screenshots/**/*.png
+**/fastlane/metadata/android/*/images/**/*.png
+**/fastlane/test_output
+
+# Code Injection
+#
+# After new code Injection tools there's a generated folder /iOSInjectionProject
+# https://github.com/johnno1962/injectionforxcode
+
+iOSInjectionProject/
+
+# gradle properties
+local.properties
+
diff --git a/Android/app/build.gradle.kts b/Android/app/build.gradle.kts
new file mode 100644
index 0000000..18afca3
--- /dev/null
+++ b/Android/app/build.gradle.kts
@@ -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")
+ }
+ }
+}
diff --git a/Android/app/proguard-rules.pro b/Android/app/proguard-rules.pro
new file mode 100644
index 0000000..378b355
--- /dev/null
+++ b/Android/app/proguard-rules.pro
@@ -0,0 +1,4 @@
+-keeppackagenames **
+-keep class skip.** { *; }
+-keep class com.sun.jna.Pointer { *; }
+-keep class sats.price.** { *; }
diff --git a/Android/app/src/main/AndroidManifest.xml b/Android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..c6c7049
--- /dev/null
+++ b/Android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Android/app/src/main/ic_launcher-playstore.png b/Android/app/src/main/ic_launcher-playstore.png
new file mode 100644
index 0000000..36bd74e
Binary files /dev/null and b/Android/app/src/main/ic_launcher-playstore.png differ
diff --git a/Android/app/src/main/kotlin/sats/price/Main.kt b/Android/app/src/main/kotlin/sats/price/Main.kt
new file mode 100644
index 0000000..4f40e99
--- /dev/null
+++ b/Android/app/src/main/kotlin/sats/price/Main.kt
@@ -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, 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)
+ }
+ }
+}
diff --git a/Android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..036d09b
--- /dev/null
+++ b/Android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..036d09b
--- /dev/null
+++ b/Android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Android/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/Android/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..96c1588
Binary files /dev/null and b/Android/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/Android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/Android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..3f6c910
Binary files /dev/null and b/Android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp differ
diff --git a/Android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/Android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..ec19b39
Binary files /dev/null and b/Android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/Android/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/Android/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..ee4b53a
Binary files /dev/null and b/Android/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/Android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp b/Android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..137fde2
Binary files /dev/null and b/Android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp differ
diff --git a/Android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/Android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b7d113e
Binary files /dev/null and b/Android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/Android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/Android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..af7f38c
Binary files /dev/null and b/Android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/Android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/Android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..9d71a4b
Binary files /dev/null and b/Android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp differ
diff --git a/Android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/Android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..8f3dfd4
Binary files /dev/null and b/Android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/Android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/Android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..6494ce9
Binary files /dev/null and b/Android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/Android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/Android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..669b548
Binary files /dev/null and b/Android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp differ
diff --git a/Android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/Android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..ed5be46
Binary files /dev/null and b/Android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..5b9168a
Binary files /dev/null and b/Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..d1df236
Binary files /dev/null and b/Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp differ
diff --git a/Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..864236d
Binary files /dev/null and b/Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/Android/app/src/main/res/values/ic_launcher_background.xml b/Android/app/src/main/res/values/ic_launcher_background.xml
new file mode 100644
index 0000000..c5d5899
--- /dev/null
+++ b/Android/app/src/main/res/values/ic_launcher_background.xml
@@ -0,0 +1,4 @@
+
+
+ #FFFFFF
+
\ No newline at end of file
diff --git a/Android/fastlane/Appfile b/Android/fastlane/Appfile
new file mode 100644
index 0000000..bbcb0fb
--- /dev/null
+++ b/Android/fastlane/Appfile
@@ -0,0 +1,11 @@
+# This file contains the app distribution configuration
+# for the Android half of the Skip app.
+# You can find the documentation at https://docs.fastlane.tools
+
+# Load the shared Skip.env properties with the app info
+require('dotenv')
+Dotenv.load '../../Skip.env'
+package_name(ENV['PRODUCT_BUNDLE_IDENTIFIER'])
+
+# Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one
+json_key_file("fastlane/apikey.json")
diff --git a/Android/fastlane/Fastfile b/Android/fastlane/Fastfile
new file mode 100644
index 0000000..9f636a1
--- /dev/null
+++ b/Android/fastlane/Fastfile
@@ -0,0 +1,49 @@
+# This file contains the fastlane.tools configuration
+# for the Android half of the Skip app.
+# You can find the documentation at https://docs.fastlane.tools
+
+# Load the shared Skip.env properties with the app info
+require('dotenv')
+Dotenv.load '../../Skip.env'
+
+default_platform(:android)
+
+# use the Homebrew gradle rather than expecting a local gradlew
+gradle_bin = (ENV['HOMEBREW_PREFIX'] ? ENV['HOMEBREW_PREFIX'] : "/opt/homebrew") + "/bin/gradle"
+
+default_platform(:android)
+
+desc "Build Skip Android App"
+lane :build do |options|
+ build_config = (options[:release] ? "Release" : "Debug")
+ gradle(
+ task: "build${build_config}",
+ gradle_path: gradle_bin,
+ flags: "--warning-mode none -x lint"
+ )
+end
+
+desc "Test Skip Android App"
+lane :test do
+ gradle(
+ task: "test",
+ gradle_path: gradle_bin
+ )
+end
+
+desc "Assemble Skip Android App"
+lane :assemble do
+ gradle(
+ gradle_path: gradle_bin,
+ task: "bundleRelease"
+ )
+ # sh "your_script.sh"
+end
+
+desc "Deploy Skip Android App to Google Play"
+lane :release do
+ assemble
+ upload_to_play_store(
+ aab: '../.build/Android/app/outputs/bundle/release/app-release.aab'
+ )
+end
diff --git a/Android/fastlane/metadata/android/en-US/full_description.txt b/Android/fastlane/metadata/android/en-US/full_description.txt
new file mode 100644
index 0000000..c65ef9c
--- /dev/null
+++ b/Android/fastlane/metadata/android/en-US/full_description.txt
@@ -0,0 +1 @@
+A great new app built with Skip!
diff --git a/Android/fastlane/metadata/android/en-US/short_description.txt b/Android/fastlane/metadata/android/en-US/short_description.txt
new file mode 100644
index 0000000..c65ef9c
--- /dev/null
+++ b/Android/fastlane/metadata/android/en-US/short_description.txt
@@ -0,0 +1 @@
+A great new app built with Skip!
diff --git a/Android/fastlane/metadata/android/en-US/title.txt b/Android/fastlane/metadata/android/en-US/title.txt
new file mode 100644
index 0000000..38f0959
--- /dev/null
+++ b/Android/fastlane/metadata/android/en-US/title.txt
@@ -0,0 +1 @@
+SatsPrice
diff --git a/Android/gradle.properties b/Android/gradle.properties
new file mode 100644
index 0000000..1b8d060
--- /dev/null
+++ b/Android/gradle.properties
@@ -0,0 +1,3 @@
+org.gradle.jvmargs=-Xmx4g
+android.useAndroidX=true
+kotlin.code.style=official
diff --git a/Android/gradle/wrapper/gradle-wrapper.properties b/Android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..9d2e5f8
--- /dev/null
+++ b/Android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,2 @@
+#Sat Aug 31 09:41:39 EEST 2024
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
diff --git a/Android/settings.gradle.kts b/Android/settings.gradle.kts
new file mode 100644
index 0000000..42a54ff
--- /dev/null
+++ b/Android/settings.gradle.kts
@@ -0,0 +1,46 @@
+// This gradle project is part of a conventional Skip app project.
+// It invokes the shared build skip plugin logic, which included as part of the skip-unit buildSrc
+// When built from Android Studio, it uses the BUILT_PRODUCTS_DIR folder to share the same build outputs as Xcode, otherwise it uses SwiftPM's .build/ folder
+pluginManagement {
+ // local override of BUILT_PRODUCTS_DIR
+ if (System.getenv("BUILT_PRODUCTS_DIR") == null) {
+ //System.setProperty("BUILT_PRODUCTS_DIR", "${System.getProperty("user.home")}/Library/Developer/Xcode/DerivedData/MySkipProject-aqywrhrzhkbvfseiqgxuufbdwdft/Build/Products/Debug-iphonesimulator")
+ }
+
+ // the source for the plugin is linked as part of the SkipUnit transpilation
+ val skipOutput = System.getenv("BUILT_PRODUCTS_DIR") ?: System.getProperty("BUILT_PRODUCTS_DIR")
+
+ val outputExt = if (skipOutput != null) ".output" else "" // Xcode saves output in package-name.output; SPM has no suffix
+ val skipOutputs: File = if (skipOutput != null) {
+ // BUILT_PRODUCTS_DIR is set when building from Xcode, in which case we will use Xcode's DerivedData plugin output
+ file(skipOutput).resolve("../../../SourcePackages/plugins/")
+ } else {
+ exec {
+ // create transpiled Kotlin and generate Gradle projects from SwiftPM modules
+ commandLine("swift", "build")
+ workingDir = file("..")
+ }
+ // SPM output folder is a peer of the parent Package.swift
+ rootDir.resolve("../.build/plugins/outputs/")
+ }
+
+ // load the Skip plugin (part of the skip-unit project), which handles configuring the Android project
+ // because this path is a symlink, we need to use the canonical path or gradle will mis-interpret it as a different build source
+ var pluginSource = skipOutputs.resolve("skip-unit${outputExt}/SkipUnit/skipstone/buildSrc/").canonicalFile
+ if (!pluginSource.isDirectory) {
+ // check new SwiftPM6 plugin "destination" folder for command-line builds
+ pluginSource = skipOutputs.resolve("skip-unit${outputExt}/SkipUnit/destination/skipstone/buildSrc/").canonicalFile
+ }
+
+ if (!pluginSource.isDirectory) {
+ throw GradleException("Missing expected Skip output folder: ${pluginSource}. Run `swift build` in the root folder to create, or specify Xcode environment BUILT_PRODUCTS_DIR.")
+ }
+ includeBuild(pluginSource.path) {
+ name = "skip-plugins"
+ }
+}
+
+plugins {
+ id("skip-plugin") apply true
+}
+
diff --git a/SatsPrice/Assets.xcassets/AccentColor.colorset/Contents.json b/Darwin/Assets.xcassets/AccentColor.colorset/Contents.json
similarity index 100%
rename from SatsPrice/Assets.xcassets/AccentColor.colorset/Contents.json
rename to Darwin/Assets.xcassets/AccentColor.colorset/Contents.json
diff --git a/SatsPrice/Assets.xcassets/AppIcon.appiconset/Contents.json b/Darwin/Assets.xcassets/AppIcon.appiconset/Contents.json
similarity index 100%
rename from SatsPrice/Assets.xcassets/AppIcon.appiconset/Contents.json
rename to Darwin/Assets.xcassets/AppIcon.appiconset/Contents.json
diff --git a/SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-1024-no-alpha 1.png b/Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-1024-no-alpha 1.png
similarity index 100%
rename from SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-1024-no-alpha 1.png
rename to Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-1024-no-alpha 1.png
diff --git a/SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-1024-no-alpha.png b/Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-1024-no-alpha.png
similarity index 100%
rename from SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-1024-no-alpha.png
rename to Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-1024-no-alpha.png
diff --git a/SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-128-no-alpha.png b/Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-128-no-alpha.png
similarity index 100%
rename from SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-128-no-alpha.png
rename to Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-128-no-alpha.png
diff --git a/SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-16-no-alpha.png b/Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-16-no-alpha.png
similarity index 100%
rename from SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-16-no-alpha.png
rename to Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-16-no-alpha.png
diff --git a/SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-256-no-alpha 1.png b/Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-256-no-alpha 1.png
similarity index 100%
rename from SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-256-no-alpha 1.png
rename to Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-256-no-alpha 1.png
diff --git a/SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-256-no-alpha.png b/Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-256-no-alpha.png
similarity index 100%
rename from SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-256-no-alpha.png
rename to Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-256-no-alpha.png
diff --git a/SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-32-no-alpha 1.png b/Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-32-no-alpha 1.png
similarity index 100%
rename from SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-32-no-alpha 1.png
rename to Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-32-no-alpha 1.png
diff --git a/SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-32-no-alpha.png b/Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-32-no-alpha.png
similarity index 100%
rename from SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-32-no-alpha.png
rename to Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-32-no-alpha.png
diff --git a/SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-512-no-alpha 1.png b/Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-512-no-alpha 1.png
similarity index 100%
rename from SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-512-no-alpha 1.png
rename to Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-512-no-alpha 1.png
diff --git a/SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-512-no-alpha.png b/Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-512-no-alpha.png
similarity index 100%
rename from SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-512-no-alpha.png
rename to Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-512-no-alpha.png
diff --git a/SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-64-no-alpha.png b/Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-64-no-alpha.png
similarity index 100%
rename from SatsPrice/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-64-no-alpha.png
rename to Darwin/Assets.xcassets/AppIcon.appiconset/bitcoin-calculator-64-no-alpha.png
diff --git a/SatsPrice/Assets.xcassets/Contents.json b/Darwin/Assets.xcassets/Contents.json
similarity index 100%
rename from SatsPrice/Assets.xcassets/Contents.json
rename to Darwin/Assets.xcassets/Contents.json
diff --git a/SatsPrice.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Darwin/Entitlements.plist
similarity index 92%
rename from SatsPrice.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
rename to Darwin/Entitlements.plist
index 0c67376..6631ffa 100644
--- a/SatsPrice.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
+++ b/Darwin/Entitlements.plist
@@ -1,5 +1,6 @@
-
+
+
diff --git a/SatsPrice/SatsPrice.xcdatamodeld/.xccurrentversion b/Darwin/Info.plist
similarity index 71%
rename from SatsPrice/SatsPrice.xcdatamodeld/.xccurrentversion
rename to Darwin/Info.plist
index 3f39f17..6d5f8f6 100644
--- a/SatsPrice/SatsPrice.xcdatamodeld/.xccurrentversion
+++ b/Darwin/Info.plist
@@ -2,7 +2,7 @@
- _XCCurrentVersionName
- SatsPrice.xcdatamodel
+ ITSAppUsesNonExemptEncryption
+
diff --git a/Darwin/SatsPrice.xcconfig b/Darwin/SatsPrice.xcconfig
new file mode 100644
index 0000000..cbd413e
--- /dev/null
+++ b/Darwin/SatsPrice.xcconfig
@@ -0,0 +1,56 @@
+#include "../Skip.env"
+
+// Set the action that will be executed as part of the Xcode Run Script phase
+// Setting to "launch" will build and run the app in the first open Android emulator or device
+// Setting to "build" will just run gradle build, but will not launch the app
+SKIP_ACTION = launch
+//SKIP_ACTION = build
+
+ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon
+ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor
+
+INFOPLIST_FILE = Info.plist
+GENERATE_INFOPLIST_FILE = YES
+
+// The user-visible name of the app (localizable)
+//INFOPLIST_KEY_CFBundleDisplayName = App Name
+//INFOPLIST_KEY_LSApplicationCategoryType = public.app-category.utilities
+
+// iOS-specific Info.plist property keys
+INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphone*] = YES
+INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphone*] = YES
+INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphone*] = YES
+INFOPLIST_KEY_UIStatusBarStyle[sdk=iphone*] = UIStatusBarStyleDefault
+INFOPLIST_KEY_UISupportedInterfaceOrientations[sdk=iphone*] = UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown
+
+IPHONEOS_DEPLOYMENT_TARGET = 16.0
+MACOSX_DEPLOYMENT_TARGET = 13.0
+SUPPORTS_MACCATALYST = NO
+
+// iPhone + iPad
+TARGETED_DEVICE_FAMILY = 1,2
+
+// iPhone only
+// TARGETED_DEVICE_FAMILY = 1
+
+SWIFT_EMIT_LOC_STRINGS = YES
+
+// the name of the product module; this can be anything, but cannot conflict with any Swift module names
+PRODUCT_MODULE_NAME = $(PRODUCT_NAME:c99extidentifier)App
+
+// On-device testing may need to override the bundle ID
+// PRODUCT_BUNDLE_IDENTIFIER[config=Debug][sdk=iphoneos*] = cool.beans.BundleIdentifer
+
+SDKROOT = auto
+SUPPORTED_PLATFORMS = iphoneos iphonesimulator macosx
+SWIFT_EMIT_LOC_STRINGS = YES
+
+SWIFT_VERSION = 5.0
+//SWIFT_VERSION = 6.0
+
+// Development team ID for on-device testing
+CODE_SIGNING_REQUIRED = NO
+CODE_SIGN_STYLE = Automatic
+CODE_SIGN_ENTITLEMENTS = Entitlements.plist
+//CODE_SIGNING_IDENTITY = -
+//DEVELOPMENT_TEAM =
diff --git a/Darwin/SatsPrice.xcodeproj/project.pbxproj b/Darwin/SatsPrice.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..b897f1b
--- /dev/null
+++ b/Darwin/SatsPrice.xcodeproj/project.pbxproj
@@ -0,0 +1,294 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 56;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 49231BAC2AC5BCEF00F98ADF /* SatsPriceApp in Frameworks */ = {isa = PBXBuildFile; productRef = 49231BAB2AC5BCEF00F98ADF /* SatsPriceApp */; };
+ 49231BAD2AC5BCEF00F98ADF /* SatsPriceApp in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 49231BAB2AC5BCEF00F98ADF /* SatsPriceApp */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
+ 496BDBEE2B8A7E9C00C09264 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 496BDBED2B8A7E9C00C09264 /* Localizable.xcstrings */; };
+ 499CD43B2AC5B799001AE8D8 /* SatsPriceAppMain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49F90C2B2A52156200F06D93 /* SatsPriceAppMain.swift */; };
+ 499CD4402AC5B799001AE8D8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 49F90C2F2A52156300F06D93 /* Assets.xcassets */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 499CD44A2AC5B9C6001AE8D8 /* Embed Frameworks */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 10;
+ files = (
+ 49231BAD2AC5BCEF00F98ADF /* SatsPriceApp in Embed Frameworks */,
+ );
+ name = "Embed Frameworks";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 4900101C2BACEA710000DE33 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; };
+ 493609562A6B7EAE00C401E2 /* SatsPrice */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = SatsPrice; path = ..; sourceTree = ""; };
+ 496BDBEB2B89A47800C09264 /* SatsPrice.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SatsPrice.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 496BDBED2B8A7E9C00C09264 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; name = Localizable.xcstrings; path = ../Sources/SatsPrice/Resources/Localizable.xcstrings; sourceTree = ""; };
+ 496EB72F2A6AE4DE00C1253A /* Skip.env */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Skip.env; path = ../Skip.env; sourceTree = ""; };
+ 496EB72F2A6AE4DE00C1253B /* SatsPrice.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = SatsPrice.xcconfig; sourceTree = ""; };
+ 496EB72F2A6AE4DE00C1253C /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; };
+ 499AB9082B0581F4005E8330 /* plugins */ = {isa = PBXFileReference; lastKnownFileType = folder; name = plugins; path = ../../../SourcePackages/plugins; sourceTree = BUILT_PRODUCTS_DIR; };
+ 49F90C2B2A52156200F06D93 /* SatsPriceAppMain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SatsPriceAppMain.swift; path = Sources/SatsPriceAppMain.swift; sourceTree = SOURCE_ROOT; };
+ 49F90C2F2A52156300F06D93 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ 49F90C312A52156300F06D93 /* Entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Entitlements.plist; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 499CD43C2AC5B799001AE8D8 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 49231BAC2AC5BCEF00F98ADF /* SatsPriceApp in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 496BDBEC2B89A47800C09264 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 496BDBEB2B89A47800C09264 /* SatsPrice.app */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 49AB54462B066A7E007B79B2 /* SkipStone */ = {
+ isa = PBXGroup;
+ children = (
+ 499AB9082B0581F4005E8330 /* plugins */,
+ );
+ name = SkipStone;
+ sourceTree = "";
+ };
+ 49F90C1F2A52156200F06D93 = {
+ isa = PBXGroup;
+ children = (
+ 496EB72F2A6AE4DE00C1253C /* README.md */,
+ 496EB72F2A6AE4DE00C1253A /* Skip.env */,
+ 496EB72F2A6AE4DE00C1253B /* SatsPrice.xcconfig */,
+ 496BDBED2B8A7E9C00C09264 /* Localizable.xcstrings */,
+ 493609562A6B7EAE00C401E2 /* SatsPrice */,
+ 49F90C2A2A52156200F06D93 /* App */,
+ 49AB54462B066A7E007B79B2 /* SkipStone */,
+ 496BDBEC2B89A47800C09264 /* Products */,
+ );
+ sourceTree = "";
+ };
+ 49F90C2A2A52156200F06D93 /* App */ = {
+ isa = PBXGroup;
+ children = (
+ 49F90C2B2A52156200F06D93 /* SatsPriceAppMain.swift */,
+ 49F90C2F2A52156300F06D93 /* Assets.xcassets */,
+ 49F90C312A52156300F06D93 /* Entitlements.plist */,
+ 4900101C2BACEA710000DE33 /* Info.plist */,
+ );
+ name = App;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 499CD4382AC5B799001AE8D8 /* SatsPrice */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 499CD4412AC5B799001AE8D8 /* Build configuration list for PBXNativeTarget "SatsPrice" */;
+ buildPhases = (
+ 499CD43A2AC5B799001AE8D8 /* Sources */,
+ 499CD43C2AC5B799001AE8D8 /* Frameworks */,
+ 499CD43E2AC5B799001AE8D8 /* Resources */,
+ 499CD4452AC5B869001AE8D8 /* Run skip gradle */,
+ 499CD44A2AC5B9C6001AE8D8 /* Embed Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = SatsPrice;
+ packageProductDependencies = (
+ 49231BAB2AC5BCEF00F98ADF /* SatsPriceApp */,
+ );
+ productName = App;
+ productReference = 496BDBEB2B89A47800C09264 /* SatsPrice.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 49F90C202A52156200F06D93 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ BuildIndependentTargetsInParallel = 1;
+ LastSwiftUpdateCheck = 1430;
+ LastUpgradeCheck = 1540;
+ };
+ buildConfigurationList = 49F90C232A52156200F06D93 /* Build configuration list for PBXProject "SatsPrice" */;
+ compatibilityVersion = "Xcode 14.0";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 49F90C1F2A52156200F06D93;
+ packageReferences = (
+ );
+ productRefGroup = 496BDBEC2B89A47800C09264 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 499CD4382AC5B799001AE8D8 /* SatsPrice */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 499CD43E2AC5B799001AE8D8 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 499CD4402AC5B799001AE8D8 /* Assets.xcassets in Resources */,
+ 496BDBEE2B8A7E9C00C09264 /* Localizable.xcstrings in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 499CD4452AC5B869001AE8D8 /* Run skip gradle */ = {
+ isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ );
+ name = "Run skip gradle";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = "/bin/sh -e";
+ shellScript = "if [ \"${SKIP_ZERO}\" != \"\" ]; then\n\techo \"note: skipping skip due to SKIP_ZERO\"\n\texit 0\nelif [ \"${ENABLE_PREVIEWS}\" == \"YES\" ]; then\n\techo \"note: skipping skip due to ENABLE_PREVIEWS\"\n\texit 0\nelif [ \"${ACTION}\" == \"install\" ]; then\n\techo \"note: skipping skip due to archive install\"\n\texit 0\nelse\n\tSKIP_ACTION=\"${SKIP_ACTION:-launch}\"\nfi\nPATH=${BUILD_ROOT}/Debug:${BUILD_ROOT}/../../SourcePackages/artifacts/skip/skip/skip.artifactbundle/macos:${PATH}:${HOMEBREW_PREFIX:-/opt/homebrew}/bin\necho \"note: running gradle build with: $(which skip) gradle -p ${PWD}/../Android ${SKIP_ACTION:-launch}${CONFIGURATION:-Debug}\"\nskip gradle -p ../Android ${SKIP_ACTION:-launch}${CONFIGURATION:-Debug}\n";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 499CD43A2AC5B799001AE8D8 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 499CD43B2AC5B799001AE8D8 /* SatsPriceAppMain.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 499CD4422AC5B799001AE8D8 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ DEVELOPMENT_TEAM = S99A5B637C;
+ ENABLE_PREVIEWS = YES;
+ INFOPLIST_KEY_CFBundleDisplayName = SatsPrice;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
+ LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
+ "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
+ MARKETING_VERSION = 0.2.0;
+ };
+ name = Debug;
+ };
+ 499CD4432AC5B799001AE8D8 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ DEVELOPMENT_TEAM = S99A5B637C;
+ ENABLE_PREVIEWS = YES;
+ INFOPLIST_KEY_CFBundleDisplayName = SatsPrice;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
+ LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
+ "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
+ MARKETING_VERSION = 0.2.0;
+ };
+ name = Release;
+ };
+ 49F90C4B2A52156300F06D93 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 496EB72F2A6AE4DE00C1253B /* SatsPrice.xcconfig */;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = NO;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ 49F90C4C2A52156300F06D93 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 496EB72F2A6AE4DE00C1253B /* SatsPrice.xcconfig */;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = NO;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ MTL_FAST_MATH = YES;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 499CD4412AC5B799001AE8D8 /* Build configuration list for PBXNativeTarget "SatsPrice" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 499CD4422AC5B799001AE8D8 /* Debug */,
+ 499CD4432AC5B799001AE8D8 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 49F90C232A52156200F06D93 /* Build configuration list for PBXProject "SatsPrice" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 49F90C4B2A52156300F06D93 /* Debug */,
+ 49F90C4C2A52156300F06D93 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+
+/* Begin XCSwiftPackageProductDependency section */
+ 49231BAB2AC5BCEF00F98ADF /* SatsPriceApp */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = SatsPriceApp;
+ };
+/* End XCSwiftPackageProductDependency section */
+ };
+ rootObject = 49F90C202A52156200F06D93 /* Project object */;
+}
diff --git a/SatsPrice.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Darwin/SatsPrice.xcodeproj/project.xcworkspace/contents.xcworkspacedata
similarity index 100%
rename from SatsPrice.xcodeproj/project.xcworkspace/contents.xcworkspacedata
rename to Darwin/SatsPrice.xcodeproj/project.xcworkspace/contents.xcworkspacedata
diff --git a/SatsPrice.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Darwin/SatsPrice.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
similarity index 100%
rename from SatsPrice.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
rename to Darwin/SatsPrice.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
diff --git a/Darwin/Sources/SatsPriceAppMain.swift b/Darwin/Sources/SatsPriceAppMain.swift
new file mode 100644
index 0000000..1126b8e
--- /dev/null
+++ b/Darwin/Sources/SatsPriceAppMain.swift
@@ -0,0 +1,10 @@
+// This is free software: you can redistribute and/or modify it
+// under the terms of the GNU General Public License 3.0
+// as published by the Free Software Foundation https://fsf.org
+
+import SwiftUI
+import SatsPrice
+
+/// The entry point to the app simply loads the App implementation from SPM module.
+@main struct AppMain: App, SatsPriceApp {
+}
diff --git a/Darwin/fastlane/AppStore.xcconfig b/Darwin/fastlane/AppStore.xcconfig
new file mode 100644
index 0000000..2dd4ae8
--- /dev/null
+++ b/Darwin/fastlane/AppStore.xcconfig
@@ -0,0 +1,5 @@
+// Additional properties included by the Fastfile build_app
+
+// This file can be used to override various properties from Skip.env
+//PRODUCT_BUNDLE_IDENTIFIER =
+//DEVELOPMENT_TEAM =
diff --git a/Darwin/fastlane/Appfile b/Darwin/fastlane/Appfile
new file mode 100644
index 0000000..2d9792e
--- /dev/null
+++ b/Darwin/fastlane/Appfile
@@ -0,0 +1,8 @@
+# For more information about the Appfile, see:
+# https://docs.fastlane.tools/advanced/#appfile
+
+require('dotenv')
+Dotenv.load '../../Skip.env'
+#app_identifier(ENV['PRODUCT_BUNDLE_IDENTIFIER'])
+
+# apple_id("my@email")
diff --git a/Darwin/fastlane/Deliverfile b/Darwin/fastlane/Deliverfile
new file mode 100644
index 0000000..67e07dd
--- /dev/null
+++ b/Darwin/fastlane/Deliverfile
@@ -0,0 +1,28 @@
+
+copyright "#{Time.now.year}"
+default_language("en-US")
+
+force(true) # Skip HTML report verification
+automatic_release(true)
+skip_screenshots(false)
+precheck_include_in_app_purchases(false)
+
+#skip_binary_upload(true)
+submit_for_review(true)
+
+submission_information({
+ add_id_info_serves_ads: false,
+ add_id_info_uses_idfa: false,
+ add_id_info_tracks_install: false,
+ add_id_info_tracks_action: false,
+ add_id_info_limits_tracking: false,
+ content_rights_has_rights: false,
+ content_rights_contains_third_party_content: false,
+ export_compliance_contains_third_party_cryptography: false,
+ export_compliance_encryption_updated: false,
+ export_compliance_platform: 'ios',
+ export_compliance_compliance_required: false,
+ export_compliance_uses_encryption: false,
+ export_compliance_is_exempt: false,
+ export_compliance_contains_proprietary_cryptography: false
+})
diff --git a/Darwin/fastlane/Fastfile b/Darwin/fastlane/Fastfile
new file mode 100644
index 0000000..874953c
--- /dev/null
+++ b/Darwin/fastlane/Fastfile
@@ -0,0 +1,32 @@
+# This file contains the fastlane.tools configuration
+# for the iOS half of the Skip app.
+# You can find the documentation at https://docs.fastlane.tools
+
+default_platform(:ios)
+
+lane :assemble do |options|
+ # only build the iOS side of the app
+ ENV["SKIP_ZERO"] = "true"
+ build_app(
+ sdk: "iphoneos",
+ xcconfig: "fastlane/AppStore.xcconfig",
+ xcargs: "-skipPackagePluginValidation -skipMacroValidation",
+ derived_data_path: "../.build/Darwin/DerivedData",
+ output_directory: "../.build/fastlane/Darwin",
+ skip_archive: ENV["FASTLANE_SKIP_ARCHIVE"] == "YES",
+ skip_codesigning: ENV["FASTLANE_SKIP_CODESIGNING"] == "YES"
+ )
+end
+
+lane :release do |options|
+ desc "Build and release app"
+
+ assemble
+
+ upload_to_app_store(
+ api_key_path: "fastlane/apikey.json",
+ app_rating_config_path: "fastlane/metadata/rating.json",
+ release_notes: { default: "Fixes and improvements." }
+ )
+end
+
diff --git a/Darwin/fastlane/metadata/en-US/description.txt b/Darwin/fastlane/metadata/en-US/description.txt
new file mode 100644
index 0000000..c65ef9c
--- /dev/null
+++ b/Darwin/fastlane/metadata/en-US/description.txt
@@ -0,0 +1 @@
+A great new app built with Skip!
diff --git a/Darwin/fastlane/metadata/en-US/keywords.txt b/Darwin/fastlane/metadata/en-US/keywords.txt
new file mode 100644
index 0000000..0fb6d6c
--- /dev/null
+++ b/Darwin/fastlane/metadata/en-US/keywords.txt
@@ -0,0 +1 @@
+app,key,words
diff --git a/Darwin/fastlane/metadata/en-US/privacy_url.txt b/Darwin/fastlane/metadata/en-US/privacy_url.txt
new file mode 100644
index 0000000..575f001
--- /dev/null
+++ b/Darwin/fastlane/metadata/en-US/privacy_url.txt
@@ -0,0 +1 @@
+https://example.org/privacy/
diff --git a/Darwin/fastlane/metadata/en-US/release_notes.txt b/Darwin/fastlane/metadata/en-US/release_notes.txt
new file mode 100644
index 0000000..2e531b6
--- /dev/null
+++ b/Darwin/fastlane/metadata/en-US/release_notes.txt
@@ -0,0 +1 @@
+Bug fixes and performance improvements.
diff --git a/Darwin/fastlane/metadata/en-US/software_url.txt b/Darwin/fastlane/metadata/en-US/software_url.txt
new file mode 100644
index 0000000..0ce62b7
--- /dev/null
+++ b/Darwin/fastlane/metadata/en-US/software_url.txt
@@ -0,0 +1 @@
+https://example.org/app/
diff --git a/Darwin/fastlane/metadata/en-US/subtitle.txt b/Darwin/fastlane/metadata/en-US/subtitle.txt
new file mode 100644
index 0000000..2289704
--- /dev/null
+++ b/Darwin/fastlane/metadata/en-US/subtitle.txt
@@ -0,0 +1 @@
+A new Skip app
diff --git a/Darwin/fastlane/metadata/en-US/support_url.txt b/Darwin/fastlane/metadata/en-US/support_url.txt
new file mode 100644
index 0000000..fcfa1f7
--- /dev/null
+++ b/Darwin/fastlane/metadata/en-US/support_url.txt
@@ -0,0 +1 @@
+https://example.org/support/
diff --git a/Darwin/fastlane/metadata/en-US/title.txt b/Darwin/fastlane/metadata/en-US/title.txt
new file mode 100644
index 0000000..38f0959
--- /dev/null
+++ b/Darwin/fastlane/metadata/en-US/title.txt
@@ -0,0 +1 @@
+SatsPrice
diff --git a/Darwin/fastlane/metadata/en-US/version_whats_new.txt b/Darwin/fastlane/metadata/en-US/version_whats_new.txt
new file mode 100644
index 0000000..5d21c24
--- /dev/null
+++ b/Darwin/fastlane/metadata/en-US/version_whats_new.txt
@@ -0,0 +1 @@
+New features and better performance.
diff --git a/Darwin/fastlane/metadata/rating.json b/Darwin/fastlane/metadata/rating.json
new file mode 100644
index 0000000..b003379
--- /dev/null
+++ b/Darwin/fastlane/metadata/rating.json
@@ -0,0 +1,17 @@
+{
+ "alcoholTobaccoOrDrugUseOrReferences": "NONE",
+ "contests": "NONE",
+ "gamblingSimulated": "NONE",
+ "horrorOrFearThemes": "NONE",
+ "matureOrSuggestiveThemes": "NONE",
+ "medicalOrTreatmentInformation": "NONE",
+ "profanityOrCrudeHumor": "NONE",
+ "sexualContentGraphicAndNudity": "NONE",
+ "sexualContentOrNudity": "NONE",
+ "violenceCartoonOrFantasy": "NONE",
+ "violenceRealisticProlongedGraphicOrSadistic": "NONE",
+ "violenceRealistic": "NONE",
+ "gambling": false,
+ "seventeenPlus": false,
+ "unrestrictedWebAccess": false
+}
diff --git a/LICENSE b/LICENSE.GPL
similarity index 100%
rename from LICENSE
rename to LICENSE.GPL
diff --git a/Package.swift b/Package.swift
new file mode 100644
index 0000000..695601f
--- /dev/null
+++ b/Package.swift
@@ -0,0 +1,24 @@
+// swift-tools-version: 5.9
+// This is a Skip (https://skip.tools) package,
+// containing a Swift Package Manager project
+// that will use the Skip build plugin to transpile the
+// Swift Package, Sources, and Tests into an
+// Android Gradle Project with Kotlin sources and JUnit tests.
+import PackageDescription
+
+let package = Package(
+ name: "sats-price",
+ defaultLocalization: "en",
+ platforms: [.iOS(.v16), .macOS(.v13), .tvOS(.v16), .watchOS(.v9), .macCatalyst(.v16)],
+ products: [
+ .library(name: "SatsPriceApp", type: .dynamic, targets: ["SatsPrice"]),
+ ],
+ dependencies: [
+ .package(url: "https://source.skip.tools/skip.git", from: "1.0.7"),
+ .package(url: "https://source.skip.tools/skip-ui.git", from: "1.0.0")
+ ],
+ targets: [
+ .target(name: "SatsPrice", dependencies: [.product(name: "SkipUI", package: "skip-ui")], resources: [.process("Resources")], plugins: [.plugin(name: "skipstone", package: "skip")]),
+ .testTarget(name: "SatsPriceTests", dependencies: ["SatsPrice", .product(name: "SkipTest", package: "skip")], resources: [.process("Resources")], plugins: [.plugin(name: "skipstone", package: "skip")]),
+ ]
+)
diff --git a/README.md b/README.md
index 936451d..ccf5f4b 100644
--- a/README.md
+++ b/README.md
@@ -2,14 +2,49 @@
This app fetches the price of Bitcoin relative to the United States Dollar from multiple sources, and converts inputted amounts between Sats, BTC, and USD.
-## Notes
+This is a free [Skip](https://skip.tools) dual-platform app project.
+It builds a native app for both iOS and Android.
-Precision is attempted to be kept up to 20 digits.
+## Building
-When NaN is displayed, it means "not a number", which can be caused by invalid input or problems fetching the price of Bitcoin from the selected source.
+This project is both a stand-alone Swift Package Manager module,
+as well as an Xcode project that builds and transpiles the project
+into a Kotlin Gradle project for Android using the Skip plugin.
+
+Building the module requires that Skip be installed using
+[Homebrew](https://brew.sh) with `brew install skiptools/skip/skip`.
+
+This will also install the necessary transpiler prerequisites:
+Kotlin, Gradle, and the Android build tools.
+
+Installation prerequisites can be confirmed by running `skip checkup`.
+
+## Testing
+
+The module can be tested using the standard `swift test` command
+or by running the test target for the macOS destination in Xcode,
+which will run the Swift tests as well as the transpiled
+Kotlin JUnit tests in the Robolectric Android simulation environment.
+
+Parity testing can be performed with `skip test`,
+which will output a table of the test results for both platforms.
+
+## Running
+
+Xcode and Android Studio must be downloaded and installed in order to
+run the app in the iOS simulator / Android emulator.
+An Android emulator must already be running, which can be launched from
+Android Studio's Device Manager.
+
+To run both the Swift and Kotlin apps simultaneously,
+launch the SatsPriceApp target from Xcode.
+A build phases runs the "Launch Android APK" script that
+will deploy the transpiled app a running Android emulator or connected device.
+Logging output for the iOS app can be viewed in the Xcode console, and in
+Android Studio's logcat tab for the transpiled Kotlin app.
## Attribution
-The [Bitcoin Calculator](https://www.flaticon.com/free-icons/bitcoin-calculator) icon was created by Icon home and licensed as free for personal and commercial use with attribution.
+This project depends on [Skip](https://skip.tools) to build as a multi-platform app.
-This project depends on [BigDecimal](https://github.com/mgriebling/BigDecimal), an MIT-licensed package for providing arbitrary-precision and fixed-precision decimal arithmetic in Swift.
+The [Bitcoin Calculator](https://www.flaticon.com/free-icons/bitcoin-calculator) icon was created by Icon home and licensed as free for personal and commercial use with attribution.
diff --git a/SatsPrice.xcodeproj/project.pbxproj b/SatsPrice.xcodeproj/project.pbxproj
deleted file mode 100644
index e352055..0000000
--- a/SatsPrice.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,718 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 56;
- objects = {
-
-/* Begin PBXBuildFile section */
- 3A7B2AA32B86407A00ACC4A7 /* FakePriceFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A7B2AA22B86407A00ACC4A7 /* FakePriceFetcher.swift */; };
- 3A8E5DA72C810C9900E9E6BD /* ManualPriceFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A8E5DA62C810C9900E9E6BD /* ManualPriceFetcher.swift */; };
- 3AE2D39D2B83338D00DE5F31 /* SatsPriceApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE2D39C2B83338D00DE5F31 /* SatsPriceApp.swift */; };
- 3AE2D3A22B83338D00DE5F31 /* SatsPrice.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 3AE2D3A02B83338D00DE5F31 /* SatsPrice.xcdatamodeld */; };
- 3AE2D3A42B83338D00DE5F31 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE2D3A32B83338D00DE5F31 /* ContentView.swift */; };
- 3AE2D3A62B83338D00DE5F31 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3AE2D3A52B83338D00DE5F31 /* Assets.xcassets */; };
- 3AE2D3AA2B83338D00DE5F31 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3AE2D3A92B83338D00DE5F31 /* Preview Assets.xcassets */; };
- 3AE2D3B42B83338E00DE5F31 /* SatsPriceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE2D3B32B83338E00DE5F31 /* SatsPriceTests.swift */; };
- 3AE2D3BE2B83338E00DE5F31 /* SatsPriceUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE2D3BD2B83338E00DE5F31 /* SatsPriceUITests.swift */; };
- 3AE2D3C02B83338E00DE5F31 /* SatsPriceUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE2D3BF2B83338E00DE5F31 /* SatsPriceUITestsLaunchTests.swift */; };
- 3AE2D3D52B83E58500DE5F31 /* SatsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE2D3D42B83E58500DE5F31 /* SatsViewModel.swift */; };
- 3AE2D3DA2B83FE5F00DE5F31 /* SatsViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE2D3D92B83FE5F00DE5F31 /* SatsViewModelTests.swift */; };
- 3AE2D3DD2B84020200DE5F31 /* BigDecimal in Frameworks */ = {isa = PBXBuildFile; productRef = 3AE2D3DC2B84020200DE5F31 /* BigDecimal */; };
- 3AE2D3DF2B84597100DE5F31 /* PriceFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE2D3DE2B84597100DE5F31 /* PriceFetcher.swift */; };
- 3AE2D3E12B8459D600DE5F31 /* CoinbasePriceFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE2D3E02B8459D600DE5F31 /* CoinbasePriceFetcher.swift */; };
- 3AE2D3E32B8461FE00DE5F31 /* CoinGeckoPriceFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE2D3E22B8461FE00DE5F31 /* CoinGeckoPriceFetcher.swift */; };
- 3AE2D3E52B846A8600DE5F31 /* PriceSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE2D3E42B846A8600DE5F31 /* PriceSource.swift */; };
- 3AE2D3E72B85690200DE5F31 /* PriceFetcherDelegator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE2D3E62B85690200DE5F31 /* PriceFetcherDelegator.swift */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXContainerItemProxy section */
- 3AE2D3B02B83338E00DE5F31 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 3AE2D3912B83338D00DE5F31 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 3AE2D3982B83338D00DE5F31;
- remoteInfo = SatsPrice;
- };
- 3AE2D3BA2B83338E00DE5F31 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 3AE2D3912B83338D00DE5F31 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 3AE2D3982B83338D00DE5F31;
- remoteInfo = SatsPrice;
- };
-/* End PBXContainerItemProxy section */
-
-/* Begin PBXFileReference section */
- 3A7B2AA22B86407A00ACC4A7 /* FakePriceFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FakePriceFetcher.swift; sourceTree = ""; };
- 3A8E5DA62C810C9900E9E6BD /* ManualPriceFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManualPriceFetcher.swift; sourceTree = ""; };
- 3AE2D3992B83338D00DE5F31 /* SatsPrice.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SatsPrice.app; sourceTree = BUILT_PRODUCTS_DIR; };
- 3AE2D39C2B83338D00DE5F31 /* SatsPriceApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SatsPriceApp.swift; sourceTree = ""; };
- 3AE2D3A12B83338D00DE5F31 /* SatsPrice.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = SatsPrice.xcdatamodel; sourceTree = ""; };
- 3AE2D3A32B83338D00DE5F31 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
- 3AE2D3A52B83338D00DE5F31 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
- 3AE2D3A72B83338D00DE5F31 /* SatsPrice.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SatsPrice.entitlements; sourceTree = ""; };
- 3AE2D3A92B83338D00DE5F31 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
- 3AE2D3AF2B83338E00DE5F31 /* SatsPriceTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SatsPriceTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
- 3AE2D3B32B83338E00DE5F31 /* SatsPriceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SatsPriceTests.swift; sourceTree = ""; };
- 3AE2D3B92B83338E00DE5F31 /* SatsPriceUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SatsPriceUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
- 3AE2D3BD2B83338E00DE5F31 /* SatsPriceUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SatsPriceUITests.swift; sourceTree = ""; };
- 3AE2D3BF2B83338E00DE5F31 /* SatsPriceUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SatsPriceUITestsLaunchTests.swift; sourceTree = ""; };
- 3AE2D3D42B83E58500DE5F31 /* SatsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SatsViewModel.swift; sourceTree = ""; };
- 3AE2D3D92B83FE5F00DE5F31 /* SatsViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SatsViewModelTests.swift; sourceTree = ""; };
- 3AE2D3DE2B84597100DE5F31 /* PriceFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceFetcher.swift; sourceTree = ""; };
- 3AE2D3E02B8459D600DE5F31 /* CoinbasePriceFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoinbasePriceFetcher.swift; sourceTree = ""; };
- 3AE2D3E22B8461FE00DE5F31 /* CoinGeckoPriceFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoinGeckoPriceFetcher.swift; sourceTree = ""; };
- 3AE2D3E42B846A8600DE5F31 /* PriceSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceSource.swift; sourceTree = ""; };
- 3AE2D3E62B85690200DE5F31 /* PriceFetcherDelegator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceFetcherDelegator.swift; sourceTree = ""; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
- 3AE2D3962B83338D00DE5F31 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 3AE2D3DD2B84020200DE5F31 /* BigDecimal in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 3AE2D3AC2B83338E00DE5F31 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 3AE2D3B62B83338E00DE5F31 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
- 3AE2D3902B83338D00DE5F31 = {
- isa = PBXGroup;
- children = (
- 3AE2D39B2B83338D00DE5F31 /* SatsPrice */,
- 3AE2D3B22B83338E00DE5F31 /* SatsPriceTests */,
- 3AE2D3BC2B83338E00DE5F31 /* SatsPriceUITests */,
- 3AE2D39A2B83338D00DE5F31 /* Products */,
- );
- sourceTree = "";
- };
- 3AE2D39A2B83338D00DE5F31 /* Products */ = {
- isa = PBXGroup;
- children = (
- 3AE2D3992B83338D00DE5F31 /* SatsPrice.app */,
- 3AE2D3AF2B83338E00DE5F31 /* SatsPriceTests.xctest */,
- 3AE2D3B92B83338E00DE5F31 /* SatsPriceUITests.xctest */,
- );
- name = Products;
- sourceTree = "";
- };
- 3AE2D39B2B83338D00DE5F31 /* SatsPrice */ = {
- isa = PBXGroup;
- children = (
- 3AE2D3E82B856B1800DE5F31 /* Network */,
- 3AE2D3A32B83338D00DE5F31 /* ContentView.swift */,
- 3AE2D39C2B83338D00DE5F31 /* SatsPriceApp.swift */,
- 3AE2D3D42B83E58500DE5F31 /* SatsViewModel.swift */,
- 3AE2D3A52B83338D00DE5F31 /* Assets.xcassets */,
- 3AE2D3A72B83338D00DE5F31 /* SatsPrice.entitlements */,
- 3AE2D3A02B83338D00DE5F31 /* SatsPrice.xcdatamodeld */,
- 3AE2D3A82B83338D00DE5F31 /* Preview Content */,
- );
- path = SatsPrice;
- sourceTree = "";
- };
- 3AE2D3A82B83338D00DE5F31 /* Preview Content */ = {
- isa = PBXGroup;
- children = (
- 3AE2D3A92B83338D00DE5F31 /* Preview Assets.xcassets */,
- );
- path = "Preview Content";
- sourceTree = "";
- };
- 3AE2D3B22B83338E00DE5F31 /* SatsPriceTests */ = {
- isa = PBXGroup;
- children = (
- 3AE2D3B32B83338E00DE5F31 /* SatsPriceTests.swift */,
- 3AE2D3D92B83FE5F00DE5F31 /* SatsViewModelTests.swift */,
- );
- path = SatsPriceTests;
- sourceTree = "";
- };
- 3AE2D3BC2B83338E00DE5F31 /* SatsPriceUITests */ = {
- isa = PBXGroup;
- children = (
- 3AE2D3BD2B83338E00DE5F31 /* SatsPriceUITests.swift */,
- 3AE2D3BF2B83338E00DE5F31 /* SatsPriceUITestsLaunchTests.swift */,
- );
- path = SatsPriceUITests;
- sourceTree = "";
- };
- 3AE2D3E82B856B1800DE5F31 /* Network */ = {
- isa = PBXGroup;
- children = (
- 3AE2D3E02B8459D600DE5F31 /* CoinbasePriceFetcher.swift */,
- 3AE2D3E22B8461FE00DE5F31 /* CoinGeckoPriceFetcher.swift */,
- 3A7B2AA22B86407A00ACC4A7 /* FakePriceFetcher.swift */,
- 3A8E5DA62C810C9900E9E6BD /* ManualPriceFetcher.swift */,
- 3AE2D3DE2B84597100DE5F31 /* PriceFetcher.swift */,
- 3AE2D3E62B85690200DE5F31 /* PriceFetcherDelegator.swift */,
- 3AE2D3E42B846A8600DE5F31 /* PriceSource.swift */,
- );
- path = Network;
- sourceTree = "";
- };
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
- 3AE2D3982B83338D00DE5F31 /* SatsPrice */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 3AE2D3C32B83338E00DE5F31 /* Build configuration list for PBXNativeTarget "SatsPrice" */;
- buildPhases = (
- 3AE2D3952B83338D00DE5F31 /* Sources */,
- 3AE2D3962B83338D00DE5F31 /* Frameworks */,
- 3AE2D3972B83338D00DE5F31 /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = SatsPrice;
- packageProductDependencies = (
- 3AE2D3DC2B84020200DE5F31 /* BigDecimal */,
- );
- productName = SatsPrice;
- productReference = 3AE2D3992B83338D00DE5F31 /* SatsPrice.app */;
- productType = "com.apple.product-type.application";
- };
- 3AE2D3AE2B83338E00DE5F31 /* SatsPriceTests */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 3AE2D3C62B83338E00DE5F31 /* Build configuration list for PBXNativeTarget "SatsPriceTests" */;
- buildPhases = (
- 3AE2D3AB2B83338E00DE5F31 /* Sources */,
- 3AE2D3AC2B83338E00DE5F31 /* Frameworks */,
- 3AE2D3AD2B83338E00DE5F31 /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- 3AE2D3B12B83338E00DE5F31 /* PBXTargetDependency */,
- );
- name = SatsPriceTests;
- productName = SatsPriceTests;
- productReference = 3AE2D3AF2B83338E00DE5F31 /* SatsPriceTests.xctest */;
- productType = "com.apple.product-type.bundle.unit-test";
- };
- 3AE2D3B82B83338E00DE5F31 /* SatsPriceUITests */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 3AE2D3C92B83338E00DE5F31 /* Build configuration list for PBXNativeTarget "SatsPriceUITests" */;
- buildPhases = (
- 3AE2D3B52B83338E00DE5F31 /* Sources */,
- 3AE2D3B62B83338E00DE5F31 /* Frameworks */,
- 3AE2D3B72B83338E00DE5F31 /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- 3AE2D3BB2B83338E00DE5F31 /* PBXTargetDependency */,
- );
- name = SatsPriceUITests;
- productName = SatsPriceUITests;
- productReference = 3AE2D3B92B83338E00DE5F31 /* SatsPriceUITests.xctest */;
- productType = "com.apple.product-type.bundle.ui-testing";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- 3AE2D3912B83338D00DE5F31 /* Project object */ = {
- isa = PBXProject;
- attributes = {
- BuildIndependentTargetsInParallel = 1;
- LastSwiftUpdateCheck = 1520;
- LastUpgradeCheck = 1520;
- TargetAttributes = {
- 3AE2D3982B83338D00DE5F31 = {
- CreatedOnToolsVersion = 15.2;
- };
- 3AE2D3AE2B83338E00DE5F31 = {
- CreatedOnToolsVersion = 15.2;
- TestTargetID = 3AE2D3982B83338D00DE5F31;
- };
- 3AE2D3B82B83338E00DE5F31 = {
- CreatedOnToolsVersion = 15.2;
- TestTargetID = 3AE2D3982B83338D00DE5F31;
- };
- };
- };
- buildConfigurationList = 3AE2D3942B83338D00DE5F31 /* Build configuration list for PBXProject "SatsPrice" */;
- compatibilityVersion = "Xcode 14.0";
- developmentRegion = en;
- hasScannedForEncodings = 0;
- knownRegions = (
- en,
- Base,
- );
- mainGroup = 3AE2D3902B83338D00DE5F31;
- packageReferences = (
- 3AE2D3DB2B84020200DE5F31 /* XCRemoteSwiftPackageReference "BigDecimal" */,
- );
- productRefGroup = 3AE2D39A2B83338D00DE5F31 /* Products */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- 3AE2D3982B83338D00DE5F31 /* SatsPrice */,
- 3AE2D3AE2B83338E00DE5F31 /* SatsPriceTests */,
- 3AE2D3B82B83338E00DE5F31 /* SatsPriceUITests */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
- 3AE2D3972B83338D00DE5F31 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 3AE2D3AA2B83338D00DE5F31 /* Preview Assets.xcassets in Resources */,
- 3AE2D3A62B83338D00DE5F31 /* Assets.xcassets in Resources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 3AE2D3AD2B83338E00DE5F31 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 3AE2D3B72B83338E00DE5F31 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
- 3AE2D3952B83338D00DE5F31 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 3AE2D3E52B846A8600DE5F31 /* PriceSource.swift in Sources */,
- 3AE2D3E72B85690200DE5F31 /* PriceFetcherDelegator.swift in Sources */,
- 3A7B2AA32B86407A00ACC4A7 /* FakePriceFetcher.swift in Sources */,
- 3AE2D3E12B8459D600DE5F31 /* CoinbasePriceFetcher.swift in Sources */,
- 3AE2D39D2B83338D00DE5F31 /* SatsPriceApp.swift in Sources */,
- 3AE2D3A22B83338D00DE5F31 /* SatsPrice.xcdatamodeld in Sources */,
- 3AE2D3A42B83338D00DE5F31 /* ContentView.swift in Sources */,
- 3A8E5DA72C810C9900E9E6BD /* ManualPriceFetcher.swift in Sources */,
- 3AE2D3D52B83E58500DE5F31 /* SatsViewModel.swift in Sources */,
- 3AE2D3E32B8461FE00DE5F31 /* CoinGeckoPriceFetcher.swift in Sources */,
- 3AE2D3DF2B84597100DE5F31 /* PriceFetcher.swift in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 3AE2D3AB2B83338E00DE5F31 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 3AE2D3DA2B83FE5F00DE5F31 /* SatsViewModelTests.swift in Sources */,
- 3AE2D3B42B83338E00DE5F31 /* SatsPriceTests.swift in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 3AE2D3B52B83338E00DE5F31 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 3AE2D3BE2B83338E00DE5F31 /* SatsPriceUITests.swift in Sources */,
- 3AE2D3C02B83338E00DE5F31 /* SatsPriceUITestsLaunchTests.swift in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin PBXTargetDependency section */
- 3AE2D3B12B83338E00DE5F31 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 3AE2D3982B83338D00DE5F31 /* SatsPrice */;
- targetProxy = 3AE2D3B02B83338E00DE5F31 /* PBXContainerItemProxy */;
- };
- 3AE2D3BB2B83338E00DE5F31 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 3AE2D3982B83338D00DE5F31 /* SatsPrice */;
- targetProxy = 3AE2D3BA2B83338E00DE5F31 /* PBXContainerItemProxy */;
- };
-/* End PBXTargetDependency section */
-
-/* Begin XCBuildConfiguration section */
- 3AE2D3C12B83338E00DE5F31 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
- ALWAYS_SEARCH_USER_PATHS = NO;
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_ENABLE_OBJC_WEAK = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- COPY_PHASE_STRIP = NO;
- DEBUG_INFORMATION_FORMAT = dwarf;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- ENABLE_TESTABILITY = YES;
- ENABLE_USER_SCRIPT_SANDBOXING = YES;
- GCC_C_LANGUAGE_STANDARD = gnu17;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
- MTL_FAST_MATH = YES;
- ONLY_ACTIVE_ARCH = YES;
- SDKROOT = iphoneos;
- SUPPORTED_PLATFORMS = "xrsimulator xros watchsimulator watchos macosx iphonesimulator iphoneos driverkit appletvsimulator appletvos";
- SUPPORTS_MACCATALYST = YES;
- SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
- SWIFT_OPTIMIZATION_LEVEL = "-Onone";
- };
- name = Debug;
- };
- 3AE2D3C22B83338E00DE5F31 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
- ALWAYS_SEARCH_USER_PATHS = NO;
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_ENABLE_OBJC_WEAK = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- COPY_PHASE_STRIP = NO;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- ENABLE_NS_ASSERTIONS = NO;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- ENABLE_USER_SCRIPT_SANDBOXING = YES;
- GCC_C_LANGUAGE_STANDARD = gnu17;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MTL_ENABLE_DEBUG_INFO = NO;
- MTL_FAST_MATH = YES;
- SDKROOT = iphoneos;
- SUPPORTED_PLATFORMS = "xrsimulator xros watchsimulator watchos macosx iphonesimulator iphoneos driverkit appletvsimulator appletvos";
- SUPPORTS_MACCATALYST = YES;
- SWIFT_COMPILATION_MODE = wholemodule;
- };
- name = Release;
- };
- 3AE2D3C42B83338E00DE5F31 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- CODE_SIGN_ENTITLEMENTS = SatsPrice/SatsPrice.entitlements;
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 3;
- DEVELOPMENT_ASSET_PATHS = "\"SatsPrice/Preview Content\"";
- DEVELOPMENT_TEAM = S99A5B637C;
- ENABLE_PREVIEWS = YES;
- GENERATE_INFOPLIST_FILE = YES;
- INFOPLIST_KEY_CFBundleDisplayName = SatsPrice;
- INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
- "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
- "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
- "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
- "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
- "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
- "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
- "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
- "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
- INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
- INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
- LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
- "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
- MACOSX_DEPLOYMENT_TARGET = 13.0;
- MARKETING_VERSION = 0.1;
- PRODUCT_BUNDLE_IDENTIFIER = xyz.tyiu.SatsPrice;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = auto;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
- SUPPORTS_MACCATALYST = NO;
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- };
- name = Debug;
- };
- 3AE2D3C52B83338E00DE5F31 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- CODE_SIGN_ENTITLEMENTS = SatsPrice/SatsPrice.entitlements;
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 3;
- DEVELOPMENT_ASSET_PATHS = "\"SatsPrice/Preview Content\"";
- DEVELOPMENT_TEAM = S99A5B637C;
- ENABLE_PREVIEWS = YES;
- GENERATE_INFOPLIST_FILE = YES;
- INFOPLIST_KEY_CFBundleDisplayName = SatsPrice;
- INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
- "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
- "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
- "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
- "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
- "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
- "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
- "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
- "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
- INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
- INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
- LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
- "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
- MACOSX_DEPLOYMENT_TARGET = 13.0;
- MARKETING_VERSION = 0.1;
- PRODUCT_BUNDLE_IDENTIFIER = xyz.tyiu.SatsPrice;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = auto;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
- SUPPORTS_MACCATALYST = NO;
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- };
- name = Release;
- };
- 3AE2D3C72B83338E00DE5F31 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
- BUNDLE_LOADER = "$(TEST_HOST)";
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
- GENERATE_INFOPLIST_FILE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 16.0;
- MACOSX_DEPLOYMENT_TARGET = 13.0;
- MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = xyz.tyiu.SatsPriceTests;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = auto;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
- SWIFT_EMIT_LOC_STRINGS = NO;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SatsPrice.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/SatsPrice";
- };
- name = Debug;
- };
- 3AE2D3C82B83338E00DE5F31 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
- BUNDLE_LOADER = "$(TEST_HOST)";
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
- GENERATE_INFOPLIST_FILE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 16.0;
- MACOSX_DEPLOYMENT_TARGET = 13.0;
- MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = xyz.tyiu.SatsPriceTests;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = auto;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
- SWIFT_EMIT_LOC_STRINGS = NO;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SatsPrice.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/SatsPrice";
- };
- name = Release;
- };
- 3AE2D3CA2B83338E00DE5F31 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
- GENERATE_INFOPLIST_FILE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 16.0;
- MACOSX_DEPLOYMENT_TARGET = 13.0;
- MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = xyz.tyiu.SatsPriceUITests;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = auto;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
- SWIFT_EMIT_LOC_STRINGS = NO;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- TEST_TARGET_NAME = SatsPrice;
- };
- name = Debug;
- };
- 3AE2D3CB2B83338E00DE5F31 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
- GENERATE_INFOPLIST_FILE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 16.0;
- MACOSX_DEPLOYMENT_TARGET = 13.0;
- MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = xyz.tyiu.SatsPriceUITests;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = auto;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
- SWIFT_EMIT_LOC_STRINGS = NO;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- TEST_TARGET_NAME = SatsPrice;
- };
- name = Release;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- 3AE2D3942B83338D00DE5F31 /* Build configuration list for PBXProject "SatsPrice" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 3AE2D3C12B83338E00DE5F31 /* Debug */,
- 3AE2D3C22B83338E00DE5F31 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 3AE2D3C32B83338E00DE5F31 /* Build configuration list for PBXNativeTarget "SatsPrice" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 3AE2D3C42B83338E00DE5F31 /* Debug */,
- 3AE2D3C52B83338E00DE5F31 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 3AE2D3C62B83338E00DE5F31 /* Build configuration list for PBXNativeTarget "SatsPriceTests" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 3AE2D3C72B83338E00DE5F31 /* Debug */,
- 3AE2D3C82B83338E00DE5F31 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 3AE2D3C92B83338E00DE5F31 /* Build configuration list for PBXNativeTarget "SatsPriceUITests" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 3AE2D3CA2B83338E00DE5F31 /* Debug */,
- 3AE2D3CB2B83338E00DE5F31 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
-/* End XCConfigurationList section */
-
-/* Begin XCRemoteSwiftPackageReference section */
- 3AE2D3DB2B84020200DE5F31 /* XCRemoteSwiftPackageReference "BigDecimal" */ = {
- isa = XCRemoteSwiftPackageReference;
- repositoryURL = "https://github.com/mgriebling/BigDecimal.git";
- requirement = {
- kind = upToNextMajorVersion;
- minimumVersion = 2.2.3;
- };
- };
-/* End XCRemoteSwiftPackageReference section */
-
-/* Begin XCSwiftPackageProductDependency section */
- 3AE2D3DC2B84020200DE5F31 /* BigDecimal */ = {
- isa = XCSwiftPackageProductDependency;
- package = 3AE2D3DB2B84020200DE5F31 /* XCRemoteSwiftPackageReference "BigDecimal" */;
- productName = BigDecimal;
- };
-/* End XCSwiftPackageProductDependency section */
-
-/* Begin XCVersionGroup section */
- 3AE2D3A02B83338D00DE5F31 /* SatsPrice.xcdatamodeld */ = {
- isa = XCVersionGroup;
- children = (
- 3AE2D3A12B83338D00DE5F31 /* SatsPrice.xcdatamodel */,
- );
- currentVersion = 3AE2D3A12B83338D00DE5F31 /* SatsPrice.xcdatamodel */;
- path = SatsPrice.xcdatamodeld;
- sourceTree = "";
- versionGroupType = wrapper.xcdatamodel;
- };
-/* End XCVersionGroup section */
- };
- rootObject = 3AE2D3912B83338D00DE5F31 /* Project object */;
-}
diff --git a/SatsPrice.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/SatsPrice.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
deleted file mode 100644
index 0b5df84..0000000
--- a/SatsPrice.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "pins" : [
- {
- "identity" : "bigdecimal",
- "kind" : "remoteSourceControl",
- "location" : "https://github.com/mgriebling/BigDecimal.git",
- "state" : {
- "revision" : "c4e8348c7fbc90f29225d5f8681ce33a16ab33a2",
- "version" : "2.2.3"
- }
- },
- {
- "identity" : "bigint",
- "kind" : "remoteSourceControl",
- "location" : "https://github.com/mgriebling/BigInt.git",
- "state" : {
- "revision" : "498d4d290658d7c43a24b9e309c321592dc294f2",
- "version" : "2.0.10"
- }
- },
- {
- "identity" : "uint128",
- "kind" : "remoteSourceControl",
- "location" : "https://github.com/mgriebling/UInt128.git",
- "state" : {
- "revision" : "59dac4f14d657fd60bacfdfb7398d38b450af74f",
- "version" : "3.1.5"
- }
- }
- ],
- "version" : 2
-}
diff --git a/SatsPrice.xcodeproj/project.xcworkspace/xcuserdata/tyiu.xcuserdatad/WorkspaceSettings.xcsettings b/SatsPrice.xcodeproj/project.xcworkspace/xcuserdata/tyiu.xcuserdatad/WorkspaceSettings.xcsettings
deleted file mode 100644
index bbfef02..0000000
--- a/SatsPrice.xcodeproj/project.xcworkspace/xcuserdata/tyiu.xcuserdatad/WorkspaceSettings.xcsettings
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
- BuildLocationStyle
- UseAppPreferences
- CustomBuildLocationType
- RelativeToDerivedData
- DerivedDataLocationStyle
- Default
- ShowSharedSchemesAutomaticallyEnabled
-
-
-
diff --git a/SatsPrice.xcodeproj/xcuserdata/tyiu.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/SatsPrice.xcodeproj/xcuserdata/tyiu.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
deleted file mode 100644
index 6edebda..0000000
--- a/SatsPrice.xcodeproj/xcuserdata/tyiu.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
diff --git a/SatsPrice.xcodeproj/xcuserdata/tyiu.xcuserdatad/xcschemes/xcschememanagement.plist b/SatsPrice.xcodeproj/xcuserdata/tyiu.xcuserdatad/xcschemes/xcschememanagement.plist
deleted file mode 100644
index b7ab8b4..0000000
--- a/SatsPrice.xcodeproj/xcuserdata/tyiu.xcuserdatad/xcschemes/xcschememanagement.plist
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
- SchemeUserState
-
- Demo (Playground) 1.xcscheme
-
- isShown
-
- orderHint
- 2
-
- Demo (Playground) 2.xcscheme
-
- isShown
-
- orderHint
- 3
-
- Demo (Playground).xcscheme
-
- isShown
-
- orderHint
- 1
-
- SatsPrice.xcscheme_^#shared#^_
-
- orderHint
- 0
-
-
-
-
diff --git a/SatsPrice/Network/PriceFetcher.swift b/SatsPrice/Network/PriceFetcher.swift
deleted file mode 100644
index 341ddc6..0000000
--- a/SatsPrice/Network/PriceFetcher.swift
+++ /dev/null
@@ -1,13 +0,0 @@
-//
-// PriceFetcher.swift
-// SatsPrice
-//
-// Created by Terry Yiu on 2/19/24.
-//
-
-import Foundation
-import BigDecimal
-
-protocol PriceFetcher {
- func btcToUsd() async throws -> BigDecimal?
-}
diff --git a/SatsPrice/SatsPrice.entitlements b/SatsPrice/SatsPrice.entitlements
deleted file mode 100644
index ee95ab7..0000000
--- a/SatsPrice/SatsPrice.entitlements
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
- com.apple.security.app-sandbox
-
- com.apple.security.network.client
-
-
-
diff --git a/SatsPrice/SatsPrice.xcdatamodeld/SatsPrice.xcdatamodel/contents b/SatsPrice/SatsPrice.xcdatamodeld/SatsPrice.xcdatamodel/contents
deleted file mode 100644
index 9ed2921..0000000
--- a/SatsPrice/SatsPrice.xcdatamodeld/SatsPrice.xcdatamodel/contents
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/SatsPrice/SatsPriceApp.swift b/SatsPrice/SatsPriceApp.swift
deleted file mode 100644
index f11b8b0..0000000
--- a/SatsPrice/SatsPriceApp.swift
+++ /dev/null
@@ -1,17 +0,0 @@
-//
-// SatsPriceApp.swift
-// SatsPrice
-//
-// Created by Terry Yiu on 2/19/24.
-//
-
-import SwiftUI
-
-@main
-struct SatsPriceApp: App {
- var body: some Scene {
- WindowGroup {
- ContentView(.coinbase)
- }
- }
-}
diff --git a/SatsPrice/SatsViewModel.swift b/SatsPrice/SatsViewModel.swift
deleted file mode 100644
index 2c5a528..0000000
--- a/SatsPrice/SatsViewModel.swift
+++ /dev/null
@@ -1,67 +0,0 @@
-//
-// SatsViewModel.swift
-// SatsPrice
-//
-// Created by Terry Yiu on 2/19/24.
-//
-
-import Foundation
-import BigDecimal
-
-class SatsViewModel: ObservableObject {
- @Published private(set) var btcToUsd: BigDecimal = BigDecimal.nan
- @Published var lastUpdated: Date = Date.now
-
- @Published private(set) var sats: BigDecimal = 0
- @Published private(set) var btc: BigDecimal = 0
- @Published private(set) var usd: BigDecimal = 0
-
- var btcToUsdString: String {
- get { btcToUsd.asString(.plain) }
- set {
- self.btcToUsd = BigDecimal(newValue)
- self.usd = btc.multiply(btcToUsd, Rounding(.down, 20))
- }
- }
-
- var satsString: String {
- get { sats.asString(.plain) }
- set {
- self.sats = BigDecimal(newValue)
-
- let preciseDivide = sats.divide(100000000)
- if preciseDivide.isNaN {
- self.btc = sats.divide(100000000, Rounding(.down, 20))
- } else {
- self.btc = sats.divide(100000000)
- }
-
- self.usd = btc.multiply(btcToUsd, Rounding(.down, 20))
- }
- }
-
- var btcString: String {
- get { btc.asString(.plain) }
- set {
- self.btc = BigDecimal(newValue)
- self.sats = btc.multiply(100000000, Rounding(.down, 20))
- self.usd = btc.multiply(btcToUsd, Rounding(.down, 20))
- }
- }
-
- var usdString: String {
- get { usd.asString(.plain) }
- set {
- self.usd = BigDecimal(newValue)
-
- let preciseDivide = usd.divide(btcToUsd)
- if preciseDivide.isNaN {
- self.btc = usd.divide(btcToUsd, Rounding(.down, 20))
- } else {
- self.btc = usd.divide(btcToUsd)
- }
-
- self.sats = btc.multiply(100000000, Rounding(.down, 20))
- }
- }
-}
diff --git a/SatsPriceTests/SatsPriceTests.swift b/SatsPriceTests/SatsPriceTests.swift
deleted file mode 100644
index 751f057..0000000
--- a/SatsPriceTests/SatsPriceTests.swift
+++ /dev/null
@@ -1,35 +0,0 @@
-//
-// SatsPriceTests.swift
-// SatsPriceTests
-//
-// Created by Terry Yiu on 2/19/24.
-//
-
-import XCTest
-
-final class SatsPriceTests: XCTestCase {
-
- override func setUpWithError() throws {
- // Put setup code here. This method is called before the invocation of each test method in the class.
- }
-
- override func tearDownWithError() throws {
- // Put teardown code here. This method is called after the invocation of each test method in the class.
- }
-
- func testExample() throws {
- // This is an example of a functional test case.
- // Use XCTAssert and related functions to verify your tests produce the correct results.
- // Any test you write for XCTest can be annotated as throws and async.
- // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
- // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
- }
-
- func testPerformanceExample() throws {
- // This is an example of a performance test case.
- measure {
- // Put the code you want to measure the time of here.
- }
- }
-
-}
diff --git a/SatsPriceUITests/SatsPriceUITests.swift b/SatsPriceUITests/SatsPriceUITests.swift
deleted file mode 100644
index 3320e60..0000000
--- a/SatsPriceUITests/SatsPriceUITests.swift
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-// SatsPriceUITests.swift
-// SatsPriceUITests
-//
-// Created by Terry Yiu on 2/19/24.
-//
-
-import XCTest
-
-final class SatsPriceUITests: XCTestCase {
-
- override func setUpWithError() throws {
- // Put setup code here. This method is called before the invocation of each test method in the class.
-
- // In UI tests it is usually best to stop immediately when a failure occurs.
- continueAfterFailure = false
-
- // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
- }
-
- override func tearDownWithError() throws {
- // Put teardown code here. This method is called after the invocation of each test method in the class.
- }
-
- func testExample() throws {
- // UI tests must launch the application that they test.
- let app = XCUIApplication()
- app.launch()
-
- // Use XCTAssert and related functions to verify your tests produce the correct results.
- }
-
- func testLaunchPerformance() throws {
- if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
- // This measures how long it takes to launch your application.
- measure(metrics: [XCTApplicationLaunchMetric()]) {
- XCUIApplication().launch()
- }
- }
- }
-}
diff --git a/SatsPriceUITests/SatsPriceUITestsLaunchTests.swift b/SatsPriceUITests/SatsPriceUITestsLaunchTests.swift
deleted file mode 100644
index 5fbea58..0000000
--- a/SatsPriceUITests/SatsPriceUITestsLaunchTests.swift
+++ /dev/null
@@ -1,32 +0,0 @@
-//
-// SatsPriceUITestsLaunchTests.swift
-// SatsPriceUITests
-//
-// Created by Terry Yiu on 2/19/24.
-//
-
-import XCTest
-
-final class SatsPriceUITestsLaunchTests: XCTestCase {
-
- override class var runsForEachTargetApplicationUIConfiguration: Bool {
- true
- }
-
- override func setUpWithError() throws {
- continueAfterFailure = false
- }
-
- func testLaunch() throws {
- let app = XCUIApplication()
- app.launch()
-
- // Insert steps here to perform after app launch but before taking a screenshot,
- // such as logging into a test account or navigating somewhere in the app
-
- let attachment = XCTAttachment(screenshot: app.screenshot())
- attachment.name = "Launch Screen"
- attachment.lifetime = .keepAlways
- add(attachment)
- }
-}
diff --git a/Skip.env b/Skip.env
new file mode 100644
index 0000000..c187154
--- /dev/null
+++ b/Skip.env
@@ -0,0 +1,20 @@
+// The configuration file for your Skip App (https://skip.tools).
+// Properties specified here are shared between
+// Darwin/SatsPrice.xcconfig and Android/settings.gradle.kts
+// and will be included in the app's metadata files
+// Info.plist and AndroidManifest.xml
+
+// PRODUCT_NAME is the default title of the app, which must match the app's Swift module name
+PRODUCT_NAME = SatsPrice
+
+// PRODUCT_BUNDLE_IDENTIFIER is the unique id for both the iOS and Android app
+PRODUCT_BUNDLE_IDENTIFIER = xyz.tyiu.SatsPrice
+
+// The semantic version of the app
+MARKETING_VERSION = 0.2.0
+
+// The build number specifying the internal app version
+CURRENT_PROJECT_VERSION = 1
+
+// The package name for the Android entry point, referenced by the AndroidManifest.xml
+ANDROID_PACKAGE_NAME = sats.price
diff --git a/SatsPrice/ContentView.swift b/Sources/SatsPrice/ContentView.swift
similarity index 83%
rename from SatsPrice/ContentView.swift
rename to Sources/SatsPrice/ContentView.swift
index 7864bc2..5e0a8ad 100644
--- a/SatsPrice/ContentView.swift
+++ b/Sources/SatsPrice/ContentView.swift
@@ -1,15 +1,11 @@
-//
-// ContentView.swift
-// SatsPrice
-//
-// Created by Terry Yiu on 2/19/24.
-//
+// This is free software: you can redistribute and/or modify it
+// under the terms of the GNU General Public License 3.0
+// as published by the Free Software Foundation https://fsf.org
-import SwiftUI
-import BigDecimal
import Combine
+import SwiftUI
-struct ContentView: View {
+public struct ContentView: View {
@ObservedObject private var satsViewModel = SatsViewModel()
@State private var priceSource: PriceSource
@@ -42,7 +38,7 @@ struct ContentView: View {
satsViewModel.lastUpdated = Date.now
}
- var body: some View {
+ public var body: some View {
Form {
Section {
Picker("Price Source", selection: $priceSource) {
@@ -54,7 +50,7 @@ struct ContentView: View {
HStack {
TextField("", text: $satsViewModel.btcToUsdString)
.disabled(priceSource != .manual)
-#if os(iOS)
+#if os(iOS) || SKIP
.keyboardType(.decimalPad)
#endif
if priceSource != .manual {
@@ -63,19 +59,21 @@ struct ContentView: View {
await updatePrice()
}
}) {
- Image(systemName: "arrow.clockwise")
+ Image(systemName: "arrow.clockwise.circle")
}
}
}
} header: {
Text("1 BTC to USD")
} footer: {
- Text("Last updated: \(dateFormatter.string(from: satsViewModel.lastUpdated))")
+ if priceSource != .manual {
+ Text("Last updated: \(dateFormatter.string(from: satsViewModel.lastUpdated))")
+ }
}
Section {
TextField("", text: $satsViewModel.satsString)
-#if os(iOS)
+#if os(iOS) || SKIP
.keyboardType(.numberPad)
#endif
} header: {
@@ -84,7 +82,7 @@ struct ContentView: View {
Section {
TextField("", text: $satsViewModel.btcString)
-#if os(iOS)
+#if os(iOS) || SKIP
.keyboardType(.decimalPad)
#endif
} header: {
@@ -93,7 +91,7 @@ struct ContentView: View {
Section {
TextField("", text: $satsViewModel.usdString)
-#if os(iOS)
+#if os(iOS) || SKIP
.keyboardType(.decimalPad)
#endif
} header: {
diff --git a/SatsPrice/Network/CoinGeckoPriceFetcher.swift b/Sources/SatsPrice/Network/CoinGeckoPriceFetcher.swift
similarity index 71%
rename from SatsPrice/Network/CoinGeckoPriceFetcher.swift
rename to Sources/SatsPrice/Network/CoinGeckoPriceFetcher.swift
index 5cc20fd..8a4658a 100644
--- a/SatsPrice/Network/CoinGeckoPriceFetcher.swift
+++ b/Sources/SatsPrice/Network/CoinGeckoPriceFetcher.swift
@@ -1,3 +1,6 @@
+// This is free software: you can redistribute and/or modify it
+// under the terms of the GNU General Public License 3.0
+// as published by the Free Software Foundation https://fsf.org
//
// CoinGeckoPriceFetcher.swift
// SatsPrice
@@ -6,20 +9,23 @@
//
import Foundation
-import BigDecimal
private struct CoinGeckoPriceResponse: Codable {
let bitcoin: CoinGeckoPrice
}
private struct CoinGeckoPrice: Codable {
+#if !SKIP
let usd: Decimal
+#else
+ let usd: String
+#endif
}
class CoinGeckoPriceFetcher : PriceFetcher {
private static let urlString = "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd&precision=18"
- func btcToUsd() async throws -> BigDecimal? {
+ func btcToUsd() async throws -> Decimal? {
do {
guard let urlComponents = URLComponents(string: CoinGeckoPriceFetcher.urlString), let url = urlComponents.url else {
return nil
@@ -30,7 +36,11 @@ class CoinGeckoPriceFetcher : PriceFetcher {
let priceResponse = try JSONDecoder().decode(CoinGeckoPriceResponse.self, from: data)
let price = priceResponse.bitcoin
- return BigDecimal(price.usd)
+#if !SKIP
+ return price.usd
+#else
+ return Decimal(price.usd)
+#endif
} catch {
return nil
}
diff --git a/SatsPrice/Network/CoinbasePriceFetcher.swift b/Sources/SatsPrice/Network/CoinbasePriceFetcher.swift
similarity index 74%
rename from SatsPrice/Network/CoinbasePriceFetcher.swift
rename to Sources/SatsPrice/Network/CoinbasePriceFetcher.swift
index 01a2855..b3add15 100644
--- a/SatsPrice/Network/CoinbasePriceFetcher.swift
+++ b/Sources/SatsPrice/Network/CoinbasePriceFetcher.swift
@@ -1,3 +1,6 @@
+// This is free software: you can redistribute and/or modify it
+// under the terms of the GNU General Public License 3.0
+// as published by the Free Software Foundation https://fsf.org
//
// CoinbasePriceFetcher.swift
// SatsPrice
@@ -6,7 +9,6 @@
//
import Foundation
-import BigDecimal
private struct CoinbasePriceResponse: Codable {
let data: CoinbasePrice
@@ -23,7 +25,7 @@ class CoinbasePriceFetcher : PriceFetcher {
private static let btc = "BTC"
private static let usd = "USD"
- func btcToUsd() async throws -> BigDecimal? {
+ func btcToUsd() async throws -> Decimal? {
do {
guard let urlComponents = URLComponents(string: CoinbasePriceFetcher.urlString), let url = urlComponents.url else {
return nil
@@ -38,7 +40,11 @@ class CoinbasePriceFetcher : PriceFetcher {
return nil
}
- return BigDecimal(coinbasePrice.amount)
+ #if !SKIP
+ return Decimal(string: coinbasePrice.amount)
+ #else
+ return Decimal(coinbasePrice.amount)
+ #endif
} catch {
return nil
}
diff --git a/SatsPrice/Network/FakePriceFetcher.swift b/Sources/SatsPrice/Network/FakePriceFetcher.swift
similarity index 50%
rename from SatsPrice/Network/FakePriceFetcher.swift
rename to Sources/SatsPrice/Network/FakePriceFetcher.swift
index 6e90d05..400d02a 100644
--- a/SatsPrice/Network/FakePriceFetcher.swift
+++ b/Sources/SatsPrice/Network/FakePriceFetcher.swift
@@ -1,3 +1,6 @@
+// This is free software: you can redistribute and/or modify it
+// under the terms of the GNU General Public License 3.0
+// as published by the Free Software Foundation https://fsf.org
//
// FakePriceFetcher.swift
// SatsPrice
@@ -7,12 +10,11 @@
#if DEBUG
import Foundation
-import BigDecimal
/// Fake price fetcher that returns a randomized price. Useful for development testing without requiring a network call.
class FakePriceFetcher: PriceFetcher {
- func btcToUsd() async throws -> BigDecimal? {
- BigDecimal(Double.random(in: 10000...100000))
+ func btcToUsd() async throws -> Decimal? {
+ Decimal(Double.random(in: 10000...100000))
}
}
#endif
diff --git a/SatsPrice/Network/ManualPriceFetcher.swift b/Sources/SatsPrice/Network/ManualPriceFetcher.swift
similarity index 52%
rename from SatsPrice/Network/ManualPriceFetcher.swift
rename to Sources/SatsPrice/Network/ManualPriceFetcher.swift
index 23d6c39..6dc9cb9 100644
--- a/SatsPrice/Network/ManualPriceFetcher.swift
+++ b/Sources/SatsPrice/Network/ManualPriceFetcher.swift
@@ -1,3 +1,6 @@
+// This is free software: you can redistribute and/or modify it
+// under the terms of the GNU General Public License 3.0
+// as published by the Free Software Foundation https://fsf.org
//
// ManualPriceFetcher.swift
// SatsPrice
@@ -6,13 +9,12 @@
//
import Foundation
-import BigDecimal
/// Fake price fetcher that returns a randomized price. Useful for development testing without requiring a network call.
class ManualPriceFetcher: PriceFetcher {
- var price: BigDecimal = 1
+ var price: Decimal = Decimal(1)
- func btcToUsd() async throws -> BigDecimal? {
+ func btcToUsd() async throws -> Decimal? {
return price
}
}
diff --git a/Sources/SatsPrice/Network/PriceFetcher.swift b/Sources/SatsPrice/Network/PriceFetcher.swift
new file mode 100644
index 0000000..2a5e14d
--- /dev/null
+++ b/Sources/SatsPrice/Network/PriceFetcher.swift
@@ -0,0 +1,15 @@
+// This is free software: you can redistribute and/or modify it
+// under the terms of the GNU General Public License 3.0
+// as published by the Free Software Foundation https://fsf.org
+//
+// PriceFetcher.swift
+// SatsPrice
+//
+// Created by Terry Yiu on 2/19/24.
+//
+
+import Foundation
+
+protocol PriceFetcher {
+ func btcToUsd() async throws -> Decimal?
+}
diff --git a/SatsPrice/Network/PriceFetcherDelegator.swift b/Sources/SatsPrice/Network/PriceFetcherDelegator.swift
similarity index 79%
rename from SatsPrice/Network/PriceFetcherDelegator.swift
rename to Sources/SatsPrice/Network/PriceFetcherDelegator.swift
index 21e7a6d..b944c14 100644
--- a/SatsPrice/Network/PriceFetcherDelegator.swift
+++ b/Sources/SatsPrice/Network/PriceFetcherDelegator.swift
@@ -1,3 +1,6 @@
+// This is free software: you can redistribute and/or modify it
+// under the terms of the GNU General Public License 3.0
+// as published by the Free Software Foundation https://fsf.org
//
// PriceFetcherDelegator.swift
// SatsPrice
@@ -6,7 +9,6 @@
//
import Foundation
-import BigDecimal
class PriceFetcherDelegator: PriceFetcher {
private let coinbasePriceFetcher = CoinbasePriceFetcher()
@@ -37,7 +39,7 @@ class PriceFetcherDelegator: PriceFetcher {
}
}
- func btcToUsd() async throws -> BigDecimal? {
+ func btcToUsd() async throws -> Decimal? {
return try await delegate.btcToUsd()
}
}
diff --git a/SatsPrice/Network/PriceSource.swift b/Sources/SatsPrice/Network/PriceSource.swift
similarity index 78%
rename from SatsPrice/Network/PriceSource.swift
rename to Sources/SatsPrice/Network/PriceSource.swift
index a2e2809..172fb85 100644
--- a/SatsPrice/Network/PriceSource.swift
+++ b/Sources/SatsPrice/Network/PriceSource.swift
@@ -1,3 +1,6 @@
+// This is free software: you can redistribute and/or modify it
+// under the terms of the GNU General Public License 3.0
+// as published by the Free Software Foundation https://fsf.org
//
// PriceSource.swift
// SatsPrice
diff --git a/Sources/SatsPrice/Resources/Localizable.xcstrings b/Sources/SatsPrice/Resources/Localizable.xcstrings
new file mode 100644
index 0000000..e866dfc
--- /dev/null
+++ b/Sources/SatsPrice/Resources/Localizable.xcstrings
@@ -0,0 +1,27 @@
+{
+ "sourceLanguage" : "en",
+ "strings" : {
+ "" : {
+
+ },
+ "1 BTC to USD" : {
+
+ },
+ "BTC" : {
+
+ },
+ "Last updated: %@" : {
+
+ },
+ "Price Source" : {
+
+ },
+ "Sats" : {
+
+ },
+ "USD" : {
+
+ }
+ },
+ "version" : "1.0"
+}
\ No newline at end of file
diff --git a/SatsPrice/Preview Content/Preview Assets.xcassets/Contents.json b/Sources/SatsPrice/Resources/Module.xcassets/Contents.json
similarity index 100%
rename from SatsPrice/Preview Content/Preview Assets.xcassets/Contents.json
rename to Sources/SatsPrice/Resources/Module.xcassets/Contents.json
diff --git a/Sources/SatsPrice/SatsPrice.swift b/Sources/SatsPrice/SatsPrice.swift
new file mode 100644
index 0000000..ef5a551
--- /dev/null
+++ b/Sources/SatsPrice/SatsPrice.swift
@@ -0,0 +1,6 @@
+// This is free software: you can redistribute and/or modify it
+// under the terms of the GNU General Public License 3.0
+// as published by the Free Software Foundation https://fsf.org
+
+public class SatsPriceModule {
+}
diff --git a/Sources/SatsPrice/SatsPriceApp.swift b/Sources/SatsPrice/SatsPriceApp.swift
new file mode 100644
index 0000000..d78e7a0
--- /dev/null
+++ b/Sources/SatsPrice/SatsPriceApp.swift
@@ -0,0 +1,43 @@
+// This is free software: you can redistribute and/or modify it
+// under the terms of the GNU General Public License 3.0
+// as published by the Free Software Foundation https://fsf.org
+
+import Foundation
+import OSLog
+import SwiftUI
+
+let logger: Logger = Logger(subsystem: "xyz.tyiu.SatsPrice", category: "SatsPrice")
+
+/// The Android SDK number we are running against, or `nil` if not running on Android
+let androidSDK = ProcessInfo.processInfo.environment["android.os.Build.VERSION.SDK_INT"].flatMap({ Int($0) })
+
+/// The shared top-level view for the app, loaded from the platform-specific App delegates below.
+///
+/// The default implementation merely loads the `ContentView` for the app and logs a message.
+public struct RootView : View {
+ public init() {
+ }
+
+ public var body: some View {
+ ContentView(.coinbase)
+ .task {
+ logger.log("Welcome to Skip on \(androidSDK != nil ? "Android" : "Darwin")!")
+ logger.warning("Skip app logs are viewable in the Xcode console for iOS; Android logs can be viewed in Studio or using adb logcat")
+ }
+ }
+}
+
+#if !SKIP
+public protocol SatsPriceApp : App {
+}
+
+/// The entry point to the SatsPrice app.
+/// The concrete implementation is in the SatsPriceApp module.
+public extension SatsPriceApp {
+ var body: some Scene {
+ WindowGroup {
+ RootView()
+ }
+ }
+}
+#endif
diff --git a/Sources/SatsPrice/SatsViewModel.swift b/Sources/SatsPrice/SatsViewModel.swift
new file mode 100644
index 0000000..c4a1ea2
--- /dev/null
+++ b/Sources/SatsPrice/SatsViewModel.swift
@@ -0,0 +1,173 @@
+// This is free software: you can redistribute and/or modify it
+// under the terms of the GNU General Public License 3.0
+// as published by the Free Software Foundation https://fsf.org
+//
+//
+// SatsViewModel.swift
+// SatsPrice
+//
+// Created by Terry Yiu on 2/19/24.
+//
+
+import Foundation
+import SwiftUI
+
+class SatsViewModel: ObservableObject {
+ @Published var lastUpdated: Date = Date.now
+
+ @Published var btcToUsdStringInternal: String = ""
+ @Published var satsStringInternal: String = ""
+ @Published var btcStringInternal: String = ""
+ @Published var usdStringInternal: String = ""
+
+ var btcToUsdString: String {
+ get {
+ btcToUsdStringInternal
+ }
+ set {
+ btcToUsdStringInternal = newValue
+
+ if let btc, let btcToUsd {
+ usdStringInternal = (btc * btcToUsd).formatString()
+ } else {
+ usdStringInternal = ""
+ }
+ }
+ }
+
+ var satsString: String {
+ get {
+ satsStringInternal
+ }
+ set {
+ satsStringInternal = newValue
+
+ if let sats {
+#if !SKIP
+ let btc = sats / Decimal(100000000)
+#else
+ let btc = sats.divide(Decimal(100000000), 20, java.math.RoundingMode.DOWN)
+#endif
+ btcStringInternal = btc.formatString()
+ if let btcToUsd {
+ usdStringInternal = (btc * btcToUsd).formatString()
+ } else {
+ usdStringInternal = ""
+ }
+ } else {
+ btcStringInternal = ""
+ usdStringInternal = ""
+ }
+ }
+ }
+
+ var btcString: String {
+ get {
+ btcStringInternal
+ }
+ set {
+ btcStringInternal = newValue
+
+ if let btc {
+ let sats = btc * Decimal(100000000)
+ satsStringInternal = sats.formatString()
+
+ if let btcToUsd {
+ usdStringInternal = (btc * btcToUsd).formatString()
+ } else {
+ usdStringInternal = ""
+ }
+ } else {
+ satsStringInternal = ""
+ usdStringInternal = ""
+ }
+ }
+ }
+
+ var usdString: String {
+ get {
+ usdStringInternal
+ }
+ set {
+ usdStringInternal = newValue
+
+ if let usd {
+ if let btcToUsd {
+#if !SKIP
+ let btc = usd / btcToUsd
+#else
+ let btc = usd.divide(btcToUsd, 20, java.math.RoundingMode.DOWN)
+#endif
+ btcStringInternal = btc.formatString()
+
+ let sats = btc * Decimal(100000000)
+ satsStringInternal = sats.formatString()
+ } else {
+ satsStringInternal = ""
+ usdStringInternal = ""
+ }
+ } else {
+ satsStringInternal = ""
+ usdStringInternal = ""
+ }
+ }
+ }
+
+ var btcToUsd: Decimal? {
+#if !SKIP
+ return Decimal(string: btcToUsdStringInternal)
+#else
+ do {
+ return Decimal(btcToUsdStringInternal)
+ } catch {
+ return nil
+ }
+#endif
+ }
+
+ var sats: Decimal? {
+#if !SKIP
+ return Decimal(string: satsStringInternal)
+#else
+ do {
+ return Decimal(satsStringInternal)
+ } catch {
+ return nil
+ }
+#endif
+ }
+
+ var btc: Decimal? {
+#if !SKIP
+ return Decimal(string: btcStringInternal)
+#else
+ do {
+ return Decimal(btcStringInternal)
+ } catch {
+ return nil
+ }
+#endif
+ }
+
+ var usd: Decimal? {
+#if !SKIP
+ return Decimal(string: usdStringInternal)
+#else
+ do {
+ return Decimal(usdStringInternal)
+ } catch {
+ return nil
+ }
+#endif
+ }
+}
+
+extension Decimal {
+ func formatString() -> String {
+#if !SKIP
+ return String(describing: self)
+#else
+ return stripTrailingZeros().toPlainString()
+#endif
+ }
+}
diff --git a/Sources/SatsPrice/Skip/skip.yml b/Sources/SatsPrice/Skip/skip.yml
new file mode 100644
index 0000000..f0bf5ee
--- /dev/null
+++ b/Sources/SatsPrice/Skip/skip.yml
@@ -0,0 +1,3 @@
+# Configuration file for https://skip.tools project
+build:
+ contents:
diff --git a/SatsPriceTests/SatsViewModelTests.swift b/Tests/SatsPriceTests/SatsViewModelTests.swift
similarity index 52%
rename from SatsPriceTests/SatsViewModelTests.swift
rename to Tests/SatsPriceTests/SatsViewModelTests.swift
index 867e787..d32562a 100644
--- a/SatsPriceTests/SatsViewModelTests.swift
+++ b/Tests/SatsPriceTests/SatsViewModelTests.swift
@@ -1,3 +1,6 @@
+// This is free software: you can redistribute and/or modify it
+// under the terms of the GNU General Public License 3.0
+// as published by the Free Software Foundation https://fsf.org
//
// SatsViewModelTests.swift
// SatsPriceTests
@@ -6,66 +9,57 @@
//
import XCTest
-import BigDecimal
@testable import SatsPrice
final class SatsViewModelTests: XCTestCase {
- override func setUpWithError() throws {
- // Put setup code here. This method is called before the invocation of each test method in the class.
- }
-
- override func tearDownWithError() throws {
- // Put teardown code here. This method is called after the invocation of each test method in the class.
- }
-
func testSatsViewModel() {
let satsViewModel = SatsViewModel()
satsViewModel.btcToUsdString = "54321"
// Test BTC updates.
satsViewModel.btcString = "1"
- XCTAssertEqual(satsViewModel.btc, BigDecimal("1"))
+ XCTAssertEqual(satsViewModel.btc, Decimal(string: "1"))
XCTAssertEqual(satsViewModel.btcString, "1")
- XCTAssertEqual(satsViewModel.sats, BigDecimal("100000000"))
+ XCTAssertEqual(satsViewModel.sats, Decimal(string: "100000000"))
XCTAssertEqual(satsViewModel.satsString, "100000000")
- XCTAssertEqual(satsViewModel.usd, BigDecimal("54321"))
+ XCTAssertEqual(satsViewModel.usd, Decimal(string: "54321"))
XCTAssertEqual(satsViewModel.usdString, "54321")
// Test Sats updates.
satsViewModel.satsString = "200000000"
- XCTAssertEqual(satsViewModel.btc, BigDecimal("2"))
+ XCTAssertEqual(satsViewModel.btc, Decimal(string: "2"))
XCTAssertEqual(satsViewModel.btcString, "2")
- XCTAssertEqual(satsViewModel.sats, BigDecimal("200000000"))
+ XCTAssertEqual(satsViewModel.sats, Decimal(string: "200000000"))
XCTAssertEqual(satsViewModel.satsString, "200000000")
- XCTAssertEqual(satsViewModel.usd, BigDecimal("108642"))
+ XCTAssertEqual(satsViewModel.usd, Decimal(string: "108642"))
XCTAssertEqual(satsViewModel.usdString, "108642")
// Test USD updates.
satsViewModel.usdString = "162963"
- XCTAssertEqual(satsViewModel.btc, BigDecimal("3"))
+ XCTAssertEqual(satsViewModel.btc, Decimal(string: "3"))
XCTAssertEqual(satsViewModel.btcString, "3")
- XCTAssertEqual(satsViewModel.sats, BigDecimal("300000000"))
+ XCTAssertEqual(satsViewModel.sats, Decimal(string: "300000000"))
XCTAssertEqual(satsViewModel.satsString, "300000000")
- XCTAssertEqual(satsViewModel.usd, BigDecimal("162963"))
+ XCTAssertEqual(satsViewModel.usd, Decimal(string: "162963"))
XCTAssertEqual(satsViewModel.usdString, "162963")
// Test fractional amounts.
satsViewModel.usdString = "1"
- XCTAssertEqual(satsViewModel.btc, BigDecimal("0.000018409086725207562452"))
- XCTAssertEqual(satsViewModel.btcString, "0.000018409086725207562452")
- XCTAssertEqual(satsViewModel.sats, BigDecimal("1840.9086725207562452"))
- XCTAssertEqual(satsViewModel.satsString, "1840.9086725207562452")
- XCTAssertEqual(satsViewModel.usd, BigDecimal("1"))
+ XCTAssertEqual(satsViewModel.btc, Decimal(string: "0.00001840908672520756245282671526665562"))
+ XCTAssertEqual(satsViewModel.btcString, "0.00001840908672520756245282671526665562")
+ XCTAssertEqual(satsViewModel.sats, Decimal(string: "1840.908672520756245282671526665562"))
+ XCTAssertEqual(satsViewModel.satsString, "1840.908672520756245282671526665562")
+ XCTAssertEqual(satsViewModel.usd, Decimal(string: "1"))
XCTAssertEqual(satsViewModel.usdString, "1")
// Test large amounts that exceed the cap of 21M BTC.
satsViewModel.usdString = "11407419999999"
- XCTAssertEqual(satsViewModel.btc, BigDecimal("210000184.09084884298"))
- XCTAssertEqual(satsViewModel.btcString, "210000184.09084884298")
- XCTAssertEqual(satsViewModel.sats, BigDecimal("21000018409084884.298"))
- XCTAssertEqual(satsViewModel.satsString, "21000018409084884.298")
- XCTAssertEqual(satsViewModel.usd, BigDecimal("11407419999999"))
+ XCTAssertEqual(satsViewModel.btc, Decimal(string: "210000184.09084884298889932070469983984"))
+ XCTAssertEqual(satsViewModel.btcString, "210000184.09084884298889932070469983984")
+ XCTAssertEqual(satsViewModel.sats, Decimal(string: "21000018409084884.298889932070469983984"))
+ XCTAssertEqual(satsViewModel.satsString, "21000018409084884.298889932070469983984")
+ XCTAssertEqual(satsViewModel.usd, Decimal(string: "11407419999999"))
XCTAssertEqual(satsViewModel.usdString, "11407419999999")
}
diff --git a/Tests/SatsPriceTests/Skip/skip.yml b/Tests/SatsPriceTests/Skip/skip.yml
new file mode 100644
index 0000000..f7eb021
--- /dev/null
+++ b/Tests/SatsPriceTests/Skip/skip.yml
@@ -0,0 +1,3 @@
+# Configuration file for https://skip.tools project
+#build:
+# contents:
\ No newline at end of file
diff --git a/Tests/SatsPriceTests/XCSkipTests.swift b/Tests/SatsPriceTests/XCSkipTests.swift
new file mode 100644
index 0000000..d9edbba
--- /dev/null
+++ b/Tests/SatsPriceTests/XCSkipTests.swift
@@ -0,0 +1,32 @@
+// This is free software: you can redistribute and/or modify it
+// under the terms of the GNU General Public License 3.0
+// as published by the Free Software Foundation https://fsf.org
+
+import Foundation
+#if os(macOS) // Skip transpiled tests only run on macOS targets
+import SkipTest
+
+/// This test case will run the transpiled tests for the Skip module.
+@available(macOS 13, macCatalyst 16, *)
+final class XCSkipTests: XCTestCase, XCGradleHarness {
+ public func testSkipModule() async throws {
+ // Run the transpiled JUnit tests for the current test module.
+ // These tests will be executed locally using Robolectric.
+ // Connected device or emulator tests can be run by setting the
+ // `ANDROID_SERIAL` environment variable to an `adb devices`
+ // ID in the scheme's Run settings.
+ //
+ // Note that it isn't currently possible to filter the tests to run.
+ try await runGradleTests()
+ }
+}
+#endif
+
+/// True when running in a transpiled Java runtime environment
+let isJava = ProcessInfo.processInfo.environment["java.io.tmpdir"] != nil
+/// True when running within an Android environment (either an emulator or device)
+let isAndroid = isJava && ProcessInfo.processInfo.environment["ANDROID_ROOT"] != nil
+/// True is the transpiled code is currently running in the local Robolectric test environment
+let isRobolectric = isJava && !isAndroid
+/// True if the system's `Int` type is 32-bit.
+let is32BitInteger = Int64(Int.max) == Int64(Int32.max)