diff --git a/yobble/Resources/Localizable.xcstrings b/yobble/Resources/Localizable.xcstrings index 70b11ef..dfc2dae 100644 --- a/yobble/Resources/Localizable.xcstrings +++ b/yobble/Resources/Localizable.xcstrings @@ -131,6 +131,9 @@ } } }, + "GIF" : { + "comment" : "Message profile category gifs" + }, "Hello, world!" : { "localizations" : { "en" : { @@ -508,6 +511,9 @@ "Глобальный поиск" : { "comment" : "Global search section" }, + "Голосовые" : { + "comment" : "Message profile category voice" + }, "Голосовые звонки пока недоступны. Как только включим WebRTC, кнопка оживёт." : { "comment" : "Message profile call action description" }, @@ -522,6 +528,9 @@ } } }, + "Группы" : { + "comment" : "Message profile category groups" + }, "Данные" : { "localizations" : { "en" : { @@ -843,8 +852,8 @@ } } }, - "История медиа синхронизируется. Как только появятся первые вложения, они покажутся здесь списком превью." : { - "comment" : "Message profile media footer" + "История вложений скоро подтянется — каждую категорию можно будет открыть отдельно." : { + "comment" : "Message profile media footer new" }, "Ищем пользователей…" : { "comment" : "Global search loading" @@ -1060,6 +1069,9 @@ }, "Массовая отчистка" : { + }, + "Медиа" : { + "comment" : "Message profile category media" }, "Медиа, ссылки и файлы" : { "comment" : "Message profile media title" @@ -1106,6 +1118,9 @@ } } }, + "Музыка" : { + "comment" : "Message profile category music" + }, "Мы используем адрес только для ответа на ваш запрос." : { "comment" : "feedback: email hint", "localizations" : { @@ -2145,6 +2160,9 @@ "Последний вход: %@" : { "comment" : "Дата последнего входа в сессию" }, + "Посты" : { + "comment" : "Message profile category posts" + }, "Похвала" : { "comment" : "feedback category: praise", "localizations" : { @@ -2383,6 +2401,9 @@ "Разблокировать" : { "comment" : "Message profile unblock alert title\nMessage profile unblock title\nUnblock confirmation action" }, + "Раздел скоро станет активным — собираем и индексируем вложения." : { + "comment" : "Message profile media placeholder message" + }, "Разрешить пересылку сообщений" : { "localizations" : { "en" : { @@ -2700,6 +2721,9 @@ }, "Сохранение..." : { + }, + "Сохранённые" : { + "comment" : "Message profile category saved" }, "Сохраните секретный ключ и введите код из приложения, чтобы завершить настройку." : { "comment" : "Сообщение после активации 2FA" @@ -2742,6 +2766,9 @@ } } }, + "Ссылки" : { + "comment" : "Message profile category links" + }, "Старый пароль" : { "comment" : "Старый пароль", "localizations" : { @@ -2898,6 +2925,9 @@ } } }, + "Файлы" : { + "comment" : "Message profile category files" + }, "Функция пока недоступна." : { "comment" : "Сообщение заглушки" }, diff --git a/yobble/Views/Chat/MessageProfileView.swift b/yobble/Views/Chat/MessageProfileView.swift index f8f3348..8f46c24 100644 --- a/yobble/Views/Chat/MessageProfileView.swift +++ b/yobble/Views/Chat/MessageProfileView.swift @@ -337,28 +337,19 @@ struct MessageProfileView: View { description: NSLocalizedString("Плитки как в Telegram — скоро здесь появятся вложения из чата.", comment: "Message profile media description") ) { card { - LazyVGrid(columns: Array(repeating: GridItem(.flexible(), spacing: 8), count: 3), spacing: 8) { - 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) - ) + ScrollView(.horizontal, showsIndicators: false) { + HStack(spacing: 12) { + ForEach(mediaCategories) { category in + mediaCategoryButton(category) + } } + .padding(.vertical, 4) } - .frame(maxWidth: .infinity) - Text(NSLocalizedString("История медиа синхронизируется. Как только появятся первые вложения, они покажутся здесь списком превью.", comment: "Message profile media footer")) + Text(NSLocalizedString("История вложений скоро подтянется — каждую категорию можно будет открыть отдельно.", comment: "Message profile media footer new")) .font(.caption) .foregroundColor(.secondary) - .padding(.top, 12) + .padding(.top, 16) } } } @@ -534,6 +525,20 @@ struct MessageProfileView: View { showPlaceholderAction(title: title, message: message) } + private var mediaCategories: [MediaCategory] { + [ + MediaCategory(title: NSLocalizedString("Медиа", comment: "Message profile category media"), icon: "photo.on.rectangle", tint: .blue), + MediaCategory(title: NSLocalizedString("Сохранённые", comment: "Message profile category saved"), icon: "bookmark.fill", tint: .purple), + MediaCategory(title: NSLocalizedString("Файлы", comment: "Message profile category files"), icon: "doc.text.fill", tint: .orange), + MediaCategory(title: NSLocalizedString("Голосовые", comment: "Message profile category voice"), icon: "waveform", tint: .green), + MediaCategory(title: NSLocalizedString("Ссылки", comment: "Message profile category links"), icon: "link", tint: .pink), + MediaCategory(title: NSLocalizedString("Группы", comment: "Message profile category groups"), icon: "person.3.fill", tint: .indigo), + MediaCategory(title: NSLocalizedString("Музыка", comment: "Message profile category music"), icon: "music.note", tint: .teal), + MediaCategory(title: NSLocalizedString("GIF", comment: "Message profile category gifs"), icon: "sparkles", tint: .yellow), + MediaCategory(title: NSLocalizedString("Посты", comment: "Message profile category posts"), icon: "bubble.left.and.bubble.right.fill", tint: .red) + ] + } + // MARK: - Derived Data private var profileBio: String? { @@ -685,26 +690,37 @@ struct MessageProfileView: View { return tags } - private var sharedMediaPlaceholderIcons: [String] { - [ - "photo.on.rectangle", - "doc.text.fill", - "link", - "paperclip", - "music.note", - "video.fill" - ] - } - - private var sharedMediaPlaceholderColors: [Color] { - [ - Color.accentColor.opacity(0.8), - Color.purple.opacity(0.8), - Color.blue.opacity(0.7), - Color.orange.opacity(0.8), - Color.green.opacity(0.7), - Color.pink.opacity(0.8) - ] + private func mediaCategoryButton(_ category: MediaCategory) -> some View { + Button { + showPlaceholderAction( + title: category.title, + message: NSLocalizedString("Раздел скоро станет активным — собираем и индексируем вложения.", comment: "Message profile media placeholder message") + ) + } label: { + VStack(alignment: .leading, spacing: 6) { + Image(systemName: category.icon) + .font(.system(size: 18, weight: .semibold)) + .foregroundColor(category.tint) + .frame(width: 36, height: 36) + .background(category.tint.opacity(0.12)) + .clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous)) + Text(category.title) + .font(.footnote) + .fontWeight(.medium) + .foregroundColor(.primary) + } + .padding(.vertical, 12) + .padding(.horizontal, 14) + .background( + RoundedRectangle(cornerRadius: 20, style: .continuous) + .fill(Color(UIColor.secondarySystemBackground)) + ) + .overlay( + RoundedRectangle(cornerRadius: 20, style: .continuous) + .stroke(Color(UIColor.separator).opacity(0.2), lineWidth: 1) + ) + } + .buttonStyle(.plain) } private var quickActionItems: [ProfileQuickAction] { @@ -917,6 +933,13 @@ private struct StatusTag: Identifiable { let tint: Color } +private struct MediaCategory: Identifiable { + let id = UUID() + let title: String + let icon: String + let tint: Color +} + private struct ProfileQuickAction: Identifiable { let id = UUID() let icon: String