mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-17 02:58:07 +00:00
Message bubbles for different file types
This commit is contained in:
parent
29d3770280
commit
d6293be80f
13 changed files with 300 additions and 13 deletions
21
Linphone/Assets.xcassets/download-simple.imageset/Contents.json
vendored
Normal file
21
Linphone/Assets.xcassets/download-simple.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "download-simple.svg",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
1
Linphone/Assets.xcassets/download-simple.imageset/download-simple.svg
vendored
Normal file
1
Linphone/Assets.xcassets/download-simple.imageset/download-simple.svg
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M224,144v64a8,8,0,0,1-8,8H40a8,8,0,0,1-8-8V144a8,8,0,0,1,16,0v56H208V144a8,8,0,0,1,16,0Zm-101.66,5.66a8,8,0,0,0,11.32,0l40-40a8,8,0,0,0-11.32-11.32L136,124.69V32a8,8,0,0,0-16,0v92.69L93.66,98.34a8,8,0,0,0-11.32,11.32Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 341 B |
21
Linphone/Assets.xcassets/file-audio.imageset/Contents.json
vendored
Normal file
21
Linphone/Assets.xcassets/file-audio.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "file-audio.svg",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
1
Linphone/Assets.xcassets/file-audio.imageset/file-audio.svg
vendored
Normal file
1
Linphone/Assets.xcassets/file-audio.imageset/file-audio.svg
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M99.06,128.61a8,8,0,0,0-8.72,1.73L68.69,152H48a8,8,0,0,0-8,8v40a8,8,0,0,0,8,8H68.69l21.65,21.66A8,8,0,0,0,104,224V136A8,8,0,0,0,99.06,128.61ZM88,204.69,77.66,194.34A8,8,0,0,0,72,192H56V168H72a8,8,0,0,0,5.66-2.34L88,155.31ZM152,180a40.55,40.55,0,0,1-20,34.91A8,8,0,0,1,124,201.09a24.49,24.49,0,0,0,0-42.18A8,8,0,0,1,132,145.09,40.55,40.55,0,0,1,152,180Zm61.66-97.66-56-56A8,8,0,0,0,152,24H56A16,16,0,0,0,40,40v80a8,8,0,0,0,16,0V40h88V88a8,8,0,0,0,8,8h48V216H168a8,8,0,0,0,0,16h32a16,16,0,0,0,16-16V88A8,8,0,0,0,213.66,82.34ZM160,51.31,188.69,80H160Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 672 B |
21
Linphone/Assets.xcassets/file-pdf.imageset/Contents.json
vendored
Normal file
21
Linphone/Assets.xcassets/file-pdf.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "file-pdf.svg",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
1
Linphone/Assets.xcassets/file-pdf.imageset/file-pdf.svg
vendored
Normal file
1
Linphone/Assets.xcassets/file-pdf.imageset/file-pdf.svg
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M224,152a8,8,0,0,1-8,8H192v16h16a8,8,0,0,1,0,16H192v16a8,8,0,0,1-16,0V152a8,8,0,0,1,8-8h32A8,8,0,0,1,224,152ZM92,172a28,28,0,0,1-28,28H56v8a8,8,0,0,1-16,0V152a8,8,0,0,1,8-8H64A28,28,0,0,1,92,172Zm-16,0a12,12,0,0,0-12-12H56v24h8A12,12,0,0,0,76,172Zm88,8a36,36,0,0,1-36,36H112a8,8,0,0,1-8-8V152a8,8,0,0,1,8-8h16A36,36,0,0,1,164,180Zm-16,0a20,20,0,0,0-20-20h-8v40h8A20,20,0,0,0,148,180ZM40,112V40A16,16,0,0,1,56,24h96a8,8,0,0,1,5.66,2.34l56,56A8,8,0,0,1,216,88v24a8,8,0,0,1-16,0V96H152a8,8,0,0,1-8-8V40H56v72a8,8,0,0,1-16,0ZM160,80h28.69L160,51.31Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 669 B |
|
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#4e6074" viewBox="0 0 256 256"><path d="M213.66,82.34l-56-56A8,8,0,0,0,152,24H56A16,16,0,0,0,40,40V216a16,16,0,0,0,16,16H200a16,16,0,0,0,16-16V88A8,8,0,0,0,213.66,82.34ZM160,51.31,188.69,80H160ZM200,216H56V40h88V88a8,8,0,0,0,8,8h48V216Zm-32-80a8,8,0,0,1-8,8H96a8,8,0,0,1,0-16h64A8,8,0,0,1,168,136Zm0,32a8,8,0,0,1-8,8H96a8,8,0,0,1,0-16h64A8,8,0,0,1,168,168Z"></path></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M213.66,82.34l-56-56A8,8,0,0,0,152,24H56A16,16,0,0,0,40,40V216a16,16,0,0,0,16,16H200a16,16,0,0,0,16-16V88A8,8,0,0,0,213.66,82.34ZM160,51.31,188.69,80H160ZM200,216H56V40h88V88a8,8,0,0,0,8,8h48V216Zm-32-80a8,8,0,0,1-8,8H96a8,8,0,0,1,0-16h64A8,8,0,0,1,168,136Zm0,32a8,8,0,0,1-8,8H96a8,8,0,0,1,0-16h64A8,8,0,0,1,168,168Z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 440 B After Width: | Height: | Size: 440 B |
21
Linphone/Assets.xcassets/file.imageset/Contents.json
vendored
Normal file
21
Linphone/Assets.xcassets/file.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "file.svg",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
1
Linphone/Assets.xcassets/file.imageset/file.svg
vendored
Normal file
1
Linphone/Assets.xcassets/file.imageset/file.svg
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M213.66,82.34l-56-56A8,8,0,0,0,152,24H56A16,16,0,0,0,40,40V216a16,16,0,0,0,16,16H200a16,16,0,0,0,16-16V88A8,8,0,0,0,213.66,82.34ZM160,51.31,188.69,80H160ZM200,216H56V40h88V88a8,8,0,0,0,8,8h48V216Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 320 B |
|
|
@ -33,6 +33,7 @@ struct ChatBubbleView: View {
|
|||
@State private var ticker = Ticker()
|
||||
@State private var isPressed: Bool = false
|
||||
@State private var timePassed: TimeInterval?
|
||||
@State private var sliderValue: Double = 0.5
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
|
|
@ -394,6 +395,47 @@ struct ChatBubbleView: View {
|
|||
}
|
||||
.clipShape(RoundedRectangle(cornerRadius: 4))
|
||||
.clipped()
|
||||
} else if eventLogMessage.message.attachments.first!.type == .voiceRecording {
|
||||
CustomSlider(
|
||||
value: $sliderValue,
|
||||
range: 0...1,
|
||||
thumbColor: .blue,
|
||||
trackColor: .gray,
|
||||
trackHeight: 8,
|
||||
cornerRadius: 10
|
||||
)
|
||||
.padding()
|
||||
} else {
|
||||
HStack {
|
||||
VStack {
|
||||
Image(getImageOfType(type: eventLogMessage.message.attachments.first!.type))
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c700)
|
||||
.frame(width: 60, height: 60, alignment: .leading)
|
||||
}
|
||||
.frame(width: 100, height: 100)
|
||||
.background(Color.grayMain2c200)
|
||||
|
||||
VStack {
|
||||
Text(eventLogMessage.message.attachments.first!.name)
|
||||
.foregroundStyle(Color.grayMain2c700)
|
||||
.default_text_style_600(styleSize: 16)
|
||||
.truncationMode(.middle)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
|
||||
Text("2,2 Mo")
|
||||
.default_text_style_300(styleSize: 16)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
}
|
||||
.padding(.horizontal, 10)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
.frame(width: geometryProxy.size.width - 110, height: 100)
|
||||
.background(.white)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||
}
|
||||
} else if eventLogMessage.message.attachments.count > 1 {
|
||||
let isGroup = conversationViewModel.displayedConversation != nil && conversationViewModel.displayedConversation!.isGroup
|
||||
|
|
@ -472,6 +514,20 @@ struct ChatBubbleView: View {
|
|||
}
|
||||
return (100, 100)
|
||||
}
|
||||
|
||||
func getImageOfType(type: AttachmentType) -> String {
|
||||
if type == .audio {
|
||||
return "file-audio"
|
||||
} else if type == .pdf {
|
||||
return "file-pdf"
|
||||
} else if type == .text {
|
||||
return "file-text"
|
||||
} else if type == .fileTransfer {
|
||||
return "download-simple"
|
||||
} else {
|
||||
return "file"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum URLType {
|
||||
|
|
|
|||
|
|
@ -21,15 +21,35 @@ import Foundation
|
|||
|
||||
public enum AttachmentType: String, Codable {
|
||||
case image
|
||||
case video
|
||||
case gif
|
||||
case video
|
||||
case audio
|
||||
case voiceRecording
|
||||
case pdf
|
||||
case text
|
||||
case fileTransfer
|
||||
case other
|
||||
|
||||
public var title: String {
|
||||
switch self {
|
||||
case .image:
|
||||
return "Image"
|
||||
default:
|
||||
case .gif:
|
||||
return "GIF"
|
||||
case .video:
|
||||
return "Video"
|
||||
case .audio:
|
||||
return "Audio"
|
||||
case .voiceRecording:
|
||||
return "Voice Recording"
|
||||
case .pdf:
|
||||
return "PDF"
|
||||
case .text:
|
||||
return "Text"
|
||||
case .fileTransfer:
|
||||
return "File Transfer"
|
||||
default:
|
||||
return "Other"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -37,8 +57,22 @@ public enum AttachmentType: String, Codable {
|
|||
switch mediaType {
|
||||
case .image:
|
||||
self = .image
|
||||
default:
|
||||
case .gif:
|
||||
self = .gif
|
||||
case .video:
|
||||
self = .video
|
||||
case .audio:
|
||||
self = .audio
|
||||
case .voiceRecording:
|
||||
self = .voiceRecording
|
||||
case .pdf:
|
||||
self = .pdf
|
||||
case .text:
|
||||
self = .text
|
||||
case .fileTransfer:
|
||||
self = .fileTransfer
|
||||
default:
|
||||
self = .other
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ public struct Message: Identifiable, Hashable {
|
|||
guard let thumbnailURL = await media.getThumbnailURL() else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
switch media.type {
|
||||
case .image:
|
||||
return Attachment(id: UUID().uuidString, name: "", url: thumbnailURL, type: .image)
|
||||
|
|
@ -134,6 +134,10 @@ public struct Message: Identifiable, Hashable {
|
|||
return nil
|
||||
}
|
||||
return Attachment(id: UUID().uuidString, name: "", thumbnail: thumbnailURL, full: fullURL, type: .video)
|
||||
case .audio:
|
||||
return Attachment(id: UUID().uuidString, name: "", url: thumbnailURL, type: .audio)
|
||||
default:
|
||||
return Attachment(id: UUID().uuidString, name: "", url: thumbnailURL, type: .other)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -272,7 +276,14 @@ public struct DraftMessage {
|
|||
|
||||
public enum MediaType {
|
||||
case image
|
||||
case gif
|
||||
case video
|
||||
case audio
|
||||
case voiceRecording
|
||||
case pdf
|
||||
case text
|
||||
case fileTransfer
|
||||
case other
|
||||
}
|
||||
|
||||
public struct Media: Identifiable, Equatable {
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ class ConversationViewModel: ObservableObject {
|
|||
id: UUID().uuidString,
|
||||
name: content.name!,
|
||||
url: path!,
|
||||
type: .image
|
||||
type: .fileTransfer
|
||||
)
|
||||
attachmentNameList += ", \(content.name!)"
|
||||
attachmentList.append(attachment)
|
||||
|
|
@ -296,6 +296,20 @@ class ConversationViewModel: ObservableObject {
|
|||
} else {
|
||||
if content.type != "video" {
|
||||
let path = URL(string: self.getNewFilePath(name: content.name ?? ""))
|
||||
var typeTmp: AttachmentType = .other
|
||||
|
||||
switch content.type {
|
||||
case "image":
|
||||
typeTmp = (content.name?.lowercased().hasSuffix("gif"))! ? .gif : .image
|
||||
case "audio":
|
||||
typeTmp = content.isVoiceRecording ? .voiceRecording : .audio
|
||||
case "application":
|
||||
typeTmp = content.subtype.lowercased() == "pdf" ? .pdf : .other
|
||||
case "text":
|
||||
typeTmp = .text
|
||||
default:
|
||||
typeTmp = .other
|
||||
}
|
||||
|
||||
if path != nil {
|
||||
let attachment =
|
||||
|
|
@ -303,7 +317,7 @@ class ConversationViewModel: ObservableObject {
|
|||
id: UUID().uuidString,
|
||||
name: content.name!,
|
||||
url: path!,
|
||||
type: (content.name?.lowercased().hasSuffix("gif"))! ? .gif : .image
|
||||
type: typeTmp
|
||||
)
|
||||
attachmentNameList += ", \(content.name!)"
|
||||
attachmentList.append(attachment)
|
||||
|
|
@ -489,7 +503,7 @@ class ConversationViewModel: ObservableObject {
|
|||
id: UUID().uuidString,
|
||||
name: content.name!,
|
||||
url: path!,
|
||||
type: .image
|
||||
type: .fileTransfer
|
||||
)
|
||||
attachmentNameList += ", \(content.name!)"
|
||||
attachmentList.append(attachment)
|
||||
|
|
@ -497,6 +511,20 @@ class ConversationViewModel: ObservableObject {
|
|||
} else {
|
||||
if content.type != "video" {
|
||||
let path = URL(string: self.getNewFilePath(name: content.name ?? ""))
|
||||
var typeTmp: AttachmentType = .other
|
||||
|
||||
switch content.type {
|
||||
case "image":
|
||||
typeTmp = (content.name?.lowercased().hasSuffix("gif"))! ? .gif : .image
|
||||
case "audio":
|
||||
typeTmp = content.isVoiceRecording ? .voiceRecording : .audio
|
||||
case "application":
|
||||
typeTmp = content.subtype.lowercased() == "pdf" ? .pdf : .other
|
||||
case "text":
|
||||
typeTmp = .text
|
||||
default:
|
||||
typeTmp = .other
|
||||
}
|
||||
|
||||
if path != nil {
|
||||
let attachment =
|
||||
|
|
@ -504,7 +532,7 @@ class ConversationViewModel: ObservableObject {
|
|||
id: UUID().uuidString,
|
||||
name: content.name!,
|
||||
url: path!,
|
||||
type: (content.name?.lowercased().hasSuffix("gif"))! ? .gif : .image
|
||||
type: typeTmp
|
||||
)
|
||||
attachmentNameList += ", \(content.name!)"
|
||||
attachmentList.append(attachment)
|
||||
|
|
@ -687,7 +715,7 @@ class ConversationViewModel: ObservableObject {
|
|||
id: UUID().uuidString,
|
||||
name: content.name ?? "???",
|
||||
url: path!,
|
||||
type: .image
|
||||
type: .fileTransfer
|
||||
)
|
||||
attachmentNameList += ", \(content.name ?? "???")"
|
||||
attachmentList.append(attachment)
|
||||
|
|
@ -695,6 +723,20 @@ class ConversationViewModel: ObservableObject {
|
|||
} else if content.name != nil && !content.name!.isEmpty {
|
||||
if content.type != "video" {
|
||||
let path = URL(string: self.getNewFilePath(name: content.name ?? ""))
|
||||
var typeTmp: AttachmentType = .other
|
||||
|
||||
switch content.type {
|
||||
case "image":
|
||||
typeTmp = (content.name?.lowercased().hasSuffix("gif"))! ? .gif : .image
|
||||
case "audio":
|
||||
typeTmp = content.isVoiceRecording ? .voiceRecording : .audio
|
||||
case "application":
|
||||
typeTmp = content.subtype.lowercased() == "pdf" ? .pdf : .other
|
||||
case "text":
|
||||
typeTmp = .text
|
||||
default:
|
||||
typeTmp = .other
|
||||
}
|
||||
|
||||
if path != nil {
|
||||
let attachment =
|
||||
|
|
@ -702,7 +744,7 @@ class ConversationViewModel: ObservableObject {
|
|||
id: UUID().uuidString,
|
||||
name: content.name!,
|
||||
url: path!,
|
||||
type: (content.name?.lowercased().hasSuffix("gif"))! ? .gif : .image
|
||||
type: typeTmp
|
||||
)
|
||||
attachmentNameList += ", \(content.name!)"
|
||||
attachmentList.append(attachment)
|
||||
|
|
@ -958,7 +1000,7 @@ class ConversationViewModel: ObservableObject {
|
|||
id: UUID().uuidString,
|
||||
name: content.name!,
|
||||
url: path!,
|
||||
type: .image
|
||||
type: .fileTransfer
|
||||
)
|
||||
attachmentNameList += ", \(content.name!)"
|
||||
attachmentList.append(attachment)
|
||||
|
|
@ -966,6 +1008,20 @@ class ConversationViewModel: ObservableObject {
|
|||
} else {
|
||||
if content.type != "video" {
|
||||
let path = URL(string: self.getNewFilePath(name: content.name ?? ""))
|
||||
var typeTmp: AttachmentType = .other
|
||||
|
||||
switch content.type {
|
||||
case "image":
|
||||
typeTmp = (content.name?.lowercased().hasSuffix("gif"))! ? .gif : .image
|
||||
case "audio":
|
||||
typeTmp = content.isVoiceRecording ? .voiceRecording : .audio
|
||||
case "application":
|
||||
typeTmp = content.subtype.lowercased() == "pdf" ? .pdf : .other
|
||||
case "text":
|
||||
typeTmp = .text
|
||||
default:
|
||||
typeTmp = .other
|
||||
}
|
||||
|
||||
if path != nil {
|
||||
let attachment =
|
||||
|
|
@ -973,7 +1029,7 @@ class ConversationViewModel: ObservableObject {
|
|||
id: UUID().uuidString,
|
||||
name: content.name!,
|
||||
url: path!,
|
||||
type: (content.name?.lowercased().hasSuffix("gif"))! ? .gif : .image
|
||||
type: typeTmp
|
||||
)
|
||||
attachmentNameList += ", \(content.name!)"
|
||||
attachmentList.append(attachment)
|
||||
|
|
@ -1566,6 +1622,48 @@ class ConversationViewModel: ObservableObject {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CustomSlider: View {
|
||||
@Binding var value: Double
|
||||
var range: ClosedRange<Double>
|
||||
var thumbColor: Color
|
||||
var trackColor: Color
|
||||
var trackHeight: CGFloat
|
||||
var cornerRadius: CGFloat
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
ZStack {
|
||||
// Slider track with rounded corners
|
||||
Rectangle()
|
||||
.fill(trackColor)
|
||||
.frame(height: trackHeight)
|
||||
.cornerRadius(cornerRadius)
|
||||
|
||||
// Progress track to show the current value
|
||||
Rectangle()
|
||||
.fill(thumbColor.opacity(0.5))
|
||||
.frame(width: CGFloat((value - range.lowerBound) / (range.upperBound - range.lowerBound)) * UIScreen.main.bounds.width, height: trackHeight)
|
||||
.cornerRadius(cornerRadius)
|
||||
|
||||
// Thumb (handle) with rounded appearance
|
||||
Circle()
|
||||
.fill(thumbColor)
|
||||
.frame(width: 30, height: 30)
|
||||
.offset(x: CGFloat((value - range.lowerBound) / (range.upperBound - range.lowerBound)) * UIScreen.main.bounds.width - 20)
|
||||
.gesture(DragGesture(minimumDistance: 0)
|
||||
.onChanged { gesture in
|
||||
let sliderWidth = UIScreen.main.bounds.width
|
||||
let dragX = gesture.location.x
|
||||
let newValue = range.lowerBound + Double(dragX / sliderWidth) * (range.upperBound - range.lowerBound)
|
||||
value = min(max(newValue, range.lowerBound), range.upperBound)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 20)
|
||||
}
|
||||
}
|
||||
// swiftlint:enable line_length
|
||||
// swiftlint:enable type_body_length
|
||||
// swiftlint:enable cyclomatic_complexity
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue