mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-04-18 04:38:27 +00:00
Fix media list UI
This commit is contained in:
parent
112d7bbaa9
commit
b753b5925e
3 changed files with 121 additions and 84 deletions
|
|
@ -2,6 +2,6 @@ import Foundation
|
|||
|
||||
public enum AppGitInfo {
|
||||
public static let branch = "feature/medias_and_documents_lists"
|
||||
public static let commit = "cad143172"
|
||||
public static let commit = "ab47b1ab5"
|
||||
public static let tag = "6.1.0-alpha"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,10 +69,12 @@ struct ConversationDocumentsListFragment: View {
|
|||
VStack(spacing: 0) {
|
||||
List {
|
||||
ForEach(conversationDocumentsListViewModel.documentsList, id: \.path) { file in
|
||||
MediaGridItemView(file: file)
|
||||
.background()
|
||||
DocumentRow(file: file)
|
||||
.padding(.vertical, 4)
|
||||
.padding(.horizontal, 8)
|
||||
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
|
||||
.listRowSeparator(.hidden)
|
||||
.listRowBackground(Color.clear)
|
||||
}
|
||||
}
|
||||
.safeAreaInset(edge: .top, content: {
|
||||
|
|
@ -82,7 +84,7 @@ struct ConversationDocumentsListFragment: View {
|
|||
.listStyle(.plain)
|
||||
.overlay(
|
||||
VStack {
|
||||
if true {
|
||||
if conversationDocumentsListViewModel.documentsList.isEmpty {
|
||||
Spacer()
|
||||
Text("conversation_no_document_found")
|
||||
.multilineTextAlignment(.leading)
|
||||
|
|
@ -90,7 +92,7 @@ struct ConversationDocumentsListFragment: View {
|
|||
Spacer()
|
||||
}
|
||||
}
|
||||
.padding(.all)
|
||||
.padding(.all)
|
||||
)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
|
|
@ -111,34 +113,62 @@ struct ConversationDocumentsListFragment: View {
|
|||
}
|
||||
|
||||
struct DocumentRow: View {
|
||||
|
||||
|
||||
@State private var selectedURLAttachment: URL?
|
||||
@ObservedObject var file: FileModel
|
||||
|
||||
var body: some View {
|
||||
ZStack(alignment: .bottomTrailing) {
|
||||
if let previewPath = file.mediaPreview,
|
||||
let image = UIImage(contentsOfFile: previewPath) {
|
||||
Image(uiImage: image)
|
||||
.resizable()
|
||||
.scaledToFill()
|
||||
.frame(height: 110)
|
||||
.clipped()
|
||||
} else {
|
||||
Rectangle()
|
||||
.fill(Color.gray.opacity(0.2))
|
||||
.frame(height: 110)
|
||||
HStack {
|
||||
VStack {
|
||||
Image(getImageOfType(filename: file.fileName, type: file.mimeTypeString))
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c700)
|
||||
.frame(width: 60, height: 60, alignment: .leading)
|
||||
}
|
||||
|
||||
if let duration = file.audioVideoDuration, file.isVideoPreview {
|
||||
Text(duration)
|
||||
.font(.caption2)
|
||||
.padding(6)
|
||||
.background(Color.black.opacity(0.6))
|
||||
.foregroundColor(.white)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 6))
|
||||
.padding(6)
|
||||
.frame(width: 100, height: 100)
|
||||
.background(Color.grayMain2c200)
|
||||
.onTapGesture {
|
||||
selectedURLAttachment = URL(fileURLWithPath: file.originalPath)
|
||||
}
|
||||
|
||||
VStack {
|
||||
Text(file.fileName)
|
||||
.foregroundStyle(Color.grayMain2c700)
|
||||
.default_text_style_600(styleSize: 14)
|
||||
.truncationMode(.middle)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
|
||||
if file.fileSize > 0 {
|
||||
Text(Int(file.fileSize).formatBytes())
|
||||
.default_text_style_300(styleSize: 14)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 10)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
.background(.white)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||
.onTapGesture {
|
||||
selectedURLAttachment = URL(fileURLWithPath: file.originalPath)
|
||||
}
|
||||
}
|
||||
|
||||
func getImageOfType(filename: String, type: String) -> String {
|
||||
print("mimemime \(type)")
|
||||
if type == "audio/mpeg" {
|
||||
return "file-audio"
|
||||
} else if type == "application/pdf"
|
||||
|| filename.lowercased().hasSuffix(".pdf") == true {
|
||||
return "file-pdf"
|
||||
} else if type.hasPrefix("text/") == true
|
||||
|| ["txt", "md", "json", "xml", "csv", "log"].contains(filename.split(separator: ".").last?.lowercased()) {
|
||||
return "file-text"
|
||||
} else {
|
||||
return "file"
|
||||
}
|
||||
.cornerRadius(8)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,33 +86,42 @@ struct ConversationMediaListFragment: View {
|
|||
struct ConversationMediaGridView: View {
|
||||
|
||||
@ObservedObject var viewModel: ConversationMediaListViewModel
|
||||
|
||||
private let columns = [
|
||||
GridItem(.flexible(), spacing: 1),
|
||||
GridItem(.flexible(), spacing: 1),
|
||||
GridItem(.flexible(), spacing: 1)
|
||||
]
|
||||
@State private var selectedURLAttachment: URL?
|
||||
private let columns = 4
|
||||
private let spacing: CGFloat = 2
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
if !viewModel.mediaList.isEmpty && !viewModel.operationInProgress {
|
||||
ScrollView {
|
||||
LazyVGrid(columns: columns, spacing: 1) {
|
||||
ForEach(viewModel.mediaList, id: \.path) { file in
|
||||
MediaGridItemView(file: file)
|
||||
.onTapGesture {
|
||||
//viewModel.openMediaEvent.send(file)
|
||||
}
|
||||
.onAppear {
|
||||
if file == viewModel.mediaList.last {
|
||||
viewModel.loadMoreData(totalItemsCount: viewModel.mediaList.count)
|
||||
GeometryReader { geometry in
|
||||
let totalSpacing = spacing * CGFloat(columns - 1)
|
||||
let itemWidth = (geometry.size.width - totalSpacing) / CGFloat(columns)
|
||||
|
||||
ScrollView {
|
||||
LazyVGrid(
|
||||
columns: Array(repeating: GridItem(.fixed(itemWidth), spacing: spacing), count: columns),
|
||||
spacing: spacing
|
||||
) {
|
||||
ForEach(viewModel.mediaList, id: \.path) { file in
|
||||
MediaGridItemView(file: file)
|
||||
.aspectRatio(1, contentMode: .fit)
|
||||
.frame(width: itemWidth, height: itemWidth)
|
||||
.clipped()
|
||||
.onTapGesture {
|
||||
selectedURLAttachment = URL(fileURLWithPath: file.originalPath)
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
if file == viewModel.mediaList.last {
|
||||
viewModel.loadMoreData(totalItemsCount: viewModel.mediaList.count)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, spacing)
|
||||
.padding(.top, spacing)
|
||||
}
|
||||
.padding(.horizontal, 2)
|
||||
.padding(.top, 12)
|
||||
}
|
||||
.quickLookPreview($selectedURLAttachment, in: viewModel.mediaList.compactMap { URL(fileURLWithPath: $0.originalPath) })
|
||||
} else if viewModel.mediaList.isEmpty && !viewModel.operationInProgress {
|
||||
Spacer()
|
||||
Text("conversation_no_media_found")
|
||||
|
|
@ -125,49 +134,47 @@ struct ConversationMediaGridView: View {
|
|||
}
|
||||
|
||||
struct MediaGridItemView: View {
|
||||
|
||||
@ObservedObject var file: FileModel
|
||||
|
||||
var body: some View {
|
||||
ZStack(alignment: .bottomTrailing) {
|
||||
if let previewPath = file.mediaPreview,
|
||||
let image = UIImage(contentsOfFile: previewPath) {
|
||||
Image(uiImage: image)
|
||||
.resizable()
|
||||
.scaledToFill()
|
||||
.frame(width: 120, height: 120)
|
||||
.clipped()
|
||||
} else {
|
||||
Rectangle()
|
||||
.fill(Color.gray.opacity(0.2))
|
||||
.frame(width: 120, height: 120)
|
||||
}
|
||||
|
||||
if file.isVideoPreview {
|
||||
VStack {
|
||||
Spacer()
|
||||
|
||||
Image("play-fill")
|
||||
.renderingMode(.template)
|
||||
GeometryReader { geo in
|
||||
ZStack(alignment: .bottomTrailing) {
|
||||
if let previewPath = file.mediaPreview,
|
||||
let image = UIImage(contentsOfFile: previewPath) {
|
||||
Image(uiImage: image)
|
||||
.resizable()
|
||||
.foregroundStyle(.white)
|
||||
.frame(width: 35, height: 35)
|
||||
|
||||
Spacer()
|
||||
.scaledToFill()
|
||||
.frame(width: geo.size.width, height: geo.size.height)
|
||||
.clipped()
|
||||
} else {
|
||||
Rectangle()
|
||||
.fill(Color.gray.opacity(0.2))
|
||||
.frame(width: geo.size.width, height: geo.size.height)
|
||||
}
|
||||
|
||||
if file.isVideoPreview {
|
||||
Image("play-fill")
|
||||
.resizable()
|
||||
.renderingMode(.template)
|
||||
.scaledToFit()
|
||||
.frame(width: geo.size.width * 0.3, height: geo.size.height * 0.3)
|
||||
.foregroundColor(.white)
|
||||
.shadow(radius: 2)
|
||||
.position(x: geo.size.width / 2, y: geo.size.height / 2)
|
||||
}
|
||||
|
||||
if let duration = file.audioVideoDuration, file.isVideoPreview {
|
||||
Text(duration)
|
||||
.font(.caption2)
|
||||
.padding(4)
|
||||
.background(Color.black.opacity(0.6))
|
||||
.foregroundColor(.white)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 4))
|
||||
.padding(6)
|
||||
}
|
||||
.frame(width: 120, height: 120)
|
||||
}
|
||||
|
||||
if let duration = file.audioVideoDuration, file.isVideoPreview {
|
||||
Text(duration)
|
||||
.font(.caption2)
|
||||
.padding(6)
|
||||
.background(Color.black.opacity(0.6))
|
||||
.foregroundColor(.white)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 6))
|
||||
.padding(6)
|
||||
}
|
||||
.cornerRadius(8)
|
||||
}
|
||||
.cornerRadius(8)
|
||||
.aspectRatio(1, contentMode: .fit)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue