Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 50 additions & 36 deletions Keychy/WidgetKeychy/AppIntent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,28 @@
// AppIntent.swift
// WidgetKeychy
//
// 위젯 키링/뭉치 선택 Intent
// 위젯 표시 유형/항목 선택 Intent
//

import WidgetKit
import AppIntents

// MARK: - 표시 유형 (키링 / 뭉치)

enum DisplayType: String, AppEnum {
case keyring = "keyring"
case bundle = "bundle"

static var typeDisplayRepresentation: TypeDisplayRepresentation = "표시 유형"

static var caseDisplayRepresentations: [DisplayType: DisplayRepresentation] = [
.keyring: "키링",
.bundle: "뭉치"
]
}

// MARK: - Keyring Entity

/// 위젯에서 선택 가능한 키링
struct KeyringEntity: AppEntity {
let id: String
let name: String
Expand All @@ -24,33 +37,26 @@ struct KeyringEntity: AppEntity {
static var defaultQuery = KeyringEntityQuery()
}

// MARK: - Keyring Entity Query

/// App Group에서 키링 목록 조회
struct KeyringEntityQuery: EntityQuery {
/// ID로 키링 찾기 (위젯 복원 시 사용)
func entities(for identifiers: [String]) async throws -> [KeyringEntity] {
let widgetKeyrings = KeyringImageCache.shared.loadWidgetKeyrings()
return widgetKeyrings
.filter { identifiers.contains($0.id) }
.map { KeyringEntity(id: $0.id, name: $0.name) }
let keyrings = KeyringImageCache.shared.loadWidgetKeyrings()
return identifiers.compactMap { id in
keyrings.first(where: { $0.id == id })
.map { KeyringEntity(id: $0.id, name: $0.name) }
}
}

/// 선택 가능한 키링 목록 (최신순)
func suggestedEntities() async throws -> [KeyringEntity] {
let widgetKeyrings = KeyringImageCache.shared.loadWidgetKeyrings()
KeyringImageCache.shared.loadWidgetKeyrings()
.sorted { $0.createdAt > $1.createdAt }
return widgetKeyrings.map { KeyringEntity(id: $0.id, name: $0.name) }
.map { KeyringEntity(id: $0.id, name: $0.name) }
}

func defaultResult() async -> KeyringEntity? {
nil
}
func defaultResult() async -> KeyringEntity? { nil }
}

// MARK: - Bundle Entity

/// 위젯에서 선택 가능한 뭉치
struct BundleEntity: AppEntity {
let id: String
let name: String
Expand All @@ -64,40 +70,48 @@ struct BundleEntity: AppEntity {
static var defaultQuery = BundleEntityQuery()
}

// MARK: - Bundle Entity Query

/// App Group에서 뭉치 목록 조회
struct BundleEntityQuery: EntityQuery {
/// ID로 뭉치 찾기 (위젯 복원 시 사용)
func entities(for identifiers: [String]) async throws -> [BundleEntity] {
let widgetBundles = BundleImageCache.shared.loadWidgetBundleModels()
return widgetBundles
.filter { identifiers.contains($0.id) }
.map { BundleEntity(id: $0.id, name: $0.name) }
let bundles = BundleImageCache.shared.loadWidgetBundleModels()
return identifiers.compactMap { id in
bundles.first(where: { $0.id == id })
.map { BundleEntity(id: $0.id, name: $0.name) }
}
}

/// 선택 가능한 뭉치 목록 (최신순)
func suggestedEntities() async throws -> [BundleEntity] {
let widgetBundles = BundleImageCache.shared.loadWidgetBundleModels()
BundleImageCache.shared.loadWidgetBundleModels()
.sorted { $0.createdAt > $1.createdAt }
return widgetBundles.map { BundleEntity(id: $0.id, name: $0.name) }
.map { BundleEntity(id: $0.id, name: $0.name) }
}

func defaultResult() async -> BundleEntity? {
nil
}
func defaultResult() async -> BundleEntity? { nil }
}

// MARK: - Selection Intent

/// 위젯 키링/뭉치 선택 인텐트
struct KeyringSelectionIntent: WidgetConfigurationIntent {
static var title: LocalizedStringResource { "키링/뭉치 선택" }
static var description: IntentDescription { "위젯에 표시할 키링 또는 뭉치를 선택하세요" }
static var title: LocalizedStringResource { "위젯 설정" }
static var description: IntentDescription { "위젯에 표시할 유형과 항목을 선택하세요" }

@Parameter(title: "표시 유형", default: .keyring)
var displayType: DisplayType

@Parameter(title: "키링")
@Parameter(title: "키링 선택")
var selectedKeyring: KeyringEntity?

@Parameter(title: "뭉치")
@Parameter(title: "뭉치 선택")
var selectedBundle: BundleEntity?

static var parameterSummary: some ParameterSummary {
When(\KeyringSelectionIntent.$displayType, .equalTo, .keyring) {
Summary("표시 유형: \(\.$displayType)") {
\.$selectedKeyring
}
} otherwise: {
Summary("표시 유형: \(\.$displayType)") {
\.$selectedBundle
}
}
}
}
41 changes: 21 additions & 20 deletions Keychy/WidgetKeychy/WidgetKeychy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ struct WidgetKeychy: Widget {
.containerBackground(.clear, for: .widget)
}
.configurationDisplayName("Keychy 위젯")
.description("위젯에 표시될 키링 또는 뭉치를 골라주세요")
.description("위젯에 표시할 유형을 선택한 후, 항목을 골라주세요.")
.contentMarginsDisabled()
.supportedFamilies([.systemSmall, .systemLarge])
}
Expand All @@ -57,25 +57,26 @@ struct KeyringWidgetEntryView: View {
@Environment(\.widgetFamily) var widgetFamily

var body: some View {
// 뭉치가 선택된 경우 뭉치 표시
if let bundle = entry.configuration.selectedBundle,
let uiImage = loadBundleImage(bundleId: bundle.id) {
Image(uiImage: uiImage)
.resizable()
.scaledToFit()
.scaleEffect(0.85) // 뭉치 약간 작게
}
// 키링이 선택된 경우 키링 표시
else if let keyring = entry.configuration.selectedKeyring,
let uiImage = loadKeyringImage(keyringId: keyring.id) {
Image(uiImage: uiImage)
.resizable()
.scaledToFit()
// 키링 기본 크기
}
// 아무것도 선택되지 않은 경우 placeholder
else {
placeholderView
switch entry.configuration.displayType {
case .keyring:
if let keyring = entry.configuration.selectedKeyring,
let uiImage = loadKeyringImage(keyringId: keyring.id) {
Image(uiImage: uiImage)
.resizable()
.scaledToFit()
} else {
placeholderView
}
case .bundle:
if let bundle = entry.configuration.selectedBundle,
let uiImage = loadBundleImage(bundleId: bundle.id) {
Image(uiImage: uiImage)
.resizable()
.scaledToFit()
.scaleEffect(0.85)
} else {
placeholderView
}
}
}

Expand Down