Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2021-02-15 21:36:02 +04:00
commit 4313ac50bc
23 changed files with 314 additions and 195 deletions

View File

@ -19,6 +19,8 @@
<dict> <dict>
<key>INIntentCategory</key> <key>INIntentCategory</key>
<string>information</string> <string>information</string>
<key>INIntentDescription</key>
<string>Display the latest message from the most important chats.</string>
<key>INIntentDescriptionID</key> <key>INIntentDescriptionID</key>
<string>jmsEbj</string> <string>jmsEbj</string>
<key>INIntentEligibleForWidgets</key> <key>INIntentEligibleForWidgets</key>
@ -56,7 +58,7 @@
<key>INIntentParameterConfigurable</key> <key>INIntentParameterConfigurable</key>
<true/> <true/>
<key>INIntentParameterDisplayName</key> <key>INIntentParameterDisplayName</key>
<string> </string> <string>SELECT CHATS</string>
<key>INIntentParameterDisplayNameID</key> <key>INIntentParameterDisplayNameID</key>
<string>WIf4LD</string> <string>WIf4LD</string>
<key>INIntentParameterDisplayPriority</key> <key>INIntentParameterDisplayPriority</key>
@ -124,7 +126,7 @@
</array> </array>
</dict> </dict>
<key>INIntentTitle</key> <key>INIntentTitle</key>
<string>Select Chats</string> <string>Chats</string>
<key>INIntentTitleID</key> <key>INIntentTitleID</key>
<string>lMot0c</string> <string>lMot0c</string>
<key>INIntentType</key> <key>INIntentType</key>
@ -135,6 +137,8 @@
<dict> <dict>
<key>INIntentCategory</key> <key>INIntentCategory</key>
<string>information</string> <string>information</string>
<key>INIntentDescription</key>
<string>"Display shortcuts of your most important chats to always have quick access to them.</string>
<key>INIntentDescriptionID</key> <key>INIntentDescriptionID</key>
<string>DwL4WQ</string> <string>DwL4WQ</string>
<key>INIntentEligibleForWidgets</key> <key>INIntentEligibleForWidgets</key>
@ -172,7 +176,7 @@
<key>INIntentParameterConfigurable</key> <key>INIntentParameterConfigurable</key>
<true/> <true/>
<key>INIntentParameterDisplayName</key> <key>INIntentParameterDisplayName</key>
<string> </string> <string>SELECT CHATS</string>
<key>INIntentParameterDisplayNameID</key> <key>INIntentParameterDisplayNameID</key>
<string>Jg5dYF</string> <string>Jg5dYF</string>
<key>INIntentParameterDisplayPriority</key> <key>INIntentParameterDisplayPriority</key>
@ -240,7 +244,7 @@
</array> </array>
</dict> </dict>
<key>INIntentTitle</key> <key>INIntentTitle</key>
<string>Select Chats</string> <string>Shortcuts</string>
<key>INIntentTitleID</key> <key>INIntentTitleID</key>
<string>3Sbb7H</string> <string>3Sbb7H</string>
<key>INIntentType</key> <key>INIntentType</key>

View File

@ -1161,6 +1161,12 @@ plist_fragment(
) )
) )
filegroup(
name = "WidgetAssets",
srcs = glob(["WidgetKitWidget/WidgetImages.xcassets/**"]),
visibility = ["//visibility:public"],
)
swift_library( swift_library(
name = "WidgetExtensionLib", name = "WidgetExtensionLib",
module_name = "WidgetExtensionLib", module_name = "WidgetExtensionLib",
@ -1168,7 +1174,7 @@ swift_library(
"WidgetKitWidget/**/*.swift", "WidgetKitWidget/**/*.swift",
]), ]),
data = [ data = [
#"SiriIntents/Intents.intentdefinition", ":WidgetAssets",
], ],
deps = [ deps = [
"//submodules/BuildConfig:BuildConfig", "//submodules/BuildConfig:BuildConfig",
@ -1205,7 +1211,9 @@ ios_extension(
":disableProvisioningProfilesSetting": None, ":disableProvisioningProfilesSetting": None,
"//conditions:default": "@build_configuration//provisioning:Widget.mobileprovision", "//conditions:default": "@build_configuration//provisioning:Widget.mobileprovision",
}), }),
deps = [":WidgetExtensionLib"], deps = [
":WidgetExtensionLib",
],
frameworks = [ frameworks = [
":SwiftSignalKitFramework", ":SwiftSignalKitFramework",
":PostboxFramework", ":PostboxFramework",

View File

@ -87,11 +87,16 @@ struct Provider: IntentTimelineProvider {
} }
func getSnapshot(for configuration: SelectFriendsIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) { func getSnapshot(for configuration: SelectFriendsIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date(), contents: .peers(ParsedPeers(accountId: 0, peers: WidgetDataPeers(accountPeerId: 0, peers: [], updateTimestamp: 0)))) let entry = SimpleEntry(date: Date(), contents: context.isPreview ? .preview : .peers(ParsedPeers(accountId: 0, peers: WidgetDataPeers(accountPeerId: 0, peers: [], updateTimestamp: 0))))
completion(entry) completion(entry)
} }
func getTimeline(for configuration: SelectFriendsIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) { func getTimeline(for configuration: SelectFriendsIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
if context.isPreview {
completion(Timeline(entries: [SimpleEntry(date: Date(), contents: .preview)], policy: .atEnd))
return
}
let currentDate = Date() let currentDate = Date()
let entryDate = Calendar.current.date(byAdding: .hour, value: 0, to: currentDate)! let entryDate = Calendar.current.date(byAdding: .hour, value: 0, to: currentDate)!
@ -240,11 +245,16 @@ struct AvatarsProvider: IntentTimelineProvider {
} }
func getSnapshot(for configuration: SelectAvatarFriendsIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) { func getSnapshot(for configuration: SelectAvatarFriendsIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date(), contents: .peers(ParsedPeers(accountId: 0, peers: WidgetDataPeers(accountPeerId: 0, peers: [], updateTimestamp: 0)))) let entry = SimpleEntry(date: Date(), contents: context.isPreview ? .preview : .peers(ParsedPeers(accountId: 0, peers: WidgetDataPeers(accountPeerId: 0, peers: [], updateTimestamp: 0))))
completion(entry) completion(entry)
} }
func getTimeline(for configuration: SelectAvatarFriendsIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) { func getTimeline(for configuration: SelectAvatarFriendsIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
if context.isPreview {
completion(Timeline(entries: [SimpleEntry(date: Date(), contents: .preview)], policy: .atEnd))
return
}
let currentDate = Date() let currentDate = Date()
let entryDate = Calendar.current.date(byAdding: .hour, value: 0, to: currentDate)! let entryDate = Calendar.current.date(byAdding: .hour, value: 0, to: currentDate)!
@ -388,6 +398,7 @@ struct AvatarsProvider: IntentTimelineProvider {
struct SimpleEntry: TimelineEntry { struct SimpleEntry: TimelineEntry {
enum Contents { enum Contents {
case recent case recent
case preview
case peers(ParsedPeers) case peers(ParsedPeers)
} }
@ -397,13 +408,10 @@ struct SimpleEntry: TimelineEntry {
enum PeersWidgetData { enum PeersWidgetData {
case empty case empty
case preview
case peers(ParsedPeers) case peers(ParsedPeers)
} }
extension PeersWidgetData {
static let previewData = PeersWidgetData.empty
}
struct AvatarItemView: View { struct AvatarItemView: View {
var peer: ParsedPeer? var peer: ParsedPeer?
var itemSize: CGFloat var itemSize: CGFloat
@ -428,23 +436,6 @@ struct WidgetView: View {
@Environment(\.colorScheme) private var colorScheme @Environment(\.colorScheme) private var colorScheme
let data: PeersWidgetData let data: PeersWidgetData
func placeholder(geometry: GeometryProxy) -> some View {
let defaultItemSize: CGFloat = 60.0
let defaultPaddingFraction: CGFloat = 0.36
let columnCount = Int(round(geometry.size.width / (defaultItemSize * (1.0 + defaultPaddingFraction))))
let itemSize = floor(geometry.size.width / (CGFloat(columnCount) + defaultPaddingFraction * CGFloat(columnCount - 1)))
let firstRowY = itemSize / 2.0
let secondRowY = itemSize / 2.0 + geometry.size.height - itemSize
return ZStack {
ForEach(0 ..< columnCount * 2, content: { i in
return Circle().frame(width: itemSize, height: itemSize).position(x: itemSize / 2.0 + floor(CGFloat(i % columnCount) * itemSize * (1.0 + defaultPaddingFraction)), y: i / columnCount == 0 ? firstRowY : secondRowY).foregroundColor(.gray)
})
}
}
private func linkForPeer(accountId: Int64, id: Int64) -> String { private func linkForPeer(accountId: Int64, id: Int64) -> String {
switch self.widgetFamily { switch self.widgetFamily {
case .systemSmall: case .systemSmall:
@ -454,94 +445,15 @@ struct WidgetView: View {
} }
} }
func peersView(geometry: GeometryProxy, peers: ParsedPeers) -> some View { func chatTopLine(_ content: ChatContent) -> some View {
let columnCount: Int
let rowCount: Int
let itemSizeFraction: CGFloat
let horizontalInsetFraction: CGFloat
let verticalInsetFraction: CGFloat
let horizontalSpacingFraction: CGFloat
let verticalSpacingFraction: CGFloat
switch self.widgetFamily {
case .systemLarge:
itemSizeFraction = 0.1762917933
horizontalInsetFraction = 0.04863221884
verticalInsetFraction = 0.04863221884
horizontalSpacingFraction = 0.06079027356
verticalSpacingFraction = 0.06079027356
columnCount = 4
rowCount = 4
case .systemMedium:
itemSizeFraction = 0.1762917933
horizontalInsetFraction = 0.04863221884
verticalInsetFraction = 0.1032258065
horizontalSpacingFraction = 0.06079027356
verticalSpacingFraction = 0.07741935484
columnCount = 4
rowCount = 2
case .systemSmall:
itemSizeFraction = 0.335483871
horizontalInsetFraction = 0.1032258065
verticalInsetFraction = 0.1032258065
horizontalSpacingFraction = 0.1161290323
verticalSpacingFraction = 0.1161290323
columnCount = 2
rowCount = 2
@unknown default:
itemSizeFraction = 0.335483871
horizontalInsetFraction = 0.1032258065
verticalInsetFraction = 0.1032258065
horizontalSpacingFraction = 0.1161290323
verticalSpacingFraction = 0.1161290323
columnCount = 2
rowCount = 2
}
let itemSize = floor(geometry.size.width * itemSizeFraction)
return ZStack {
ForEach(0 ..< min(peers.peers.count, columnCount * rowCount), content: { i in
Link(destination: URL(string: linkForPeer(accountId: peers.peers[i].accountId, id: peers.peers[i].peer.id))!, label: {
AvatarItemView(
peer: peers.peers[i],
itemSize: itemSize,
placeholderColor: getPlaceholderColor()
).frame(width: itemSize, height: itemSize)
}).frame(width: itemSize, height: itemSize)
.position(x: floor(horizontalInsetFraction * geometry.size.width + itemSize / 2.0 + CGFloat(i % columnCount) * (itemSize + horizontalSpacingFraction * geometry.size.width)), y: floor(verticalInsetFraction * geometry.size.height + itemSize / 2.0 + CGFloat(i / columnCount) * (itemSize + verticalSpacingFraction * geometry.size.height)))
})
}
}
func peerViews() -> AnyView {
switch data {
case .empty:
return AnyView(GeometryReader { geometry in
placeholder(geometry: geometry)
})
case let .peers(peers):
return AnyView(GeometryReader { geometry in
peersView(geometry: geometry, peers: peers)
})
}
}
var body1: some View {
ZStack {
peerViews()
}
.padding(0.0)
}
func chatTopLine(_ peer: ParsedPeer?) -> some View {
let dateText: String let dateText: String
let chatTitle: AnyView let chatTitle: AnyView
let date: Text let date: Text
var isPlaceholder = false
if let peer = peer { switch content {
case let .peer(peer):
if let message = peer.peer.message { if let message = peer.peer.message {
dateText = DateFormatter.localizedString(from: Date(timeIntervalSince1970: Double(message.timestamp)), dateStyle: .none, timeStyle: .short) dateText = DateFormatter.localizedString(from: Date(timeIntervalSince1970: Double(message.timestamp)), dateStyle: .none, timeStyle: .short)
} else { } else {
@ -553,14 +465,23 @@ struct WidgetView: View {
.foregroundColor(.primary)) .foregroundColor(.primary))
date = Text(dateText) date = Text(dateText)
.font(Font.system(size: 14.0, weight: .regular, design: .default)).foregroundColor(.secondary) .font(Font.system(size: 14.0, weight: .regular, design: .default)).foregroundColor(.secondary)
} else { case let .preview(index):
dateText = index == 0 ? "9:00" : "8:42"
chatTitle = AnyView(Text("News Channel")
.lineLimit(1)
.font(Font.system(size: 16.0, weight: .medium, design: .default))
.foregroundColor(.primary))
date = Text(dateText)
.font(Font.system(size: 14.0, weight: .regular, design: .default)).foregroundColor(.secondary)
case .placeholder:
isPlaceholder = true
dateText = " " dateText = " "
chatTitle = AnyView(Text(" ").font(Font.system(size: 16.0, weight: .medium, design: .default)).foregroundColor(.primary)) chatTitle = AnyView(Text(" ").font(Font.system(size: 16.0, weight: .medium, design: .default)).foregroundColor(.primary))
date = Text(dateText) date = Text(dateText)
.font(Font.system(size: 16.0, weight: .regular, design: .default)).foregroundColor(.secondary) .font(Font.system(size: 16.0, weight: .regular, design: .default)).foregroundColor(.secondary)
} }
return HStack(alignment: .center, spacing: 0.0, content: { return HStack(alignment: .center, spacing: 0.0, content: {
if peer != nil { if !isPlaceholder {
chatTitle chatTitle
} else { } else {
chatTitle chatTitle
@ -574,7 +495,7 @@ struct WidgetView: View {
) )
} }
Spacer() Spacer()
if peer != nil { if !isPlaceholder {
date date
} else { } else {
date date
@ -590,13 +511,12 @@ struct WidgetView: View {
.padding(0.0) .padding(0.0)
} }
func chatBottomLine(_ peer: ParsedPeer?) -> AnyView { func chatBottomLine(_ content: ChatContent) -> AnyView {
var text = peer?.peer.message?.text ?? "" var text = ""
text += "\n" var isPlaceholder = false
if peer == nil { switch content {
text = "First Line Of Text Here\nSecond line fwqefeqwfqwef qwef wq" case let .peer(peer):
} if let message = peer.peer.message {
if let message = peer?.peer.message {
//TODO:localize //TODO:localize
switch message.content { switch message.content {
case .text: case .text:
@ -663,6 +583,17 @@ struct WidgetView: View {
} }
} }
} }
text += "\n"
case let .preview(index):
if index == 0 {
text = "☀️ 23 °C\n☁️ Passing Clouds"
} else {
text = "😂 Sticker"
text += "\n"
}
case .placeholder:
isPlaceholder = true
}
let textView = Text(text) let textView = Text(text)
.lineLimit(2) .lineLimit(2)
@ -671,7 +602,7 @@ struct WidgetView: View {
.multilineTextAlignment(.leading) .multilineTextAlignment(.leading)
.padding(0.0) .padding(0.0)
if peer != nil { if !isPlaceholder {
return AnyView(textView) return AnyView(textView)
} else { } else {
return AnyView( return AnyView(
@ -709,16 +640,23 @@ struct WidgetView: View {
} }
} }
func chatContent(_ peer: ParsedPeer?) -> some View { enum ChatContent {
case peer(ParsedPeer)
case preview(Int)
case placeholder
}
func chatContent(_ content: ChatContent) -> some View {
return VStack(alignment: .leading, spacing: 0.0, content: { return VStack(alignment: .leading, spacing: 0.0, content: {
chatTopLine(peer) chatTopLine(content)
chatBottomLine(peer) chatBottomLine(content)
}) })
} }
func chatContentView(_ index: Int, size: CGSize) -> AnyView { func chatContentView(_ index: Int, size: CGSize) -> AnyView {
let peers: ParsedPeers? let peers: ParsedPeers?
var isPlaceholder = false var isPlaceholder = false
var isPreview = false
switch data { switch data {
case let .peers(peersValue): case let .peers(peersValue):
if peersValue.peers.count <= index { if peersValue.peers.count <= index {
@ -727,6 +665,9 @@ struct WidgetView: View {
} else { } else {
peers = peersValue peers = peersValue
} }
case .preview:
peers = nil
isPreview = true
default: default:
peers = nil peers = nil
} }
@ -739,6 +680,20 @@ struct WidgetView: View {
) )
} }
if isPreview {
return AnyView(
HStack(alignment: .center, spacing: 0.0, content: {
Image("Widget/Avatar\(index == 0 ? "Channel" : "1")")
.aspectRatio(1.0, contentMode: .fit)
.clipShape(Circle())
.frame(width: 54.0, height: 54.0, alignment: .leading)
.padding(EdgeInsets(top: 0.0, leading: 10.0, bottom: 0.0, trailing: 10.0))
chatContent(.preview(index)).frame(maxWidth: .infinity).padding(EdgeInsets(top: 0.0, leading: 0.0, bottom: 0.0, trailing: 10.0))
})
.frame(width: size.width, height: itemHeight, alignment: .leading)
)
}
let url: URL let url: URL
if let peers = peers { if let peers = peers {
url = URL(string: linkForPeer(accountId: peers.peers[index].accountId, id: peers.peers[index].peer.id))! url = URL(string: linkForPeer(accountId: peers.peers[index].accountId, id: peers.peers[index].peer.id))!
@ -746,11 +701,18 @@ struct WidgetView: View {
url = URL(string: "\(buildConfig.appSpecificUrlScheme)://")! url = URL(string: "\(buildConfig.appSpecificUrlScheme)://")!
} }
let content: ChatContent
if let peer = peers?.peers[index] {
content = .peer(peer)
} else {
content = .placeholder
}
return AnyView( return AnyView(
Link(destination: url, label: { Link(destination: url, label: {
HStack(alignment: .center, spacing: 0.0, content: { HStack(alignment: .center, spacing: 0.0, content: {
AvatarItemView(peer: peers?.peers[index], itemSize: 54.0, placeholderColor: getPlaceholderColor()).frame(width: 54.0, height: 54.0, alignment: .leading).padding(EdgeInsets(top: 0.0, leading: 10.0, bottom: 0.0, trailing: 10.0)) AvatarItemView(peer: peers?.peers[index], itemSize: 54.0, placeholderColor: getPlaceholderColor()).frame(width: 54.0, height: 54.0, alignment: .leading).padding(EdgeInsets(top: 0.0, leading: 10.0, bottom: 0.0, trailing: 10.0))
chatContent(peers?.peers[index]).frame(maxWidth: .infinity).padding(EdgeInsets(top: 0.0, leading: 0.0, bottom: 0.0, trailing: 10.0)) chatContent(content).frame(maxWidth: .infinity).padding(EdgeInsets(top: 0.0, leading: 0.0, bottom: 0.0, trailing: 10.0))
}) })
}) })
.frame(width: size.width, height: itemHeight, alignment: .leading) .frame(width: size.width, height: itemHeight, alignment: .leading)
@ -795,7 +757,7 @@ struct WidgetView: View {
let formatter = DateFormatter() let formatter = DateFormatter()
formatter.dateStyle = .short formatter.dateStyle = .short
formatter.timeStyle = .none formatter.timeStyle = .none
text = "updated on \(formatter.string(from: date))" text = "updated \(formatter.string(from: date))"
} else { } else {
let formatter = DateFormatter() let formatter = DateFormatter()
formatter.dateStyle = .none formatter.dateStyle = .none
@ -803,6 +765,21 @@ struct WidgetView: View {
text = "updated at \(formatter.string(from: date))" text = "updated at \(formatter.string(from: date))"
} }
} }
case .preview:
let date = Date()
let calendar = Calendar.current
//TODO:localize
if !calendar.isDate(Date(), inSameDayAs: date) {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .none
text = "updated \(formatter.string(from: date))"
} else {
let formatter = DateFormatter()
formatter.dateStyle = .none
formatter.timeStyle = .short
text = "updated at \(formatter.string(from: date))"
}
default: default:
text = "Long tap to edit widget" text = "Long tap to edit widget"
} }
@ -902,6 +879,7 @@ struct AvatarsWidgetView: View {
func itemView(index: Int) -> some View { func itemView(index: Int) -> some View {
let peers: ParsedPeers? let peers: ParsedPeers?
var isPlaceholder = false var isPlaceholder = false
var isPreview = false
switch data { switch data {
case let .peers(peersValue): case let .peers(peersValue):
if peersValue.peers.count <= index { if peersValue.peers.count <= index {
@ -910,6 +888,9 @@ struct AvatarsWidgetView: View {
} else { } else {
peers = peersValue peers = peersValue
} }
case .preview:
peers = nil
isPreview = true
default: default:
peers = nil peers = nil
} }
@ -921,8 +902,9 @@ struct AvatarsWidgetView: View {
}) })
}).aspectRatio(1.0, contentMode: .fit)) }).aspectRatio(1.0, contentMode: .fit))
} else if isPlaceholder { } else if isPlaceholder {
//return AnyView(Circle().aspectRatio(1.0, contentMode: .fit).foregroundColor(.clear))
return AnyView(Circle().aspectRatio(1.0, contentMode: .fit).foregroundColor(getPlaceholderColor())) return AnyView(Circle().aspectRatio(1.0, contentMode: .fit).foregroundColor(getPlaceholderColor()))
} else if isPreview {
return AnyView(Image("Widget/Avatar\(index + 1)").aspectRatio(1.0, contentMode: .fit).clipShape(Circle()))
} else { } else {
return AnyView(Circle().aspectRatio(1.0, contentMode: .fit).foregroundColor(getPlaceholderColor())) return AnyView(Circle().aspectRatio(1.0, contentMode: .fit).foregroundColor(getPlaceholderColor()))
} }
@ -999,6 +981,8 @@ func getWidgetData(contents: SimpleEntry.Contents) -> PeersWidgetData {
switch contents { switch contents {
case .recent: case .recent:
return .empty return .empty
case .preview:
return .preview
case let .peers(peers): case let .peers(peers):
return .peers(peers) return .peers(peers)
} }
@ -1012,8 +996,8 @@ struct Static_Widget: Widget {
WidgetView(data: getWidgetData(contents: entry.contents)) WidgetView(data: getWidgetData(contents: entry.contents))
}) })
.supportedFamilies([.systemMedium]) .supportedFamilies([.systemMedium])
.configurationDisplayName(presentationData.widgetGalleryTitle) .configurationDisplayName("Chats")
.description(presentationData.widgetGalleryDescription) .description("Display the latest message from the most important chats.")
} }
} }
@ -1025,8 +1009,8 @@ struct Static_AvatarsWidget: Widget {
AvatarsWidgetView(data: getWidgetData(contents: entry.contents)) AvatarsWidgetView(data: getWidgetData(contents: entry.contents))
}) })
.supportedFamilies([.systemMedium]) .supportedFamilies([.systemMedium])
.configurationDisplayName(presentationData.widgetGalleryTitle) .configurationDisplayName("Shortcuts")
.description(presentationData.widgetGalleryDescription) .description("Display shortcuts of your most important chats to always have quick access to them.")
} }
} }

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Avatar1.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Avatar2.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Avatar3.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Avatar4.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Avatar5.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Avatar6.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Avatar7.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Avatar8.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "AvatarChannel.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,9 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"provides-namespace" : true
}
}