Compare commits
6 Commits
b34f3c2a1a
...
19939dcf61
| Author | SHA1 | Date | |
|---|---|---|---|
| 19939dcf61 | |||
| 549b2126a9 | |||
| 95a5c77cb9 | |||
| 76f3fdefdf | |||
| 1c8e80df1f | |||
| ac274ec885 |
@ -172,6 +172,7 @@ struct ChatProfile: Decodable {
|
|||||||
let permissions: ChatPermissions?
|
let permissions: ChatPermissions?
|
||||||
let profilePermissions: ChatProfilePermissions?
|
let profilePermissions: ChatProfilePermissions?
|
||||||
let relationship: RelationshipStatus?
|
let relationship: RelationshipStatus?
|
||||||
|
let rating: Double?
|
||||||
let isOfficial: Bool
|
let isOfficial: Bool
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
@ -187,6 +188,7 @@ struct ChatProfile: Decodable {
|
|||||||
case permissions
|
case permissions
|
||||||
case profilePermissions
|
case profilePermissions
|
||||||
case relationship
|
case relationship
|
||||||
|
case rating
|
||||||
case isOfficial
|
case isOfficial
|
||||||
case isVerified
|
case isVerified
|
||||||
}
|
}
|
||||||
@ -205,12 +207,45 @@ struct ChatProfile: Decodable {
|
|||||||
self.permissions = try container.decodeIfPresent(ChatPermissions.self, forKey: .permissions)
|
self.permissions = try container.decodeIfPresent(ChatPermissions.self, forKey: .permissions)
|
||||||
self.profilePermissions = try container.decodeIfPresent(ChatProfilePermissions.self, forKey: .profilePermissions)
|
self.profilePermissions = try container.decodeIfPresent(ChatProfilePermissions.self, forKey: .profilePermissions)
|
||||||
self.relationship = try container.decodeIfPresent(RelationshipStatus.self, forKey: .relationship)
|
self.relationship = try container.decodeIfPresent(RelationshipStatus.self, forKey: .relationship)
|
||||||
|
let ratingPayload = try container.decodeIfPresent(ChatProfileRatingPayload.self, forKey: .rating)
|
||||||
|
self.rating = ratingPayload?.resolvedRating
|
||||||
let explicitOfficial = try container.decodeIfPresent(Bool.self, forKey: .isOfficial)
|
let explicitOfficial = try container.decodeIfPresent(Bool.self, forKey: .isOfficial)
|
||||||
let verifiedFlag = try container.decodeIfPresent(Bool.self, forKey: .isVerified)
|
let verifiedFlag = try container.decodeIfPresent(Bool.self, forKey: .isVerified)
|
||||||
self.isOfficial = explicitOfficial ?? verifiedFlag ?? false
|
self.isOfficial = explicitOfficial ?? verifiedFlag ?? false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private struct ChatProfileRatingPayload: Decodable {
|
||||||
|
let status: String?
|
||||||
|
let rating: Double?
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case rating
|
||||||
|
case status
|
||||||
|
}
|
||||||
|
|
||||||
|
init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
status = try container.decodeIfPresent(String.self, forKey: .status)
|
||||||
|
|
||||||
|
if let doubleValue = try? container.decode(Double.self, forKey: .rating) {
|
||||||
|
rating = doubleValue
|
||||||
|
} else if let stringValue = try? container.decode(String.self, forKey: .rating),
|
||||||
|
let doubleValue = Double(stringValue) {
|
||||||
|
rating = doubleValue
|
||||||
|
} else if let intValue = try? container.decode(Int.self, forKey: .rating) {
|
||||||
|
rating = Double(intValue)
|
||||||
|
} else {
|
||||||
|
rating = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var resolvedRating: Double? {
|
||||||
|
guard status?.lowercased() == "fine" else { return nil }
|
||||||
|
return rating
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension ChatProfile {
|
extension ChatProfile {
|
||||||
init(
|
init(
|
||||||
userId: String,
|
userId: String,
|
||||||
@ -225,6 +260,7 @@ extension ChatProfile {
|
|||||||
permissions: ChatPermissions? = nil,
|
permissions: ChatPermissions? = nil,
|
||||||
profilePermissions: ChatProfilePermissions? = nil,
|
profilePermissions: ChatProfilePermissions? = nil,
|
||||||
relationship: RelationshipStatus? = nil,
|
relationship: RelationshipStatus? = nil,
|
||||||
|
rating: Double? = nil,
|
||||||
isOfficial: Bool = false
|
isOfficial: Bool = false
|
||||||
) {
|
) {
|
||||||
self.userId = userId
|
self.userId = userId
|
||||||
@ -239,6 +275,7 @@ extension ChatProfile {
|
|||||||
self.permissions = permissions
|
self.permissions = permissions
|
||||||
self.profilePermissions = profilePermissions
|
self.profilePermissions = profilePermissions
|
||||||
self.relationship = relationship
|
self.relationship = relationship
|
||||||
|
self.rating = rating
|
||||||
self.isOfficial = isOfficial
|
self.isOfficial = isOfficial
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -273,9 +310,25 @@ struct ChatProfilePermissions: Decodable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct RelationshipStatus: Decodable {
|
struct RelationshipStatus: Decodable {
|
||||||
|
let isTargetInContactsOfCurrentUser: Bool
|
||||||
let isCurrentUserInContactsOfTarget: Bool
|
let isCurrentUserInContactsOfTarget: Bool
|
||||||
let isTargetUserBlockedByCurrentUser: Bool
|
let isTargetUserBlockedByCurrentUser: Bool
|
||||||
let isCurrentUserInBlacklistOfTarget: Bool
|
let isCurrentUserInBlacklistOfTarget: Bool
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case isTargetInContactsOfCurrentUser
|
||||||
|
case isCurrentUserInContactsOfTarget
|
||||||
|
case isTargetUserBlockedByCurrentUser
|
||||||
|
case isCurrentUserInBlacklistOfTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
self.isTargetInContactsOfCurrentUser = try container.decodeIfPresent(Bool.self, forKey: .isTargetInContactsOfCurrentUser) ?? false
|
||||||
|
self.isCurrentUserInContactsOfTarget = try container.decodeIfPresent(Bool.self, forKey: .isCurrentUserInContactsOfTarget) ?? false
|
||||||
|
self.isTargetUserBlockedByCurrentUser = try container.decodeIfPresent(Bool.self, forKey: .isTargetUserBlockedByCurrentUser) ?? false
|
||||||
|
self.isCurrentUserInBlacklistOfTarget = try container.decodeIfPresent(Bool.self, forKey: .isCurrentUserInBlacklistOfTarget) ?? false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum JSONValue: Decodable {
|
enum JSONValue: Decodable {
|
||||||
|
|||||||
@ -20,6 +20,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"%@" : {
|
||||||
|
"comment" : "Message profile joined format"
|
||||||
|
},
|
||||||
"%@ %@" : {
|
"%@ %@" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"ru" : {
|
"ru" : {
|
||||||
@ -30,6 +33,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"%@ из 5" : {
|
||||||
|
"comment" : "Message profile rating format"
|
||||||
|
},
|
||||||
"%@: %@" : {
|
"%@: %@" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"ru" : {
|
"ru" : {
|
||||||
@ -182,6 +188,9 @@
|
|||||||
},
|
},
|
||||||
"Profile" : {
|
"Profile" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Push включены — приходят все новые сообщения." : {
|
||||||
|
"comment" : "Message profile notifications subtitle on"
|
||||||
},
|
},
|
||||||
"Push-уведомления" : {
|
"Push-уведомления" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -214,6 +223,9 @@
|
|||||||
},
|
},
|
||||||
"Yobble Passport" : {
|
"Yobble Passport" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Автоудаление" : {
|
||||||
|
"comment" : "Message profile auto delete alert title\nMessage profile auto delete title"
|
||||||
},
|
},
|
||||||
"Автоудаление аккаунта" : {
|
"Автоудаление аккаунта" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -227,6 +239,9 @@
|
|||||||
},
|
},
|
||||||
"Аккаунт не найден." : {
|
"Аккаунт не найден." : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Аккаунт удалён" : {
|
||||||
|
"comment" : "Message profile deleted tag"
|
||||||
},
|
},
|
||||||
"Активные сессии" : {
|
"Активные сессии" : {
|
||||||
"comment" : "Заголовок экрана активных сессий",
|
"comment" : "Заголовок экрана активных сессий",
|
||||||
@ -249,7 +264,7 @@
|
|||||||
|
|
||||||
},
|
},
|
||||||
"Безопасность" : {
|
"Безопасность" : {
|
||||||
"comment" : "Заголовок экрана настроек безопасности",
|
"comment" : "Message profile safety section title\nЗаголовок экрана настроек безопасности",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@ -261,13 +276,31 @@
|
|||||||
},
|
},
|
||||||
"Безопасность аккаунта" : {
|
"Безопасность аккаунта" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Биография" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Блокировка и жалобы доступны из профиля, как в Telegram." : {
|
||||||
|
"comment" : "Message profile safety section description"
|
||||||
},
|
},
|
||||||
"Блокировка контакта \"%1$@\" появится позже." : {
|
"Блокировка контакта \"%1$@\" появится позже." : {
|
||||||
"comment" : "Contacts block placeholder message"
|
"comment" : "Contacts block placeholder message"
|
||||||
},
|
},
|
||||||
|
"Блокировка чата пока в дизайне. Готовим отдельный экран со статусом и жалобой." : {
|
||||||
|
"comment" : "Message profile block alert message"
|
||||||
|
},
|
||||||
"Бот" : {
|
"Бот" : {
|
||||||
"comment" : "Тип сессии — бот"
|
"comment" : "Тип сессии — бот"
|
||||||
},
|
},
|
||||||
|
"был(а) %@" : {
|
||||||
|
"comment" : "Message profile last seen relative format"
|
||||||
|
},
|
||||||
|
"В ваших контактах" : {
|
||||||
|
"comment" : "Message profile user in contacts tag"
|
||||||
|
},
|
||||||
|
"в сети" : {
|
||||||
|
"comment" : "Message profile online status"
|
||||||
|
},
|
||||||
"В чате пока нет сообщений." : {
|
"В чате пока нет сообщений." : {
|
||||||
|
|
||||||
},
|
},
|
||||||
@ -319,7 +352,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Видео" : {
|
"Видео" : {
|
||||||
"comment" : "Video message placeholder"
|
"comment" : "Message profile video action\nVideo message placeholder"
|
||||||
|
},
|
||||||
|
"Видео созвоны появятся вместе с звонками. Интерфейс повторит Telegram." : {
|
||||||
|
"comment" : "Message profile video action description"
|
||||||
},
|
},
|
||||||
"Видимость и контент" : {
|
"Видимость и контент" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -424,6 +460,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Вы в его контактах" : {
|
||||||
|
"comment" : "Message profile contact tag"
|
||||||
|
},
|
||||||
|
"Вы в его чёрном списке" : {
|
||||||
|
"comment" : "Message profile blacklist tag"
|
||||||
|
},
|
||||||
"Вы всегда можете отключить двухфакторную защиту, но мы рекомендуем оставлять её включённой для безопасности." : {
|
"Вы всегда можете отключить двухфакторную защиту, но мы рекомендуем оставлять её включённой для безопасности." : {
|
||||||
"comment" : "Рекомендация оставить 2FA включенной"
|
"comment" : "Рекомендация оставить 2FA включенной"
|
||||||
},
|
},
|
||||||
@ -475,6 +517,9 @@
|
|||||||
"Глобальный поиск" : {
|
"Глобальный поиск" : {
|
||||||
"comment" : "Global search section"
|
"comment" : "Global search section"
|
||||||
},
|
},
|
||||||
|
"Голосовые звонки пока недоступны. Как только включим WebRTC, кнопка оживёт." : {
|
||||||
|
"comment" : "Message profile call action description"
|
||||||
|
},
|
||||||
"Готово" : {
|
"Готово" : {
|
||||||
"comment" : "Profile update success title\nЗаголовок успешного уведомления",
|
"comment" : "Profile update success title\nЗаголовок успешного уведомления",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -498,6 +543,9 @@
|
|||||||
},
|
},
|
||||||
"Данные и кэш" : {
|
"Данные и кэш" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Дата регистрации в Yobble" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Двухфакторная аутентификация" : {
|
"Двухфакторная аутентификация" : {
|
||||||
"comment" : "Заголовок экрана 2FA\nПереход к настройкам двухфакторной аутентификации",
|
"comment" : "Заголовок экрана 2FA\nПереход к настройкам двухфакторной аутентификации",
|
||||||
@ -518,6 +566,9 @@
|
|||||||
},
|
},
|
||||||
"Для начала, мы рекомендуем настроить параметры безопасности вашего аккаунта." : {
|
"Для начала, мы рекомендуем настроить параметры безопасности вашего аккаунта." : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Добавить в контакты" : {
|
||||||
|
"comment" : "Message profile add to contacts title"
|
||||||
},
|
},
|
||||||
"Добавить друзей" : {
|
"Добавить друзей" : {
|
||||||
"comment" : "Add friends",
|
"comment" : "Add friends",
|
||||||
@ -530,6 +581,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Добавить контакт" : {
|
||||||
|
"comment" : "Message profile add contact alert title"
|
||||||
|
},
|
||||||
"Добавление новых блокировок появится позже." : {
|
"Добавление новых блокировок появится позже." : {
|
||||||
"comment" : "Add blocked user placeholder message"
|
"comment" : "Add blocked user placeholder message"
|
||||||
},
|
},
|
||||||
@ -541,6 +595,9 @@
|
|||||||
},
|
},
|
||||||
"Добро пожаловать в Yobble!" : {
|
"Добро пожаловать в Yobble!" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Дополнительные действия." : {
|
||||||
|
"comment" : "Message profile more action description"
|
||||||
},
|
},
|
||||||
"Другие устройства (%d)" : {
|
"Другие устройства (%d)" : {
|
||||||
"comment" : "Заголовок секции других устройств с количеством"
|
"comment" : "Заголовок секции других устройств с количеством"
|
||||||
@ -568,9 +625,24 @@
|
|||||||
},
|
},
|
||||||
"Если предпочитаете классический вход, используйте логин и пароль." : {
|
"Если предпочитаете классический вход, используйте логин и пароль." : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Ещё" : {
|
||||||
|
"comment" : "Message profile more action"
|
||||||
|
},
|
||||||
|
"Ещё…" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Жалоба" : {
|
||||||
|
"comment" : "Message profile report alert title"
|
||||||
|
},
|
||||||
|
"Заблокирован" : {
|
||||||
|
"comment" : "Message profile blocked tag"
|
||||||
},
|
},
|
||||||
"Заблокированные" : {
|
"Заблокированные" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Заблокировать" : {
|
||||||
|
"comment" : "Message profile block alert title\nMessage profile block title"
|
||||||
},
|
},
|
||||||
"Заблокировать контакт" : {
|
"Заблокировать контакт" : {
|
||||||
"comment" : "Contacts context action block"
|
"comment" : "Contacts context action block"
|
||||||
@ -590,6 +662,9 @@
|
|||||||
"Завершить эту сессию?" : {
|
"Завершить эту сессию?" : {
|
||||||
"comment" : "Заголовок подтверждения завершения отдельной сессии"
|
"comment" : "Заголовок подтверждения завершения отдельной сессии"
|
||||||
},
|
},
|
||||||
|
"Заглушить" : {
|
||||||
|
"comment" : "Message profile mute action"
|
||||||
|
},
|
||||||
"Заглушка: Push-уведомления" : {
|
"Заглушка: Push-уведомления" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
@ -688,6 +763,9 @@
|
|||||||
"Защита приложением будет добавлена в будущих обновлениях." : {
|
"Защита приложением будет добавлена в будущих обновлениях." : {
|
||||||
"comment" : "Сообщение заглушки пароля на приложение"
|
"comment" : "Сообщение заглушки пароля на приложение"
|
||||||
},
|
},
|
||||||
|
"Звонок" : {
|
||||||
|
"comment" : "Message profile call action"
|
||||||
|
},
|
||||||
"Здесь не будут чаты" : {
|
"Здесь не будут чаты" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@ -718,6 +796,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Избранное" : {
|
||||||
|
"comment" : "Message profile self chat type"
|
||||||
|
},
|
||||||
"Избранные сообщения" : {
|
"Избранные сообщения" : {
|
||||||
"comment" : "Saved messages title"
|
"comment" : "Saved messages title"
|
||||||
},
|
},
|
||||||
@ -746,6 +827,12 @@
|
|||||||
"Изображение" : {
|
"Изображение" : {
|
||||||
"comment" : "Image message placeholder"
|
"comment" : "Image message placeholder"
|
||||||
},
|
},
|
||||||
|
"Имя в чате" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Имя, логин и статус — как в профиле Telegram." : {
|
||||||
|
"comment" : "Message profile about description"
|
||||||
|
},
|
||||||
"Инвайт-код (необязательно)" : {
|
"Инвайт-код (необязательно)" : {
|
||||||
"comment" : "Инвайт-код",
|
"comment" : "Инвайт-код",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -768,6 +855,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"История медиа синхронизируется. Как только появятся первые вложения, они покажутся здесь списком превью." : {
|
||||||
|
"comment" : "Message profile media footer"
|
||||||
|
},
|
||||||
"Ищем пользователей…" : {
|
"Ищем пользователей…" : {
|
||||||
"comment" : "Global search loading"
|
"comment" : "Global search loading"
|
||||||
},
|
},
|
||||||
@ -801,6 +891,9 @@
|
|||||||
"Кликер в разработке" : {
|
"Кликер в разработке" : {
|
||||||
"comment" : "Concept tab placeholder title"
|
"comment" : "Concept tab placeholder title"
|
||||||
},
|
},
|
||||||
|
"Кнопка поделиться соберёт ссылку, QR и кнопку пересылки контакта." : {
|
||||||
|
"comment" : "Message profile share alert message"
|
||||||
|
},
|
||||||
"Код дружбы" : {
|
"Код дружбы" : {
|
||||||
"comment" : "Friend code badge"
|
"comment" : "Friend code badge"
|
||||||
},
|
},
|
||||||
@ -813,6 +906,9 @@
|
|||||||
"Коды восстановления" : {
|
"Коды восстановления" : {
|
||||||
"comment" : "Раздел кодов восстановления 2FA"
|
"comment" : "Раздел кодов восстановления 2FA"
|
||||||
},
|
},
|
||||||
|
"Контакт" : {
|
||||||
|
"comment" : "Message profile contact section title"
|
||||||
|
},
|
||||||
"Контактов пока нет" : {
|
"Контактов пока нет" : {
|
||||||
"comment" : "Contacts empty state title"
|
"comment" : "Contacts empty state title"
|
||||||
},
|
},
|
||||||
@ -931,6 +1027,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Личный чат" : {
|
||||||
|
"comment" : "Message profile private chat type"
|
||||||
|
},
|
||||||
"Логин" : {
|
"Логин" : {
|
||||||
"comment" : "Логин",
|
"comment" : "Логин",
|
||||||
"extractionState" : "stale",
|
"extractionState" : "stale",
|
||||||
@ -979,6 +1078,9 @@
|
|||||||
},
|
},
|
||||||
"Массовая отчистка" : {
|
"Массовая отчистка" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Медиа, ссылки и файлы" : {
|
||||||
|
"comment" : "Message profile media title"
|
||||||
},
|
},
|
||||||
"Мессенджер-режим сейчас проработан примерно на 50%." : {
|
"Мессенджер-режим сейчас проработан примерно на 50%." : {
|
||||||
|
|
||||||
@ -1050,6 +1152,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Мы постепенно повторяем знакомый паттерн Telegram, чтобы переход был комфортным. Укажите, что ещё ожидать на экране профиля — добавим приоритетно." : {
|
||||||
|
"comment" : "Message profile footer"
|
||||||
|
},
|
||||||
"Мы свяжемся с вами по адресу %@, как только ответим." : {
|
"Мы свяжемся с вами по адресу %@, как только ответим." : {
|
||||||
"comment" : "feedback: success email",
|
"comment" : "feedback: success email",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -1072,6 +1177,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"На Yobble" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"На платформе с %@" : {
|
||||||
|
"comment" : "Message profile joined format"
|
||||||
|
},
|
||||||
"Назад" : {
|
"Назад" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
@ -1174,6 +1285,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Настройки чата" : {
|
||||||
|
"comment" : "Message profile chat settings title"
|
||||||
|
},
|
||||||
"Начальная настройка" : {
|
"Начальная настройка" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
@ -1389,6 +1503,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Недоступно" : {
|
||||||
|
"comment" : "Message profile rating unavailable"
|
||||||
|
},
|
||||||
"Неизвестная ошибка" : {
|
"Неизвестная ошибка" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@ -1520,6 +1637,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"О пользователе" : {
|
||||||
|
"comment" : "Message profile about title"
|
||||||
|
},
|
||||||
"О приложении" : {
|
"О приложении" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@ -1599,6 +1719,9 @@
|
|||||||
},
|
},
|
||||||
"Отображаемое имя" : {
|
"Отображаемое имя" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Отправим ссылку или QR — как в Telegram." : {
|
||||||
|
"comment" : "Message profile share contact subtitle"
|
||||||
},
|
},
|
||||||
"Отправить код ещё раз" : {
|
"Отправить код ещё раз" : {
|
||||||
|
|
||||||
@ -1661,12 +1784,18 @@
|
|||||||
},
|
},
|
||||||
"Очистить всё" : {
|
"Очистить всё" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Очистить историю" : {
|
||||||
|
"comment" : "Message profile clear history title"
|
||||||
},
|
},
|
||||||
"Очистить кэш (кроме текущего)" : {
|
"Очистить кэш (кроме текущего)" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Очистить кэш текущего пользователя" : {
|
"Очистить кэш текущего пользователя" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Очистка истории" : {
|
||||||
|
"comment" : "Message profile clear history alert title"
|
||||||
},
|
},
|
||||||
"Ошибка" : {
|
"Ошибка" : {
|
||||||
"comment" : "Common error title\nContacts load error title\nProfile update error title\nЗаголовок сообщения об ошибке",
|
"comment" : "Common error title\nContacts load error title\nProfile update error title\nЗаголовок сообщения об ошибке",
|
||||||
@ -1844,6 +1973,12 @@
|
|||||||
"Перейдите в раздел \"Настройки > Сменить пароль\" и следуйте инструкциям." : {
|
"Перейдите в раздел \"Настройки > Сменить пароль\" и следуйте инструкциям." : {
|
||||||
"comment" : "FAQ answer: reset password"
|
"comment" : "FAQ answer: reset password"
|
||||||
},
|
},
|
||||||
|
"Перестанет появляться в чате и не сможет писать." : {
|
||||||
|
"comment" : "Message profile block subtitle"
|
||||||
|
},
|
||||||
|
"Плитки как в Telegram — скоро здесь появятся вложения из чата." : {
|
||||||
|
"comment" : "Message profile media description"
|
||||||
|
},
|
||||||
"По умолчанию это полноценная соцсеть с лентой, историями и подписками. Если нужно только общение без лишнего контента, переключитесь на режим “Только чаты”. Переключить режим можно в любой момент." : {
|
"По умолчанию это полноценная соцсеть с лентой, историями и подписками. Если нужно только общение без лишнего контента, переключитесь на режим “Только чаты”. Переключить режим можно в любой момент." : {
|
||||||
|
|
||||||
},
|
},
|
||||||
@ -1895,6 +2030,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Поделиться" : {
|
||||||
|
"comment" : "Message profile share alert title"
|
||||||
|
},
|
||||||
|
"Поделиться профилем" : {
|
||||||
|
"comment" : "Message profile share contact title"
|
||||||
|
},
|
||||||
"Подключение" : {
|
"Подключение" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
@ -1918,6 +2059,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Подтверждённый профиль" : {
|
||||||
|
"comment" : "Message profile verified tag"
|
||||||
|
},
|
||||||
|
"Пожаловаться" : {
|
||||||
|
"comment" : "Message profile report title"
|
||||||
|
},
|
||||||
"Пожалуйста, введите корректный e-mail." : {
|
"Пожалуйста, введите корректный e-mail." : {
|
||||||
"comment" : "feedback: email error",
|
"comment" : "feedback: email error",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -1933,7 +2080,7 @@
|
|||||||
|
|
||||||
},
|
},
|
||||||
"Поиск" : {
|
"Поиск" : {
|
||||||
|
"comment" : "Message profile search action"
|
||||||
},
|
},
|
||||||
"Поиск отменён." : {
|
"Поиск отменён." : {
|
||||||
"comment" : "Search cancelled"
|
"comment" : "Search cancelled"
|
||||||
@ -2011,6 +2158,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Пользователь снова сможет писать вам." : {
|
||||||
|
"comment" : "Message profile unblock subtitle"
|
||||||
|
},
|
||||||
|
"Пользователь удалён" : {
|
||||||
|
"comment" : "Message profile deleted user status"
|
||||||
|
},
|
||||||
"Помощь" : {
|
"Помощь" : {
|
||||||
"comment" : "Help Center",
|
"comment" : "Help Center",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -2023,13 +2176,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Понятно" : {
|
"Понятно" : {
|
||||||
"comment" : "Chat creation error acknowledgment"
|
"comment" : "Chat creation error acknowledgment\nPlaceholder alert dismiss"
|
||||||
},
|
},
|
||||||
"Попробовать снова можно через %d сек" : {
|
"Попробовать снова можно через %d сек" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Попробуйте изменить запрос поиска." : {
|
"Попробуйте изменить запрос поиска." : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Последний визит" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Последний вход: %@" : {
|
"Последний вход: %@" : {
|
||||||
"comment" : "Дата последнего входа в сессию"
|
"comment" : "Дата последнего входа в сессию"
|
||||||
@ -2045,6 +2201,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Появится мутация на 1 час, 1 день или навсегда." : {
|
||||||
|
"comment" : "Message profile mute action description"
|
||||||
|
},
|
||||||
|
"Появится отдельная запись в адресной книге Yobble." : {
|
||||||
|
"comment" : "Message profile add to contacts subtitle"
|
||||||
|
},
|
||||||
"Правила сервиса" : {
|
"Правила сервиса" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
@ -2083,6 +2245,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Приватный диалог" : {
|
||||||
|
"comment" : "Message profile default chat type"
|
||||||
|
},
|
||||||
"Приглашение достигло лимита использования." : {
|
"Приглашение достигло лимита использования." : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@ -2228,7 +2393,7 @@
|
|||||||
"comment" : "Contacts placeholder message"
|
"comment" : "Contacts placeholder message"
|
||||||
},
|
},
|
||||||
"Профиль" : {
|
"Профиль" : {
|
||||||
"comment" : "Message profile placeholder nav title",
|
"comment" : "Message profile navigation title",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@ -2241,9 +2406,6 @@
|
|||||||
"Профиль в разработке" : {
|
"Профиль в разработке" : {
|
||||||
"comment" : "Search placeholder title"
|
"comment" : "Search placeholder title"
|
||||||
},
|
},
|
||||||
"Профиль для сообщений пока в разработке." : {
|
|
||||||
"comment" : "Message profile placeholder title"
|
|
||||||
},
|
|
||||||
"Профиль и поиск" : {
|
"Профиль и поиск" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@ -2262,9 +2424,12 @@
|
|||||||
},
|
},
|
||||||
"Публичная информация" : {
|
"Публичная информация" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Публичное имя" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Разблокировать" : {
|
"Разблокировать" : {
|
||||||
"comment" : "Unblock confirmation action"
|
"comment" : "Message profile unblock alert title\nMessage profile unblock title\nUnblock confirmation action"
|
||||||
},
|
},
|
||||||
"Разрешить пересылку сообщений" : {
|
"Разрешить пересылку сообщений" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -2379,11 +2544,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Редактор контактов скоро появится. Мы сохраним имя, телефон и заметку." : {
|
||||||
|
"comment" : "Message profile add contact alert message"
|
||||||
|
},
|
||||||
"Режим" : {
|
"Режим" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Режим автоудаления появится чуть позже. Мы добавим пресеты на 24 часа, 7 дней и 1 месяц — совсем как в Telegram." : {
|
||||||
|
"comment" : "Message profile auto delete alert message"
|
||||||
},
|
},
|
||||||
"Режим мессенжера" : {
|
"Режим мессенжера" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Рейтинг собеседника" : {
|
||||||
|
"comment" : "Message profile rating title"
|
||||||
},
|
},
|
||||||
"Сборка:" : {
|
"Сборка:" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -2501,11 +2675,20 @@
|
|||||||
"Скоро" : {
|
"Скоро" : {
|
||||||
"comment" : "Add blocked user placeholder title\nContacts placeholder title\nЗаголовок заглушки"
|
"comment" : "Add blocked user placeholder title\nContacts placeholder title\nЗаголовок заглушки"
|
||||||
},
|
},
|
||||||
"Скоро здесь появится информация о собеседнике, статусе и дополнительных действиях." : {
|
"Скоро можно будет искать сообщения, ссылки и файлы в этом чате." : {
|
||||||
"comment" : "Message profile placeholder description"
|
"comment" : "Message profile search action description"
|
||||||
|
},
|
||||||
|
"Скоро можно будет очистить сообщения выборочно или целиком. Пока подготовим дизайн." : {
|
||||||
|
"comment" : "Message profile clear history alert message"
|
||||||
},
|
},
|
||||||
"Скоро появится мини-игра, где можно заработать очки для кастомизации профиля. Следите за обновлениями!" : {
|
"Скоро появится мини-игра, где можно заработать очки для кастомизации профиля. Следите за обновлениями!" : {
|
||||||
"comment" : "Concept tab placeholder description"
|
"comment" : "Concept tab placeholder description"
|
||||||
|
},
|
||||||
|
"Скоро появится разблокировка с подтверждением и синхронизацией." : {
|
||||||
|
"comment" : "Message profile unblock alert message"
|
||||||
|
},
|
||||||
|
"Скрыть" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Слишком много запросов." : {
|
"Слишком много запросов." : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -2557,6 +2740,9 @@
|
|||||||
},
|
},
|
||||||
"Сообщение слишком длинное." : {
|
"Сообщение слишком длинное." : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Сообщения пока сохраняются навсегда." : {
|
||||||
|
"comment" : "Message profile auto delete subtitle"
|
||||||
},
|
},
|
||||||
"Сообщите о материалах" : {
|
"Сообщите о материалах" : {
|
||||||
"comment" : "feedback category subtitle: content",
|
"comment" : "feedback category subtitle: content",
|
||||||
@ -2569,6 +2755,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Сообщите о спаме или нарушении правил." : {
|
||||||
|
"comment" : "Message profile report subtitle"
|
||||||
|
},
|
||||||
"Сохранение..." : {
|
"Сохранение..." : {
|
||||||
|
|
||||||
},
|
},
|
||||||
@ -2693,8 +2882,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Тип диалога" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Тишина включена. Чат не тревожит до включения сигнала." : {
|
||||||
|
"comment" : "Message profile notifications subtitle off"
|
||||||
|
},
|
||||||
"Только чаты (готово 60%)" : {
|
"Только чаты (готово 60%)" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Тонкие настройки диалога по образцу профиля Telegram." : {
|
||||||
|
"comment" : "Message profile chat settings description"
|
||||||
},
|
},
|
||||||
"Ты шо ебанутый? А ниче тот факт что новый пароль должен отличаться от старого." : {
|
"Ты шо ебанутый? А ниче тот факт что новый пароль должен отличаться от старого." : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -2721,6 +2919,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Уведомления" : {
|
"Уведомления" : {
|
||||||
|
"comment" : "Message profile notifications title",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@ -2742,6 +2941,9 @@
|
|||||||
"Удалить контакт" : {
|
"Удалить контакт" : {
|
||||||
"comment" : "Contacts context action delete"
|
"comment" : "Contacts context action delete"
|
||||||
},
|
},
|
||||||
|
"Удалить переписку только для себя." : {
|
||||||
|
"comment" : "Message profile clear history subtitle"
|
||||||
|
},
|
||||||
"Удалить фото" : {
|
"Удалить фото" : {
|
||||||
"comment" : "Avatar delete"
|
"comment" : "Avatar delete"
|
||||||
},
|
},
|
||||||
@ -2765,6 +2967,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Управление карточкой собеседника." : {
|
||||||
|
"comment" : "Message profile contact section description"
|
||||||
|
},
|
||||||
|
"Форма жалобы появится чуть позже — добавим прикрепление скриншотов и тип нарушения." : {
|
||||||
|
"comment" : "Message profile report alert message"
|
||||||
|
},
|
||||||
"Функция пока недоступна." : {
|
"Функция пока недоступна." : {
|
||||||
"comment" : "Сообщение заглушки"
|
"comment" : "Сообщение заглушки"
|
||||||
},
|
},
|
||||||
@ -2892,6 +3100,9 @@
|
|||||||
},
|
},
|
||||||
"Этот аккаунт недоступен." : {
|
"Этот аккаунт недоступен." : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Юзернейм" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Я ознакомился и принимаю правила сервиса" : {
|
"Я ознакомился и принимаю правила сервиса" : {
|
||||||
|
|
||||||
|
|||||||
1042
yobble/Views/Chat/MessageProfileView.swift
Normal file
1042
yobble/Views/Chat/MessageProfileView.swift
Normal file
File diff suppressed because it is too large
Load Diff
@ -52,7 +52,7 @@ struct PrivateChatView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NavigationLink(
|
NavigationLink(
|
||||||
destination: MessageProfilePlaceholderView(chat: chat, currentUserId: currentUserId),
|
destination: MessageProfileView(chat: chat, currentUserId: currentUserId),
|
||||||
isActive: $isProfilePresented
|
isActive: $isProfilePresented
|
||||||
) {
|
) {
|
||||||
EmptyView()
|
EmptyView()
|
||||||
@ -723,156 +723,6 @@ private var headerPlaceholderAvatar: some View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MessageProfilePlaceholderView: View {
|
|
||||||
let chat: PrivateChatListItem
|
|
||||||
let currentUserId: String?
|
|
||||||
private let avatarSize: CGFloat = 96
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
ScrollView {
|
|
||||||
VStack(spacing: 24) {
|
|
||||||
profileAvatar
|
|
||||||
|
|
||||||
VStack(spacing: 4) {
|
|
||||||
Text(displayName)
|
|
||||||
.font(.title3)
|
|
||||||
.fontWeight(.semibold)
|
|
||||||
.multilineTextAlignment(.center)
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
|
|
||||||
if let login = loginDisplay {
|
|
||||||
Text(login)
|
|
||||||
.font(.subheadline)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(NSLocalizedString("Профиль для сообщений пока в разработке.", comment: "Message profile placeholder title"))
|
|
||||||
.font(.body)
|
|
||||||
.multilineTextAlignment(.center)
|
|
||||||
|
|
||||||
Text(NSLocalizedString("Скоро здесь появится информация о собеседнике, статусе и дополнительных действиях.", comment: "Message profile placeholder description"))
|
|
||||||
.font(.footnote)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
.multilineTextAlignment(.center)
|
|
||||||
}
|
|
||||||
.padding(.horizontal, 24)
|
|
||||||
.padding(.top, 60)
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
}
|
|
||||||
.background(Color(UIColor.systemBackground))
|
|
||||||
.navigationTitle(NSLocalizedString("Профиль", comment: "Message profile placeholder nav title"))
|
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var displayName: String {
|
|
||||||
if let custom = trimmed(chat.chatData?.customName) {
|
|
||||||
return custom
|
|
||||||
}
|
|
||||||
if let full = trimmed(chat.chatData?.fullName) {
|
|
||||||
return full
|
|
||||||
}
|
|
||||||
if let login = trimmed(chat.chatData?.login) {
|
|
||||||
return "@\(login)"
|
|
||||||
}
|
|
||||||
return NSLocalizedString("Неизвестный пользователь", comment: "Message profile fallback title")
|
|
||||||
}
|
|
||||||
|
|
||||||
private var loginDisplay: String? {
|
|
||||||
guard let login = trimmed(chat.chatData?.login) else { return nil }
|
|
||||||
return "@\(login)"
|
|
||||||
}
|
|
||||||
|
|
||||||
private var isDeletedUser: Bool {
|
|
||||||
trimmed(chat.chatData?.login) == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
private var isOfficial: Bool {
|
|
||||||
chat.chatData?.isOfficial ?? false
|
|
||||||
}
|
|
||||||
|
|
||||||
private var avatarBackgroundColor: Color {
|
|
||||||
if isDeletedUser {
|
|
||||||
return Color(.systemGray5)
|
|
||||||
}
|
|
||||||
return isOfficial ? Color.accentColor.opacity(0.85) : Color.accentColor.opacity(0.15)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var avatarTextColor: Color {
|
|
||||||
if isDeletedUser {
|
|
||||||
return Color.accentColor
|
|
||||||
}
|
|
||||||
return isOfficial ? Color.white : Color.accentColor
|
|
||||||
}
|
|
||||||
|
|
||||||
private var avatarInitial: String {
|
|
||||||
if let name = trimmed(chat.chatData?.customName) ?? trimmed(chat.chatData?.fullName) {
|
|
||||||
let components = name.split(separator: " ")
|
|
||||||
let initials = components.prefix(2).compactMap { $0.first }
|
|
||||||
if !initials.isEmpty {
|
|
||||||
return initials.map { String($0) }.joined().uppercased()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let login = trimmed(chat.chatData?.login) {
|
|
||||||
return String(login.prefix(1)).uppercased()
|
|
||||||
}
|
|
||||||
|
|
||||||
return "?"
|
|
||||||
}
|
|
||||||
|
|
||||||
private var avatarUrl: URL? {
|
|
||||||
guard let chatData = chat.chatData,
|
|
||||||
let fileId = chatData.avatars?.current?.fileId else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
let userId = chatData.userId
|
|
||||||
return URL(string: "\(AppConfig.API_SERVER)/v1/storage/download/avatar/\(userId)?file_id=\(fileId)")
|
|
||||||
}
|
|
||||||
|
|
||||||
@ViewBuilder
|
|
||||||
private var profileAvatar: some View {
|
|
||||||
if let url = avatarUrl,
|
|
||||||
let fileId = chat.chatData?.avatars?.current?.fileId,
|
|
||||||
let userId = currentUserId {
|
|
||||||
CachedAvatarView(url: url, fileId: fileId, userId: userId) {
|
|
||||||
placeholderAvatar
|
|
||||||
}
|
|
||||||
.aspectRatio(contentMode: .fill)
|
|
||||||
.frame(width: avatarSize, height: avatarSize)
|
|
||||||
.clipShape(Circle())
|
|
||||||
} else {
|
|
||||||
placeholderAvatar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var placeholderAvatar: some View {
|
|
||||||
Circle()
|
|
||||||
.fill(avatarBackgroundColor)
|
|
||||||
.frame(width: avatarSize, height: avatarSize)
|
|
||||||
.overlay(
|
|
||||||
Group {
|
|
||||||
if isDeletedUser {
|
|
||||||
Image(systemName: "person.slash")
|
|
||||||
.symbolRenderingMode(.hierarchical)
|
|
||||||
.font(.system(size: avatarSize * 0.45, weight: .semibold))
|
|
||||||
.foregroundColor(avatarTextColor)
|
|
||||||
} else {
|
|
||||||
Text(avatarInitial)
|
|
||||||
.font(.system(size: avatarSize * 0.45, weight: .semibold))
|
|
||||||
.foregroundColor(avatarTextColor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func trimmed(_ text: String?) -> String? {
|
|
||||||
guard let text = text?.trimmingCharacters(in: .whitespacesAndNewlines), !text.isEmpty else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if canImport(UIKit)
|
#if canImport(UIKit)
|
||||||
private struct LegacyMultilineTextView: UIViewRepresentable {
|
private struct LegacyMultilineTextView: UIViewRepresentable {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user