ReadKeep/URLShare/TagRepository.swift
Ilyas Hallak a3b3863fa3 Refactor tag management system with improved search and real-time sync
- Add CreateLabelUseCase for consistent label creation across app and extension
- Implement TagRepository for Share Extension to persist new labels to Core Data
- Enhance CoreDataTagManagementView with real-time search functionality
- Add automatic tag synchronization on app startup and resume
- Improve Core Data context configuration for better extension support
- Unify label terminology across UI components (tags -> labels)
- Fix label persistence issues in Share Extension
- Add immediate Core Data persistence for newly created labels
- Bump version to 36
2025-11-10 21:29:38 +01:00

64 lines
2.8 KiB
Swift

import Foundation
import CoreData
/// Simple repository for managing tags in Share Extension
class TagRepository {
private let logger = Logger.data
/// Saves a new label to Core Data if it doesn't already exist
/// - Parameters:
/// - name: The label name to save
/// - context: The managed object context to use
func saveNewLabel(name: String, context: NSManagedObjectContext) {
let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmedName.isEmpty else { return }
// Perform save in a synchronous block to ensure it completes before extension closes
context.performAndWait {
// Check if label already exists
let fetchRequest: NSFetchRequest<TagEntity> = TagEntity.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "name == %@", trimmedName)
fetchRequest.fetchLimit = 1
do {
let existingTags = try context.fetch(fetchRequest)
// Only create if it doesn't exist
if existingTags.isEmpty {
let newTag = TagEntity(context: context)
newTag.name = trimmedName
newTag.count = 1 // New label is being used immediately
try context.save()
logger.info("Successfully saved new label '\(trimmedName)' to Core Data")
// Force immediate persistence to disk for share extension
// Based on: https://www.avanderlee.com/swift/core-data-app-extension-data-sharing/
// 1. Process pending changes
context.processPendingChanges()
// 2. Ensure persistent store coordinator writes to disk
// This is critical for extensions as they may be terminated quickly
if context.persistentStoreCoordinator != nil {
// Refresh all objects to ensure changes are pushed to store
context.refreshAllObjects()
// Reset staleness interval temporarily to force immediate persistence
let originalStalenessInterval = context.stalenessInterval
context.stalenessInterval = 0
context.refreshAllObjects()
context.stalenessInterval = originalStalenessInterval
logger.debug("Forced context refresh to ensure persistence")
}
} else {
logger.debug("Label '\(trimmedName)' already exists, skipping creation")
}
} catch {
logger.error("Failed to save new label '\(trimmedName)': \(error.localizedDescription)")
}
}
}
}