diff --git a/IntentsExtension/IntentHandler.swift b/IntentsExtension/IntentHandler.swift index 542cb467..4e4f5c27 100644 --- a/IntentsExtension/IntentHandler.swift +++ b/IntentsExtension/IntentHandler.swift @@ -15,5 +15,26 @@ class IntentHandler: INExtension { return self } +} + +extension IntentHandler: MyCardIntentHandling { + func provideMyCardOptionsCollection(for intent: MyCardIntent, with completion: @escaping (INObjectCollection?, Error?) -> Void) { + // TODO: - 서버 통신 혹은 DB 에서 선택 목록 가져온다. + let myCards: [MyCard] = Card.mockData.map { card in + let myCard = MyCard(identifier: card.cardID, display: card.title) + + return myCard + } + let collection = INObjectCollection(items: myCards) + + completion(collection, nil) + } + func defaultMyCard(for intent: MyCardIntent) -> MyCard? { + // TODO: - 내 명함이 존재하면 첫 번째 명함을 기본값으로 설정. 존재하지 않다면 nil 반환. + let myCard = MyCard(identifier: Card.mockData[0].cardID, + display: Card.mockData[0].title) + + return myCard + } } diff --git a/NADA-iOS-forRelease.xcodeproj/project.pbxproj b/NADA-iOS-forRelease.xcodeproj/project.pbxproj index efe59940..e690bc2b 100644 --- a/NADA-iOS-forRelease.xcodeproj/project.pbxproj +++ b/NADA-iOS-forRelease.xcodeproj/project.pbxproj @@ -101,6 +101,8 @@ F80975EA2990A27900075B93 /* Widgets.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = F838B66A298E5C5300D84340 /* Widgets.intentdefinition */; }; F811720027383097002742CF /* ChangeGroupRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = F81171FF27383097002742CF /* ChangeGroupRequest.swift */; }; F822E7A92709CEB60020452C /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = F822E7A82709CEB60020452C /* Notification.swift */; }; + F8257750299546920067E145 /* Card.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87122752733046300A24E74 /* Card.swift */; }; + F8257751299546930067E145 /* Card.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87122752733046300A24E74 /* Card.swift */; }; F8268DB927730B0100BF114B /* FirstCardAlertBottomSheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8268DB827730B0100BF114B /* FirstCardAlertBottomSheetViewController.swift */; }; F82FEB4C27639F3100DA7847 /* MainCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F82FEB4A27639F3100DA7847 /* MainCardCell.swift */; }; F82FEB4D27639F3100DA7847 /* MainCardCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F82FEB4B27639F3100DA7847 /* MainCardCell.xib */; }; @@ -1465,6 +1467,7 @@ F8BCDD25298FFAF90044D0B4 /* WidgetsBundle.swift in Sources */, F8BCDD22298FFA830044D0B4 /* QRCodeWidget.swift in Sources */, F8BCDD26298FFB0B0044D0B4 /* MyCardWidget.swift in Sources */, + F8257750299546920067E145 /* Card.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1473,6 +1476,7 @@ buildActionMask = 2147483647; files = ( F80975E92990A27400075B93 /* Widgets.intentdefinition in Sources */, + F8257751299546930067E145 /* Card.swift in Sources */, F87D222D298ECAFB001A882B /* IntentHandler.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/NADA-iOS-forRelease/Sources/NetworkModel/Card/Card.swift b/NADA-iOS-forRelease/Sources/NetworkModel/Card/Card.swift index f8dfb582..0e387416 100644 --- a/NADA-iOS-forRelease/Sources/NetworkModel/Card/Card.swift +++ b/NADA-iOS-forRelease/Sources/NetworkModel/Card/Card.swift @@ -47,4 +47,10 @@ struct Card: Codable { // twoTmi = (try? values.decode(String.self, forKey: .twoTmi)) // threeTmi = (try? values.decode(String.self, forKey: .threeTmi)) // } + + static let mockData = [ + Card(cardID: "id1", background: "imgCardBg01", title: "첫 번째 카드", name: "1현규", birthDate: "", mbti: "", instagram: "", link: "", cardDescription: "", phoneNumber: "", isMincho: true, isSoju: true, isBoomuk: true, isSauced: true, oneTmi: "", twoTmi: "", threeTmi: ""), + Card(cardID: "id2", background: "imgCardBg02", title: "두 번째 카드", name: "2현규", birthDate: "", mbti: "", instagram: "", link: "", cardDescription: "", phoneNumber: "", isMincho: true, isSoju: true, isBoomuk: true, isSauced: true, oneTmi: "", twoTmi: "", threeTmi: ""), + Card(cardID: "id3", background: "imgCardBg03", title: "세 번째 카드", name: "3현규", birthDate: "", mbti: "", instagram: "", link: "", cardDescription: "", phoneNumber: "", isMincho: true, isSoju: true, isBoomuk: true, isSauced: true, oneTmi: "", twoTmi: "", threeTmi: "") + ] } diff --git a/Widgets/Resource/Assets.xcassets/imgCardBg01.imageset/Contents.json b/Widgets/Resource/Assets.xcassets/imgCardBg01.imageset/Contents.json new file mode 100644 index 00000000..211a708e --- /dev/null +++ b/Widgets/Resource/Assets.xcassets/imgCardBg01.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "스크린샷 2023-02-18 오전 1.16.55.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "스크린샷 2023-02-18 오전 1.16.55 1.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "스크린샷 2023-02-18 오전 1.16.55 2.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/Widgets/Resource/Assets.xcassets/imgCardBg01.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.16.55 1.png" "b/Widgets/Resource/Assets.xcassets/imgCardBg01.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.16.55 1.png" new file mode 100644 index 00000000..d1ff1434 Binary files /dev/null and "b/Widgets/Resource/Assets.xcassets/imgCardBg01.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.16.55 1.png" differ diff --git "a/Widgets/Resource/Assets.xcassets/imgCardBg01.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.16.55 2.png" "b/Widgets/Resource/Assets.xcassets/imgCardBg01.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.16.55 2.png" new file mode 100644 index 00000000..d1ff1434 Binary files /dev/null and "b/Widgets/Resource/Assets.xcassets/imgCardBg01.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.16.55 2.png" differ diff --git "a/Widgets/Resource/Assets.xcassets/imgCardBg01.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.16.55.png" "b/Widgets/Resource/Assets.xcassets/imgCardBg01.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.16.55.png" new file mode 100644 index 00000000..d1ff1434 Binary files /dev/null and "b/Widgets/Resource/Assets.xcassets/imgCardBg01.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.16.55.png" differ diff --git a/Widgets/Resource/Assets.xcassets/imgCardBg02.imageset/Contents.json b/Widgets/Resource/Assets.xcassets/imgCardBg02.imageset/Contents.json new file mode 100644 index 00000000..d88be5e8 --- /dev/null +++ b/Widgets/Resource/Assets.xcassets/imgCardBg02.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "스크린샷 2023-02-18 오전 1.17.11.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "스크린샷 2023-02-18 오전 1.17.11 1.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "스크린샷 2023-02-18 오전 1.17.11 2.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/Widgets/Resource/Assets.xcassets/imgCardBg02.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.17.11 1.png" "b/Widgets/Resource/Assets.xcassets/imgCardBg02.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.17.11 1.png" new file mode 100644 index 00000000..0077ddfc Binary files /dev/null and "b/Widgets/Resource/Assets.xcassets/imgCardBg02.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.17.11 1.png" differ diff --git "a/Widgets/Resource/Assets.xcassets/imgCardBg02.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.17.11 2.png" "b/Widgets/Resource/Assets.xcassets/imgCardBg02.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.17.11 2.png" new file mode 100644 index 00000000..0077ddfc Binary files /dev/null and "b/Widgets/Resource/Assets.xcassets/imgCardBg02.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.17.11 2.png" differ diff --git "a/Widgets/Resource/Assets.xcassets/imgCardBg02.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.17.11.png" "b/Widgets/Resource/Assets.xcassets/imgCardBg02.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.17.11.png" new file mode 100644 index 00000000..0077ddfc Binary files /dev/null and "b/Widgets/Resource/Assets.xcassets/imgCardBg02.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.17.11.png" differ diff --git a/Widgets/Resource/Assets.xcassets/imgCardBg03.imageset/Contents.json b/Widgets/Resource/Assets.xcassets/imgCardBg03.imageset/Contents.json new file mode 100644 index 00000000..e31dae7c --- /dev/null +++ b/Widgets/Resource/Assets.xcassets/imgCardBg03.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "스크린샷 2023-02-18 오전 1.17.21 2.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "스크린샷 2023-02-18 오전 1.17.21 1.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "스크린샷 2023-02-18 오전 1.17.21.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/Widgets/Resource/Assets.xcassets/imgCardBg03.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.17.21 1.png" "b/Widgets/Resource/Assets.xcassets/imgCardBg03.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.17.21 1.png" new file mode 100644 index 00000000..a3a330b4 Binary files /dev/null and "b/Widgets/Resource/Assets.xcassets/imgCardBg03.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.17.21 1.png" differ diff --git "a/Widgets/Resource/Assets.xcassets/imgCardBg03.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.17.21 2.png" "b/Widgets/Resource/Assets.xcassets/imgCardBg03.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.17.21 2.png" new file mode 100644 index 00000000..a3a330b4 Binary files /dev/null and "b/Widgets/Resource/Assets.xcassets/imgCardBg03.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.17.21 2.png" differ diff --git "a/Widgets/Resource/Assets.xcassets/imgCardBg03.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.17.21.png" "b/Widgets/Resource/Assets.xcassets/imgCardBg03.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.17.21.png" new file mode 100644 index 00000000..a3a330b4 Binary files /dev/null and "b/Widgets/Resource/Assets.xcassets/imgCardBg03.imageset/\354\212\244\355\201\254\353\246\260\354\203\267 2023-02-18 \354\230\244\354\240\204 1.17.21.png" differ diff --git a/Widgets/Resource/Assets.xcassets/widgetEmpty.imageset/Contents.json b/Widgets/Resource/Assets.xcassets/widgetEmpty.imageset/Contents.json new file mode 100644 index 00000000..cfefd211 --- /dev/null +++ b/Widgets/Resource/Assets.xcassets/widgetEmpty.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "widgetEmpty.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "widgetEmpty@2x.png" + }, + { + "filename" : "widgetEmpty@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Widgets/Resource/Assets.xcassets/widgetEmpty.imageset/widgetEmpty.png b/Widgets/Resource/Assets.xcassets/widgetEmpty.imageset/widgetEmpty.png new file mode 100644 index 00000000..6e0f1bae Binary files /dev/null and b/Widgets/Resource/Assets.xcassets/widgetEmpty.imageset/widgetEmpty.png differ diff --git a/Widgets/Resource/Assets.xcassets/widgetEmpty.imageset/widgetEmpty@2x.png b/Widgets/Resource/Assets.xcassets/widgetEmpty.imageset/widgetEmpty@2x.png new file mode 100644 index 00000000..6d855304 Binary files /dev/null and b/Widgets/Resource/Assets.xcassets/widgetEmpty.imageset/widgetEmpty@2x.png differ diff --git a/Widgets/Resource/Assets.xcassets/widgetEmpty.imageset/widgetEmpty@3x.png b/Widgets/Resource/Assets.xcassets/widgetEmpty.imageset/widgetEmpty@3x.png new file mode 100644 index 00000000..17ea084e Binary files /dev/null and b/Widgets/Resource/Assets.xcassets/widgetEmpty.imageset/widgetEmpty@3x.png differ diff --git a/Widgets/Resource/Widgets.intentdefinition b/Widgets/Resource/Widgets.intentdefinition index 78da667f..bc07e3c3 100644 --- a/Widgets/Resource/Widgets.intentdefinition +++ b/Widgets/Resource/Widgets.intentdefinition @@ -103,7 +103,7 @@ INTypeDisplayNameID J1deG2 INTypeLastPropertyTag - 100 + 101 INTypeName MyCard INTypeProperties @@ -158,20 +158,6 @@ INTypePropertyType SpeakableString - - INTypePropertyDisplayName - Card ID - INTypePropertyDisplayNameID - aRJ51O - INTypePropertyDisplayPriority - 5 - INTypePropertyName - cardID - INTypePropertyTag - 100 - INTypePropertyType - String - diff --git a/Widgets/WidgetsBundle/MyCardWidget.swift b/Widgets/WidgetsBundle/MyCardWidget.swift index c2c0ae43..d44d3937 100644 --- a/Widgets/WidgetsBundle/MyCardWidget.swift +++ b/Widgets/WidgetsBundle/MyCardWidget.swift @@ -11,58 +11,151 @@ import Intents struct MyCardProvider: IntentTimelineProvider { func placeholder(in context: Context) -> MyCardEntry { - MyCardEntry(date: Date(), configuration: MyCardIntent()) + MyCardEntry(date: Date(), widgetCard: WidgetCard(cardID: "", title: "일이삼사오육칠팔구", userName: "일이삼사오육", backgroundImage: UIImage())) } func getSnapshot(for configuration: MyCardIntent, in context: Context, completion: @escaping (MyCardEntry) -> Void) { - let entry = MyCardEntry(date: Date(), configuration: configuration) + let entry: MyCardEntry + + if let cardID = configuration.myCard?.identifier, + let card = fetchMyCard(with: cardID) { + entry = MyCardEntry(date: Date(), widgetCard: WidgetCard(cardID: card.cardID, + title: card.title, + userName: card.name, + // TODO: - image 를 통신하거나 DB 에서 꺼내오는 작업이 필요하다. + backgroundImage: UIImage(named: card.background) ?? UIImage())) + } else { + entry = MyCardEntry(date: Date(), widgetCard: nil) + } + completion(entry) } func getTimeline(for configuration: MyCardIntent, in context: Context, completion: @escaping (Timeline) -> Void) { var entries: [MyCardEntry] = [] - // Generate a timeline consisting of five entries an hour apart, starting from the current date. let currentDate = Date() - for hourOffset in 0 ..< 5 { - let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! - let entry = MyCardEntry(date: entryDate, configuration: configuration) - entries.append(entry) + + if let cardID = configuration.myCard?.identifier, + let card = fetchMyCard(with: cardID) { + for hourOffset in 0 ..< 5 { + let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate) ?? Date() + let entry = MyCardEntry(date: entryDate, widgetCard: WidgetCard(cardID: card.cardID, + title: card.title, + userName: card.name, + // TODO: - image 를 통신하거나 DB 에서 꺼내오는 작업이 필요하다. + backgroundImage: UIImage(named: card.background) ?? UIImage())) + entries.append(entry) + } + } else { + for hourOffset in 0 ..< 5 { + let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate) ?? Date() + entries.append(MyCardEntry(date: entryDate, widgetCard: nil)) + } } - let timeline = Timeline(entries: entries, policy: .atEnd) + completion(timeline) } } +extension MyCardProvider { + // TODO: - 서버 혹은 DB 를 활용하여 내 명함을 조회하는 함수로 변경. + private func fetchMyCard(with cardID: String) -> Card? { + var matchedCard: Card? + + Card.mockData.forEach { card in + if card.cardID == cardID { + matchedCard = card + } + } + + return matchedCard + } +} + +struct WidgetCard { + let cardID: String + let title: String + let userName: String + let backgroundImage: UIImage +} + struct MyCardEntry: TimelineEntry { let date: Date - let configuration: MyCardIntent + let widgetCard: WidgetCard? } struct MyCardEntryView: View { var entry: MyCardProvider.Entry + @Environment(\.colorScheme) var colorScheme + var body: some View { - Text(entry.date, style: .time) + if let widgetCard = entry.widgetCard { + ZStack { + Color.white + GeometryReader { proxy in + HStack(spacing: 0) { + Image(uiImage: widgetCard.backgroundImage) + .resizable() + .aspectRatio(contentMode: .fill) + .frame(width: proxy.size.height * (92 / 152), height: proxy.size.height) + .clipped() + Color.backgroundColor(for: colorScheme) + } + } + VStack { + HStack { + Text(widgetCard.title) + .font(.system(size: 15)) + .foregroundColor(.init(white: 1.0, opacity: 0.8)) + .padding(EdgeInsets(top: 12, leading: 10, bottom: 0, trailing: 0)) + .lineLimit(1) + Spacer() + Image("logoNada") + .padding(EdgeInsets(top: 10, leading: 0, bottom: 0, trailing: 10)) + } + Spacer() + HStack { + Spacer() + Text(widgetCard.userName) + .font(.system(size: 15)) + .foregroundColor(.userNameColor(for: colorScheme)) + .padding(EdgeInsets(top: 0, leading: 10, bottom: 11, trailing: 10)) + .lineLimit(1) + } + } + } + .widgetURL(URL(string: "openMyCardWidget")) + } else { + Image("widgetEmpty") + .resizable() + .scaledToFill() + } } } struct MyCardWidget: Widget { - let kind: String = "Widgets" - + let kind: String = "MyCardWidget" + var body: some WidgetConfiguration { - IntentConfiguration(kind: kind, intent: MyCardIntent.self, provider: MyCardProvider()) { entry in + IntentConfiguration(kind: kind, + intent: MyCardIntent.self, + provider: MyCardProvider()) { entry in MyCardEntryView(entry: entry) } - .configurationDisplayName("My Widget") - .description("This is an example widget.") + .configurationDisplayName("명함 위젯") + .description("명함 이미지를 보여주고,\n내 명함으로 빠르게 접근합니다.") + .supportedFamilies([.systemSmall]) } } struct MyCardWidget_Previews: PreviewProvider { static var previews: some View { - MyCardEntryView(entry: MyCardEntry(date: Date(), configuration: MyCardIntent())) + MyCardEntryView(entry: MyCardEntry(date: Date(), widgetCard: nil)) + .previewContext(WidgetPreviewContext(family: .systemSmall)) + MyCardEntryView(entry: MyCardEntry(date: Date(), widgetCard: WidgetCard(cardID: Card.mockData[0].cardID, title: Card.mockData[0].title, userName: Card.mockData[0].name, backgroundImage: UIImage(named: Card.mockData[2].background) ?? UIImage()))) .previewContext(WidgetPreviewContext(family: .systemSmall)) } }