diff --git a/.gitignore b/.gitignore
index a927c61..bd69837 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,5 @@
/*.xcodeproj
xcuserdata/
AGENTS.md
+Demo.swiftpm/.build
+.claude
diff --git a/Demo.swiftpm/.swiftpm/configuration/AppInfo.json b/Demo.swiftpm/.swiftpm/configuration/AppInfo.json
new file mode 100644
index 0000000..289ade8
--- /dev/null
+++ b/Demo.swiftpm/.swiftpm/configuration/AppInfo.json
@@ -0,0 +1,4 @@
+{
+ "bundleIdentifierPrefix": "org.bitcoinui",
+ "displayName": "BitcoinUI Demo"
+}
diff --git a/Demo.swiftpm/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/Demo.swiftpm/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/Demo.swiftpm/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/Demo.swiftpm/Demo.xcodeproj/project.pbxproj b/Demo.swiftpm/Demo.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..b61c86c
--- /dev/null
+++ b/Demo.swiftpm/Demo.xcodeproj/project.pbxproj
@@ -0,0 +1,365 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 77;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 35C47B2B2E19EFD8F23EF916 /* BitcoinUI in Frameworks */ = {isa = PBXBuildFile; productRef = 6B11C3BFDEC3F38F6907EA34 /* BitcoinUI */; };
+ 3DC2973F6A461014810F7551 /* SeedPhrasesDemoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C4991E001B4261AC706DB2E /* SeedPhrasesDemoView.swift */; };
+ 3F9F15AC7DBBED6446811312 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6376510D5BA52EBE4C0667E6 /* ContentView.swift */; };
+ 6675346D138D75E5B5E27A86 /* AddressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD999E918A6CEAE408D93B08 /* AddressView.swift */; };
+ 86CB226A25B435ACACED4AA4 /* TextStylesDemoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34F1DA4859C42192A67E246 /* TextStylesDemoView.swift */; };
+ 87E4587B2DE439C6339E9ECC /* DemoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DF36C68B50A12726B1B9B3D /* DemoApp.swift */; };
+ ADC1660ECBBF6A93FD3410CD /* ButtonsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13435783C64ADBBEB45E94F5 /* ButtonsView.swift */; };
+ C91C03C35ADD039051A92075 /* ComponentSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5726AAFF07141D681B449458 /* ComponentSection.swift */; };
+ E23FC183965794AB6C809F48 /* ColorsDemoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11933D15AFE190BCA80E253F /* ColorsDemoView.swift */; };
+ EFBC04A282D1E523BAAB5ACE /* ImagesDemoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B47143E8CC564DCC5F15A293 /* ImagesDemoView.swift */; };
+ FA6F016DE424AEFA2599C42D /* QRCodeDemoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64E307BC3F87902D5663118 /* QRCodeDemoView.swift */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 11933D15AFE190BCA80E253F /* ColorsDemoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorsDemoView.swift; sourceTree = ""; };
+ 13435783C64ADBBEB45E94F5 /* ButtonsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonsView.swift; sourceTree = ""; };
+ 20F4AF675AD6F7A10AB46782 /* BitcoinUI */ = {isa = PBXFileReference; lastKnownFileType = folder; name = BitcoinUI; path = ..; sourceTree = SOURCE_ROOT; };
+ 3C4991E001B4261AC706DB2E /* SeedPhrasesDemoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedPhrasesDemoView.swift; sourceTree = ""; };
+ 5726AAFF07141D681B449458 /* ComponentSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComponentSection.swift; sourceTree = ""; };
+ 6376510D5BA52EBE4C0667E6 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
+ 6DF36C68B50A12726B1B9B3D /* DemoApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoApp.swift; sourceTree = ""; };
+ B47143E8CC564DCC5F15A293 /* ImagesDemoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagesDemoView.swift; sourceTree = ""; };
+ B64E307BC3F87902D5663118 /* QRCodeDemoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeDemoView.swift; sourceTree = ""; };
+ BD999E918A6CEAE408D93B08 /* AddressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressView.swift; sourceTree = ""; };
+ E158E1D8DDD5F3DC89B171A3 /* Demo.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ F34F1DA4859C42192A67E246 /* TextStylesDemoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextStylesDemoView.swift; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ F85CE95CC7B9E76D63880B75 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 35C47B2B2E19EFD8F23EF916 /* BitcoinUI in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 18C0F436F671F250CAEFD15D /* Packages */ = {
+ isa = PBXGroup;
+ children = (
+ 20F4AF675AD6F7A10AB46782 /* BitcoinUI */,
+ );
+ name = Packages;
+ sourceTree = "";
+ };
+ 20D12AFFC5038BCC5E0ECDCF /* Components */ = {
+ isa = PBXGroup;
+ children = (
+ BD999E918A6CEAE408D93B08 /* AddressView.swift */,
+ 13435783C64ADBBEB45E94F5 /* ButtonsView.swift */,
+ 11933D15AFE190BCA80E253F /* ColorsDemoView.swift */,
+ 5726AAFF07141D681B449458 /* ComponentSection.swift */,
+ B47143E8CC564DCC5F15A293 /* ImagesDemoView.swift */,
+ B64E307BC3F87902D5663118 /* QRCodeDemoView.swift */,
+ 3C4991E001B4261AC706DB2E /* SeedPhrasesDemoView.swift */,
+ F34F1DA4859C42192A67E246 /* TextStylesDemoView.swift */,
+ );
+ path = Components;
+ sourceTree = "";
+ };
+ 89EED0D913153940931D2FE8 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ E158E1D8DDD5F3DC89B171A3 /* Demo.app */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ ACE36DE3FB2F24706FD66339 /* Sources */ = {
+ isa = PBXGroup;
+ children = (
+ 6376510D5BA52EBE4C0667E6 /* ContentView.swift */,
+ 6DF36C68B50A12726B1B9B3D /* DemoApp.swift */,
+ 20D12AFFC5038BCC5E0ECDCF /* Components */,
+ );
+ path = Sources;
+ sourceTree = "";
+ };
+ E5BB6DC2E977B912CC1AF702 = {
+ isa = PBXGroup;
+ children = (
+ 18C0F436F671F250CAEFD15D /* Packages */,
+ ACE36DE3FB2F24706FD66339 /* Sources */,
+ 89EED0D913153940931D2FE8 /* Products */,
+ );
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 22478BC664898A9B8DD4D258 /* Demo */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 67F59FA59F734371A2570797 /* Build configuration list for PBXNativeTarget "Demo" */;
+ buildPhases = (
+ A1DCA12CEE65932D9EECDBA4 /* Sources */,
+ F85CE95CC7B9E76D63880B75 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Demo;
+ packageProductDependencies = (
+ 6B11C3BFDEC3F38F6907EA34 /* BitcoinUI */,
+ );
+ productName = Demo;
+ productReference = E158E1D8DDD5F3DC89B171A3 /* Demo.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 5533C1BE5094A04FCE853B33 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ BuildIndependentTargetsInParallel = YES;
+ LastUpgradeCheck = 1600;
+ };
+ buildConfigurationList = 388F02421550F69BF7947B85 /* Build configuration list for PBXProject "Demo" */;
+ compatibilityVersion = "Xcode 14.0";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ Base,
+ en,
+ );
+ mainGroup = E5BB6DC2E977B912CC1AF702;
+ minimizedProjectReferenceProxies = 1;
+ packageReferences = (
+ D282B09AE8FB5CC0A51A1597 /* XCLocalSwiftPackageReference "..//" */,
+ );
+ preferredProjectObjectVersion = 77;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 22478BC664898A9B8DD4D258 /* Demo */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ A1DCA12CEE65932D9EECDBA4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 6675346D138D75E5B5E27A86 /* AddressView.swift in Sources */,
+ ADC1660ECBBF6A93FD3410CD /* ButtonsView.swift in Sources */,
+ E23FC183965794AB6C809F48 /* ColorsDemoView.swift in Sources */,
+ C91C03C35ADD039051A92075 /* ComponentSection.swift in Sources */,
+ 3F9F15AC7DBBED6446811312 /* ContentView.swift in Sources */,
+ 87E4587B2DE439C6339E9ECC /* DemoApp.swift in Sources */,
+ EFBC04A282D1E523BAAB5ACE /* ImagesDemoView.swift in Sources */,
+ FA6F016DE424AEFA2599C42D /* QRCodeDemoView.swift in Sources */,
+ 3DC2973F6A461014810F7551 /* SeedPhrasesDemoView.swift in Sources */,
+ 86CB226A25B435ACACED4AA4 /* TextStylesDemoView.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 1E0D38BE0A23451ACF3D4625 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ INFOPLIST_FILE = Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = org.bitcoinui.demo;
+ SDKROOT = iphoneos;
+ SWIFT_VERSION = 5;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Release;
+ };
+ 431C1D0126FDE809DBCC1F6E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ 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;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ 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;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ MTL_FAST_MATH = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = iphoneos;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
+ SWIFT_VERSION = 5.0;
+ };
+ name = Release;
+ };
+ 553BCFF4DF4A314DE3D572F3 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ INFOPLIST_FILE = Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = org.bitcoinui.demo;
+ SDKROOT = iphoneos;
+ SWIFT_VERSION = 5;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 76F22F9F8EFF9E558750A9FE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ 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;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "DEBUG=1",
+ );
+ 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;
+ IPHONEOS_DEPLOYMENT_TARGET = 16.0;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = iphoneos;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ };
+ name = Debug;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 388F02421550F69BF7947B85 /* Build configuration list for PBXProject "Demo" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 76F22F9F8EFF9E558750A9FE /* Debug */,
+ 431C1D0126FDE809DBCC1F6E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Debug;
+ };
+ 67F59FA59F734371A2570797 /* Build configuration list for PBXNativeTarget "Demo" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 553BCFF4DF4A314DE3D572F3 /* Debug */,
+ 1E0D38BE0A23451ACF3D4625 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Debug;
+ };
+/* End XCConfigurationList section */
+
+/* Begin XCLocalSwiftPackageReference section */
+ D282B09AE8FB5CC0A51A1597 /* XCLocalSwiftPackageReference "..//" */ = {
+ isa = XCLocalSwiftPackageReference;
+ relativePath = "..//";
+ };
+/* End XCLocalSwiftPackageReference section */
+
+/* Begin XCSwiftPackageProductDependency section */
+ 6B11C3BFDEC3F38F6907EA34 /* BitcoinUI */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = BitcoinUI;
+ };
+/* End XCSwiftPackageProductDependency section */
+ };
+ rootObject = 5533C1BE5094A04FCE853B33 /* Project object */;
+}
diff --git a/Demo.swiftpm/Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Demo.swiftpm/Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/Demo.swiftpm/Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/Demo.swiftpm/Info.plist b/Demo.swiftpm/Info.plist
new file mode 100644
index 0000000..b2b42b1
--- /dev/null
+++ b/Demo.swiftpm/Info.plist
@@ -0,0 +1,22 @@
+
+
+
+
+ CFBundleIdentifier
+ org.bitcoinui.demo
+ CFBundleName
+ Demo
+ CFBundleDisplayName
+ BitcoinUI Demo
+ CFBundleVersion
+ 1
+ CFBundleShortVersionString
+ 1.0
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundlePackageType
+ APPL
+ UILaunchScreen
+
+
+
diff --git a/Demo.swiftpm/Package.swift b/Demo.swiftpm/Package.swift
new file mode 100644
index 0000000..d5f8ef4
--- /dev/null
+++ b/Demo.swiftpm/Package.swift
@@ -0,0 +1,22 @@
+// swift-tools-version: 5.10
+import PackageDescription
+
+let package = Package(
+ name: "Demo",
+ platforms: [
+ .iOS(.v16),
+ .macOS(.v13)
+ ],
+ dependencies: [
+ .package(name: "BitcoinUI", path: "../")
+ ],
+ targets: [
+ .executableTarget(
+ name: "Demo",
+ dependencies: [
+ .product(name: "BitcoinUI", package: "BitcoinUI")
+ ],
+ path: "Sources"
+ )
+ ]
+)
diff --git a/Demo.swiftpm/Sources/Components/AddressView.swift b/Demo.swiftpm/Sources/Components/AddressView.swift
new file mode 100644
index 0000000..365bd2a
--- /dev/null
+++ b/Demo.swiftpm/Sources/Components/AddressView.swift
@@ -0,0 +1,33 @@
+import SwiftUI
+import BitcoinUI
+
+struct AddressView: View {
+ let address = "tb1pw6y0vtmsn46epvz0j8ddc46ketmp28t82p22hcrrkch3a0jhu40qe267dl"
+
+ var body: some View {
+ ScrollView {
+ VStack(alignment: .leading, spacing: 24) {
+
+ ComponentSection("3 Columns (default)") {
+ AddressFormattedView(address: address)
+ }
+
+ ComponentSection("4 Columns") {
+ AddressFormattedView(address: address, columns: 4)
+ }
+
+ ComponentSection("2 Columns") {
+ AddressFormattedView(address: address, columns: 2)
+ }
+ }
+ .padding()
+ }
+ .navigationTitle("Address")
+ }
+}
+
+#Preview {
+ NavigationStack {
+ AddressView()
+ }
+}
diff --git a/Demo.swiftpm/Sources/Components/ButtonsView.swift b/Demo.swiftpm/Sources/Components/ButtonsView.swift
new file mode 100644
index 0000000..a7ae75c
--- /dev/null
+++ b/Demo.swiftpm/Sources/Components/ButtonsView.swift
@@ -0,0 +1,47 @@
+import SwiftUI
+import BitcoinUI
+
+struct ButtonsView: View {
+ var body: some View {
+ ScrollView {
+ VStack(alignment: .leading, spacing: 24) {
+
+ ComponentSection("Filled") {
+ Button("BitcoinFilled") {}
+ .buttonStyle(BitcoinFilled())
+ Button("BitcoinFilled (Capsule)") {}
+ .buttonStyle(BitcoinFilled(isCapsule: true))
+ Button("Disabled") {}
+ .buttonStyle(BitcoinFilled())
+ .disabled(true)
+ }
+
+ ComponentSection("Outlined") {
+ Button("BitcoinOutlined") {}
+ .buttonStyle(BitcoinOutlined())
+ Button("BitcoinOutlined (Capsule)") {}
+ .buttonStyle(BitcoinOutlined(isCapsule: true))
+ Button("Disabled") {}
+ .buttonStyle(BitcoinOutlined())
+ .disabled(true)
+ }
+
+ ComponentSection("Plain") {
+ Button("BitcoinPlain") {}
+ .buttonStyle(BitcoinPlain())
+ Button("Disabled") {}
+ .buttonStyle(BitcoinPlain())
+ .disabled(true)
+ }
+ }
+ .padding()
+ }
+ .navigationTitle("Buttons")
+ }
+}
+
+#Preview {
+ NavigationStack {
+ ButtonsView()
+ }
+}
diff --git a/Demo.swiftpm/Sources/Components/ColorsDemoView.swift b/Demo.swiftpm/Sources/Components/ColorsDemoView.swift
new file mode 100644
index 0000000..5b16762
--- /dev/null
+++ b/Demo.swiftpm/Sources/Components/ColorsDemoView.swift
@@ -0,0 +1,70 @@
+import SwiftUI
+import BitcoinUI
+
+struct ColorsDemoView: View {
+ var body: some View {
+ ScrollView {
+ VStack(alignment: .leading, spacing: 24) {
+
+ ComponentSection("Brand") {
+ colorRow([
+ ("Orange", .bitcoinOrange),
+ ("Red", .bitcoinRed),
+ ("Green", .bitcoinGreen),
+ ("Blue", .bitcoinBlue),
+ ("Purple", .bitcoinPurple),
+ ])
+ }
+
+ ComponentSection("Neutral") {
+ colorRow([
+ ("White", .bitcoinWhite),
+ ("N1", .bitcoinNeutral1),
+ ("N2", .bitcoinNeutral2),
+ ("N3", .bitcoinNeutral3),
+ ("N4", .bitcoinNeutral4),
+ ])
+ colorRow([
+ ("N5", .bitcoinNeutral5),
+ ("N6", .bitcoinNeutral6),
+ ("N7", .bitcoinNeutral7),
+ ("N8", .bitcoinNeutral8),
+ ("Black", .bitcoinBlack),
+ ])
+ }
+
+ ComponentSection("Special") {
+ colorRow([
+ ("MyMattress", .bitcoinMyMattress),
+ ])
+ }
+ }
+ .padding()
+ }
+ .navigationTitle("Colors")
+ }
+
+ private func colorRow(_ items: [(String, Color)]) -> some View {
+ HStack(spacing: 12) {
+ ForEach(items, id: \.0) { label, color in
+ VStack(spacing: 4) {
+ Circle()
+ .fill(color)
+ .frame(width: 44, height: 44)
+ .overlay(Circle().stroke(Color.secondary.opacity(0.2), lineWidth: 1))
+ Text(label)
+ .font(.caption2)
+ .foregroundStyle(.secondary)
+ .multilineTextAlignment(.center)
+ }
+ .frame(maxWidth: .infinity)
+ }
+ }
+ }
+}
+
+#Preview {
+ NavigationStack {
+ ColorsDemoView()
+ }
+}
diff --git a/Demo.swiftpm/Sources/Components/ComponentSection.swift b/Demo.swiftpm/Sources/Components/ComponentSection.swift
new file mode 100644
index 0000000..fc27178
--- /dev/null
+++ b/Demo.swiftpm/Sources/Components/ComponentSection.swift
@@ -0,0 +1,20 @@
+import SwiftUI
+
+struct ComponentSection: View {
+ let title: String
+ let content: Content
+
+ init(_ title: String, @ViewBuilder content: () -> Content) {
+ self.title = title
+ self.content = content()
+ }
+
+ var body: some View {
+ VStack(alignment: .leading, spacing: 12) {
+ Text(title)
+ .font(.headline)
+ .foregroundStyle(.secondary)
+ content
+ }
+ }
+}
diff --git a/Demo.swiftpm/Sources/Components/ImagesDemoView.swift b/Demo.swiftpm/Sources/Components/ImagesDemoView.swift
new file mode 100644
index 0000000..b80bac5
--- /dev/null
+++ b/Demo.swiftpm/Sources/Components/ImagesDemoView.swift
@@ -0,0 +1,48 @@
+import SwiftUI
+import BitcoinUI
+
+struct ImagesDemoView: View {
+ private let icons = [
+ "bitbox", "blockstream-jade", "cobo-vault", "coldcard",
+ "foundation-passport", "generic-hardware-wallet", "keepkey",
+ "ledger-nano", "opendime", "satoshi-v2", "seedplate",
+ "trezor-model-t", "trezor-one",
+ ]
+
+ private let columns = [
+ GridItem(.adaptive(minimum: 80), spacing: 16),
+ ]
+
+ var body: some View {
+ ScrollView {
+ VStack(alignment: .leading, spacing: 24) {
+ ComponentSection("Hardware Wallets") {
+ LazyVGrid(columns: columns, spacing: 16) {
+ ForEach(icons, id: \.self) { name in
+ VStack(spacing: 6) {
+ BitcoinImage(named: name)
+ .resizable()
+ .aspectRatio(contentMode: .fit)
+ .frame(width: 48, height: 48)
+ Text(name)
+ .font(.caption2)
+ .foregroundStyle(.secondary)
+ .multilineTextAlignment(.center)
+ .lineLimit(2)
+ }
+ .frame(maxWidth: .infinity)
+ }
+ }
+ }
+ }
+ .padding()
+ }
+ .navigationTitle("Images")
+ }
+}
+
+#Preview {
+ NavigationStack {
+ ImagesDemoView()
+ }
+}
diff --git a/Demo.swiftpm/Sources/Components/QRCodeDemoView.swift b/Demo.swiftpm/Sources/Components/QRCodeDemoView.swift
new file mode 100644
index 0000000..0244cdf
--- /dev/null
+++ b/Demo.swiftpm/Sources/Components/QRCodeDemoView.swift
@@ -0,0 +1,62 @@
+import SwiftUI
+import BitcoinUI
+
+struct QRCodeDemoView: View {
+ private let address = "tb1q05g8l05sgqsnzuc2mrmq0chlq7ktxtce4js5dj"
+ private let invoice = "lntbs1234560u1pnf4qfudq4f4hkuerp0ys9wctvd3jhgnp4q235egp5u2nec2ddcza8eykpd3gl3g0es0m7gncarzeuwuw6xhpqq"
+
+ var body: some View {
+ ScrollView {
+ VStack(alignment: .leading, spacing: 24) {
+
+ ComponentSection("Bitcoin") {
+ QRCodeView(qrCodeType: .bitcoin(address))
+ .frame(maxWidth: 240)
+ .frame(maxWidth: .infinity)
+ }
+
+ ComponentSection("Bitcoin (Rounded)") {
+ QRCodeView(qrCodeType: .bitcoin(address), cornerRadius: 20)
+ .frame(maxWidth: 240)
+ .frame(maxWidth: .infinity)
+ }
+
+ ComponentSection("Lightning") {
+ QRCodeView(qrCodeType: .lightning(invoice))
+ .frame(maxWidth: 240)
+ .frame(maxWidth: .infinity)
+ }
+
+ ComponentSection("BIP21") {
+ QRCodeView(
+ qrCodeType: .bip21(
+ "bitcoin:\(address)?amount=0.001&label=Demo"
+ ),
+ cornerRadius: 12
+ )
+ .frame(maxWidth: 240)
+ .frame(maxWidth: .infinity)
+ }
+
+ ComponentSection("Custom Colors") {
+ QRCodeView(
+ qrCodeType: .bitcoin(address),
+ cornerRadius: 16,
+ foregroundColor: .bitcoinOrange,
+ backgroundColor: .black
+ )
+ .frame(maxWidth: 240)
+ .frame(maxWidth: .infinity)
+ }
+ }
+ .padding()
+ }
+ .navigationTitle("QR Code")
+ }
+}
+
+#Preview {
+ NavigationStack {
+ QRCodeDemoView()
+ }
+}
diff --git a/Demo.swiftpm/Sources/Components/SeedPhrasesDemoView.swift b/Demo.swiftpm/Sources/Components/SeedPhrasesDemoView.swift
new file mode 100644
index 0000000..25810ac
--- /dev/null
+++ b/Demo.swiftpm/Sources/Components/SeedPhrasesDemoView.swift
@@ -0,0 +1,56 @@
+import SwiftUI
+import BitcoinUI
+
+struct SeedPhrasesDemoView: View {
+ private let words12 = [
+ "paddle", "train", "boil", "catch", "trim", "plastic",
+ "wolf", "hazard", "govern", "oval", "drama", "gun",
+ ]
+ private let words24 = [
+ "paddle", "train", "boil", "catch", "trim", "plastic",
+ "wolf", "hazard", "govern", "oval", "drama", "gun",
+ "swim", "accuse", "degree", "teach", "game", "penalty",
+ "social", "hard", "crush", "media", "radar", "click",
+ ]
+
+ var body: some View {
+ ScrollView {
+ VStack(alignment: .leading, spacing: 24) {
+
+ ComponentSection("12 Words (2 per row)") {
+ SeedPhraseView(words: words12, preferredWordsPerRow: 2)
+ }
+
+ ComponentSection("12 Words (3 per row)") {
+ SeedPhraseView(words: words12, preferredWordsPerRow: 3)
+ }
+
+ ComponentSection("24 Words with Paging") {
+ SeedPhraseView(
+ words: words24,
+ preferredWordsPerRow: 2,
+ usePaging: true,
+ wordsPerPage: 6
+ )
+ .frame(height: 200)
+ }
+
+ ComponentSection("Privacy Sensitive") {
+ SeedPhraseView(
+ words: words12,
+ preferredWordsPerRow: 2,
+ privacySensitive: true
+ )
+ }
+ }
+ .padding()
+ }
+ .navigationTitle("Seed Phrase")
+ }
+}
+
+#Preview {
+ NavigationStack {
+ SeedPhrasesDemoView()
+ }
+}
diff --git a/Demo.swiftpm/Sources/Components/TextStylesDemoView.swift b/Demo.swiftpm/Sources/Components/TextStylesDemoView.swift
new file mode 100644
index 0000000..b12c241
--- /dev/null
+++ b/Demo.swiftpm/Sources/Components/TextStylesDemoView.swift
@@ -0,0 +1,39 @@
+import SwiftUI
+import BitcoinUI
+
+struct TextStylesDemoView: View {
+ var body: some View {
+ ScrollView {
+ VStack(alignment: .leading, spacing: 24) {
+
+ ComponentSection("Titles") {
+ VStack(alignment: .leading, spacing: 8) {
+ Text("BitcoinTitle1").textStyle(BitcoinTitle1())
+ Text("BitcoinTitle2").textStyle(BitcoinTitle2())
+ Text("BitcoinTitle3").textStyle(BitcoinTitle3())
+ Text("BitcoinTitle4").textStyle(BitcoinTitle4())
+ Text("BitcoinTitle5").textStyle(BitcoinTitle5())
+ }
+ }
+
+ ComponentSection("Body") {
+ VStack(alignment: .leading, spacing: 8) {
+ Text("BitcoinBody1").textStyle(BitcoinBody1())
+ Text("BitcoinBody2").textStyle(BitcoinBody2())
+ Text("BitcoinBody3").textStyle(BitcoinBody3())
+ Text("BitcoinBody4").textStyle(BitcoinBody4())
+ Text("BitcoinBody5").textStyle(BitcoinBody5())
+ }
+ }
+ }
+ .padding()
+ }
+ .navigationTitle("Text Styles")
+ }
+}
+
+#Preview {
+ NavigationStack {
+ TextStylesDemoView()
+ }
+}
diff --git a/Demo.swiftpm/Sources/ContentView.swift b/Demo.swiftpm/Sources/ContentView.swift
new file mode 100644
index 0000000..fb8f943
--- /dev/null
+++ b/Demo.swiftpm/Sources/ContentView.swift
@@ -0,0 +1,26 @@
+import SwiftUI
+
+struct ContentView: View {
+ var body: some View {
+ NavigationStack {
+ List {
+ Section("Components") {
+ NavigationLink("Buttons", destination: ButtonsView())
+ NavigationLink("Address", destination: AddressView())
+ NavigationLink("QR Code", destination: QRCodeDemoView())
+ NavigationLink("Seed Phrase", destination: SeedPhrasesDemoView())
+ }
+ Section("Foundations") {
+ NavigationLink("Text Styles", destination: TextStylesDemoView())
+ NavigationLink("Colors", destination: ColorsDemoView())
+ NavigationLink("Images", destination: ImagesDemoView())
+ }
+ }
+ .navigationTitle("BitcoinUI")
+ }
+ }
+}
+
+#Preview {
+ ContentView()
+}
diff --git a/Demo.swiftpm/Sources/DemoApp.swift b/Demo.swiftpm/Sources/DemoApp.swift
new file mode 100644
index 0000000..470184c
--- /dev/null
+++ b/Demo.swiftpm/Sources/DemoApp.swift
@@ -0,0 +1,10 @@
+import SwiftUI
+
+@main
+struct DemoApp: App {
+ var body: some Scene {
+ WindowGroup {
+ ContentView()
+ }
+ }
+}
diff --git a/Demo.swiftpm/project.yml b/Demo.swiftpm/project.yml
new file mode 100644
index 0000000..8a187f3
--- /dev/null
+++ b/Demo.swiftpm/project.yml
@@ -0,0 +1,22 @@
+name: Demo
+options:
+ bundleIdPrefix: org.bitcoinui
+ deploymentTarget:
+ iOS: "16.0"
+ xcodeVersion: "16"
+packages:
+ BitcoinUI:
+ path: ../
+targets:
+ Demo:
+ type: application
+ platform: iOS
+ sources: Sources
+ settings:
+ base:
+ SWIFT_VERSION: "5"
+ PRODUCT_BUNDLE_IDENTIFIER: org.bitcoinui.demo
+ INFOPLIST_FILE: Info.plist
+ dependencies:
+ - package: BitcoinUI
+ product: BitcoinUI
diff --git a/README.md b/README.md
index 4132f8b..4630791 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,7 @@
Bitcoin UI components and review for native iOS apps.
[Swift Package](#swift-package)
+[Demo App](#demo-app)
[Design Review](#design-review)
## Swift Package
@@ -28,6 +29,12 @@ Text("Bitcoin Orange")
.multilineTextAlignment(.center)
```
+## Demo App
+
+Open `Demo.swiftpm/Demo.xcodeproj` in Xcode, select an iOS Simulator, and press Run (⌘R).
+
+






+
## Design Review
Install `bitcoinui` in your AI coding tool.
diff --git a/SnapshotsDemo/01.png b/SnapshotsDemo/01.png
new file mode 100644
index 0000000..f91d07c
Binary files /dev/null and b/SnapshotsDemo/01.png differ
diff --git a/SnapshotsDemo/02.png b/SnapshotsDemo/02.png
new file mode 100644
index 0000000..5bf74d9
Binary files /dev/null and b/SnapshotsDemo/02.png differ
diff --git a/SnapshotsDemo/03.png b/SnapshotsDemo/03.png
new file mode 100644
index 0000000..673e4fd
Binary files /dev/null and b/SnapshotsDemo/03.png differ
diff --git a/SnapshotsDemo/04.png b/SnapshotsDemo/04.png
new file mode 100644
index 0000000..ee8cc7f
Binary files /dev/null and b/SnapshotsDemo/04.png differ
diff --git a/SnapshotsDemo/05.png b/SnapshotsDemo/05.png
new file mode 100644
index 0000000..d3e4c77
Binary files /dev/null and b/SnapshotsDemo/05.png differ
diff --git a/SnapshotsDemo/06.png b/SnapshotsDemo/06.png
new file mode 100644
index 0000000..d2ea376
Binary files /dev/null and b/SnapshotsDemo/06.png differ
diff --git a/SnapshotsDemo/07.png b/SnapshotsDemo/07.png
new file mode 100644
index 0000000..19cd7bb
Binary files /dev/null and b/SnapshotsDemo/07.png differ
diff --git a/SnapshotsDemo/08.png b/SnapshotsDemo/08.png
new file mode 100644
index 0000000..da4dda1
Binary files /dev/null and b/SnapshotsDemo/08.png differ