mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Custom Notification Tones (#5527)
* added foundation for custom notifications * feat: add localizations for tone names also, if available, include the pro sound in the element x sound list * use a static file location to store the notification tone and update the file at that location when selected * if there's a problem previewing or setting the alert tone, toast the user with the error * rename tone directory * create NotificationToneManager to handle tone business logic * conform to project formatting * assign custom sound to actual notifications * dry up notification generation in the nse * add compilation condition for including notification alert tone and remove from share extension * swift format had some opinions * flatten the notification tone ui, removing system/elementx designations * fix stored file url breaking due to sandbox path changes * tone manager can import custom tones and provide a list of imported tones * ui support for custom tones * can delete custom imported tones * sort the custom tones * add additional preset sounds * can choose caf files for custom sounds and fix location persistence issues * store sound locations with relative links this is a better solution than storing bookmarks since bookmark resolution can be variable and differ from freshly derived urls * add docs for new notification features * run tone conversion in background * resolved several ai found issues * added protocol and mocks for notification tone manager * added tests for notification settings screen vm interactions with the tone manager * add tests for notification tone manager * rename element tone names per feedback * move custom tone option to the top of the notification tone list * rename Tone to Sound for consistency with Android * remove additional bundled tones * restore accidentally deleted Element Default sound file * system alert tones are filtered by what's available on the system prior to finalizing the collection * Add a couple more caf file conversion log statements * Simplify the notification sound conversion logic * Update notification sound strings in sync with Android * update xcodeproj after rebase * remove conditional compilation and include NotificationAlertSound in share extension * Use AudioPlayer instead of custom tone previewer and remove the previewer * rename NotificationTone * Consolidate and move errors to top of NotificationToneManager * tone manager no longer depends on userinterfacecontroller * Move static Tone properties to NotificationToneManager * resolve view model initializer feedback * update xcodeproj * fatalerror when tone manager cannot init * Remove banner icon on alert tone error * fixup review feedback * Moved URL handling to NotificationToneManager
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Represents a notification alert tone and its backing audio file location.
|
||||
struct NotificationTone: Hashable, Comparable, Codable {
|
||||
/// Display name for the tone, falling back to the filename stem.
|
||||
var label: String {
|
||||
labelOverride ?? URL(filePath: "/\(relativePath.last, default: "")").deletingPathExtension().lastPathComponent
|
||||
}
|
||||
|
||||
private let labelOverride: String?
|
||||
let storageLocationRoot: StorageLocation
|
||||
let relativePath: [String]
|
||||
|
||||
/// The audio filename including its extension.
|
||||
var filename: String {
|
||||
relativePath.last ?? ""
|
||||
}
|
||||
|
||||
/// - Parameters:
|
||||
/// - labelOverride: Optional custom display name. If `nil`, the filename stem is used.
|
||||
/// - storageLocationRoot: Where the file lives (system, bundle, or library).
|
||||
/// - relativePath: Path components relative to the storage root, e.g. `["New", "Bloom.caf"]`.
|
||||
init(labelOverride: String?, storageLocationRoot: StorageLocation, relativePath: [String]) {
|
||||
self.labelOverride = labelOverride
|
||||
self.storageLocationRoot = storageLocationRoot
|
||||
self.relativePath = relativePath
|
||||
}
|
||||
|
||||
/// Indicates which storage root backs the tone's audio file.
|
||||
enum StorageLocation: Codable, Hashable {
|
||||
/// The device's system sounds directory.
|
||||
case system
|
||||
/// The app's main bundle resources.
|
||||
case appBundle
|
||||
/// The app's Library directory (user-imported tones).
|
||||
case appLibrary
|
||||
}
|
||||
|
||||
/// Creates a tone backed by a file in the system sounds directory.
|
||||
static func createSystemSound(label: String?, filename: String, systemSoundsSubdirectory: [String] = []) -> NotificationTone {
|
||||
NotificationTone(labelOverride: label, storageLocationRoot: .system, relativePath: systemSoundsSubdirectory + [filename])
|
||||
}
|
||||
|
||||
/// Creates a tone backed by a file in the app bundle.
|
||||
static func createBundledSound(label: String?, filename: String) -> NotificationTone {
|
||||
NotificationTone(labelOverride: label, storageLocationRoot: .appBundle, relativePath: [filename])
|
||||
}
|
||||
|
||||
/// Creates a tone backed by a user-imported file in the app library.
|
||||
static func createCustomUserSound(filename: String) -> NotificationTone {
|
||||
NotificationTone(labelOverride: nil, storageLocationRoot: .appLibrary, relativePath: [filename])
|
||||
}
|
||||
|
||||
static func < (lhs: NotificationTone, rhs: NotificationTone) -> Bool {
|
||||
lhs.label < rhs.label
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user