Skip to content

Commit

Permalink
Merge pull request TeamNADA#369 from hyun99999/feature/TeamNADA#366
Browse files Browse the repository at this point in the history
feat: 내 명함 목록을 선택할 수 있는 Configurable Widget 추가 (TeamNADA#366)
  • Loading branch information
hyun99999 authored Feb 28, 2023
2 parents 7ff956d + 6556ae1 commit 0f88244
Show file tree
Hide file tree
Showing 21 changed files with 233 additions and 31 deletions.
21 changes: 21 additions & 0 deletions IntentsExtension/IntentHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,26 @@ class IntentHandler: INExtension {

return self
}
}

extension IntentHandler: MyCardIntentHandling {
func provideMyCardOptionsCollection(for intent: MyCardIntent, with completion: @escaping (INObjectCollection<MyCard>?, 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
}
}
4 changes: 4 additions & 0 deletions NADA-iOS-forRelease.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -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;
};
Expand All @@ -1473,6 +1476,7 @@
buildActionMask = 2147483647;
files = (
F80975E92990A27400075B93 /* Widgets.intentdefinition in Sources */,
F8257751299546930067E145 /* Card.swift in Sources */,
F87D222D298ECAFB001A882B /* IntentHandler.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
6 changes: 6 additions & 0 deletions NADA-iOS-forRelease/Sources/NetworkModel/Card/Card.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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: "")
]
}
Original file line number Diff line number Diff line change
@@ -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
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -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
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -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
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -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"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 1 addition & 15 deletions Widgets/Resource/Widgets.intentdefinition
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@
<key>INTypeDisplayNameID</key>
<string>J1deG2</string>
<key>INTypeLastPropertyTag</key>
<integer>100</integer>
<integer>101</integer>
<key>INTypeName</key>
<string>MyCard</string>
<key>INTypeProperties</key>
Expand Down Expand Up @@ -158,20 +158,6 @@
<key>INTypePropertyType</key>
<string>SpeakableString</string>
</dict>
<dict>
<key>INTypePropertyDisplayName</key>
<string>Card ID</string>
<key>INTypePropertyDisplayNameID</key>
<string>aRJ51O</string>
<key>INTypePropertyDisplayPriority</key>
<integer>5</integer>
<key>INTypePropertyName</key>
<string>cardID</string>
<key>INTypePropertyTag</key>
<integer>100</integer>
<key>INTypePropertyType</key>
<string>String</string>
</dict>
</array>
</dict>
</array>
Expand Down
125 changes: 109 additions & 16 deletions Widgets/WidgetsBundle/MyCardWidget.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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<Entry>) -> 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))
}
}

0 comments on commit 0f88244

Please sign in to comment.