Add Note contact field and fix birthday display

This commit is contained in:
Ilya Laktyushin 2019-11-13 20:21:30 +04:00
parent 8e2e882726
commit edb09cf389
13 changed files with 2737 additions and 2689 deletions

View File

@ -5104,3 +5104,5 @@ Any member of this group will be able to see messages in the channel.";
"GroupInfo.ShowMoreMembers_3_10" = "%@ more";
"GroupInfo.ShowMoreMembers_many" = "%@ more";
"GroupInfo.ShowMoreMembers_any" = "%@ more";
"ContactInfo.Note" = "note";

View File

@ -261,8 +261,9 @@ public final class DeviceContactExtendedData: Equatable {
public let birthdayDate: Date?
public let socialProfiles: [DeviceContactSocialProfileData]
public let instantMessagingProfiles: [DeviceContactInstantMessagingProfileData]
public let note: String
public init(basicData: DeviceContactBasicData, middleName: String, prefix: String, suffix: String, organization: String, jobTitle: String, department: String, emailAddresses: [DeviceContactEmailAddressData], urls: [DeviceContactUrlData], addresses: [DeviceContactAddressData], birthdayDate: Date?, socialProfiles: [DeviceContactSocialProfileData], instantMessagingProfiles: [DeviceContactInstantMessagingProfileData]) {
public init(basicData: DeviceContactBasicData, middleName: String, prefix: String, suffix: String, organization: String, jobTitle: String, department: String, emailAddresses: [DeviceContactEmailAddressData], urls: [DeviceContactUrlData], addresses: [DeviceContactAddressData], birthdayDate: Date?, socialProfiles: [DeviceContactSocialProfileData], instantMessagingProfiles: [DeviceContactInstantMessagingProfileData], note: String) {
self.basicData = basicData
self.middleName = middleName
self.prefix = prefix
@ -276,6 +277,7 @@ public final class DeviceContactExtendedData: Equatable {
self.birthdayDate = birthdayDate
self.socialProfiles = socialProfiles
self.instantMessagingProfiles = instantMessagingProfiles
self.note = note
}
public static func ==(lhs: DeviceContactExtendedData, rhs: DeviceContactExtendedData) -> Bool {
@ -318,6 +320,9 @@ public final class DeviceContactExtendedData: Equatable {
if lhs.instantMessagingProfiles != rhs.instantMessagingProfiles {
return false
}
if lhs.note != rhs.note {
return false
}
return true
}
}
@ -369,6 +374,7 @@ public extension DeviceContactExtendedData {
if let birthdayDate = self.birthdayDate {
contact.birthday = Calendar(identifier: .gregorian).dateComponents([.day, .month, .year], from: birthdayDate)
}
contact.note = self.note
return contact
}
@ -420,7 +426,7 @@ public extension DeviceContactExtendedData {
}
let basicData = DeviceContactBasicData(firstName: contact.givenName, lastName: contact.familyName, phoneNumbers: phoneNumbers)
self.init(basicData: basicData, middleName: contact.middleName, prefix: contact.namePrefix, suffix: contact.nameSuffix, organization: contact.organizationName, jobTitle: contact.jobTitle, department: contact.departmentName, emailAddresses: emailAddresses, urls: urls, addresses: addresses, birthdayDate: birthdayDate, socialProfiles: socialProfiles, instantMessagingProfiles: instantMessagingProfiles)
self.init(basicData: basicData, middleName: contact.middleName, prefix: contact.namePrefix, suffix: contact.nameSuffix, organization: contact.organizationName, jobTitle: contact.jobTitle, department: contact.departmentName, emailAddresses: emailAddresses, urls: urls, addresses: addresses, birthdayDate: birthdayDate, socialProfiles: socialProfiles, instantMessagingProfiles: instantMessagingProfiles, note: contact.note)
}
var isPrimitive: Bool {
@ -454,6 +460,9 @@ public extension DeviceContactExtendedData {
if !self.instantMessagingProfiles.isEmpty {
return false
}
if !self.note.isEmpty {
return false
}
return true
}
}
@ -467,7 +476,7 @@ public extension DeviceContactExtendedData {
if let phone = user.phone, !phone.isEmpty {
phoneNumbers.append(DeviceContactPhoneNumberData(label: "_$!<Mobile>!$_", value: phone))
}
self.init(basicData: DeviceContactBasicData(firstName: user.firstName ?? "", lastName: user.lastName ?? "", phoneNumbers: phoneNumbers), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [])
self.init(basicData: DeviceContactBasicData(firstName: user.firstName ?? "", lastName: user.lastName ?? "", phoneNumbers: phoneNumbers), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: "")
}
}

View File

@ -524,7 +524,7 @@ public class ContactsController: ViewController {
switch status {
case .allowed:
let contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: "", lastName: "", phoneNumbers: [DeviceContactPhoneNumberData(label: "_$!<Mobile>!$_", value: "+")]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [])
let contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: "", lastName: "", phoneNumbers: [DeviceContactPhoneNumberData(label: "_$!<Mobile>!$_", value: "+")]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: "")
(strongSelf.navigationController as? NavigationController)?.pushViewController(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: strongSelf.context, subject: .create(peer: nil, contactData: contactData, isSharing: false, shareViaException: false, completion: { peer, stableId, contactData in
guard let strongSelf = self else {
return

View File

@ -75,6 +75,7 @@ private enum DeviceContactInfoEntryTag: Equatable, ItemListItemTag {
case info(Int)
case birthday
case editingPhone(Int64)
case note
func isEqual(to other: ItemListItemTag) -> Bool {
return self == (other as? DeviceContactInfoEntryTag)
@ -90,6 +91,7 @@ private enum DeviceContactInfoDataId: Hashable {
case birthday
case socialProfile(DeviceContactSocialProfileData)
case instantMessenger(DeviceContactInstantMessagingProfileData)
case note
}
private enum DeviceContactInfoConstantEntryId: Hashable {
@ -104,6 +106,7 @@ private enum DeviceContactInfoConstantEntryId: Hashable {
case phoneNumberSharingInfo
case phoneNumberShareViaException
case phoneNumberShareViaExceptionInfo
case note
}
private enum DeviceContactInfoEntryId: Hashable {
@ -138,6 +141,7 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry {
case birthday(Int, PresentationTheme, String, Date, String, Bool?)
case socialProfile(Int, Int, PresentationTheme, String, DeviceContactSocialProfileData, String, Bool?)
case instantMessenger(Int, Int, PresentationTheme, String, DeviceContactInstantMessagingProfileData, String, Bool?)
case note(Int, PresentationTheme, String, String, Bool?)
var section: ItemListSectionId {
switch self {
@ -192,6 +196,8 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry {
return .socialProfile(catIndex)
case let .instantMessenger(_, catIndex, _, _, _, _, _):
return .instantMessenger(catIndex)
case .note:
return .constant(.note)
}
}
@ -329,6 +335,12 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry {
} else {
return false
}
case let .note(lhsIndex, lhsTheme, lhsTitle, lhsText, lhsSelected):
if case let .note(rhsIndex, rhsTheme, rhsTitle, rhsText, rhsSelected) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsText == rhsText, lhsSelected == rhsSelected {
return true
} else {
return false
}
}
}
@ -370,6 +382,8 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry {
return index
case let .instantMessenger(index, _, _, _, _, _, _):
return index
case let .note(index, _, _, _, _):
return index
}
}
@ -540,6 +554,16 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry {
arguments.displayCopyContextMenu(.info(index), text)
}
}, tag: DeviceContactInfoEntryTag.info(index))
case let .note(_, theme, title, text, selected):
return ItemListTextWithLabelItem(theme: theme, label: title, text: text, style: arguments.isPlain ? .plain : .blocks, enabledEntityTypes: [], multiline: true, selected: selected, sectionId: self.section, action: {
if selected != nil {
arguments.toggleSelection(.note)
}
}, longTapAction: {
if selected == nil {
arguments.displayCopyContextMenu(.note, text)
}
}, tag: DeviceContactInfoEntryTag.note)
}
}
}
@ -585,8 +609,8 @@ private func filteredContactData(contactData: DeviceContactExtendedData, exclude
})
let includeJob = !excludedComponents.contains(.job)
let includeBirthday = !excludedComponents.contains(.birthday)
return DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: contactData.basicData.firstName, lastName: contactData.basicData.lastName, phoneNumbers: phoneNumbers), middleName: contactData.middleName, prefix: contactData.prefix, suffix: contactData.suffix, organization: includeJob ? contactData.organization : "", jobTitle: includeJob ? contactData.jobTitle : "", department: includeJob ? contactData.department : "", emailAddresses: emailAddresses, urls: urls, addresses: addresses, birthdayDate: includeBirthday ? contactData.birthdayDate : nil, socialProfiles: socialProfiles, instantMessagingProfiles: instantMessagingProfiles)
let includeNote = !excludedComponents.contains(.note)
return DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: contactData.basicData.firstName, lastName: contactData.basicData.lastName, phoneNumbers: phoneNumbers), middleName: contactData.middleName, prefix: contactData.prefix, suffix: contactData.suffix, organization: includeJob ? contactData.organization : "", jobTitle: includeJob ? contactData.jobTitle : "", department: includeJob ? contactData.department : "", emailAddresses: emailAddresses, urls: urls, addresses: addresses, birthdayDate: includeBirthday ? contactData.birthdayDate : nil, socialProfiles: socialProfiles, instantMessagingProfiles: instantMessagingProfiles, note: includeNote ? contactData.note : "")
}
private func deviceContactInfoEntries(account: Account, presentationData: PresentationData, peer: Peer?, isShare: Bool, shareViaException: Bool, contactData: DeviceContactExtendedData, isContact: Bool, state: DeviceContactInfoState, selecting: Bool, editingPhoneNumbers: Bool) -> [DeviceContactInfoEntry] {
@ -714,14 +738,13 @@ private func deviceContactInfoEntries(account: Account, presentationData: Presen
if let birthday = contactData.birthdayDate {
let dateText: String
let calendar = Calendar(identifier: .gregorian)
var components = calendar.dateComponents(Set([.era, .year, .month, .day]), from: birthday)
components.hour = 12
let components = calendar.dateComponents(Set([.era, .year, .month, .day]), from: birthday)
if let year = components.year, year > 1 {
dateText = stringForDate(timestamp: Int32(birthday.timeIntervalSince1970), strings: presentationData.strings)
dateText = stringForDate(date: birthday, timeZone: TimeZone.current, strings: presentationData.strings)
} else {
dateText = stringForDateWithoutYear(date: birthday, strings: presentationData.strings)
dateText = stringForDateWithoutYear(date: birthday, timeZone: TimeZone.current, strings: presentationData.strings)
}
entries.append(.birthday(entries.count, presentationData.theme, "birthday", birthday, dateText, selecting ? !state.excludedComponents.contains(.birthday) : nil))
entries.append(.birthday(entries.count, presentationData.theme, presentationData.strings.ContactInfo_BirthdayLabel, birthday, dateText, selecting ? !state.excludedComponents.contains(.birthday) : nil))
}
var socialProfileIndex = 0
@ -753,6 +776,10 @@ private func deviceContactInfoEntries(account: Account, presentationData: Presen
instantMessagingProfileIndex += 1
}
if !contactData.note.isEmpty {
entries.append(.note(entries.count, presentationData.theme, presentationData.strings.ContactInfo_Note, contactData.note, selecting ? !state.excludedComponents.contains(.note) : nil))
}
return entries
}
@ -1071,7 +1098,7 @@ public func deviceContactInfoController(context: AccountContext, subject: Device
urls.append(appProfile)
}
}
composedContactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: firstName, lastName: lastName, phoneNumbers: filteredPhoneNumbers), middleName: filteredData.middleName, prefix: filteredData.prefix, suffix: filteredData.suffix, organization: filteredData.organization, jobTitle: filteredData.jobTitle, department: filteredData.department, emailAddresses: filteredData.emailAddresses, urls: urls, addresses: filteredData.addresses, birthdayDate: filteredData.birthdayDate, socialProfiles: filteredData.socialProfiles, instantMessagingProfiles: filteredData.instantMessagingProfiles)
composedContactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: firstName, lastName: lastName, phoneNumbers: filteredPhoneNumbers), middleName: filteredData.middleName, prefix: filteredData.prefix, suffix: filteredData.suffix, organization: filteredData.organization, jobTitle: filteredData.jobTitle, department: filteredData.department, emailAddresses: filteredData.emailAddresses, urls: urls, addresses: filteredData.addresses, birthdayDate: filteredData.birthdayDate, socialProfiles: filteredData.socialProfiles, instantMessagingProfiles: filteredData.instantMessagingProfiles, note: filteredData.note)
}
rightNavigationButton = ItemListNavigationButton(content: .text(isShare ? presentationData.strings.Common_Done : presentationData.strings.Compose_Create), style: .bold, enabled: (isShare || !filteredPhoneNumbers.isEmpty) && composedContactData != nil, action: {
if let composedContactData = composedContactData {

View File

@ -1281,7 +1281,7 @@ public func userInfoController(context: AccountContext, peerId: PeerId, mode: Pe
var signals: [Signal<DeviceContactExtendedData?, NoError>] = []
if let contactDataManager = context.sharedContext.contactDataManager {
for (id, basicData) in records {
signals.append(contactDataManager.appendContactData(DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: firstName, lastName: lastName, phoneNumbers: basicData.phoneNumbers), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: []), to: id))
signals.append(contactDataManager.appendContactData(DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: firstName, lastName: lastName, phoneNumbers: basicData.phoneNumbers), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: ""), to: id))
}
}
return combineLatest(signals)

View File

@ -183,7 +183,7 @@ private func collectExternalShareItems(strings: PresentationStrings, dateTimeFor
if let vCard = contact.vCardData, let vCardData = vCard.data(using: .utf8), let parsed = DeviceContactExtendedData(vcard: vCardData) {
contactData = parsed
} else {
contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: contact.firstName, lastName: contact.lastName, phoneNumbers: [DeviceContactPhoneNumberData(label: "_$!<Mobile>!$_", value: contact.phoneNumber)]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [])
contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: contact.firstName, lastName: contact.lastName, phoneNumbers: [DeviceContactPhoneNumberData(label: "_$!<Mobile>!$_", value: contact.phoneNumber)]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: "")
}
if let vCard = contactData.serializedVCard() {

View File

@ -93,10 +93,19 @@ public func stringForDate(timestamp: Int32, strings: PresentationStrings) -> Str
return formatter.string(from: Date(timeIntervalSince1970: Double(timestamp)))
}
public func stringForDateWithoutYear(date: Date, strings: PresentationStrings) -> String {
public func stringForDate(date: Date, timeZone: TimeZone? = TimeZone(secondsFromGMT: 0), strings: PresentationStrings) -> String {
let formatter = DateFormatter()
formatter.timeStyle = .none
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateStyle = .medium
formatter.timeZone = timeZone
formatter.locale = localeWithStrings(strings)
return formatter.string(from: date)
}
public func stringForDateWithoutYear(date: Date, timeZone: TimeZone? = TimeZone(secondsFromGMT: 0), strings: PresentationStrings) -> String {
let formatter = DateFormatter()
formatter.timeStyle = .none
formatter.timeZone = timeZone
formatter.locale = localeWithStrings(strings)
formatter.setLocalizedDateFormatFromTemplate("MMMMd")
return formatter.string(from: date)

View File

@ -5885,7 +5885,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
guard let contact = contact as? TelegramUser, let phoneNumber = contact.phone else {
return
}
let contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: contact.firstName ?? "", lastName: contact.lastName ?? "", phoneNumbers: [DeviceContactPhoneNumberData(label: "_$!<Mobile>!$_", value: phoneNumber)]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [])
let contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: contact.firstName ?? "", lastName: contact.lastName ?? "", phoneNumbers: [DeviceContactPhoneNumberData(label: "_$!<Mobile>!$_", value: phoneNumber)]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: "")
let context = strongSelf.context
dataSignal = (strongSelf.context.sharedContext.contactDataManager?.basicData() ?? .single([:]))
|> take(1)

View File

@ -416,7 +416,7 @@ private final class DeviceContactDataLegacyContext: DeviceContactDataContext {
func getExtendedContactData(stableId: DeviceContactStableId) -> DeviceContactExtendedData? {
if let contact = self.getContactById(stableId: stableId) {
let basicData = DeviceContactDataLegacyContext.parseContact(contact).1
return DeviceContactExtendedData(basicData: basicData, middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [])
return DeviceContactExtendedData(basicData: basicData, middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: "")
} else {
return nil
}
@ -449,7 +449,7 @@ private final class DeviceContactDataLegacyContext: DeviceContactDataContext {
let stableId = "ab-\(ABRecordGetRecordID(contact))"
if let contact = self.getContactById(stableId: stableId) {
let parsedContact = DeviceContactDataLegacyContext.parseContact(contact).1
result = (stableId, DeviceContactExtendedData(basicData: parsedContact, middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: []))
result = (stableId, DeviceContactExtendedData(basicData: parsedContact, middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: ""))
}
}
}

View File

@ -15,7 +15,7 @@ func openAddContactImpl(context: AccountContext, firstName: String = "", lastNam
|> deliverOnMainQueue).start(next: { value in
switch value {
case .allowed:
let contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: firstName, lastName: lastName, phoneNumbers: [DeviceContactPhoneNumberData(label: label, value: phoneNumber)]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [])
let contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: firstName, lastName: lastName, phoneNumbers: [DeviceContactPhoneNumberData(label: label, value: phoneNumber)]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: "")
present(deviceContactInfoController(context: context, subject: .create(peer: nil, contactData: contactData, isSharing: false, shareViaException: false, completion: { peer, stableId, contactData in
if let peer = peer {
if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic) {

View File

@ -377,7 +377,7 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool {
if let vCard = contact.vCardData, let vCardData = vCard.data(using: .utf8), let parsed = DeviceContactExtendedData(vcard: vCardData) {
contactData = parsed
} else {
contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: contact.firstName, lastName: contact.lastName, phoneNumbers: [DeviceContactPhoneNumberData(label: "_$!<Mobile>!$_", value: contact.phoneNumber)]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [])
contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: contact.firstName, lastName: contact.lastName, phoneNumbers: [DeviceContactPhoneNumberData(label: "_$!<Mobile>!$_", value: contact.phoneNumber)]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: "")
}
let controller = deviceContactInfoController(context: params.context, subject: .vcard(peer, nil, contactData), completed: nil, cancelled: nil)
params.navigationController?.pushViewController(controller)