-
Notifications
You must be signed in to change notification settings - Fork 357
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// | ||
// ChipFeatures.swift | ||
// MullvadVPN | ||
// | ||
// Created by Mojgan on 2024-12-06. | ||
// Copyright © 2024 Mullvad VPN AB. All rights reserved. | ||
// | ||
import Foundation | ||
import MullvadSettings | ||
import SwiftUICore | ||
Check failure on line 10 in ios/MullvadVPN/View controllers/Tunnel/FeatureIndicators/ChipFeatures.swift GitHub Actions / Unit tests
Check failure on line 10 in ios/MullvadVPN/View controllers/Tunnel/FeatureIndicators/ChipFeatures.swift GitHub Actions / Unit tests
Check failure on line 10 in ios/MullvadVPN/View controllers/Tunnel/FeatureIndicators/ChipFeatures.swift GitHub Actions / Unit tests
Check failure on line 10 in ios/MullvadVPN/View controllers/Tunnel/FeatureIndicators/ChipFeatures.swift GitHub Actions / Unit tests
Check failure on line 10 in ios/MullvadVPN/View controllers/Tunnel/FeatureIndicators/ChipFeatures.swift GitHub Actions / Unit tests
Check failure on line 10 in ios/MullvadVPN/View controllers/Tunnel/FeatureIndicators/ChipFeatures.swift GitHub Actions / Unit tests
Check failure on line 10 in ios/MullvadVPN/View controllers/Tunnel/FeatureIndicators/ChipFeatures.swift GitHub Actions / Unit tests
Check failure on line 10 in ios/MullvadVPN/View controllers/Tunnel/FeatureIndicators/ChipFeatures.swift GitHub Actions / Unit tests
Check failure on line 10 in ios/MullvadVPN/View controllers/Tunnel/FeatureIndicators/ChipFeatures.swift GitHub Actions / Unit tests
|
||
|
||
protocol ChipFeature { | ||
var isEnabled: Bool { get } | ||
func name() -> LocalizedStringKey | ||
} | ||
|
||
struct DaitaFeature: ChipFeature { | ||
let settings: LatestTunnelSettings | ||
|
||
var isEnabled: Bool { | ||
settings.daita.daitaState.isEnabled | ||
} | ||
|
||
func name() -> LocalizedStringKey { | ||
LocalizedStringKey("DAITA") | ||
} | ||
} | ||
|
||
struct QuantumResistanceFeature: ChipFeature { | ||
let settings: LatestTunnelSettings | ||
var isEnabled: Bool { | ||
settings.tunnelQuantumResistance.isEnabled | ||
} | ||
|
||
func name() -> LocalizedStringKey { | ||
LocalizedStringKey("Quantum resistance") | ||
} | ||
} | ||
|
||
struct MultihopFeature: ChipFeature { | ||
let settings: LatestTunnelSettings | ||
var isEnabled: Bool { | ||
settings.tunnelMultihopState.isEnabled | ||
} | ||
|
||
func name() -> LocalizedStringKey { | ||
LocalizedStringKey("Multihop") | ||
} | ||
} | ||
|
||
struct ObfuscationFeature: ChipFeature { | ||
let settings: LatestTunnelSettings | ||
|
||
var isEnabled: Bool { | ||
settings.wireGuardObfuscation.state.isEnabled | ||
} | ||
|
||
func name() -> LocalizedStringKey { | ||
LocalizedStringKey("Obfuscation") | ||
} | ||
} | ||
|
||
struct DNSFeature: ChipFeature { | ||
let settings: LatestTunnelSettings | ||
|
||
var isEnabled: Bool { | ||
settings.dnsSettings.enableCustomDNS || !settings.dnsSettings.blockingOptions.isEmpty | ||
} | ||
|
||
func name() -> LocalizedStringKey { | ||
if !settings.dnsSettings.blockingOptions.isEmpty { | ||
return LocalizedStringKey("DNS content blockers") | ||
} | ||
return LocalizedStringKey("Custom DNS") | ||
} | ||
} | ||
|
||
struct IPOverrideFeature: ChipFeature { | ||
let repository: IPOverrideRepositoryProtocol | ||
|
||
var isEnabled: Bool { | ||
!repository.fetchAll().isEmpty | ||
} | ||
|
||
func name() -> LocalizedStringKey { | ||
LocalizedStringKey("Server IP override") | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
// | ||
// ChipContainerView.swift | ||
// MullvadVPN | ||
// | ||
// Created by Mojgan on 2024-12-05. | ||
// Copyright © 2024 Mullvad VPN AB. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import SwiftUI | ||
struct ChipContainerView<ViewModel>: View where ViewModel: ChipViewModelProtocol { | ||
@ObservedObject var viewModel: ViewModel | ||
@State private var isExpanded = false | ||
|
||
init(viewModel: ViewModel) { | ||
self.viewModel = viewModel | ||
} | ||
|
||
var body: some View { | ||
GeometryReader { geo in | ||
let containerWidth = geo.size.width | ||
let chipsPerLine = 2 | ||
if isExpanded { | ||
ZStack(alignment: .topLeading) { | ||
createChipViews(chips: viewModel.chips, containerWidth: containerWidth) | ||
} | ||
} else { | ||
HStack { | ||
createChipViews(chips: Array(viewModel.chips.prefix(chipsPerLine)), containerWidth: containerWidth) | ||
if viewModel.chips.count > chipsPerLine { | ||
Button(action: { | ||
withAnimation { | ||
isExpanded.toggle() | ||
} | ||
}, label: { | ||
Text(LocalizedStringKey("\(viewModel.chips.count - chipsPerLine) more...")) | ||
.font(.body) | ||
.lineLimit(1) | ||
.multilineTextAlignment(.center) | ||
.foregroundStyle(UIColor.primaryTextColor.color) | ||
}) | ||
} | ||
Spacer() | ||
} | ||
} | ||
} | ||
} | ||
|
||
private func createChipViews(chips: [ChipModel], containerWidth: CGFloat) -> some View { | ||
var width = CGFloat.zero | ||
var height = CGFloat.zero | ||
|
||
return ForEach(chips) { data in | ||
ChipView(item: data) | ||
.padding(UIMetrics.padding4) | ||
.alignmentGuide(.leading) { dimension in | ||
if abs(width - dimension.width) > containerWidth { | ||
width = 0 | ||
height -= dimension.height | ||
} | ||
let result = width | ||
if data.id == viewModel.chips.last!.id { | ||
width = 0 | ||
} else { | ||
width -= dimension.width | ||
} | ||
return result | ||
} | ||
.alignmentGuide(.top) { _ in | ||
let result = height | ||
if data.id == viewModel.chips.last!.id { | ||
height = 0 | ||
} | ||
return result | ||
} | ||
} | ||
} | ||
} | ||
|
||
#Preview("ChipContainerView") { | ||
ChipContainerView(viewModel: MockChipViewModel()) | ||
} | ||
|
||
private class MockChipViewModel: ChipViewModelProtocol { | ||
@Published var chips: [ChipModel] = (5 ..< 20).map { index in | ||
let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" | ||
return ChipModel(name: LocalizedStringKey(String((0 ..< index).map { _ in letters.randomElement()! }))) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// | ||
// FeatureChipModel.swift | ||
// MullvadVPN | ||
// | ||
// Created by Mojgan on 2024-12-05. | ||
// Copyright © 2024 Mullvad VPN AB. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import SwiftUICore | ||
|
||
struct ChipModel: Identifiable { | ||
let id = UUID() | ||
let name: LocalizedStringKey | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// | ||
// FeatureChipView.swift | ||
// MullvadVPN | ||
// | ||
// Created by Mojgan on 2024-12-05. | ||
// Copyright © 2024 Mullvad VPN AB. All rights reserved. | ||
// | ||
|
||
import SwiftUI | ||
|
||
struct ChipView: View { | ||
let item: ChipModel | ||
var body: some View { | ||
HStack(spacing: UIMetrics.padding4) { | ||
Text(item.name) | ||
.font(.body) | ||
.lineLimit(1) | ||
.multilineTextAlignment(.center) | ||
.foregroundStyle(UIColor.primaryTextColor.color) | ||
} | ||
.padding(.horizontal, UIMetrics.padding8) | ||
.padding(.vertical, UIMetrics.padding4) | ||
.background( | ||
RoundedRectangle(cornerRadius: 8.0) | ||
.stroke( | ||
UIColor.primaryColor.color, | ||
lineWidth: 1 | ||
) | ||
.background( | ||
RoundedRectangle(cornerRadius: 8.0) | ||
.fill(UIColor.secondaryColor.color) | ||
) | ||
) | ||
} | ||
} | ||
|
||
#Preview { | ||
ChipView(item: ChipModel(name: LocalizedStringKey("Example"))) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// | ||
// ChipViewModelProtocol.swift | ||
// MullvadVPN | ||
// | ||
// Created by Mojgan on 2024-12-05. | ||
// Copyright © 2024 Mullvad VPN AB. All rights reserved. | ||
// | ||
|
||
import SwiftUI | ||
protocol ChipViewModelProtocol: ObservableObject { | ||
var chips: [ChipModel] { get } | ||
} | ||
|
||
class FeaturesIndicatoresMockViewModel: ChipViewModelProtocol { | ||
@Published var chips: [ChipModel] = [ | ||
ChipModel(name: LocalizedStringKey("DAITA")), | ||
ChipModel(name: LocalizedStringKey("Obfuscation")), | ||
ChipModel(name: LocalizedStringKey("Quantum resistance")), | ||
ChipModel(name: LocalizedStringKey("Multihop")), | ||
ChipModel(name: LocalizedStringKey("DNS content blockers")), | ||
ChipModel(name: LocalizedStringKey("Custom DNS")), | ||
ChipModel(name: LocalizedStringKey("Server IP override")), | ||
] | ||
} |