Compare commits
4 Commits
c84a8e36a0
...
12be44673a
| Author | SHA1 | Date | |
|---|---|---|---|
| 12be44673a | |||
| ee4a19155f | |||
| 66bd6a99d4 | |||
| 55839ffd5d |
@ -131,6 +131,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"GIF" : {
|
||||||
|
"comment" : "Message profile category gifs"
|
||||||
|
},
|
||||||
"Hello, world!" : {
|
"Hello, world!" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@ -508,6 +511,9 @@
|
|||||||
"Глобальный поиск" : {
|
"Глобальный поиск" : {
|
||||||
"comment" : "Global search section"
|
"comment" : "Global search section"
|
||||||
},
|
},
|
||||||
|
"Голосовые" : {
|
||||||
|
"comment" : "Message profile category voice"
|
||||||
|
},
|
||||||
"Голосовые звонки пока недоступны. Как только включим WebRTC, кнопка оживёт." : {
|
"Голосовые звонки пока недоступны. Как только включим WebRTC, кнопка оживёт." : {
|
||||||
"comment" : "Message profile call action description"
|
"comment" : "Message profile call action description"
|
||||||
},
|
},
|
||||||
@ -522,6 +528,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Группы" : {
|
||||||
|
"comment" : "Message profile category groups"
|
||||||
|
},
|
||||||
"Данные" : {
|
"Данные" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@ -843,9 +852,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"История медиа синхронизируется. Как только появятся первые вложения, они покажутся здесь списком превью." : {
|
|
||||||
"comment" : "Message profile media footer"
|
|
||||||
},
|
|
||||||
"Ищем пользователей…" : {
|
"Ищем пользователей…" : {
|
||||||
"comment" : "Global search loading"
|
"comment" : "Global search loading"
|
||||||
},
|
},
|
||||||
@ -1061,8 +1067,8 @@
|
|||||||
"Массовая отчистка" : {
|
"Массовая отчистка" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Медиа, ссылки и файлы" : {
|
"Медиа" : {
|
||||||
"comment" : "Message profile media title"
|
"comment" : "Message profile category media"
|
||||||
},
|
},
|
||||||
"Мессенджер-режим сейчас проработан примерно на 50%." : {
|
"Мессенджер-режим сейчас проработан примерно на 50%." : {
|
||||||
|
|
||||||
@ -1106,6 +1112,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Музыка" : {
|
||||||
|
"comment" : "Message profile category music"
|
||||||
|
},
|
||||||
"Мы используем адрес только для ответа на ваш запрос." : {
|
"Мы используем адрес только для ответа на ваш запрос." : {
|
||||||
"comment" : "feedback: email hint",
|
"comment" : "feedback: email hint",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -1943,12 +1952,6 @@
|
|||||||
"Перейдите в раздел \"Настройки > Сменить пароль\" и следуйте инструкциям." : {
|
"Перейдите в раздел \"Настройки > Сменить пароль\" и следуйте инструкциям." : {
|
||||||
"comment" : "FAQ answer: reset password"
|
"comment" : "FAQ answer: reset password"
|
||||||
},
|
},
|
||||||
"Перестанет появляться в чате и не сможет писать." : {
|
|
||||||
"comment" : "Message profile block subtitle"
|
|
||||||
},
|
|
||||||
"Плитки как в Telegram — скоро здесь появятся вложения из чата." : {
|
|
||||||
"comment" : "Message profile media description"
|
|
||||||
},
|
|
||||||
"По умолчанию это полноценная соцсеть с лентой, историями и подписками. Если нужно только общение без лишнего контента, переключитесь на режим “Только чаты”. Переключить режим можно в любой момент." : {
|
"По умолчанию это полноценная соцсеть с лентой, историями и подписками. Если нужно только общение без лишнего контента, переключитесь на режим “Только чаты”. Переключить режим можно в любой момент." : {
|
||||||
|
|
||||||
},
|
},
|
||||||
@ -2119,9 +2122,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Пользователь снова сможет писать вам." : {
|
|
||||||
"comment" : "Message profile unblock subtitle"
|
|
||||||
},
|
|
||||||
"Пользователь удалён" : {
|
"Пользователь удалён" : {
|
||||||
"comment" : "Message profile deleted user status"
|
"comment" : "Message profile deleted user status"
|
||||||
},
|
},
|
||||||
@ -2151,6 +2151,9 @@
|
|||||||
"Последний вход: %@" : {
|
"Последний вход: %@" : {
|
||||||
"comment" : "Дата последнего входа в сессию"
|
"comment" : "Дата последнего входа в сессию"
|
||||||
},
|
},
|
||||||
|
"Посты" : {
|
||||||
|
"comment" : "Message profile category posts"
|
||||||
|
},
|
||||||
"Похвала" : {
|
"Похвала" : {
|
||||||
"comment" : "feedback category: praise",
|
"comment" : "feedback category: praise",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -2165,9 +2168,6 @@
|
|||||||
"Появится мутация на 1 час, 1 день или навсегда." : {
|
"Появится мутация на 1 час, 1 день или навсегда." : {
|
||||||
"comment" : "Message profile mute action description"
|
"comment" : "Message profile mute action description"
|
||||||
},
|
},
|
||||||
"Появится отдельная запись в адресной книге Yobble." : {
|
|
||||||
"comment" : "Message profile add to contacts subtitle"
|
|
||||||
},
|
|
||||||
"Правила сервиса" : {
|
"Правила сервиса" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
@ -2392,6 +2392,12 @@
|
|||||||
"Разблокировать" : {
|
"Разблокировать" : {
|
||||||
"comment" : "Message profile unblock alert title\nMessage profile unblock title\nUnblock confirmation action"
|
"comment" : "Message profile unblock alert title\nMessage profile unblock title\nUnblock confirmation action"
|
||||||
},
|
},
|
||||||
|
"Раздел скоро станет активным — собираем и индексируем вложения." : {
|
||||||
|
"comment" : "Message profile media placeholder message"
|
||||||
|
},
|
||||||
|
"Разделы временно показывают заглушки — позже спрячем пустые категории." : {
|
||||||
|
"comment" : "Message profile media footer new"
|
||||||
|
},
|
||||||
"Разрешить пересылку сообщений" : {
|
"Разрешить пересылку сообщений" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@ -2709,6 +2715,9 @@
|
|||||||
},
|
},
|
||||||
"Сохранение..." : {
|
"Сохранение..." : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Сохранённые" : {
|
||||||
|
"comment" : "Message profile category saved"
|
||||||
},
|
},
|
||||||
"Сохраните секретный ключ и введите код из приложения, чтобы завершить настройку." : {
|
"Сохраните секретный ключ и введите код из приложения, чтобы завершить настройку." : {
|
||||||
"comment" : "Сообщение после активации 2FA"
|
"comment" : "Сообщение после активации 2FA"
|
||||||
@ -2751,6 +2760,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Ссылки" : {
|
||||||
|
"comment" : "Message profile category links"
|
||||||
|
},
|
||||||
"Старый пароль" : {
|
"Старый пароль" : {
|
||||||
"comment" : "Старый пароль",
|
"comment" : "Старый пароль",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -2907,6 +2919,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Файлы" : {
|
||||||
|
"comment" : "Message profile category files"
|
||||||
|
},
|
||||||
"Функция пока недоступна." : {
|
"Функция пока недоступна." : {
|
||||||
"comment" : "Сообщение заглушки"
|
"comment" : "Сообщение заглушки"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -232,6 +232,11 @@ struct MessageProfileView: View {
|
|||||||
title: NSLocalizedString("Юзернейм", comment: ""),
|
title: NSLocalizedString("Юзернейм", comment: ""),
|
||||||
value: login
|
value: login
|
||||||
)
|
)
|
||||||
|
}else{
|
||||||
|
infoRow(
|
||||||
|
title: NSLocalizedString("Юзернейм", comment: ""),
|
||||||
|
value: "Неизвестный пользователь"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let membership = membershipDescription {
|
if let membership = membershipDescription {
|
||||||
@ -253,31 +258,23 @@ struct MessageProfileView: View {
|
|||||||
|
|
||||||
if shouldShowRelationshipQuickActions {
|
if shouldShowRelationshipQuickActions {
|
||||||
rowDivider
|
rowDivider
|
||||||
VStack(spacing: 8) {
|
filledActionButton(
|
||||||
buttonRow(
|
title: NSLocalizedString("Добавить в контакты", comment: "Message profile add to contacts title"),
|
||||||
icon: "person.badge.plus",
|
tint: Color.accentColor
|
||||||
title: NSLocalizedString("Добавить в контакты", comment: "Message profile add to contacts title"),
|
) {
|
||||||
subtitle: NSLocalizedString("Появится отдельная запись в адресной книге Yobble.", comment: "Message profile add to contacts subtitle"),
|
handleAddContactTap()
|
||||||
iconTint: .accentColor
|
|
||||||
) {
|
|
||||||
handleAddContactTap()
|
|
||||||
}
|
|
||||||
|
|
||||||
buttonRow(
|
|
||||||
icon: "hand.raised.slash.fill",
|
|
||||||
title: isBlockedByCurrentUser
|
|
||||||
? NSLocalizedString("Разблокировать", comment: "Message profile unblock title")
|
|
||||||
: NSLocalizedString("Заблокировать", comment: "Message profile block title"),
|
|
||||||
subtitle: isBlockedByCurrentUser
|
|
||||||
? NSLocalizedString("Пользователь снова сможет писать вам.", comment: "Message profile unblock subtitle")
|
|
||||||
: NSLocalizedString("Перестанет появляться в чате и не сможет писать.", comment: "Message profile block subtitle"),
|
|
||||||
iconTint: .red,
|
|
||||||
destructive: true
|
|
||||||
) {
|
|
||||||
handleBlockToggleTap()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.padding(.top, 4)
|
|
||||||
|
rowDivider
|
||||||
|
filledActionButton(
|
||||||
|
title: isBlockedByCurrentUser
|
||||||
|
? NSLocalizedString("Разблокировать", comment: "Message profile unblock title")
|
||||||
|
: NSLocalizedString("Заблокировать", comment: "Message profile block title"),
|
||||||
|
tint: isBlockedByCurrentUser ? Color.green : Color.red
|
||||||
|
) {
|
||||||
|
handleBlockToggleTap()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -335,34 +332,20 @@ struct MessageProfileView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var mediaPreviewSection: some View {
|
private var mediaPreviewSection: some View {
|
||||||
section(
|
VStack(alignment: .leading, spacing: 12) {
|
||||||
title: NSLocalizedString("Медиа, ссылки и файлы", comment: "Message profile media title"),
|
|
||||||
description: NSLocalizedString("Плитки как в Telegram — скоро здесь появятся вложения из чата.", comment: "Message profile media description")
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
) {
|
HStack(spacing: 12) {
|
||||||
card {
|
ForEach(mediaCategories) { category in
|
||||||
LazyVGrid(columns: Array(repeating: GridItem(.flexible(), spacing: 8), count: 3), spacing: 8) {
|
mediaCategoryButton(category)
|
||||||
ForEach(Array(sharedMediaPlaceholderIcons.enumerated()), id: \.offset) { index, icon in
|
|
||||||
RoundedRectangle(cornerRadius: 16, style: .continuous)
|
|
||||||
.fill(sharedMediaPlaceholderColors[index % sharedMediaPlaceholderColors.count])
|
|
||||||
.frame(height: 72)
|
|
||||||
.overlay(
|
|
||||||
Image(systemName: icon)
|
|
||||||
.font(.system(size: 20, weight: .semibold))
|
|
||||||
.foregroundColor(.white.opacity(0.9))
|
|
||||||
)
|
|
||||||
.overlay(
|
|
||||||
RoundedRectangle(cornerRadius: 16, style: .continuous)
|
|
||||||
.stroke(Color.white.opacity(0.18), lineWidth: 1)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity)
|
.padding(.vertical, 4)
|
||||||
|
|
||||||
Text(NSLocalizedString("История медиа синхронизируется. Как только появятся первые вложения, они покажутся здесь списком превью.", comment: "Message profile media footer"))
|
|
||||||
.font(.caption)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
.padding(.top, 12)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Text(NSLocalizedString("Разделы временно показывают заглушки.", comment: "Message profile media footer new"))
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,6 +461,30 @@ struct MessageProfileView: View {
|
|||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func filledActionButton(
|
||||||
|
title: String,
|
||||||
|
subtitle: String? = nil,
|
||||||
|
tint: Color,
|
||||||
|
action: @escaping () -> Void
|
||||||
|
) -> some View {
|
||||||
|
Button(action: action) {
|
||||||
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
|
Text(title)
|
||||||
|
.font(.body)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
if let subtitle {
|
||||||
|
Text(subtitle)
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(tint.opacity(0.7))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.foregroundColor(tint)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
.padding(.vertical, 10)
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
}
|
||||||
|
|
||||||
private func iconBackground<Content: View>(color: Color, @ViewBuilder content: () -> Content) -> some View {
|
private func iconBackground<Content: View>(color: Color, @ViewBuilder content: () -> Content) -> some View {
|
||||||
RoundedRectangle(cornerRadius: 14, style: .continuous)
|
RoundedRectangle(cornerRadius: 14, style: .continuous)
|
||||||
.fill(color)
|
.fill(color)
|
||||||
@ -513,6 +520,20 @@ struct MessageProfileView: View {
|
|||||||
showPlaceholderAction(title: title, message: message)
|
showPlaceholderAction(title: title, message: message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var mediaCategories: [MediaCategory] {
|
||||||
|
[
|
||||||
|
MediaCategory(title: NSLocalizedString("Медиа", comment: "Message profile category media")),
|
||||||
|
MediaCategory(title: NSLocalizedString("Сохранённые", comment: "Message profile category saved")),
|
||||||
|
MediaCategory(title: NSLocalizedString("Файлы", comment: "Message profile category files")),
|
||||||
|
MediaCategory(title: NSLocalizedString("Голосовые", comment: "Message profile category voice")),
|
||||||
|
MediaCategory(title: NSLocalizedString("Ссылки", comment: "Message profile category links")),
|
||||||
|
MediaCategory(title: NSLocalizedString("Группы", comment: "Message profile category groups")),
|
||||||
|
MediaCategory(title: NSLocalizedString("Музыка", comment: "Message profile category music")),
|
||||||
|
MediaCategory(title: NSLocalizedString("GIF", comment: "Message profile category gifs")),
|
||||||
|
MediaCategory(title: NSLocalizedString("Посты", comment: "Message profile category posts"))
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Derived Data
|
// MARK: - Derived Data
|
||||||
|
|
||||||
private var profileBio: String? {
|
private var profileBio: String? {
|
||||||
@ -664,26 +685,31 @@ struct MessageProfileView: View {
|
|||||||
return tags
|
return tags
|
||||||
}
|
}
|
||||||
|
|
||||||
private var sharedMediaPlaceholderIcons: [String] {
|
private func mediaCategoryButton(_ category: MediaCategory) -> some View {
|
||||||
[
|
Button {
|
||||||
"photo.on.rectangle",
|
showPlaceholderAction(
|
||||||
"doc.text.fill",
|
title: category.title,
|
||||||
"link",
|
message: NSLocalizedString("Раздел скоро станет активным — собираем и индексируем вложения.", comment: "Message profile media placeholder message")
|
||||||
"paperclip",
|
)
|
||||||
"music.note",
|
} label: {
|
||||||
"video.fill"
|
VStack(alignment: .leading, spacing: 6) {
|
||||||
]
|
Text(category.title)
|
||||||
}
|
.font(.footnote)
|
||||||
|
.fontWeight(.medium)
|
||||||
private var sharedMediaPlaceholderColors: [Color] {
|
.foregroundColor(.primary)
|
||||||
[
|
}
|
||||||
Color.accentColor.opacity(0.8),
|
.padding(.vertical, 12)
|
||||||
Color.purple.opacity(0.8),
|
.padding(.horizontal, 14)
|
||||||
Color.blue.opacity(0.7),
|
.background(
|
||||||
Color.orange.opacity(0.8),
|
RoundedRectangle(cornerRadius: 20, style: .continuous)
|
||||||
Color.green.opacity(0.7),
|
.fill(Color(UIColor.secondarySystemBackground))
|
||||||
Color.pink.opacity(0.8)
|
)
|
||||||
]
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 20, style: .continuous)
|
||||||
|
.stroke(Color(UIColor.separator).opacity(0.2), lineWidth: 1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var quickActionItems: [ProfileQuickAction] {
|
private var quickActionItems: [ProfileQuickAction] {
|
||||||
@ -896,6 +922,11 @@ private struct StatusTag: Identifiable {
|
|||||||
let tint: Color
|
let tint: Color
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private struct MediaCategory: Identifiable {
|
||||||
|
let id = UUID()
|
||||||
|
let title: String
|
||||||
|
}
|
||||||
|
|
||||||
private struct ProfileQuickAction: Identifiable {
|
private struct ProfileQuickAction: Identifiable {
|
||||||
let id = UUID()
|
let id = UUID()
|
||||||
let icon: String
|
let icon: String
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user