-
Notifications
You must be signed in to change notification settings - Fork 356
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
492 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
ios/MullvadVPN/View controllers/Tunnel/FeatureIndicators/ChipFeatures.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 SwiftUI | ||
|
||
protocol ChipFeature { | ||
var isEnabled: Bool { get } | ||
var name: LocalizedStringKey { get } | ||
} | ||
|
||
struct DaitaFeature: ChipFeature { | ||
let settings: LatestTunnelSettings | ||
|
||
var isEnabled: Bool { | ||
settings.daita.daitaState.isEnabled | ||
} | ||
|
||
var name: LocalizedStringKey { | ||
LocalizedStringKey("DAITA") | ||
} | ||
} | ||
|
||
struct QuantumResistanceFeature: ChipFeature { | ||
let settings: LatestTunnelSettings | ||
var isEnabled: Bool { | ||
settings.tunnelQuantumResistance.isEnabled | ||
} | ||
|
||
var name: LocalizedStringKey { | ||
LocalizedStringKey("Quantum resistance") | ||
} | ||
} | ||
|
||
struct MultihopFeature: ChipFeature { | ||
let settings: LatestTunnelSettings | ||
var isEnabled: Bool { | ||
settings.tunnelMultihopState.isEnabled | ||
} | ||
|
||
var name: LocalizedStringKey { | ||
LocalizedStringKey("Multihop") | ||
} | ||
} | ||
|
||
struct ObfuscationFeature: ChipFeature { | ||
let settings: LatestTunnelSettings | ||
|
||
var isEnabled: Bool { | ||
settings.wireGuardObfuscation.state.isEnabled | ||
} | ||
|
||
var name: LocalizedStringKey { | ||
LocalizedStringKey("Obfuscation") | ||
} | ||
} | ||
|
||
struct DNSFeature: ChipFeature { | ||
let settings: LatestTunnelSettings | ||
|
||
var isEnabled: Bool { | ||
settings.dnsSettings.enableCustomDNS || !settings.dnsSettings.blockingOptions.isEmpty | ||
} | ||
|
||
var name: LocalizedStringKey { | ||
if !settings.dnsSettings.blockingOptions.isEmpty { | ||
return LocalizedStringKey("DNS content blockers") | ||
} | ||
return LocalizedStringKey("Custom DNS") | ||
} | ||
} | ||
|
||
struct IPOverrideFeature: ChipFeature { | ||
let overrides: [IPOverride] | ||
|
||
var isEnabled: Bool { | ||
!overrides.isEmpty | ||
} | ||
|
||
var name: LocalizedStringKey { | ||
LocalizedStringKey("Server IP override") | ||
} | ||
} |
95 changes: 95 additions & 0 deletions
95
ios/MullvadVPN/View controllers/Tunnel/FeatureIndicators/ChipView/ChipContainerView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// | ||
// ChipContainerView.swift | ||
// MullvadVPN | ||
// | ||
// Created by Mojgan on 2024-12-05. | ||
// Copyright © 2024 Mullvad VPN AB. All rights reserved. | ||
// | ||
|
||
import SwiftUI | ||
|
||
struct ChipContainerView<ViewModel>: View where ViewModel: ChipViewModelProtocol { | ||
@ObservedObject var viewModel: ViewModel | ||
|
||
@State var chipHeight: CGFloat = 0 | ||
@State var fullContainerHeight: CGFloat = 0 | ||
@State var visibleContainerHeight: CGFloat = 0 | ||
|
||
var body: some View { | ||
GeometryReader { geo in | ||
let containerWidth = geo.size.width | ||
let chipsOverflow = !viewModel.isExpanded && (fullContainerHeight > chipHeight) | ||
let numberOfChips = chipsOverflow ? 2 : viewModel.chips.count | ||
|
||
HStack { | ||
ZStack(alignment: .topLeading) { | ||
createChipViews(chips: Array(viewModel.chips.prefix(numberOfChips)), containerWidth: containerWidth) | ||
} | ||
.sizeOfView { visibleContainerHeight = $0.height } | ||
|
||
if chipsOverflow { | ||
Text(LocalizedStringKey("\(viewModel.chips.count - numberOfChips) more...")) | ||
.font(.subheadline) | ||
.lineLimit(1) | ||
.foregroundStyle(UIColor.primaryTextColor.color) | ||
.padding(.bottom, 12) | ||
} | ||
|
||
Spacer() | ||
} | ||
.background(preRenderViewSize(containerWidth: containerWidth)) | ||
}.frame(height: visibleContainerHeight) | ||
} | ||
|
||
// Renders all chips on screen, in this case specifically to get their combined height. | ||
// Used to determine if content would overflow if view was not expanded and should | ||
// only be called from a background modifier. | ||
private func preRenderViewSize(containerWidth: CGFloat) -> some View { | ||
ZStack(alignment: .topLeading) { | ||
createChipViews(chips: viewModel.chips, containerWidth: containerWidth) | ||
} | ||
.hidden() | ||
.sizeOfView { fullContainerHeight = $0.height } | ||
} | ||
|
||
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(EdgeInsets(top: 6, leading: 0, bottom: 6, trailing: 8)) | ||
.alignmentGuide(.leading) { dimension in | ||
if abs(width - dimension.width) > containerWidth { | ||
width = 0 | ||
height -= dimension.height | ||
} | ||
let result = width | ||
if data.id == chips.last!.id { | ||
width = 0 | ||
} else { | ||
width -= dimension.width | ||
} | ||
return result | ||
} | ||
.alignmentGuide(.top) { _ in | ||
let result = height | ||
if data.id == chips.last!.id { | ||
height = 0 | ||
} | ||
return result | ||
} | ||
.sizeOfView { chipHeight = $0.height } | ||
} | ||
} | ||
} | ||
|
||
#Preview("Normal") { | ||
ChipContainerView(viewModel: MockFeatureIndicatorsViewModel()) | ||
.background(UIColor.secondaryColor.color) | ||
} | ||
|
||
#Preview("Expanded") { | ||
ChipContainerView(viewModel: MockFeatureIndicatorsViewModel(isExpanded: true)) | ||
.background(UIColor.secondaryColor.color) | ||
} |
Oops, something went wrong.