Add task completion animations, subscription trials, and quiet debug console
- Completion animations: play user-selected animation on task card after completing, with DataManager guard to prevent race condition during animation playback. Works in both AllTasksView and ResidenceDetailView. Animation preference persisted via @AppStorage and configurable from Settings. - Subscription: add trial fields (trialStart, trialEnd, trialActive) and subscriptionSource to model, cross-platform purchase guard, trial banner in upgrade prompt, and platform-aware subscription management in profile. - Analytics: disable PostHog SDK debug logging and remove console print statements to reduce debug console noise. - Documents: remove redundant nested do-catch blocks in ViewModel wrapper. - Widgets: add debounced timeline reloads and thread-safe file I/O queue. - Onboarding: fix animation leak on disappear, remove unused state vars. - Remove unused files (ContentView, StateFlowExtensions, CustomView). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -124,20 +124,16 @@ class DocumentViewModelWrapper: ObservableObject {
|
||||
forceRefresh: false
|
||||
)
|
||||
|
||||
do {
|
||||
if let success = result as? ApiResultSuccess<NSArray> {
|
||||
let documents = success.data as? [Document] ?? []
|
||||
self.documentsState = DocumentStateSuccess(documents: documents)
|
||||
} else if let error = ApiResultBridge.error(from: result) {
|
||||
self.documentsState = DocumentStateError(message: error.message)
|
||||
} else {
|
||||
self.documentsState = DocumentStateError(message: "Failed to load documents")
|
||||
}
|
||||
if let success = result as? ApiResultSuccess<NSArray> {
|
||||
let documents = success.data as? [Document] ?? []
|
||||
self.documentsState = DocumentStateSuccess(documents: documents)
|
||||
} else if let error = ApiResultBridge.error(from: result) {
|
||||
self.documentsState = DocumentStateError(message: error.message)
|
||||
} else {
|
||||
self.documentsState = DocumentStateError(message: "Failed to load documents")
|
||||
}
|
||||
} catch {
|
||||
do {
|
||||
self.documentsState = DocumentStateError(message: error.localizedDescription)
|
||||
}
|
||||
self.documentsState = DocumentStateError(message: error.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,19 +146,15 @@ class DocumentViewModelWrapper: ObservableObject {
|
||||
do {
|
||||
let result = try await APILayer.shared.getDocument(id: id, forceRefresh: false)
|
||||
|
||||
do {
|
||||
if let success = result as? ApiResultSuccess<Document>, let document = success.data {
|
||||
self.documentDetailState = DocumentDetailStateSuccess(document: document)
|
||||
} else if let error = ApiResultBridge.error(from: result) {
|
||||
self.documentDetailState = DocumentDetailStateError(message: error.message)
|
||||
} else {
|
||||
self.documentDetailState = DocumentDetailStateError(message: "Failed to load document")
|
||||
}
|
||||
if let success = result as? ApiResultSuccess<Document>, let document = success.data {
|
||||
self.documentDetailState = DocumentDetailStateSuccess(document: document)
|
||||
} else if let error = ApiResultBridge.error(from: result) {
|
||||
self.documentDetailState = DocumentDetailStateError(message: error.message)
|
||||
} else {
|
||||
self.documentDetailState = DocumentDetailStateError(message: "Failed to load document")
|
||||
}
|
||||
} catch {
|
||||
do {
|
||||
self.documentDetailState = DocumentDetailStateError(message: error.localizedDescription)
|
||||
}
|
||||
self.documentDetailState = DocumentDetailStateError(message: error.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,21 +207,17 @@ class DocumentViewModelWrapper: ObservableObject {
|
||||
endDate: endDate
|
||||
)
|
||||
|
||||
do {
|
||||
if let success = result as? ApiResultSuccess<Document>, let document = success.data {
|
||||
self.updateState = UpdateStateSuccess(document: document)
|
||||
// Also refresh the detail state
|
||||
self.documentDetailState = DocumentDetailStateSuccess(document: document)
|
||||
} else if let error = ApiResultBridge.error(from: result) {
|
||||
self.updateState = UpdateStateError(message: error.message)
|
||||
} else {
|
||||
self.updateState = UpdateStateError(message: "Failed to update document")
|
||||
}
|
||||
if let success = result as? ApiResultSuccess<Document>, let document = success.data {
|
||||
self.updateState = UpdateStateSuccess(document: document)
|
||||
// Also refresh the detail state
|
||||
self.documentDetailState = DocumentDetailStateSuccess(document: document)
|
||||
} else if let error = ApiResultBridge.error(from: result) {
|
||||
self.updateState = UpdateStateError(message: error.message)
|
||||
} else {
|
||||
self.updateState = UpdateStateError(message: "Failed to update document")
|
||||
}
|
||||
} catch {
|
||||
do {
|
||||
self.updateState = UpdateStateError(message: error.localizedDescription)
|
||||
}
|
||||
self.updateState = UpdateStateError(message: error.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -241,19 +229,15 @@ class DocumentViewModelWrapper: ObservableObject {
|
||||
do {
|
||||
let result = try await APILayer.shared.deleteDocument(id: id)
|
||||
|
||||
do {
|
||||
if result is ApiResultSuccess<KotlinUnit> {
|
||||
self.deleteState = DeleteStateSuccess()
|
||||
} else if let error = ApiResultBridge.error(from: result) {
|
||||
self.deleteState = DeleteStateError(message: error.message)
|
||||
} else {
|
||||
self.deleteState = DeleteStateError(message: "Failed to delete document")
|
||||
}
|
||||
if result is ApiResultSuccess<KotlinUnit> {
|
||||
self.deleteState = DeleteStateSuccess()
|
||||
} else if let error = ApiResultBridge.error(from: result) {
|
||||
self.deleteState = DeleteStateError(message: error.message)
|
||||
} else {
|
||||
self.deleteState = DeleteStateError(message: "Failed to delete document")
|
||||
}
|
||||
} catch {
|
||||
do {
|
||||
self.deleteState = DeleteStateError(message: error.localizedDescription)
|
||||
}
|
||||
self.deleteState = DeleteStateError(message: error.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -273,21 +257,17 @@ class DocumentViewModelWrapper: ObservableObject {
|
||||
do {
|
||||
let result = try await APILayer.shared.deleteDocumentImage(documentId: documentId, imageId: imageId)
|
||||
|
||||
do {
|
||||
if let success = result as? ApiResultSuccess<Document>, let document = success.data {
|
||||
self.deleteImageState = DeleteImageStateSuccess()
|
||||
// Refresh detail state with updated document (image removed)
|
||||
self.documentDetailState = DocumentDetailStateSuccess(document: document)
|
||||
} else if let error = ApiResultBridge.error(from: result) {
|
||||
self.deleteImageState = DeleteImageStateError(message: error.message)
|
||||
} else {
|
||||
self.deleteImageState = DeleteImageStateError(message: "Failed to delete image")
|
||||
}
|
||||
if let success = result as? ApiResultSuccess<Document>, let document = success.data {
|
||||
self.deleteImageState = DeleteImageStateSuccess()
|
||||
// Refresh detail state with updated document (image removed)
|
||||
self.documentDetailState = DocumentDetailStateSuccess(document: document)
|
||||
} else if let error = ApiResultBridge.error(from: result) {
|
||||
self.deleteImageState = DeleteImageStateError(message: error.message)
|
||||
} else {
|
||||
self.deleteImageState = DeleteImageStateError(message: "Failed to delete image")
|
||||
}
|
||||
} catch {
|
||||
do {
|
||||
self.deleteImageState = DeleteImageStateError(message: error.localizedDescription)
|
||||
}
|
||||
self.deleteImageState = DeleteImageStateError(message: error.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user