Commit 44631092 authored by Jose Blaya's avatar Jose Blaya
Browse files

Merge branch '225-piax-region-selection-favorite-server' into...

Merge branch '225-piax-region-selection-favorite-server' into '224-piax-region-selection-no-results-view'

Resolve "PIAX. Region Selection. Favorite server."

See merge request ios/vpn-ios!343
parents 01c7112a 318b573d
......@@ -171,6 +171,12 @@
DDC8124D2176185D00CB290C /* SwiftGen+SeguesStoryboards.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC8124B2176185000CB290C /* SwiftGen+SeguesStoryboards.swift */; };
DDC8124F21761B0B00CB290C /* SwiftGen+ScenesStoryboards.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC8124E21761B0B00CB290C /* SwiftGen+ScenesStoryboards.swift */; };
DDC8125021761B0B00CB290C /* SwiftGen+ScenesStoryboards.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC8124E21761B0B00CB290C /* SwiftGen+ScenesStoryboards.swift */; };
DDD271DE21D616AA00B6D20F /* Server+Favorite.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD271DD21D616AA00B6D20F /* Server+Favorite.swift */; };
DDD271DF21D616AA00B6D20F /* Server+Favorite.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD271DD21D616AA00B6D20F /* Server+Favorite.swift */; };
DDD271E121D6262100B6D20F /* PropertyStoring.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD271E021D6262100B6D20F /* PropertyStoring.swift */; };
DDD271E221D6262100B6D20F /* PropertyStoring.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD271E021D6262100B6D20F /* PropertyStoring.swift */; };
DDD271F021D6718F00B6D20F /* RegionFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD271EF21D6718F00B6D20F /* RegionFilter.swift */; };
DDD271F121D6718F00B6D20F /* RegionFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD271EF21D6718F00B6D20F /* RegionFilter.swift */; };
FE61F5CECAD02C55C725A488 /* Pods_PIA_VPN_Tunnel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E770360A2D0093A53075E293 /* Pods_PIA_VPN_Tunnel.framework */; };
/* End PBXBuildFile section */
......@@ -420,6 +426,9 @@
DD746959217F07AC00B7BD73 /* DNSList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DNSList.swift; sourceTree = "<group>"; };
DDC8124B2176185000CB290C /* SwiftGen+SeguesStoryboards.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SwiftGen+SeguesStoryboards.swift"; sourceTree = "<group>"; };
DDC8124E21761B0B00CB290C /* SwiftGen+ScenesStoryboards.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SwiftGen+ScenesStoryboards.swift"; sourceTree = "<group>"; };
DDD271DD21D616AA00B6D20F /* Server+Favorite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Server+Favorite.swift"; sourceTree = "<group>"; };
DDD271E021D6262100B6D20F /* PropertyStoring.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PropertyStoring.swift; sourceTree = "<group>"; };
DDD271EF21D6718F00B6D20F /* RegionFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegionFilter.swift; sourceTree = "<group>"; };
E770360A2D0093A53075E293 /* Pods_PIA_VPN_Tunnel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PIA_VPN_Tunnel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
EDFACF2A7A2C3C206153EE1F /* Pods-PIA VPN dev.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PIA VPN dev.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PIA VPN dev/Pods-PIA VPN dev.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
......@@ -565,6 +574,7 @@
0EA660071FEC7A9500CB2B0D /* PIATunnelProvider+UI.swift */,
0EFDC1CB1FE35C9A007C0B9B /* Server+Automatic.swift */,
0EB966761FDF11B80086ABC2 /* Server+UI.swift */,
DDD271DD21D616AA00B6D20F /* Server+Favorite.swift */,
0EB966731FDF0D6E0086ABC2 /* ServerProvider+UI.swift */,
0E3A352B1FD9CDC5000B0F99 /* Theme+App.swift */,
0E1F318520176A5F00FC1000 /* Theme+DarkPalette.swift */,
......@@ -572,6 +582,7 @@
0E441E252055AEDF007528D5 /* ThemeStrategy+App.swift */,
0EE14D141FF15626008D9AC2 /* UINavigationController+StatusBar.swift */,
0E9452AA1FDB5EF600891948 /* UINavigationItem+Shortcuts.swift */,
DDD271E021D6262100B6D20F /* PropertyStoring.swift */,
);
name = Extensions;
sourceTree = "<group>";
......@@ -592,6 +603,7 @@
0EB0A84B204F0CE2008BCF1D /* DataCounter.swift */,
0EFDC1D91FE4640C007C0B9B /* DNSResolver.swift */,
0EFDC1D61FE46177007C0B9B /* SensitiveOperation.swift */,
DDD271EF21D6718F00B6D20F /* RegionFilter.swift */,
);
name = Utils;
sourceTree = "<group>";
......@@ -1212,12 +1224,14 @@
"${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework",
"${BUILT_PRODUCTS_DIR}/AlamofireImage/AlamofireImage.framework",
"${BUILT_PRODUCTS_DIR}/DZNEmptyDataSet/DZNEmptyDataSet.framework",
"${BUILT_PRODUCTS_DIR}/DynamicBlurView/DynamicBlurView.framework",
"${BUILT_PRODUCTS_DIR}/FXPageControl/FXPageControl.framework",
"${BUILT_PRODUCTS_DIR}/Gloss/Gloss.framework",
"${BUILT_PRODUCTS_DIR}/MBProgressHUD/MBProgressHUD.framework",
"${PODS_ROOT}/OpenSSL-Apple/frameworks/iPhone/openssl.framework",
"${BUILT_PRODUCTS_DIR}/PIALibrary/PIALibrary.framework",
"${BUILT_PRODUCTS_DIR}/PIATunnel/PIATunnel.framework",
"${BUILT_PRODUCTS_DIR}/PopupDialog/PopupDialog.framework",
"${BUILT_PRODUCTS_DIR}/QuickLayout/QuickLayout.framework",
"${BUILT_PRODUCTS_DIR}/ReachabilitySwift/Reachability.framework",
"${BUILT_PRODUCTS_DIR}/SideMenu/SideMenu.framework",
......@@ -1236,12 +1250,14 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AlamofireImage.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DZNEmptyDataSet.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DynamicBlurView.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FXPageControl.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Gloss.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MBProgressHUD.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PIALibrary.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PIATunnel.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PopupDialog.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/QuickLayout.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reachability.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SideMenu.framework",
......@@ -1292,12 +1308,14 @@
"${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework",
"${BUILT_PRODUCTS_DIR}/AlamofireImage/AlamofireImage.framework",
"${BUILT_PRODUCTS_DIR}/DZNEmptyDataSet/DZNEmptyDataSet.framework",
"${BUILT_PRODUCTS_DIR}/DynamicBlurView/DynamicBlurView.framework",
"${BUILT_PRODUCTS_DIR}/FXPageControl/FXPageControl.framework",
"${BUILT_PRODUCTS_DIR}/Gloss/Gloss.framework",
"${BUILT_PRODUCTS_DIR}/MBProgressHUD/MBProgressHUD.framework",
"${PODS_ROOT}/OpenSSL-Apple/frameworks/iPhone/openssl.framework",
"${BUILT_PRODUCTS_DIR}/PIALibrary/PIALibrary.framework",
"${BUILT_PRODUCTS_DIR}/PIATunnel/PIATunnel.framework",
"${BUILT_PRODUCTS_DIR}/PopupDialog/PopupDialog.framework",
"${BUILT_PRODUCTS_DIR}/QuickLayout/QuickLayout.framework",
"${BUILT_PRODUCTS_DIR}/ReachabilitySwift/Reachability.framework",
"${BUILT_PRODUCTS_DIR}/SideMenu/SideMenu.framework",
......@@ -1314,12 +1332,14 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AlamofireImage.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DZNEmptyDataSet.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DynamicBlurView.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FXPageControl.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Gloss.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MBProgressHUD.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PIALibrary.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PIATunnel.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PopupDialog.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/QuickLayout.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reachability.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SideMenu.framework",
......@@ -1415,6 +1435,7 @@
0E98BB6F1FD5BC6200B41D6B /* Bootstrapper.swift in Sources */,
0E9452A01FDB547D00891948 /* ExpirationCell.swift in Sources */,
0EFDC1F01FE4B9E6007C0B9B /* AppConfiguration.swift in Sources */,
DDD271DF21D616AA00B6D20F /* Server+Favorite.swift in Sources */,
DD1AA4972180AD92005116D7 /* CustomDNSSettingsViewController.swift in Sources */,
0E9452A31FDB568700891948 /* MenuItemCell.swift in Sources */,
0EFDC1DB1FE4640C007C0B9B /* DNSResolver.swift in Sources */,
......@@ -1433,6 +1454,7 @@
0E441E322055B8A7007528D5 /* Theme+Extension.swift in Sources */,
0EA4ACAB20487B5800431F7D /* FakeSwitch.swift in Sources */,
DDC8124D2176185D00CB290C /* SwiftGen+SeguesStoryboards.swift in Sources */,
DDD271E221D6262100B6D20F /* PropertyStoring.swift in Sources */,
0EFB839120209CF200980F69 /* VPNPermissionViewController.swift in Sources */,
0EFDC1D81FE46177007C0B9B /* SensitiveOperation.swift in Sources */,
0E3A35291FD9A960000B0F99 /* DashboardViewController.swift in Sources */,
......@@ -1464,6 +1486,7 @@
0E9AEA6320683FDF00B6E59A /* AboutComponent.swift in Sources */,
DD74695B217F07AC00B7BD73 /* DNSList.swift in Sources */,
0E9452AF1FDB5F7A00891948 /* PIAPageControl.swift in Sources */,
DDD271F121D6718F00B6D20F /* RegionFilter.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......@@ -1500,6 +1523,7 @@
0E98BB6E1FD5BC6200B41D6B /* Bootstrapper.swift in Sources */,
0E94529F1FDB547D00891948 /* ExpirationCell.swift in Sources */,
0E441E262055AEDF007528D5 /* ThemeStrategy+App.swift in Sources */,
DDD271DE21D616AA00B6D20F /* Server+Favorite.swift in Sources */,
DD1AA4962180AD92005116D7 /* CustomDNSSettingsViewController.swift in Sources */,
0EFDC1EF1FE4B9E6007C0B9B /* AppConfiguration.swift in Sources */,
0E9452A21FDB568700891948 /* MenuItemCell.swift in Sources */,
......@@ -1518,6 +1542,7 @@
0E7AA9092023CA0700E1F07A /* HUD.swift in Sources */,
0EA4ACAA20487B5800431F7D /* FakeSwitch.swift in Sources */,
DDC8124C2176185000CB290C /* SwiftGen+SeguesStoryboards.swift in Sources */,
DDD271E121D6262100B6D20F /* PropertyStoring.swift in Sources */,
0EFB839020209CF200980F69 /* VPNPermissionViewController.swift in Sources */,
0EFDC1D71FE46177007C0B9B /* SensitiveOperation.swift in Sources */,
0E3A35281FD9A960000B0F99 /* DashboardViewController.swift in Sources */,
......@@ -1549,6 +1574,7 @@
0E9AEA6220683FDF00B6E59A /* AboutComponent.swift in Sources */,
DD74695A217F07AC00B7BD73 /* DNSList.swift in Sources */,
0E9452AE1FDB5F7A00891948 /* PIAPageControl.swift in Sources */,
DDD271F021D6718F00B6D20F /* RegionFilter.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......
......@@ -14,6 +14,7 @@ import SwiftyBeaver
private let log = SwiftyBeaver.self
class AppPreferences {
private struct Entries {
static let version = "Version"
......@@ -28,6 +29,10 @@ class AppPreferences {
static let lastVPNConnectionStatus = "LastVPNConnectionStatus"
static let piaSocketType = "PIASocketType"
static let favoriteServerIdentifiers = "FavoriteServerIdentifiers"
static let regionFilter = "RegionFilter"
}
static let shared = AppPreferences()
......@@ -104,6 +109,30 @@ class AppPreferences {
}
}
var favoriteServerIdentifiers: [String] {
get {
if let serverIdentifiers = defaults.array(forKey: Entries.favoriteServerIdentifiers) as? [String] {
return serverIdentifiers
}
return []
}
set {
defaults.set(newValue, forKey: Entries.favoriteServerIdentifiers)
}
}
var regionFilter: RegionFilter {
get {
guard let rawValue = defaults.string(forKey: Entries.regionFilter) else {
return .name
}
return RegionFilter(rawValue: rawValue) ?? .name
}
set {
defaults.set(newValue.rawValue, forKey: Entries.regionFilter)
}
}
private init() {
guard let defaults = UserDefaults(suiteName: AppConstants.appGroup) else {
fatalError("Unable to initialize app preferences")
......@@ -113,6 +142,8 @@ class AppPreferences {
defaults.register(defaults: [
Entries.version: AppPreferences.currentVersion,
Entries.launched: false,
Entries.regionFilter: RegionFilter.name.rawValue,
Entries.favoriteServerIdentifiers: [],
Entries.didAskToEnableNotifications: false,
Entries.themeCode: ThemeCode.light.rawValue
])
......
{
"images" : [
{
"idiom" : "universal",
"filename" : "group92.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
......@@ -2,7 +2,7 @@
"images" : [
{
"idiom" : "universal",
"filename" : "group4Copy2.pdf"
"filename" : "15IllustrationNoResultDarkCopy2.pdf"
}
],
"info" : {
......
......@@ -2,7 +2,7 @@
"images" : [
{
"idiom" : "universal",
"filename" : "group2Copy.pdf"
"filename" : "15IllustrationNoResultLightCopy2.pdf"
}
],
"info" : {
......
//
// PropertyStoring.swift
// PIA VPN
//
// Created by Jose Antonio Blaya Garcia on 28/12/2018.
// Copyright © 2018 London Trust Media. All rights reserved.
//
import Foundation
protocol PropertyStoring {
associatedtype T
func getAssociatedObject(_ key: UnsafeRawPointer!, defaultValue: T) -> T
}
extension PropertyStoring {
func getAssociatedObject(_ key: UnsafeRawPointer!, defaultValue: T) -> T {
guard let value = objc_getAssociatedObject(self, key) as? T else {
return defaultValue
}
return value
}
}
......@@ -22,12 +22,14 @@ class RegionCell: UITableViewCell, Restylable {
@IBOutlet private weak var selectedRegionImageView: UIImageView!
private var isFavorite: Bool!
private weak var server: Server!
override func setSelected(_ selected: Bool, animated: Bool) {
}
func fill(withServer server: Server, isSelected: Bool) {
viewShouldRestyle()
self.server = server
imvFlag.setImage(fromServer: server)
labelRegion.text = server.name
......@@ -50,10 +52,10 @@ class RegionCell: UITableViewCell, Restylable {
accessibilityIdentifier = "uitests.regions.region_name"
self.favoriteImageView.image = self.favoriteImageView.image?.withRenderingMode(.alwaysTemplate)
self.favoriteImageView.alpha = CGFloat(NSNumber(booleanLiteral: server.name != L10n.Global.automatic).floatValue)
self.favoriteButton.alpha = CGFloat(NSNumber(booleanLiteral: server.name != L10n.Global.automatic).floatValue)
self.favoriteImageView.alpha = CGFloat(NSNumber(booleanLiteral: !server.isAutomatic).floatValue)
self.favoriteButton.alpha = CGFloat(NSNumber(booleanLiteral: !server.isAutomatic).floatValue)
self.isFavorite = isSelected
self.isFavorite = server.isFavorite
self.updateFavoriteImage()
self.setSelected(false, animated: false)
......@@ -78,6 +80,7 @@ class RegionCell: UITableViewCell, Restylable {
@IBAction func favoriteServer(_ sender: UIButton) {
self.isFavorite = !self.isFavorite
self.isFavorite ? self.server.favorite() : self.server.unfavorite()
self.animateFavoriteImage()
}
......
//
// RegionFilter.swift
// PIA VPN
//
// Created by Jose Antonio Blaya Garcia on 28/12/2018.
// Copyright © 2018 London Trust Media. All rights reserved.
//
import Foundation
public enum RegionFilter: String {
case name
case latency
case favorite
}
......@@ -9,6 +9,7 @@
import UIKit
import PIALibrary
import DZNEmptyDataSet
import PopupDialog
class RegionsViewController: AutolayoutViewController {
private struct Cells {
......@@ -33,7 +34,14 @@ class RegionsViewController: AutolayoutViewController {
title = L10n.Menu.Item.region
var servers = Client.providers.serverProvider.currentServers
servers.insert(Server.automatic, at: 0)
let favoriteServers = AppPreferences.shared.favoriteServerIdentifiers
for server in servers {
server.isFavorite = favoriteServers.contains(server.identifier)
}
self.servers = servers
filterServers()
selectedServer = Client.preferences.displayedServer
......@@ -41,11 +49,45 @@ class RegionsViewController: AutolayoutViewController {
NotificationCenter.default.addObserver(self, selector: #selector(viewHasRotated), name: .UIDeviceOrientationDidChange, object: nil)
setupSearchBarController()
stylePopupDialog()
tableView.emptyDataSetSource = self
tableView.emptyDataSetDelegate = self
}
private func setupRightBarButton() {
navigationItem.rightBarButtonItem = UIBarButtonItem(
image: Asset.Piax.Global.iconFilter.image,
style: .plain,
target: self,
action: #selector(showFilter(_:))
)
navigationItem.rightBarButtonItem?.accessibilityLabel = L10n.Region.Accessibility.filter
}
private func stylePopupDialog() {
let dialogAppearance = PopupDialogDefaultView.appearance()
dialogAppearance.backgroundColor = Theme.current.palette.appearance == .dark ? UIColor.piaGrey6 : .white
dialogAppearance.titleFont = TextStyle.textStyle12.font!
dialogAppearance.titleColor = Theme.current.palette.appearance == .dark ? .white : TextStyle.textStyle12.color
let containerAppearance = PopupDialogContainerView.appearance()
containerAppearance.cornerRadius = 0
containerAppearance.shadowEnabled = false
let overlayAppearance = PopupDialogOverlayView.appearance()
overlayAppearance.color = .black
overlayAppearance.blurEnabled = false
overlayAppearance.liveBlurEnabled = false
overlayAppearance.opacity = 0.5
let buttonAppearance = DefaultButton.appearance()
buttonAppearance.titleFont = TextStyle.textStyle21.font!
buttonAppearance.titleColor = TextStyle.textStyle21.color
buttonAppearance.buttonColor = Theme.current.palette.appearance == .dark ? UIColor.piaGrey6 : .white
buttonAppearance.separatorColor = Theme.current.palette.appearance == .dark ? UIColor.piaGrey10 : UIColor.piaGrey1
}
private func setupSearchBarController() {
searchController.searchResultsUpdater = self
if #available(iOS 9.1, *) {
......@@ -58,8 +100,10 @@ class RegionsViewController: AutolayoutViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
styleNavigationBarWithTitle(L10n.Menu.Item.region)
setupRightBarButton()
let selectedRow = servers.index { (server) -> Bool in
return (server.identifier == selectedServer.identifier)
}
......@@ -71,6 +115,53 @@ class RegionsViewController: AutolayoutViewController {
}
// MARK: Actions
@objc private func showFilter(_ sender: Any?) {
let popup = PopupDialog(title: L10n.Region.Filter.sortby.uppercased(),
message: nil)
let buttonName = DefaultButton(title: L10n.Region.Filter.name.uppercased(), dismissOnTap: true) {
AppPreferences.shared.regionFilter = .name
self.filterServers()
}
let buttonLatency = DefaultButton(title: L10n.Region.Filter.latency.uppercased(), dismissOnTap: true) {
AppPreferences.shared.regionFilter = .latency
self.filterServers()
}
let buttonFavorites = DefaultButton(title: L10n.Region.Filter.favorites.uppercased(), dismissOnTap: true) {
AppPreferences.shared.regionFilter = .favorite
self.filterServers()
}
switch AppPreferences.shared.regionFilter {
case .name:
buttonName.titleColor = UIColor.piaGreenDark20
case .latency:
buttonLatency.titleColor = UIColor.piaGreenDark20
default:
buttonFavorites.titleColor = UIColor.piaGreenDark20
}
popup.addButtons([buttonName, buttonLatency, buttonFavorites])
self.present(popup, animated: true, completion: nil)
}
private func filterServers() {
self.servers = servers.filter({ !$0.isAutomatic })
switch AppPreferences.shared.regionFilter {
case .name:
self.servers = self.servers.sorted(by: { $0.name < $1.name })
case .latency:
self.servers = self.servers.sorted(by: { $0.pingTime ?? 0 < $1.pingTime ?? 0 })
default:
self.servers = self.servers.sorted(by: { $0.isFavorite && !$1.isFavorite })
}
tableView.reloadData()
self.servers.insert(Server.automatic, at: 0)
tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
}
@objc private func viewHasRotated() {
styleNavigationBarWithTitle(L10n.Menu.Item.region)
}
......
//
// Server+Favorite.swift
// PIA VPN
//
// Created by Jose Antonio Blaya Garcia on 28/12/2018.
// Copyright © 2018 London Trust Media. All rights reserved.
//
import Foundation
import PIALibrary
protocol Favoritable {
/// Favorite this server and update the cached servers
func favorite()
/// Unfavorite this server and update the cached servers
func unfavorite()
}
extension Server: Favoritable, PropertyStoring {
typealias T = Bool
private struct CustomProperties {
static var isFavorite = false
}
var isFavorite: Bool {
get {
return getAssociatedObject(&CustomProperties.isFavorite, defaultValue: CustomProperties.isFavorite)
}
set {
return objc_setAssociatedObject(self, &CustomProperties.isFavorite, newValue, .OBJC_ASSOCIATION_RETAIN)
}
}
func favorite() {
self.isFavorite = true
var currentFavorites = AppPreferences.shared.favoriteServerIdentifiers
currentFavorites.append(self.identifier)
AppPreferences.shared.favoriteServerIdentifiers = currentFavorites
}
func unfavorite() {
self.isFavorite = false
let currentFavorites = AppPreferences.shared.favoriteServerIdentifiers
let filteredFavorites = currentFavorites.filter({$0 != self.identifier})
AppPreferences.shared.favoriteServerIdentifiers = filteredFavorites
}
}
......@@ -53,6 +53,7 @@ enum Asset {
static let favoriteUnselectedDark = ImageAsset(name: "favorite-unselected-dark")
static let favoriteUnselected = ImageAsset(name: "favorite-unselected")
static let iconBack = ImageAsset(name: "icon-back")
static let iconFilter = ImageAsset(name: "icon-filter")
static let pagecontrolSelectedDot = ImageAsset(name: "pagecontrol-selected-dot")
static let pagecontrolUnselectedDot = ImageAsset(name: "pagecontrol-unselected-dot")
static let regionSelected = ImageAsset(name: "region-selected")
......@@ -331,6 +332,7 @@ enum Asset {
Piax.Global.favoriteUnselectedDark,
Piax.Global.favoriteUnselected,
Piax.Global.iconBack,
Piax.Global.iconFilter,
Piax.Global.pagecontrolSelectedDot,
Piax.Global.pagecontrolUnselectedDot,
Piax.Global.regionSelected,
......
......@@ -279,6 +279,20 @@ internal enum L10n {
}
internal enum Region {
internal enum Accessibility {
/// Filter
internal static let filter = L10n.tr("Localizable", "region.accessibility.filter")
}
internal enum Filter {
/// Favorites
internal static let favorites = L10n.tr("Localizable", "region.filter.favorites")
/// Latency
internal static let latency = L10n.tr("Localizable", "region.filter.latency")
/// Name
internal static let name = L10n.tr("Localizable", "region.filter.name")
/// Sort regions by
internal static let sortby = L10n.tr("Localizable", "region.filter.sortby")
}
internal enum Search {
/// Search for a region
internal static let placeholder = L10n.tr("Localizable", "region.search.placeholder")
......
......@@ -202,3 +202,8 @@
// REGION
"region.search.placeholder" = "Search for a region";
"region.accessibility.filter" = "Filter";
"region.filter.sortby" = "Sort regions by";
"region.filter.name" = "Name";
"region.filter.latency" = "Latency";
"region.filter.favorites" = "Favorites";
......@@ -65,6 +65,7 @@ def app_pods
pod 'FXPageControl'
pod 'MBProgressHUD'
pod 'DZNEmptyDataSet'
pod 'PopupDialog'
end
def tunnel_pods
......@@ -90,3 +91,13 @@ end
target 'PIA VPN Tunnel' do
tunnel_pods
end
post_install do |installer|
installer.pods_project.targets.each do |target|
if ['PopupDialog'].include? target.name
target.build_configurations.each do |config|
config.build_settings['SWIFT_VERSION'] = '4.2'
end
end
end
end
......@@ -4,6 +4,7 @@ PODS:
- Alamofire (~> 4.7)
- Crashlytics (3.11.1):
- Fabric (~> 1.8.1)
- DynamicBlurView (3.0.1)
- DZNEmptyDataSet (1.8.1)
- Fabric (1.8.1)
- Firebase/Core (5.11.0):
......@@ -94,6 +95,8 @@ PODS:
- PIATunnel/Core (1.1.8):
- OpenSSL-Apple (~> 1.1.0h)
- SwiftyBeaver