107 lines
4.2 KiB
Swift
107 lines
4.2 KiB
Swift
//
|
|
/*
|
|
* SwiftFin is subject to the terms of the Mozilla Public
|
|
* License, v2.0. If a copy of the MPL was not distributed with this
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*
|
|
* Copyright 2021 Aiden Vigue & Jellyfin Contributors
|
|
*/
|
|
|
|
import SwiftUI
|
|
|
|
struct TruncatedTextView: View {
|
|
|
|
@State private var truncated: Bool = false
|
|
@State private var shrinkText: String
|
|
private var text: String
|
|
let font: UIFont
|
|
let lineLimit: Int
|
|
let seeMoreAction: () -> Void
|
|
|
|
private var moreLessText: String {
|
|
if !truncated {
|
|
return ""
|
|
} else {
|
|
return "See More"
|
|
}
|
|
}
|
|
|
|
init(_ text: String,
|
|
lineLimit: Int,
|
|
font: UIFont = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.body),
|
|
seeMoreAction: @escaping () -> Void) {
|
|
self.text = text
|
|
self.lineLimit = lineLimit
|
|
_shrinkText = State(wrappedValue: text)
|
|
self.font = font
|
|
self.seeMoreAction = seeMoreAction
|
|
}
|
|
|
|
var body: some View {
|
|
VStack(alignment: .center) {
|
|
Group {
|
|
Text(shrinkText)
|
|
.overlay {
|
|
if truncated {
|
|
LinearGradient(stops: [.init(color: .systemBackground.opacity(0), location: 0.5),
|
|
.init(color: .systemBackground.opacity(0.8), location: 0.7),
|
|
.init(color: .systemBackground, location: 1)],
|
|
startPoint: .top,
|
|
endPoint: .bottom)
|
|
}
|
|
}
|
|
}
|
|
.lineLimit(lineLimit)
|
|
.background {
|
|
// Render the limited text and measure its size
|
|
Text(text)
|
|
.lineLimit(lineLimit + 2)
|
|
.background {
|
|
GeometryReader { visibleTextGeometry in
|
|
Color.clear
|
|
.onAppear {
|
|
let size = CGSize(width: visibleTextGeometry.size.width, height: .greatestFiniteMagnitude)
|
|
let attributes:[NSAttributedString.Key:Any] = [NSAttributedString.Key.font: font]
|
|
var low = 0
|
|
var heigh = shrinkText.count
|
|
var mid = heigh
|
|
while ((heigh - low) > 1) {
|
|
let attributedText = NSAttributedString(string: shrinkText, attributes: attributes)
|
|
let boundingRect = attributedText.boundingRect(with: size, options: NSStringDrawingOptions.usesLineFragmentOrigin, context: nil)
|
|
if boundingRect.size.height > visibleTextGeometry.size.height {
|
|
truncated = true
|
|
heigh = mid
|
|
mid = (heigh + low)/2
|
|
|
|
} else {
|
|
if mid == text.count {
|
|
break
|
|
} else {
|
|
low = mid
|
|
mid = (low + heigh)/2
|
|
}
|
|
}
|
|
shrinkText = String(text.prefix(mid))
|
|
}
|
|
|
|
if truncated {
|
|
shrinkText = String(shrinkText.prefix(shrinkText.count - 2))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.hidden()
|
|
}
|
|
.font(Font(font))
|
|
|
|
if truncated {
|
|
Button {
|
|
seeMoreAction()
|
|
} label: {
|
|
Text(moreLessText)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|