Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 67 additions & 62 deletions Bitkit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,44 @@
);
target = 4A319B4E2E8F24F2002B9AC9 /* BitkitWidgetExtension */;
};
4A319B672E8F24F5002B9AC9 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Components/Widgets/BlocksWidgetContent.swift,
Components/Widgets/FactsWidgetContent.swift,
Components/Widgets/NewsWidgetContent.swift,
Components/Widgets/PriceWidgetContent.swift,
Components/Widgets/WeatherWidgetContent.swift,
Components/Widgets/WidgetPalette.swift,
Constants/WidgetEnv.swift,
"Fonts/InterTight-Black.ttf",
"Fonts/InterTight-Bold.ttf",
"Fonts/InterTight-ExtraBold.ttf",
"Fonts/InterTight-Medium.ttf",
"Fonts/InterTight-Regular.ttf",
"Fonts/InterTight-SemiBold.ttf",
Models/BitcoinFacts.swift,
Models/BlocksWidgetData.swift,
Models/BlocksWidgetFields.swift,
Models/BlocksWidgetOptions.swift,
Models/NewsWidgetData.swift,
Models/NewsWidgetOptions.swift,
Models/PriceWidgetData.swift,
Models/PriceWidgetOptions.swift,
Models/WeatherWidgetData.swift,
Models/WeatherWidgetOptions.swift,
Services/Widgets/BlocksHomeScreenWidgetOptionsStore.swift,
Services/Widgets/MempoolWeatherAPI.swift,
Services/Widgets/NewsHomeScreenWidgetOptionsStore.swift,
Services/Widgets/PriceHomeScreenWidgetOptionsStore.swift,
Services/Widgets/WeatherHomeScreenWidgetOptionsStore.swift,
Styles/Colors.swift,
Styles/Fonts.swift,
Styles/TextStyle.swift,
Utilities/LocalizeHelpers.swift,
);
target = 4A319B4E2E8F24F2002B9AC9 /* BitkitWidgetExtension */;
};
96A44F3D2CEF5EA700FBACFF /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Expand All @@ -123,8 +161,8 @@
Extensions/HexBytes.swift,
"Extensions/LDKNode+AddressType.swift",
Extensions/PaymentDetails.swift,
Models/BlocktankNotificationType.swift,
Models/BlocksWidgetOptions.swift,
Models/BlocktankNotificationType.swift,
Models/LnPeer.swift,
Models/PubkyPublicKeyFormat.swift,
Models/Toast.swift,
Expand Down Expand Up @@ -180,39 +218,6 @@
);
target = 961058DB2C355B5500E1F1D8 /* BitkitNotification */;
};
4A319B672E8F24F5002B9AC9 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Fonts/InterTight-Black.ttf,
Fonts/InterTight-Bold.ttf,
Fonts/InterTight-ExtraBold.ttf,
Fonts/InterTight-Medium.ttf,
Fonts/InterTight-Regular.ttf,
Constants/WidgetEnv.swift,
Fonts/InterTight-SemiBold.ttf,
Components/Widgets/WeatherWidgetContent.swift,
Models/BlocksWidgetData.swift,
Models/BlocksWidgetFields.swift,
Models/BlocksWidgetOptions.swift,
Models/BitcoinFacts.swift,
Models/NewsWidgetData.swift,
Models/NewsWidgetOptions.swift,
Models/PriceWidgetData.swift,
Models/PriceWidgetOptions.swift,
Models/WeatherWidgetData.swift,
Models/WeatherWidgetOptions.swift,
Services/Widgets/BlocksHomeScreenWidgetOptionsStore.swift,
Services/Widgets/MempoolWeatherAPI.swift,
Services/Widgets/NewsHomeScreenWidgetOptionsStore.swift,
Services/Widgets/PriceHomeScreenWidgetOptionsStore.swift,
Services/Widgets/WeatherHomeScreenWidgetOptionsStore.swift,
Styles/Colors.swift,
Styles/Fonts.swift,
Styles/TextStyle.swift,
Utilities/LocalizeHelpers.swift,
);
target = 4A319B4E2E8F24F2002B9AC9 /* BitkitWidgetExtension */;
};
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */

/* Begin PBXFileSystemSynchronizedRootGroup section */
Expand Down Expand Up @@ -554,31 +559,6 @@
};
/* End PBXResourcesBuildPhase section */

/* Begin PBXVariantGroup section */
4A319B712E8F2600002B9AC9 /* Localizable.strings */ = {
isa = PBXVariantGroup;
children = (
4A319B722E8F2600002B9AC9 /* ar */,
4A319B732E8F2600002B9AC9 /* ca */,
4A319B742E8F2600002B9AC9 /* cs */,
4A319B752E8F2600002B9AC9 /* de */,
4A319B762E8F2600002B9AC9 /* el */,
4A319B772E8F2600002B9AC9 /* en */,
4A319B782E8F2600002B9AC9 /* es-419 */,
4A319B792E8F2600002B9AC9 /* es */,
4A319B7A2E8F2600002B9AC9 /* fr */,
4A319B7B2E8F2600002B9AC9 /* it */,
4A319B7C2E8F2600002B9AC9 /* nl */,
4A319B7D2E8F2600002B9AC9 /* pl */,
4A319B7E2E8F2600002B9AC9 /* pt-BR */,
4A319B7F2E8F2600002B9AC9 /* pt */,
4A319B802E8F2600002B9AC9 /* ru */,
);
name = Localizable.strings;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */

/* Begin PBXShellScriptBuildPhase section */
96EMBED0012026012000FRAME /* Remove Static Framework Stubs */ = {
isa = PBXShellScriptBuildPhase;
Expand Down Expand Up @@ -663,6 +643,31 @@
};
/* End PBXTargetDependency section */

/* Begin PBXVariantGroup section */
4A319B712E8F2600002B9AC9 /* Localizable.strings */ = {
isa = PBXVariantGroup;
children = (
4A319B722E8F2600002B9AC9 /* ar */,
4A319B732E8F2600002B9AC9 /* ca */,
4A319B742E8F2600002B9AC9 /* cs */,
4A319B752E8F2600002B9AC9 /* de */,
4A319B762E8F2600002B9AC9 /* el */,
4A319B772E8F2600002B9AC9 /* en */,
4A319B782E8F2600002B9AC9 /* es-419 */,
4A319B792E8F2600002B9AC9 /* es */,
4A319B7A2E8F2600002B9AC9 /* fr */,
4A319B7B2E8F2600002B9AC9 /* it */,
4A319B7C2E8F2600002B9AC9 /* nl */,
4A319B7D2E8F2600002B9AC9 /* pl */,
4A319B7E2E8F2600002B9AC9 /* pt-BR */,
4A319B7F2E8F2600002B9AC9 /* pt */,
4A319B802E8F2600002B9AC9 /* ru */,
);
name = Localizable.strings;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */

/* Begin XCBuildConfiguration section */
4A319B632E8F24F4002B9AC9 /* Debug */ = {
isa = XCBuildConfiguration;
Expand All @@ -684,7 +689,7 @@
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.2.1;
PRODUCT_BUNDLE_IDENTIFIER = "to.bitkit.widget";
PRODUCT_BUNDLE_IDENTIFIER = to.bitkit.widget;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
Expand Down Expand Up @@ -717,7 +722,7 @@
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.2.1;
PRODUCT_BUNDLE_IDENTIFIER = "to.bitkit.widget";
PRODUCT_BUNDLE_IDENTIFIER = to.bitkit.widget;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
Expand Down Expand Up @@ -1143,7 +1148,7 @@
repositoryURL = "https://github.com/pubky/paykit-rs";
requirement = {
kind = exactVersion;
version = 0.1.0-rc5;
version = "0.1.0-rc5";
};
};
18D65DFE2EB9649F00252335 /* XCRemoteSwiftPackageReference "vss-rust-client-ffi" */ = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"images" : [
{
"filename" : "bitcoin.pdf",
"filename" : "bitcoin-symbol.pdf",
"idiom" : "universal"
}
],
Expand Down
69 changes: 1 addition & 68 deletions Bitkit/Components/Widgets/BlocksWidget.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,78 +42,11 @@ struct BlocksWidget: View {
WidgetContentBuilder.errorView(t("widgets__blocks__error"))
} else if let data = viewModel.blockData {
BlocksWidgetWideContent(data: data, options: options)
.frame(height: BlocksWidgetWideContent.inAppContentHeight)
}
}
}

// MARK: - Wide layout (in-app + 343-wide carousel page + .systemMedium / .systemLarge OS widget)

struct BlocksWidgetWideContent: View {
let data: CachedBlock
let options: BlocksWidgetOptions

var body: some View {
VStack(alignment: .leading, spacing: 12) {
ForEach(options.enabledFields, id: \.self) { field in
BlocksWidgetWideRow(field: field, value: field.value(from: data))
}
}
.frame(maxWidth: .infinity, alignment: .leading)
}
}

private struct BlocksWidgetWideRow: View {
let field: BlocksWidgetField
let value: String

var body: some View {
HStack(alignment: .center, spacing: 8) {
Image(field.iconName)
.resizable()
.renderingMode(.template)
.foregroundColor(.brandAccent)
.frame(width: 20, height: 20)

BodyMText(field.label, textColor: .white80)
.lineLimit(1)
.frame(maxWidth: .infinity, alignment: .leading)

BodyMSBText(value)
.lineLimit(1)
.truncationMode(.middle)
}
}
}

// MARK: - Compact layout (small carousel preview + 163×192 OS small widget)

struct BlocksWidgetCompactContent: View {
let data: CachedBlock
let options: BlocksWidgetOptions

var body: some View {
VStack(alignment: .leading, spacing: 16) {
ForEach(options.enabledFields, id: \.self) { field in
HStack(alignment: .center, spacing: 8) {
Image(field.iconName)
.resizable()
.renderingMode(.template)
.foregroundColor(.brandAccent)
.frame(width: 20, height: 20)

BodySSBText(field.value(from: data))
.lineLimit(1)
.truncationMode(.middle)
}
}
}
.padding(16)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
.background(Color.gray6)
.cornerRadius(16)
}
}

#Preview {
BlocksWidget()
.padding()
Expand Down
95 changes: 95 additions & 0 deletions Bitkit/Components/Widgets/BlocksWidgetContent.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import SwiftUI
import WidgetKit

// Shared Bitcoin Blocks widget content, reused by the in-app feed, the carousel preview, and the
// home-screen WidgetKit extension. Colors adapt to `widgetRenderingMode` via ``WidgetPalette``.

// MARK: - Wide layout (in-app + 343-wide carousel page + .systemMedium / .systemLarge OS widget)

struct BlocksWidgetWideContent: View {
static let inAppContentHeight: CGFloat = 124

let data: CachedBlock
let options: BlocksWidgetOptions

@Environment(\.widgetRenderingMode) private var renderingMode

var body: some View {
let palette = WidgetPalette(renderingMode: renderingMode)
VStack(alignment: .leading, spacing: 0) {
ForEach(Array(options.enabledFields.enumerated()), id: \.element) { index, field in
if index > 0 {
Spacer(minLength: 8)
}
BlocksWidgetWideRow(field: field, value: field.value(from: data), palette: palette)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
}
}

private struct BlocksWidgetWideRow: View {
let field: BlocksWidgetField
let value: String
let palette: WidgetPalette

var body: some View {
HStack(alignment: .center, spacing: 8) {
BlocksWidgetIcon(field: field, palette: palette)

BodyMText(field.label, textColor: palette.label)
.lineLimit(1)
.frame(maxWidth: .infinity, alignment: .leading)

BodyMSBText(value, textColor: palette.title)
.lineLimit(1)
.truncationMode(.middle)
.widgetAccentable()
}
}
}

// MARK: - Compact layout (small carousel preview + .systemSmall OS widget)

struct BlocksWidgetCompactContent: View {
let data: CachedBlock
let options: BlocksWidgetOptions

@Environment(\.widgetRenderingMode) private var renderingMode

var body: some View {
let palette = WidgetPalette(renderingMode: renderingMode)
VStack(alignment: .leading, spacing: 0) {
ForEach(Array(options.enabledFields.enumerated()), id: \.element) { index, field in
if index > 0 {
Spacer(minLength: 8)
}
HStack(alignment: .center, spacing: 8) {
BlocksWidgetIcon(field: field, palette: palette)

BodySSBText(field.value(from: data), textColor: palette.title)
.lineLimit(1)
.truncationMode(.middle)
.widgetAccentable()
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
}
}

// MARK: - Shared row icon

private struct BlocksWidgetIcon: View {
let field: BlocksWidgetField
let palette: WidgetPalette

var body: some View {
Image(field.iconName)
.resizable()
.renderingMode(.template)
.foregroundColor(palette.accent)
.frame(width: 20, height: 20)
.widgetAccentable()
}
}
Loading
Loading