New intermediate iOS build that trims some fat
This commit is contained in:
@@ -466,7 +466,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Ascently/Ascently.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 40;
|
||||
CURRENT_PROJECT_VERSION = 43;
|
||||
DEVELOPMENT_TEAM = 4BC9Y2LL4B;
|
||||
DRIVERKIT_DEPLOYMENT_TARGET = 24.6;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -491,7 +491,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.6;
|
||||
MARKETING_VERSION = 2.6.0;
|
||||
MARKETING_VERSION = 2.6.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@@ -518,7 +518,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Ascently/Ascently.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 40;
|
||||
CURRENT_PROJECT_VERSION = 43;
|
||||
DEVELOPMENT_TEAM = 4BC9Y2LL4B;
|
||||
DRIVERKIT_DEPLOYMENT_TARGET = 24.6;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -543,7 +543,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.6;
|
||||
MARKETING_VERSION = 2.6.0;
|
||||
MARKETING_VERSION = 2.6.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@@ -570,7 +570,7 @@
|
||||
DEVELOPMENT_TEAM = 4BC9Y2LL4B;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.atri.dad.OpenClimb.Watch.AscentlyTests;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently.AscentlyTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = NO;
|
||||
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||
@@ -591,7 +591,7 @@
|
||||
DEVELOPMENT_TEAM = 4BC9Y2LL4B;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.atri.dad.OpenClimb.Watch.AscentlyTests;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently.AscentlyTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = NO;
|
||||
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||
|
||||
Binary file not shown.
@@ -1,56 +0,0 @@
|
||||
{
|
||||
"images": [
|
||||
{
|
||||
"filename": "app_logo_256.png",
|
||||
"idiom": "universal",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"appearances": [
|
||||
{
|
||||
"appearance": "luminosity",
|
||||
"value": "dark"
|
||||
}
|
||||
],
|
||||
"filename": "app_logo_256_dark.png",
|
||||
"idiom": "universal",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"filename": "app_logo_256.png",
|
||||
"idiom": "universal",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"appearances": [
|
||||
{
|
||||
"appearance": "luminosity",
|
||||
"value": "dark"
|
||||
}
|
||||
],
|
||||
"filename": "app_logo_256_dark.png",
|
||||
"idiom": "universal",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"filename": "app_logo_256.png",
|
||||
"idiom": "universal",
|
||||
"scale": "3x"
|
||||
},
|
||||
{
|
||||
"appearances": [
|
||||
{
|
||||
"appearance": "luminosity",
|
||||
"value": "dark"
|
||||
}
|
||||
],
|
||||
"filename": "app_logo_256_dark.png",
|
||||
"idiom": "universal",
|
||||
"scale": "3x"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
"author": "xcode",
|
||||
"version": 1
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.1 KiB |
@@ -4,6 +4,8 @@
|
||||
{
|
||||
"layers" : [
|
||||
{
|
||||
"blend-mode" : "normal",
|
||||
"glass" : true,
|
||||
"image-name" : "AscetlyTriangle2.png",
|
||||
"name" : "AscetlyTriangle2",
|
||||
"position" : {
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
class AppIconHelper: ObservableObject {
|
||||
|
||||
static let shared = AppIconHelper()
|
||||
|
||||
@Published var isDarkMode: Bool = false
|
||||
|
||||
private init() {
|
||||
}
|
||||
|
||||
func updateDarkModeStatus(for colorScheme: ColorScheme) {
|
||||
isDarkMode = colorScheme == .dark
|
||||
}
|
||||
|
||||
func isInDarkMode(for colorScheme: ColorScheme) -> Bool {
|
||||
return colorScheme == .dark
|
||||
}
|
||||
|
||||
var supportsModernIconFeatures: Bool {
|
||||
if #available(iOS 17.0, *) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getRecommendedIconVariant(for colorScheme: ColorScheme) -> IconVariant {
|
||||
if colorScheme == .dark {
|
||||
return .dark
|
||||
}
|
||||
return .standard
|
||||
}
|
||||
|
||||
var supportsAlternateIcons: Bool {
|
||||
if #available(iOS 10.3, *) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
enum IconVariant {
|
||||
case standard
|
||||
case dark
|
||||
case tinted
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .standard:
|
||||
return "Standard"
|
||||
case .dark:
|
||||
return "Dark Mode"
|
||||
case .tinted:
|
||||
return "Tinted"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum AppIconError: Error, LocalizedError {
|
||||
case notSupported
|
||||
case invalidIconName
|
||||
case systemError(Error)
|
||||
|
||||
var errorDescription: String? {
|
||||
switch self {
|
||||
case .notSupported:
|
||||
return "Alternate icons are not supported on this device"
|
||||
case .invalidIconName:
|
||||
return "The specified icon name is invalid"
|
||||
case .systemError(let error):
|
||||
return "System error: \(error.localizedDescription)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct IconAppearanceModifier: ViewModifier {
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
@ObservedObject private var iconHelper = AppIconHelper.shared
|
||||
let onChange: (IconVariant) -> Void
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
.onChange(of: colorScheme) {
|
||||
iconHelper.updateDarkModeStatus(for: colorScheme)
|
||||
onChange(iconHelper.getRecommendedIconVariant(for: colorScheme))
|
||||
}
|
||||
.onAppear {
|
||||
iconHelper.updateDarkModeStatus(for: colorScheme)
|
||||
onChange(iconHelper.getRecommendedIconVariant(for: colorScheme))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension View {
|
||||
func onIconAppearanceChange(_ onChange: @escaping (IconVariant) -> Void) -> some View {
|
||||
modifier(IconAppearanceModifier(onChange: onChange))
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
extension AppIconHelper {
|
||||
static var preview: AppIconHelper {
|
||||
let helper = AppIconHelper()
|
||||
helper.isDarkMode = false
|
||||
return helper
|
||||
}
|
||||
|
||||
static var darkModePreview: AppIconHelper {
|
||||
let helper = AppIconHelper()
|
||||
helper.isDarkMode = true
|
||||
return helper
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,578 +0,0 @@
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
#if DEBUG
|
||||
|
||||
struct IconTestView: View {
|
||||
@ObservedObject private var iconHelper = AppIconHelper.shared
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
@State private var showingTestSheet = false
|
||||
@State private var testResults: [String] = []
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
List {
|
||||
StatusSection()
|
||||
|
||||
IconDisplaySection()
|
||||
|
||||
TestingSection()
|
||||
|
||||
DebugSection()
|
||||
|
||||
ResultsSection()
|
||||
}
|
||||
.navigationTitle("Icon Testing")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button("Run Tests") {
|
||||
runIconTests()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $showingTestSheet) {
|
||||
IconComparisonSheet()
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func StatusSection() -> some View {
|
||||
Section("System Status") {
|
||||
StatusRow(title: "Color Scheme", value: colorScheme.description)
|
||||
StatusRow(
|
||||
title: "Dark Mode Detected",
|
||||
value: iconHelper.isInDarkMode(for: colorScheme) ? "Yes" : "No")
|
||||
StatusRow(
|
||||
title: "iOS 17+ Features",
|
||||
value: iconHelper.supportsModernIconFeatures ? "Supported" : "Not Available")
|
||||
StatusRow(
|
||||
title: "Alternate Icons",
|
||||
value: iconHelper.supportsAlternateIcons ? "Supported" : "Not Available")
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func IconDisplaySection() -> some View {
|
||||
Section("Icon Display Test") {
|
||||
VStack(spacing: 20) {
|
||||
// App Icon Representation
|
||||
HStack(spacing: 20) {
|
||||
VStack {
|
||||
RoundedRectangle(cornerRadius: 16)
|
||||
.fill(.blue.gradient)
|
||||
.frame(width: 60, height: 60)
|
||||
.overlay {
|
||||
Image(systemName: "mountain.2.fill")
|
||||
.foregroundColor(.white)
|
||||
.font(.title2)
|
||||
}
|
||||
Text("Standard")
|
||||
.font(.caption)
|
||||
}
|
||||
|
||||
VStack {
|
||||
RoundedRectangle(cornerRadius: 16)
|
||||
.fill(.blue.gradient)
|
||||
.colorInvert()
|
||||
.frame(width: 60, height: 60)
|
||||
.overlay {
|
||||
Image(systemName: "mountain.2.fill")
|
||||
.foregroundColor(.white)
|
||||
.font(.title2)
|
||||
}
|
||||
Text("Dark Mode")
|
||||
.font(.caption)
|
||||
}
|
||||
|
||||
VStack {
|
||||
RoundedRectangle(cornerRadius: 16)
|
||||
.fill(.secondary)
|
||||
.frame(width: 60, height: 60)
|
||||
.overlay {
|
||||
Image(systemName: "mountain.2.fill")
|
||||
.foregroundColor(.primary)
|
||||
.font(.title2)
|
||||
}
|
||||
Text("Tinted")
|
||||
.font(.caption)
|
||||
}
|
||||
}
|
||||
|
||||
// In-App Icon Test
|
||||
HStack(spacing: 16) {
|
||||
Text("In-App Icon:")
|
||||
.font(.subheadline)
|
||||
.fontWeight(.medium)
|
||||
|
||||
Image("AppLogo")
|
||||
.resizable()
|
||||
.frame(width: 24, height: 24)
|
||||
.background(Circle().fill(.quaternary))
|
||||
|
||||
Text("24x24")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
Image("AppLogo")
|
||||
.resizable()
|
||||
.frame(width: 32, height: 32)
|
||||
.background(Circle().fill(.quaternary))
|
||||
|
||||
Text("32x32")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 8)
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func DebugSection() -> some View {
|
||||
Section("Dark Mode Debug") {
|
||||
HStack {
|
||||
Text("System Color Scheme:")
|
||||
.foregroundColor(.secondary)
|
||||
Spacer()
|
||||
Text(colorScheme == .dark ? "Dark" : "Light")
|
||||
.fontWeight(.medium)
|
||||
.foregroundColor(colorScheme == .dark ? .green : .orange)
|
||||
}
|
||||
|
||||
HStack {
|
||||
Text("IconHelper Dark Mode:")
|
||||
.foregroundColor(.secondary)
|
||||
Spacer()
|
||||
Text(iconHelper.isDarkMode ? "Dark" : "Light")
|
||||
.fontWeight(.medium)
|
||||
.foregroundColor(iconHelper.isDarkMode ? .green : .orange)
|
||||
}
|
||||
|
||||
HStack {
|
||||
Text("Recommended Variant:")
|
||||
.foregroundColor(.secondary)
|
||||
Spacer()
|
||||
Text(iconHelper.getRecommendedIconVariant(for: colorScheme).description)
|
||||
.fontWeight(.medium)
|
||||
}
|
||||
|
||||
// Current app icon preview
|
||||
VStack {
|
||||
Text("Current App Icon Preview")
|
||||
.font(.headline)
|
||||
.padding(.top)
|
||||
|
||||
HStack(spacing: 20) {
|
||||
VStack {
|
||||
RoundedRectangle(cornerRadius: 16)
|
||||
.fill(colorScheme == .dark ? .black : Color(.systemGray6))
|
||||
.frame(width: 60, height: 60)
|
||||
.overlay {
|
||||
// Mock app icon based on current mode
|
||||
if colorScheme == .dark {
|
||||
ZStack {
|
||||
// Left mountain (yellow/amber) - Android #FFC107
|
||||
Polygon(points: [
|
||||
CGPoint(x: 0.2, y: 0.8), CGPoint(x: 0.45, y: 0.3),
|
||||
CGPoint(x: 0.7, y: 0.8),
|
||||
])
|
||||
.fill(Color(red: 1.0, green: 0.76, blue: 0.03))
|
||||
.stroke(
|
||||
Color(red: 0.11, green: 0.11, blue: 0.11),
|
||||
lineWidth: 1
|
||||
)
|
||||
.frame(width: 50, height: 50)
|
||||
|
||||
// Right mountain (red) - Android #F44336, overlapping
|
||||
Polygon(points: [
|
||||
CGPoint(x: 0.5, y: 0.8), CGPoint(x: 0.75, y: 0.2),
|
||||
CGPoint(x: 1.0, y: 0.8),
|
||||
])
|
||||
.fill(Color(red: 0.96, green: 0.26, blue: 0.21))
|
||||
.stroke(
|
||||
Color(red: 0.11, green: 0.11, blue: 0.11),
|
||||
lineWidth: 1
|
||||
)
|
||||
.frame(width: 50, height: 50)
|
||||
}
|
||||
} else {
|
||||
ZStack {
|
||||
// Left mountain (yellow/amber) - Android #FFC107
|
||||
Polygon(points: [
|
||||
CGPoint(x: 0.2, y: 0.8), CGPoint(x: 0.45, y: 0.3),
|
||||
CGPoint(x: 0.7, y: 0.8),
|
||||
])
|
||||
.fill(Color(red: 1.0, green: 0.76, blue: 0.03))
|
||||
.stroke(
|
||||
Color(red: 0.11, green: 0.11, blue: 0.11),
|
||||
lineWidth: 1
|
||||
)
|
||||
.frame(width: 50, height: 50)
|
||||
|
||||
// Right mountain (red) - Android #F44336, overlapping
|
||||
Polygon(points: [
|
||||
CGPoint(x: 0.5, y: 0.8), CGPoint(x: 0.75, y: 0.2),
|
||||
CGPoint(x: 1.0, y: 0.8),
|
||||
])
|
||||
.fill(Color(red: 0.96, green: 0.26, blue: 0.21))
|
||||
.stroke(
|
||||
Color(red: 0.11, green: 0.11, blue: 0.11),
|
||||
lineWidth: 1
|
||||
)
|
||||
.frame(width: 50, height: 50)
|
||||
}
|
||||
}
|
||||
}
|
||||
Text(colorScheme == .dark ? "Dark Mode" : "Light Mode")
|
||||
.font(.caption)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 8)
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func TestingSection() -> some View {
|
||||
Section("Testing Tools") {
|
||||
Button("Compare Light/Dark Modes") {
|
||||
showingTestSheet = true
|
||||
}
|
||||
|
||||
Button("Test Icon Appearance Changes") {
|
||||
testIconAppearanceChanges()
|
||||
}
|
||||
|
||||
Button("Validate Asset Configuration") {
|
||||
validateAssetConfiguration()
|
||||
}
|
||||
|
||||
Button("Check Bundle Resources") {
|
||||
checkBundleResources()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func ResultsSection() -> some View {
|
||||
if !testResults.isEmpty {
|
||||
Section("Test Results") {
|
||||
ForEach(testResults.indices, id: \.self) { index in
|
||||
HStack {
|
||||
Image(
|
||||
systemName: testResults[index].contains("PASS")
|
||||
? "checkmark.circle.fill" : "exclamationmark.triangle.fill"
|
||||
)
|
||||
.foregroundColor(testResults[index].contains("PASS") ? .green : .orange)
|
||||
|
||||
Text(testResults[index])
|
||||
.font(.caption)
|
||||
}
|
||||
}
|
||||
|
||||
Button("Clear Results") {
|
||||
testResults.removeAll()
|
||||
}
|
||||
.foregroundColor(.red)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func runIconTests() {
|
||||
testResults.removeAll()
|
||||
|
||||
// Test 1: Check iOS version compatibility
|
||||
if iconHelper.supportsModernIconFeatures {
|
||||
testResults.append("PASS: iOS 17+ features supported")
|
||||
} else {
|
||||
testResults.append(
|
||||
"WARNING: Running on iOS version that doesn't support modern icon features")
|
||||
}
|
||||
|
||||
// Test 2: Check dark mode detection
|
||||
let detectedDarkMode = iconHelper.isInDarkMode(for: colorScheme)
|
||||
let systemDarkMode = colorScheme == .dark
|
||||
if detectedDarkMode == systemDarkMode {
|
||||
testResults.append("PASS: Dark mode detection matches system setting")
|
||||
} else {
|
||||
testResults.append("WARNING: Dark mode detection mismatch")
|
||||
}
|
||||
|
||||
// Test 3: Check recommended variant
|
||||
let variant = iconHelper.getRecommendedIconVariant(for: colorScheme)
|
||||
testResults.append("PASS: Recommended icon variant: \(variant.description)")
|
||||
|
||||
// Test 4: Test asset availability
|
||||
validateAssetConfiguration()
|
||||
|
||||
// Test 5: Test bundle resources
|
||||
checkBundleResources()
|
||||
}
|
||||
|
||||
private func testIconAppearanceChanges() {
|
||||
iconHelper.updateDarkModeStatus(for: colorScheme)
|
||||
let variant = iconHelper.getRecommendedIconVariant(for: colorScheme)
|
||||
testResults.append(
|
||||
"PASS: Icon appearance test completed - Current variant: \(variant.description)")
|
||||
}
|
||||
|
||||
private func validateAssetConfiguration() {
|
||||
// Check if main bundle contains the expected icon assets
|
||||
let expectedAssets = [
|
||||
"AppIcon",
|
||||
"AppLogo",
|
||||
]
|
||||
|
||||
for asset in expectedAssets {
|
||||
testResults.append("PASS: Asset '\(asset)' configuration found")
|
||||
}
|
||||
}
|
||||
|
||||
private func checkBundleResources() {
|
||||
// Check bundle identifier
|
||||
let bundleId = Bundle.main.bundleIdentifier ?? "Unknown"
|
||||
testResults.append("PASS: Bundle ID: \(bundleId)")
|
||||
|
||||
// Check app version
|
||||
let version =
|
||||
Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown"
|
||||
let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "Unknown"
|
||||
testResults.append("PASS: App version: \(version) (\(build))")
|
||||
}
|
||||
}
|
||||
|
||||
struct StatusRow: View {
|
||||
let title: String
|
||||
let value: String
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
Text(title)
|
||||
.foregroundColor(.secondary)
|
||||
Spacer()
|
||||
Text(value)
|
||||
.fontWeight(.medium)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct IconComparisonSheet: View {
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
VStack(spacing: 30) {
|
||||
Text("Icon Appearance Comparison")
|
||||
.font(.title2)
|
||||
.fontWeight(.bold)
|
||||
|
||||
VStack(spacing: 20) {
|
||||
// Current Mode
|
||||
VStack {
|
||||
Text("Current Mode: \(colorScheme.description)")
|
||||
.font(.headline)
|
||||
|
||||
HStack(spacing: 20) {
|
||||
Image("AppLogo")
|
||||
.resizable()
|
||||
.frame(width: 64, height: 64)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 12)
|
||||
.fill(.quaternary)
|
||||
)
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Text("AppLogo")
|
||||
.font(.subheadline)
|
||||
.fontWeight(.medium)
|
||||
Text("In-app icon display")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Divider()
|
||||
|
||||
// Mock App Icons
|
||||
VStack {
|
||||
Text("App Icon Variants")
|
||||
.font(.headline)
|
||||
|
||||
HStack(spacing: 20) {
|
||||
VStack {
|
||||
RoundedRectangle(cornerRadius: 16)
|
||||
.fill(.white)
|
||||
.frame(width: 64, height: 64)
|
||||
.overlay {
|
||||
ZStack {
|
||||
// Left mountain (yellow/amber)
|
||||
Polygon(points: [
|
||||
CGPoint(x: 0.2, y: 0.8),
|
||||
CGPoint(x: 0.45, y: 0.3),
|
||||
CGPoint(x: 0.7, y: 0.8),
|
||||
])
|
||||
.fill(Color(red: 1.0, green: 0.76, blue: 0.03))
|
||||
.stroke(
|
||||
Color(red: 0.11, green: 0.11, blue: 0.11),
|
||||
lineWidth: 0.5)
|
||||
|
||||
// Right mountain (red), overlapping
|
||||
Polygon(points: [
|
||||
CGPoint(x: 0.5, y: 0.8),
|
||||
CGPoint(x: 0.75, y: 0.2),
|
||||
CGPoint(x: 1.0, y: 0.8),
|
||||
])
|
||||
.fill(Color(red: 0.96, green: 0.26, blue: 0.21))
|
||||
.stroke(
|
||||
Color(red: 0.11, green: 0.11, blue: 0.11),
|
||||
lineWidth: 0.5)
|
||||
}
|
||||
}
|
||||
Text("Light")
|
||||
.font(.caption)
|
||||
}
|
||||
|
||||
VStack {
|
||||
RoundedRectangle(cornerRadius: 16)
|
||||
.fill(Color(red: 0.1, green: 0.1, blue: 0.1))
|
||||
.frame(width: 64, height: 64)
|
||||
.overlay {
|
||||
ZStack {
|
||||
// Left mountain (yellow/amber)
|
||||
Polygon(points: [
|
||||
CGPoint(x: 0.2, y: 0.8),
|
||||
CGPoint(x: 0.45, y: 0.3),
|
||||
CGPoint(x: 0.7, y: 0.8),
|
||||
])
|
||||
.fill(Color(red: 1.0, green: 0.76, blue: 0.03))
|
||||
.stroke(
|
||||
Color(red: 0.11, green: 0.11, blue: 0.11),
|
||||
lineWidth: 0.5)
|
||||
|
||||
// Right mountain (red), overlapping
|
||||
Polygon(points: [
|
||||
CGPoint(x: 0.5, y: 0.8),
|
||||
CGPoint(x: 0.75, y: 0.2),
|
||||
CGPoint(x: 1.0, y: 0.8),
|
||||
])
|
||||
.fill(Color(red: 0.96, green: 0.26, blue: 0.21))
|
||||
.stroke(
|
||||
Color(red: 0.11, green: 0.11, blue: 0.11),
|
||||
lineWidth: 0.5)
|
||||
}
|
||||
}
|
||||
Text("Dark")
|
||||
.font(.caption)
|
||||
}
|
||||
|
||||
VStack {
|
||||
RoundedRectangle(cornerRadius: 16)
|
||||
.fill(.clear)
|
||||
.frame(width: 64, height: 64)
|
||||
.overlay {
|
||||
ZStack {
|
||||
// Left mountain (monochrome)
|
||||
Polygon(points: [
|
||||
CGPoint(x: 0.2, y: 0.8),
|
||||
CGPoint(x: 0.45, y: 0.3),
|
||||
CGPoint(x: 0.7, y: 0.8),
|
||||
])
|
||||
.fill(.black.opacity(0.8))
|
||||
.stroke(.black, lineWidth: 0.5)
|
||||
|
||||
// Right mountain (monochrome), overlapping
|
||||
Polygon(points: [
|
||||
CGPoint(x: 0.5, y: 0.8),
|
||||
CGPoint(x: 0.75, y: 0.2),
|
||||
CGPoint(x: 1.0, y: 0.8),
|
||||
])
|
||||
.fill(.black.opacity(0.9))
|
||||
.stroke(.black, lineWidth: 0.5)
|
||||
}
|
||||
}
|
||||
Text("Tinted")
|
||||
.font(.caption)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
VStack(spacing: 8) {
|
||||
Text("Switch between light/dark mode in Settings")
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.secondary)
|
||||
.multilineTextAlignment(.center)
|
||||
|
||||
Text("The icon should adapt automatically")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.navigationTitle("Icon Test")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button("Done") {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ColorScheme {
|
||||
var description: String {
|
||||
switch self {
|
||||
case .light:
|
||||
return "Light"
|
||||
case .dark:
|
||||
return "Dark"
|
||||
@unknown default:
|
||||
return "Unknown"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
IconTestView()
|
||||
}
|
||||
|
||||
#Preview("Dark Mode") {
|
||||
IconTestView()
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
|
||||
struct Polygon: Shape {
|
||||
let points: [CGPoint]
|
||||
|
||||
func path(in rect: CGRect) -> Path {
|
||||
var path = Path()
|
||||
|
||||
guard !points.isEmpty else { return path }
|
||||
|
||||
let scaledPoints = points.map { point in
|
||||
CGPoint(
|
||||
x: point.x * rect.width,
|
||||
y: point.y * rect.height
|
||||
)
|
||||
}
|
||||
|
||||
path.move(to: scaledPoints[0])
|
||||
for point in scaledPoints.dropFirst() {
|
||||
path.addLine(to: point)
|
||||
}
|
||||
path.closeSubpath()
|
||||
|
||||
return path
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -44,19 +44,18 @@ class ThemeManager: ObservableObject {
|
||||
accentColor = .blue
|
||||
}
|
||||
|
||||
// Curated list of preset colors that maintain good contrast
|
||||
static let presetColors: [Color] = [
|
||||
.blue, // Default Blue
|
||||
.purple, // Purple
|
||||
.pink, // Pink
|
||||
.red, // Red
|
||||
.orange, // Orange
|
||||
.green, // Green
|
||||
.teal, // Teal
|
||||
.indigo, // Indigo
|
||||
.mint, // Mint
|
||||
Color(uiColor: .systemBrown), // Brown
|
||||
Color(uiColor: .systemCyan) // Cyan
|
||||
.blue,
|
||||
.purple,
|
||||
.pink,
|
||||
.red,
|
||||
.orange,
|
||||
.green,
|
||||
.teal,
|
||||
.indigo,
|
||||
.mint,
|
||||
Color(uiColor: .systemBrown),
|
||||
Color(uiColor: .systemCyan)
|
||||
]
|
||||
|
||||
var contrastingTextColor: Color {
|
||||
@@ -68,10 +67,8 @@ class ThemeManager: ObservableObject {
|
||||
|
||||
uiColor.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
|
||||
|
||||
// Calculate relative luminance
|
||||
let luminance = 0.299 * red + 0.587 * green + 0.114 * blue
|
||||
|
||||
// Return black for light colors, white for dark colors
|
||||
return luminance > 0.5 ? .black : .white
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,9 +427,6 @@ struct ExportDataView: View {
|
||||
if let fileURL = tempFileURL {
|
||||
ShareLink(
|
||||
item: fileURL,
|
||||
preview: SharePreview(
|
||||
"Ascently Data Export",
|
||||
image: Image("AppLogo"))
|
||||
) {
|
||||
Label("Share Data", systemImage: "square.and.arrow.up")
|
||||
.font(.headline)
|
||||
|
||||
Reference in New Issue
Block a user