mirror of
https://github.com/yattee/yattee.git
synced 2026-10-31 00:47:17 +00:00
Remove dead code found by Periphery on all platforms
Delete declarations that Periphery reports unused on every platform that compiles them (iOS, macOS, tvOS), including nine views used only by their own previews. Platform-gated code still used on another platform, device- only MPV render paths, migration models, CloudKit record names, App Intents metadata and unused parameters are kept.
This commit is contained in:
@@ -172,26 +172,6 @@ final class Bookmark {
|
||||
}
|
||||
}
|
||||
|
||||
/// Formatted view count string.
|
||||
var formattedViewCount: String? {
|
||||
guard let viewCount else { return nil }
|
||||
return CountFormatter.compact(viewCount)
|
||||
}
|
||||
|
||||
/// Formatted published date, preferring parsed Date over API-provided text.
|
||||
///
|
||||
/// A date that would render as "in 0 seconds" is shown as nothing at all —
|
||||
/// see ``Video/formattedPublishedDate``.
|
||||
var formattedPublishedDate: String? {
|
||||
if let publishedAt {
|
||||
guard !RelativeDateFormatter.isEffectivelyNow(publishedAt) else { return nil }
|
||||
let formatter = RelativeDateTimeFormatter()
|
||||
formatter.unitsStyle = .full
|
||||
return formatter.localizedString(for: publishedAt, relativeTo: Date())
|
||||
}
|
||||
return publishedText
|
||||
}
|
||||
|
||||
/// Converts this bookmark to a Video model for playback.
|
||||
func toVideo() -> Video {
|
||||
let videoIDObj: VideoID
|
||||
|
||||
@@ -131,41 +131,6 @@ extension DataManager {
|
||||
save()
|
||||
}
|
||||
|
||||
/// Deletes notification settings for a channel.
|
||||
/// - Parameter channelID: The channel ID to delete settings for.
|
||||
func deleteNotificationSettings(for channelID: String) {
|
||||
let descriptor = FetchDescriptor<ChannelNotificationSettings>(
|
||||
predicate: #Predicate { $0.channelID == channelID }
|
||||
)
|
||||
|
||||
do {
|
||||
let results = try modelContext.fetch(descriptor)
|
||||
guard !results.isEmpty else { return }
|
||||
|
||||
// Capture scopes before deleting
|
||||
let scopes = results.map {
|
||||
SourceScope.from(
|
||||
sourceRawValue: $0.sourceRawValue,
|
||||
globalProvider: $0.globalProvider,
|
||||
instanceURLString: $0.instanceURLString,
|
||||
externalExtractor: nil
|
||||
)
|
||||
}
|
||||
|
||||
for settings in results {
|
||||
modelContext.delete(settings)
|
||||
}
|
||||
save()
|
||||
|
||||
// Queue scoped CloudKit deletions
|
||||
for scope in scopes {
|
||||
cloudKitSync?.queueChannelNotificationSettingsDelete(channelID: channelID, scope: scope)
|
||||
}
|
||||
} catch {
|
||||
LoggingService.shared.logCloudKitError("Failed to delete notification settings", error: error)
|
||||
}
|
||||
}
|
||||
|
||||
/// Inserts or updates notification settings from CloudKit sync.
|
||||
/// - Parameter settings: The notification settings to upsert.
|
||||
func upsertChannelNotificationSettings(_ settings: ChannelNotificationSettings) {
|
||||
|
||||
@@ -43,61 +43,6 @@ extension DataManager {
|
||||
}
|
||||
}
|
||||
|
||||
/// Subscribes to a channel from an Author.
|
||||
/// - Parameters:
|
||||
/// - author: The author/channel to subscribe to.
|
||||
/// - source: The content source (YouTube or PeerTube).
|
||||
func subscribe(to author: Author, source: ContentSource) {
|
||||
let channelID = author.id
|
||||
let descriptor = FetchDescriptor<Subscription>(
|
||||
predicate: #Predicate { $0.channelID == channelID }
|
||||
)
|
||||
|
||||
do {
|
||||
let existing = try modelContext.fetch(descriptor)
|
||||
guard existing.isEmpty else {
|
||||
return
|
||||
}
|
||||
|
||||
let sourceRaw: String
|
||||
var instanceURL: String?
|
||||
|
||||
switch source {
|
||||
case .global:
|
||||
sourceRaw = "global"
|
||||
case .federated(_, let instance):
|
||||
sourceRaw = "federated"
|
||||
instanceURL = instance.absoluteString
|
||||
case .extracted:
|
||||
// Extracted sources don't support subscriptions
|
||||
return
|
||||
}
|
||||
|
||||
let subscription = Subscription(
|
||||
channelID: channelID,
|
||||
sourceRawValue: sourceRaw,
|
||||
instanceURLString: instanceURL,
|
||||
name: author.name,
|
||||
subscriberCount: author.subscriberCount,
|
||||
avatarURLString: author.thumbnailURL?.absoluteString
|
||||
)
|
||||
modelContext.insert(subscription)
|
||||
save()
|
||||
|
||||
// Queue for CloudKit sync
|
||||
cloudKitSync?.queueSubscriptionSave(subscription)
|
||||
|
||||
let change = SubscriptionChange(addedSubscriptions: [subscription], removedChannelIDs: [])
|
||||
NotificationCenter.default.post(
|
||||
name: .subscriptionsDidChange,
|
||||
object: nil,
|
||||
userInfo: [SubscriptionChange.userInfoKey: change]
|
||||
)
|
||||
} catch {
|
||||
LoggingService.shared.logCloudKitError("Failed to subscribe", error: error)
|
||||
}
|
||||
}
|
||||
|
||||
/// Unsubscribes from a channel.
|
||||
func unsubscribe(from channelID: String) {
|
||||
let descriptor = FetchDescriptor<Subscription>(
|
||||
@@ -137,42 +82,6 @@ extension DataManager {
|
||||
}
|
||||
}
|
||||
|
||||
/// Bulk adds subscriptions from channel data (for testing).
|
||||
func bulkAddSubscriptions(_ channels: [(id: String, name: String)]) {
|
||||
var addedCount = 0
|
||||
|
||||
for channel in channels {
|
||||
let channelID = channel.id
|
||||
let descriptor = FetchDescriptor<Subscription>(
|
||||
predicate: #Predicate { $0.channelID == channelID }
|
||||
)
|
||||
|
||||
do {
|
||||
let existing = try modelContext.fetch(descriptor)
|
||||
guard existing.isEmpty else {
|
||||
continue
|
||||
}
|
||||
|
||||
let subscription = Subscription(
|
||||
channelID: channel.id,
|
||||
sourceRawValue: "youtube",
|
||||
instanceURLString: nil,
|
||||
name: channel.name
|
||||
)
|
||||
modelContext.insert(subscription)
|
||||
addedCount += 1
|
||||
} catch {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if addedCount > 0 {
|
||||
save()
|
||||
SubscriptionFeedCache.shared.invalidate()
|
||||
LoggingService.shared.info("Bulk added \(addedCount) subscriptions", category: .general)
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if subscribed to a channel.
|
||||
func isSubscribed(to channelID: String) -> Bool {
|
||||
let descriptor = FetchDescriptor<Subscription>(
|
||||
@@ -257,40 +166,6 @@ extension DataManager {
|
||||
// Note: caller is responsible for calling save() after batch operations
|
||||
}
|
||||
|
||||
/// Removes subscriptions matching the given channel IDs.
|
||||
func removeSubscriptions(matching channelIDs: Set<String>) {
|
||||
let allSubscriptions = subscriptions()
|
||||
var removedCount = 0
|
||||
var deleteInfo: [(channelID: String, scope: SourceScope)] = []
|
||||
|
||||
for subscription in allSubscriptions {
|
||||
if channelIDs.contains(subscription.channelID) {
|
||||
// Capture scope before deleting
|
||||
let scope = SourceScope.from(
|
||||
sourceRawValue: subscription.sourceRawValue,
|
||||
globalProvider: subscription.providerName,
|
||||
instanceURLString: subscription.instanceURLString,
|
||||
externalExtractor: nil
|
||||
)
|
||||
deleteInfo.append((subscription.channelID, scope))
|
||||
modelContext.delete(subscription)
|
||||
removedCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
if removedCount > 0 {
|
||||
save()
|
||||
|
||||
// Queue CloudKit deletions
|
||||
for info in deleteInfo {
|
||||
cloudKitSync?.queueSubscriptionDelete(channelID: info.channelID, scope: info.scope)
|
||||
}
|
||||
|
||||
SubscriptionFeedCache.shared.invalidate()
|
||||
LoggingService.shared.info("Removed \(removedCount) test subscriptions", category: .general)
|
||||
}
|
||||
}
|
||||
|
||||
/// Deletes all locally stored subscriptions, including their iCloud copies.
|
||||
/// Server-account subscriptions (Invidious/Piped) are unaffected.
|
||||
func deleteAllSubscriptions() {
|
||||
|
||||
@@ -40,8 +40,4 @@ struct SubscriptionChange {
|
||||
let removedChannelIDs: [String]
|
||||
|
||||
static let userInfoKey = "subscriptionChange"
|
||||
|
||||
var isEmpty: Bool {
|
||||
addedSubscriptions.isEmpty && removedChannelIDs.isEmpty
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,20 +149,6 @@ final class WatchEntry {
|
||||
return min(watchedSeconds / duration, 1.0)
|
||||
}
|
||||
|
||||
/// Formatted total duration.
|
||||
var formattedDuration: String {
|
||||
guard duration > 0 else { return "" }
|
||||
let hours = Int(duration) / 3600
|
||||
let minutes = (Int(duration) % 3600) / 60
|
||||
let seconds = Int(duration) % 60
|
||||
|
||||
if hours > 0 {
|
||||
return String(format: "%d:%02d:%02d", hours, minutes, seconds)
|
||||
} else {
|
||||
return String(format: "%d:%02d", minutes, seconds)
|
||||
}
|
||||
}
|
||||
|
||||
/// Formatted remaining time.
|
||||
var remainingTime: String {
|
||||
let remaining = max(0, duration - watchedSeconds)
|
||||
|
||||
Reference in New Issue
Block a user