Add support for credits section

This commit is contained in:
Ira Limitanei 2026-01-19 16:36:02 +09:00
parent 5c37730483
commit 4ec1ac3769
Signed by: lambdaclan
GPG Key ID: 43D6A575B03B80E4
3 changed files with 117 additions and 4 deletions

View File

@ -11,6 +11,40 @@ import Foundation
/// URL links for about dialog.
public typealias AboutLink = (title: String, url: URL?)
/// The type of contribution made by a credited person.
public enum ContributionRole {
/// A person who contributed to development.
case developer
/// A person who contributed to design.
case designer
/// A person who contributed artwork or visuals.
case artist
/// A person who contributed translations.
case translator
}
/// A credited person and their contribution role.
public struct CreditEntry {
/// The contributor's role.
public var role: ContributionRole
/// The contributor's name.
public var name: String
/// Create a new credit entry.
/// - Parameters:
/// - role: The contributor's role.
/// - name: The contributor's name.
public init(role: ContributionRole, name: String) {
self.role = role
self.name = name
}
}
/// Initialization options for the about dialog wrapper.
public struct AdwaitaAboutDialogConfig {
@ -89,10 +123,12 @@ public struct AdwaitaAboutDialogConfig {
public var copyright: String?
/// The app's license.
public var license: String?
/// The app's release notes
/// The app's release notes.
public var releaseNotes: String?
/// The comments about the application
/// The comments about the application.
public var comments: String?
/// Recognition by name and role of contributors.
public var credits: [CreditEntry]?
/// Initialize the about dialog wrapper.
/// - Parameters:
@ -108,6 +144,7 @@ public struct AdwaitaAboutDialogConfig {
/// - license: The app's license.
/// - releaseNotes: The app's release notes.
/// - comments: The comments about the application.
/// - credits: Recognition by name and role of contributors.
public init(
appName: String? = nil,
developer: String? = nil,
@ -120,7 +157,8 @@ public struct AdwaitaAboutDialogConfig {
copyright: String? = nil,
license: String? = nil,
releaseNotes: String? = nil,
comments: String? = nil
comments: String? = nil,
credits: [CreditEntry]? = nil
) {
self.appName = appName
self.developer = developer
@ -134,6 +172,48 @@ public struct AdwaitaAboutDialogConfig {
self.license = license
self.releaseNotes = releaseNotes
self.comments = comments
self.credits = credits
}
/// Apply the credit entries to the given dialog.
/// - Parameters:
/// - credits: The list of credit entries to apply.
/// - dialog: The underlying Adwaita dialog instance to update with the credit information.
private func applyCredits(_ credits: [CreditEntry], to dialog: OpaquePointer) {
var developers: [String] = []
var designers: [String] = []
var artists: [String] = []
var translators: [String] = []
for entry in credits {
switch entry.role {
case .developer:
developers.append(entry.name)
case .designer:
designers.append(entry.name)
case .artist:
artists.append(entry.name)
case .translator:
translators.append(entry.name)
}
}
if let ptr = developers.cMutableArray, !developers.isEmpty {
adw_about_dialog_set_developers(dialog, ptr)
}
if let ptr = designers.cMutableArray, !designers.isEmpty {
adw_about_dialog_set_designers(dialog, ptr)
}
if let ptr = artists.cMutableArray, !artists.isEmpty {
adw_about_dialog_set_artists(dialog, ptr)
}
if !translators.isEmpty {
let joined = translators.joined(separator: "\n")
adw_about_dialog_set_translator_credits(dialog, joined)
}
}
/// Apply the configuration values to the given dialog.
@ -159,6 +239,10 @@ public struct AdwaitaAboutDialogConfig {
}
links?.forEach { (title: String, url: URL?) in adw_about_dialog_add_link(dialog, title, url?.absoluteString) }
if let credits {
applyCredits(credits, to: dialog)
}
}
}

View File

@ -5,11 +5,13 @@
// Created by david-swift on 06.08.23.
//
import Foundation
extension Array where Element == String {
/// Get the C version of the array.
var cArray: UnsafePointer<UnsafePointer<CChar>?>? {
let cStrings = self.map { $0.utf8CString }
let cStrings = map { $0.utf8CString }
let cStringPointers = cStrings.map { $0.withUnsafeBufferPointer { $0.baseAddress } }
let optionalCStringPointers = cStringPointers + [nil]
var optionalCStringPointersCopy = optionalCStringPointers
@ -25,4 +27,23 @@ extension Array where Element == String {
return UnsafePointer(pointer)
}
/// Get the mutable C version of the array.
var cMutableArray: UnsafeMutablePointer<UnsafePointer<CChar>?>? {
// Allocate space for N strings + NULL terminator
let pointer = UnsafeMutablePointer<UnsafePointer<CChar>?>.allocate(
capacity: count + 1
)
// Convert each Swift string into a stable C string
for (index, string) in enumerated() {
let cstr = strdup(string) // allocate real C string
pointer[index] = UnsafePointer(cstr)
}
// Add NULL terminator
pointer[count] = nil
return pointer
}
}

View File

@ -166,6 +166,14 @@ struct Demo: App {
cfg.license = "MIT"
cfg.releaseNotes = AdwaitaAboutDialogConfig.demoReleaseNotes
cfg.comments = AdwaitaAboutDialogConfig.demoComments
cfg.credits = [
.init(role: .developer, name: "Jane Doe"),
.init(role: .developer, name: "John Roe"),
.init(role: .designer, name: "Mika Sato"),
.init(role: .artist, name: "Leo Martins"),
.init(role: .translator, name: "Yuki Nakamura"),
.init(role: .translator, name: "Tod Brown")
]
}
.preferencesDialog(visible: $preferences)
.preferencesPage("Page 1", icon: .default(icon: .audioHeadset)) { page in