mirror of
https://github.com/ProtonMail/ios-mail.git
synced 2026-06-14 09:54:45 +00:00
106 lines
3.8 KiB
Swift
106 lines
3.8 KiB
Swift
// Copyright (c) 2024 Proton Technologies AG
|
|
//
|
|
// This file is part of Proton Mail.
|
|
//
|
|
// Proton Mail is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Proton Mail is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Proton Mail. If not, see https://www.gnu.org/licenses/.
|
|
|
|
import InboxCore
|
|
import InboxDesignSystem
|
|
import SwiftUI
|
|
|
|
struct OneLineLabelsListView: View {
|
|
let labels: [LabelUIModel]
|
|
private let labelsSpacing: CGFloat = DS.Spacing.small
|
|
private let horizontalPadding: CGFloat = DS.Spacing.compact
|
|
private let minimalLabelWidth: CGFloat = DS.Spacing.extraLarge
|
|
private let height: CGFloat = 20
|
|
private let font = UIFont.font(textStyle: .caption2, weight: .semibold)
|
|
|
|
var body: some View {
|
|
GeometryReader { geometry in
|
|
HStack(spacing: labelsSpacing) {
|
|
ForEach(labelsFittingSpace(labels: labels, availableWidth: geometry.size.width), id: \.self) { label in
|
|
switch label {
|
|
case .regular(let viewModel):
|
|
Text(viewModel.text)
|
|
.font(.caption2)
|
|
.fontWeight(.semibold)
|
|
.foregroundColor(DS.Color.Global.white)
|
|
.lineLimit(1)
|
|
.frame(height: height)
|
|
.frame(minWidth: minimalLabelWidth)
|
|
.padding(.horizontal, horizontalPadding)
|
|
.background(viewModel.color)
|
|
.clipShape(RoundedRectangle(cornerRadius: DS.Radius.medium))
|
|
case .count(let count):
|
|
Text(Strings.plus(count: count))
|
|
.foregroundStyle(DS.Color.Text.weak)
|
|
.fontWeight(.semibold)
|
|
.font(.caption)
|
|
}
|
|
}
|
|
}
|
|
}.frame(height: height)
|
|
}
|
|
|
|
// MARK: - Private
|
|
|
|
private enum Label: Hashable {
|
|
case regular(model: LabelUIModel)
|
|
case count(Int)
|
|
}
|
|
|
|
@MainActor
|
|
private func labelsFittingSpace(labels: [LabelUIModel], availableWidth: CGFloat) -> [Label] {
|
|
let padding = 2 * horizontalPadding
|
|
|
|
var availableWidth: CGFloat = availableWidth
|
|
var labelsToDisplay: [Label] = []
|
|
|
|
for label in labels {
|
|
let labelWidth = calculateLabel(label.text, font: font) + padding
|
|
let requiredSpace = labelWidth + labelsSpacing
|
|
|
|
if requiredSpace < availableWidth || labelsToDisplay.isEmpty {
|
|
availableWidth -= requiredSpace
|
|
labelsToDisplay.append(.regular(model: label))
|
|
} else {
|
|
labelsToDisplay.append(.count(labels.count - labelsToDisplay.count))
|
|
break
|
|
}
|
|
}
|
|
|
|
return labelsToDisplay
|
|
}
|
|
|
|
@MainActor
|
|
private func calculateLabel(_ text: String, font: UIFont) -> CGFloat {
|
|
let label = UILabel()
|
|
label.text = text
|
|
label.font = font
|
|
label.numberOfLines = 1
|
|
label.sizeToFit()
|
|
return max(label.frame.width, minimalLabelWidth)
|
|
}
|
|
}
|
|
|
|
#Preview {
|
|
VStack {
|
|
ForEach(OneLineLabelsListViewPreviewDataProvider.labels, id: \.self) { labels in
|
|
OneLineLabelsListView(labels: labels)
|
|
}
|
|
Spacer()
|
|
}.padding()
|
|
}
|