Makefile, linting, and formatting
This commit is contained in:
22
ios/.editorconfig
Normal file
22
ios/.editorconfig
Normal file
@@ -0,0 +1,22 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.swift]
|
||||
indent_size = 4
|
||||
max_line_length = 140
|
||||
|
||||
[*.{plist,storyboard,xib,xcscheme,xcworkspacedata}]
|
||||
indent_size = 2
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
68
ios/.swiftformat
Normal file
68
ios/.swiftformat
Normal file
@@ -0,0 +1,68 @@
|
||||
# SwiftFormat Configuration for Ascently iOS
|
||||
# Maintains consistent formatting across the project
|
||||
|
||||
# File options
|
||||
--exclude build,Pods,DerivedData,.build
|
||||
|
||||
# Format options
|
||||
--swiftversion 6.0
|
||||
--indent 4
|
||||
--tabwidth 4
|
||||
--maxwidth 140
|
||||
--wraparguments before-first
|
||||
--wrapparameters before-first
|
||||
--wrapcollections before-first
|
||||
--wrapconditions after-first
|
||||
--wrapreturntype preserve
|
||||
--wrapeffects preserve
|
||||
--closingparen balanced
|
||||
--funcattributes prev-line
|
||||
--typeattributes prev-line
|
||||
--varattributes preserve
|
||||
--storedvarattrs same-line
|
||||
--computedvarattrs preserve
|
||||
--complexattributes prev-line
|
||||
--typeblanklines preserve
|
||||
--structthreshold 20
|
||||
--enumthreshold 20
|
||||
--extensionacl on-declarations
|
||||
--organizetypes class,struct,enum,extension,protocol
|
||||
--modifierorder acl,setteracl,override,static,final,required,convenience,lazy,dynamic
|
||||
--self remove
|
||||
--importgrouping alpha
|
||||
--semicolons inline
|
||||
--operatorfunc spaced
|
||||
--nospaceoperators ..<,...
|
||||
--ranges no-space
|
||||
--emptybraces no-space
|
||||
--trimwhitespace always
|
||||
--stripunusedargs closure-only
|
||||
--header ignore
|
||||
--guardelse auto
|
||||
--elseposition same-line
|
||||
--shortoptionals always
|
||||
--linebreaks lf
|
||||
--xcodeindentation disabled
|
||||
--fragment false
|
||||
--conflictmarkers reject
|
||||
--ifdef no-indent
|
||||
--extensionlength 0
|
||||
|
||||
# Enable rules
|
||||
--enable isEmpty,sortedSwitchCases,redundantInit,redundantGet,redundantObjc
|
||||
--enable blankLineAfterSwitchCase,consecutiveSpaces,duplicateImports
|
||||
--enable elseOnSameLine,emptyBraces,hoistAwait,hoistPatternLet,hoistTry
|
||||
--enable leadingDelimiters,redundantBackticks,redundantBreak,redundantClosure
|
||||
--enable redundantExtensionACL,redundantFileprivate,redundantLetError
|
||||
--enable redundantNilInit,redundantParens,redundantPattern,redundantRawValues
|
||||
--enable redundantReturn,redundantSelf,redundantType,redundantVoidReturnType
|
||||
--enable semicolons,sortImports,spaceAroundBraces,spaceAroundBrackets
|
||||
--enable spaceAroundComments,spaceAroundGenerics,spaceAroundOperators
|
||||
--enable spaceAroundParens,spaceInsideBraces,spaceInsideBrackets
|
||||
--enable spaceInsideComments,spaceInsideGenerics,spaceInsideParens
|
||||
--enable strongOutlets,strongifiedSelf,todos,trailingClosures,trailingCommas
|
||||
--enable typeSugar,unusedArguments,void,wrapArguments,wrapAttributes
|
||||
--enable yodaConditions,blankLinesBetweenScopes,blankLinesAtEndOfScope
|
||||
|
||||
# Disable rules
|
||||
--disable wrapMultilineStatementBraces
|
||||
139
ios/.swiftlint.yml
Normal file
139
ios/.swiftlint.yml
Normal file
@@ -0,0 +1,139 @@
|
||||
excluded:
|
||||
- build
|
||||
- Pods
|
||||
- DerivedData
|
||||
- .build
|
||||
- AscentlyTests
|
||||
|
||||
disabled_rules:
|
||||
- trailing_whitespace
|
||||
- todo
|
||||
- nesting
|
||||
- opening_brace
|
||||
- multiple_closures_with_trailing_closure
|
||||
- trailing_comma
|
||||
- attributes
|
||||
- function_parameter_count
|
||||
- large_tuple
|
||||
|
||||
opt_in_rules:
|
||||
- empty_count
|
||||
- explicit_init
|
||||
- closure_spacing
|
||||
- overridden_super_call
|
||||
- redundant_nil_coalescing
|
||||
- first_where
|
||||
- sorted_first_last
|
||||
- contains_over_filter_count
|
||||
- contains_over_filter_is_empty
|
||||
- empty_string
|
||||
- prefer_zero_over_explicit_init
|
||||
- flatmap_over_map_reduce
|
||||
- last_where
|
||||
- sorted_imports
|
||||
- toggle_bool
|
||||
- unavailable_function
|
||||
- unneeded_parentheses_in_closure_argument
|
||||
- vertical_whitespace_closing_braces
|
||||
- yoda_condition
|
||||
- collection_alignment
|
||||
- literal_expression_end_indentation
|
||||
|
||||
line_length:
|
||||
warning: 140
|
||||
error: 250
|
||||
ignores_comments: true
|
||||
ignores_urls: true
|
||||
ignores_function_declarations: true
|
||||
ignores_interpolated_strings: true
|
||||
|
||||
type_body_length:
|
||||
warning: 600
|
||||
error: 1000
|
||||
|
||||
file_length:
|
||||
warning: 1000
|
||||
error: 1500
|
||||
ignore_comment_only_lines: true
|
||||
|
||||
function_body_length:
|
||||
warning: 100
|
||||
error: 200
|
||||
|
||||
cyclomatic_complexity:
|
||||
warning: 20
|
||||
error: 30
|
||||
ignores_case_statements: true
|
||||
|
||||
identifier_name:
|
||||
min_length:
|
||||
warning: 2
|
||||
error: 1
|
||||
max_length:
|
||||
warning: 50
|
||||
error: 60
|
||||
validates_start_with_lowercase: error
|
||||
allowed_symbols:
|
||||
- _
|
||||
excluded:
|
||||
- id
|
||||
- i
|
||||
- j
|
||||
- x
|
||||
- y
|
||||
- z
|
||||
- to
|
||||
- at
|
||||
- or
|
||||
- is
|
||||
- no
|
||||
- go
|
||||
- db
|
||||
- DATA_JSON_FILENAME
|
||||
- IMAGES_DIR_NAME
|
||||
- METADATA_FILENAME
|
||||
# ViewBuilder section functions (SwiftUI convention)
|
||||
- StatusSection
|
||||
- IconDisplaySection
|
||||
- DebugSection
|
||||
- TestingSection
|
||||
- ResultsSection
|
||||
- GymSelectionSection
|
||||
- SessionDetailsSection
|
||||
- ProblemSelectionSection
|
||||
- CreateProblemSection
|
||||
- AttemptDetailsSection
|
||||
- BasicInfoSection
|
||||
- ClimbTypesSection
|
||||
- DifficultySystemsSection
|
||||
- NotesSection
|
||||
- ClimbTypeSection
|
||||
- DifficultySection
|
||||
- LocationSection
|
||||
- TagsSection
|
||||
- PhotosSection
|
||||
- AdditionalInfoSection
|
||||
|
||||
type_name:
|
||||
min_length:
|
||||
warning: 3
|
||||
error: 2
|
||||
max_length:
|
||||
warning: 50
|
||||
error: 60
|
||||
|
||||
force_cast: warning
|
||||
|
||||
force_try: warning
|
||||
|
||||
large_tuple:
|
||||
warning: 4
|
||||
error: 6
|
||||
|
||||
nesting:
|
||||
type_level:
|
||||
warning: 3
|
||||
function_level:
|
||||
warning: 5
|
||||
|
||||
reporter: "xcode"
|
||||
@@ -465,7 +465,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Ascently/Ascently.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 38;
|
||||
CURRENT_PROJECT_VERSION = 39;
|
||||
DEVELOPMENT_TEAM = 4BC9Y2LL4B;
|
||||
DRIVERKIT_DEPLOYMENT_TARGET = 24.6;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -487,7 +487,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.6;
|
||||
MARKETING_VERSION = 2.5.1;
|
||||
MARKETING_VERSION = 2.5.2;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@@ -513,7 +513,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Ascently/Ascently.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 38;
|
||||
CURRENT_PROJECT_VERSION = 39;
|
||||
DEVELOPMENT_TEAM = 4BC9Y2LL4B;
|
||||
DRIVERKIT_DEPLOYMENT_TARGET = 24.6;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -535,7 +535,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.6;
|
||||
MARKETING_VERSION = 2.5.1;
|
||||
MARKETING_VERSION = 2.5.2;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@@ -602,7 +602,7 @@
|
||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||
CODE_SIGN_ENTITLEMENTS = SessionStatusLiveExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 38;
|
||||
CURRENT_PROJECT_VERSION = 39;
|
||||
DEVELOPMENT_TEAM = 4BC9Y2LL4B;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = SessionStatusLive/Info.plist;
|
||||
@@ -613,7 +613,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.5.1;
|
||||
MARKETING_VERSION = 2.5.2;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently.SessionStatusLive;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
@@ -632,7 +632,7 @@
|
||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||
CODE_SIGN_ENTITLEMENTS = SessionStatusLiveExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 38;
|
||||
CURRENT_PROJECT_VERSION = 39;
|
||||
DEVELOPMENT_TEAM = 4BC9Y2LL4B;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = SessionStatusLive/Info.plist;
|
||||
@@ -643,7 +643,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.5.1;
|
||||
MARKETING_VERSION = 2.5.2;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently.SessionStatusLive;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
||||
Binary file not shown.
@@ -45,7 +45,7 @@ struct ContentView: View {
|
||||
}
|
||||
.environmentObject(dataManager)
|
||||
.environmentObject(MusicService.shared)
|
||||
.onChange(of: scenePhase) { oldPhase, newPhase in
|
||||
.onChange(of: scenePhase) { _, newPhase in
|
||||
if newPhase == .active {
|
||||
// Add slight delay to ensure app is fully loaded
|
||||
Task {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import MusicKit
|
||||
import AVFoundation
|
||||
import SwiftUI
|
||||
import Combine
|
||||
import MusicKit
|
||||
import SwiftUI
|
||||
|
||||
@MainActor
|
||||
class MusicService: ObservableObject {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Foundation
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
class ServerSyncProvider: SyncProvider {
|
||||
var type: SyncProviderType { .server }
|
||||
@@ -235,7 +235,7 @@ class ServerSyncProvider: SyncProvider {
|
||||
}.map { problem -> BackupProblem in
|
||||
let backupProblem = BackupProblem(from: problem)
|
||||
if !problem.imagePaths.isEmpty {
|
||||
let normalizedPaths = problem.imagePaths.enumerated().map { index, _ in
|
||||
let normalizedPaths = problem.imagePaths.indices.map { index in
|
||||
ImageNamingUtils.generateImageFilename(
|
||||
problemId: problem.id.uuidString, imageIndex: index)
|
||||
}
|
||||
@@ -859,7 +859,6 @@ class ServerSyncProvider: SyncProvider {
|
||||
attempts: filteredAttempts,
|
||||
deletedItems: backup.deletedItems
|
||||
)
|
||||
|
||||
} else {
|
||||
// Filter out deleted items even when no image path mapping
|
||||
let deletedGymIds = Set(
|
||||
@@ -930,7 +929,6 @@ class ServerSyncProvider: SyncProvider {
|
||||
// Update local data state to match imported data timestamp
|
||||
DataStateManager.shared.setLastModified(backup.exportedAt)
|
||||
AppLogger.info("Data state synchronized to imported timestamp: \(backup.exportedAt)", tag: logTag)
|
||||
|
||||
} catch {
|
||||
throw SyncError.importFailed(error)
|
||||
}
|
||||
|
||||
@@ -153,9 +153,7 @@ struct SyncMerger {
|
||||
let activeSessionIds = Set(
|
||||
local.compactMap { attempt in
|
||||
return attempt.sessionId
|
||||
}.filter { sessionId in
|
||||
// Check if this session ID belongs to an active session
|
||||
// For now, we'll be conservative and not delete attempts during merge
|
||||
}.filter { _ in
|
||||
return true
|
||||
})
|
||||
|
||||
|
||||
@@ -133,7 +133,6 @@ class SyncService: ObservableObject {
|
||||
if let lastSync = userDefaults.object(forKey: Keys.lastSyncTime) as? Date {
|
||||
self.lastSyncTime = lastSync
|
||||
}
|
||||
|
||||
} catch {
|
||||
syncError = error.localizedDescription
|
||||
throw error
|
||||
|
||||
@@ -238,7 +238,6 @@ class ImageManager {
|
||||
|
||||
saveMigrationState(initialState)
|
||||
performMigrationWithCheckpoints(files: allLegacyFiles, currentState: initialState)
|
||||
|
||||
} catch {
|
||||
logError("ERROR: Failed to start migration: \(error)")
|
||||
}
|
||||
@@ -255,7 +254,6 @@ class ImageManager {
|
||||
|
||||
logInfo("Resuming with \(remainingFiles.count) remaining files")
|
||||
performMigrationWithCheckpoints(files: remainingFiles, currentState: state)
|
||||
|
||||
} catch {
|
||||
logError("ERROR: Failed to resume migration: \(error)")
|
||||
// Fallback: start fresh
|
||||
@@ -325,7 +323,6 @@ class ImageManager {
|
||||
migratedCount += 1
|
||||
|
||||
logInfo("Migrated: \(fileName) (\(migratedCount)/\(currentState.totalFiles))")
|
||||
|
||||
} catch {
|
||||
failedCount += 1
|
||||
logError("ERROR: Failed to migrate \(fileName): \(error)")
|
||||
@@ -676,7 +673,7 @@ class ImageManager {
|
||||
|
||||
for fileName in files {
|
||||
let filePath = imagesDirectory.appendingPathComponent(fileName)
|
||||
if let data = try? Data(contentsOf: filePath), data.count > 0 {
|
||||
if let data = try? Data(contentsOf: filePath), !data.isEmpty {
|
||||
// Basic validation - check if file has content and is reasonable size
|
||||
if data.count > 100 { // Minimum viable image size
|
||||
validFiles += 1
|
||||
@@ -825,7 +822,7 @@ class ImageManager {
|
||||
let primaryEmpty =
|
||||
(try? fileManager.contentsOfDirectory(atPath: imagesDirectory.path).isEmpty) ?? true
|
||||
let backupHasFiles =
|
||||
((try? fileManager.contentsOfDirectory(atPath: backupDirectory.path)) ?? []).count > 0
|
||||
!((try? fileManager.contentsOfDirectory(atPath: backupDirectory.path)) ?? []).isEmpty
|
||||
|
||||
if primaryEmpty && backupHasFiles {
|
||||
logDebug("DEBUG SAFE: Primary empty but backup exists - restoring")
|
||||
@@ -944,7 +941,6 @@ class ImageManager {
|
||||
}
|
||||
|
||||
logInfo("Completed migration from previous Application Support directory")
|
||||
|
||||
} catch {
|
||||
logError("ERROR: Failed to migrate from previous Application Support: \(error)")
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import SwiftUI
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
class ThemeManager: ObservableObject {
|
||||
@Published var accentColor: Color = .blue {
|
||||
|
||||
@@ -73,7 +73,7 @@ struct ZipUtils {
|
||||
|
||||
do {
|
||||
let imageData = try Data(contentsOf: imageURL)
|
||||
if imageData.count > 0 {
|
||||
if !imageData.isEmpty {
|
||||
let imageEntryName = "\(IMAGES_DIR_NAME)/\(imageName)"
|
||||
try addFileToZip(
|
||||
filename: imageEntryName,
|
||||
|
||||
@@ -526,7 +526,6 @@ struct AddAttemptView: View {
|
||||
|
||||
dismiss()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct ProblemSelectionRow: View {
|
||||
@@ -1302,7 +1301,6 @@ struct EditAttemptView: View {
|
||||
|
||||
dismiss()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#Preview {
|
||||
|
||||
@@ -168,7 +168,6 @@ struct AddEditProblemView: View {
|
||||
await loadSelectedPhotos()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
@@ -224,7 +223,6 @@ struct AddEditProblemView: View {
|
||||
.fill(.quaternary)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -366,7 +366,7 @@ struct BarChartView: View {
|
||||
)
|
||||
} else {
|
||||
VStack(alignment: .leading) {
|
||||
// Chart area
|
||||
// Chart area
|
||||
HStack(alignment: .bottom, spacing: spacing / CGFloat(sortedData.count)) {
|
||||
ForEach(Array(sortedData.enumerated()), id: \.offset) { index, gradeCount in
|
||||
VStack(spacing: 4) {
|
||||
|
||||
@@ -231,7 +231,6 @@ struct SessionDetailView: View {
|
||||
uniqueProblemsCompleted: completedProblems.count
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct SessionHeaderCard: View {
|
||||
@@ -305,7 +304,6 @@ struct SessionHeaderCard: View {
|
||||
formatter.dateStyle = .full
|
||||
return formatter.string(from: date)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct SessionStatsCard: View {
|
||||
|
||||
@@ -182,7 +182,8 @@ struct ProblemsView: View {
|
||||
Button(action: {
|
||||
showingFilters = true
|
||||
}) {
|
||||
Image(systemName: (selectedClimbType != nil || selectedGym != nil) ? "line.3.horizontal.decrease.circle.fill" : "line.3.horizontal.decrease.circle")
|
||||
let hasFilters = selectedClimbType != nil || selectedGym != nil
|
||||
Image(systemName: hasFilters ? "line.3.horizontal.decrease.circle.fill" : "line.3.horizontal.decrease.circle")
|
||||
.font(.system(size: 16, weight: .medium))
|
||||
.foregroundColor(themeManager.accentColor)
|
||||
}
|
||||
@@ -365,7 +366,6 @@ struct FilterSection: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct FilterChip: View {
|
||||
@@ -392,8 +392,6 @@ struct FilterChip: View {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct ProblemRow: View {
|
||||
let problem: Problem
|
||||
@EnvironmentObject var dataManager: ClimbingDataManager
|
||||
|
||||
@@ -256,7 +256,6 @@ struct ActiveSessionBanner: View {
|
||||
SessionDetailView(sessionId: session.id)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct SessionRow: View {
|
||||
|
||||
@@ -251,9 +251,16 @@ struct DataManagementSection: View {
|
||||
dataManager.resetAllData()
|
||||
}
|
||||
} message: {
|
||||
Text(
|
||||
"Are you sure you want to reset all data? This will permanently delete:\n\n• All gyms and their information\n• All problems and their images\n• All climbing sessions\n• All attempts and progress data\n\nThis action cannot be undone. Consider exporting your data first."
|
||||
)
|
||||
Text("""
|
||||
Are you sure you want to reset all data? This will permanently delete:
|
||||
|
||||
• All gyms and their information
|
||||
• All problems and their images
|
||||
• All climbing sessions
|
||||
• All attempts and progress data
|
||||
|
||||
This action cannot be undone. Consider exporting your data first.
|
||||
""")
|
||||
}
|
||||
|
||||
.alert("Delete All Images", isPresented: $showingDeleteImagesAlert) {
|
||||
@@ -262,9 +269,14 @@ struct DataManagementSection: View {
|
||||
deleteAllImages()
|
||||
}
|
||||
} message: {
|
||||
Text(
|
||||
"This will permanently delete ALL image files from your device.\n\nProblems will keep their references but the actual image files will be removed. This cannot be undone.\n\nConsider exporting your data first if you want to keep your images."
|
||||
)
|
||||
Text("""
|
||||
This will permanently delete ALL image files from your device.
|
||||
|
||||
Problems will keep their references but the actual image files will be removed. \
|
||||
This cannot be undone.
|
||||
|
||||
Consider exporting your data first if you want to keep your images.
|
||||
""")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -651,7 +663,6 @@ struct SyncSection: View {
|
||||
.foregroundColor(.red)
|
||||
.padding(.leading, 24)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $showingSyncSettings) {
|
||||
|
||||
@@ -22,7 +22,6 @@ struct SessionStatusLiveLiveActivity: Widget {
|
||||
LiveActivityView(context: context)
|
||||
.activityBackgroundTint(Color.blue.opacity(0.2))
|
||||
.activitySystemActionForegroundColor(Color.primary)
|
||||
|
||||
} dynamicIsland: { context in
|
||||
DynamicIsland {
|
||||
DynamicIslandExpandedRegion(.leading) {
|
||||
|
||||
Reference in New Issue
Block a user