From 76c50e637d6b2f674e281d06028a561287a5a5db Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Mon, 10 Dec 2018 12:36:39 +0100 Subject: [PATCH 1/4] Add reviewer singleton Prompt for rating after N events. --- Passepartout.xcodeproj/project.pbxproj | 4 ++ Passepartout/Sources/Reviewer.swift | 75 ++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 Passepartout/Sources/Reviewer.swift diff --git a/Passepartout.xcodeproj/project.pbxproj b/Passepartout.xcodeproj/project.pbxproj index 75cd62e6..318b0471 100644 --- a/Passepartout.xcodeproj/project.pbxproj +++ b/Passepartout.xcodeproj/project.pbxproj @@ -40,6 +40,7 @@ 0E5E5DE521511C5F00E318A3 /* GracefulVPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5E5DE421511C5F00E318A3 /* GracefulVPN.swift */; }; 0E6BE13A20CFB76800A6DD36 /* ApplicationError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E6BE13920CFB76800A6DD36 /* ApplicationError.swift */; }; 0E6BE13F20CFBAB300A6DD36 /* DebugLogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E6BE13E20CFBAB300A6DD36 /* DebugLogViewController.swift */; }; + 0E78179F21BE852200950C58 /* Reviewer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E78179E21BE852200950C58 /* Reviewer.swift */; }; 0E79D13F21919EC900BB5FB2 /* PlaceholderConnectionProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E79D13E21919EC900BB5FB2 /* PlaceholderConnectionProfile.swift */; }; 0E79D14121919F5600BB5FB2 /* ProfileKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E79D14021919F5600BB5FB2 /* ProfileKey.swift */; }; 0E89DFC5213DF7AE00741BA1 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E89DFC4213DF7AE00741BA1 /* Preferences.swift */; }; @@ -162,6 +163,7 @@ 0E5E5DE421511C5F00E318A3 /* GracefulVPN.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GracefulVPN.swift; sourceTree = ""; }; 0E6BE13920CFB76800A6DD36 /* ApplicationError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationError.swift; sourceTree = ""; }; 0E6BE13E20CFBAB300A6DD36 /* DebugLogViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebugLogViewController.swift; sourceTree = ""; }; + 0E78179E21BE852200950C58 /* Reviewer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reviewer.swift; sourceTree = ""; }; 0E79D13E21919EC900BB5FB2 /* PlaceholderConnectionProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceholderConnectionProfile.swift; sourceTree = ""; }; 0E79D14021919F5600BB5FB2 /* ProfileKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileKey.swift; sourceTree = ""; }; 0E89DFC4213DF7AE00741BA1 /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = ""; }; @@ -468,6 +470,7 @@ 0E39BCF2214DA9310035E9DE /* AppConstants.swift */, 0E6BE13920CFB76800A6DD36 /* ApplicationError.swift */, 0EDE8DED20C93E4C004C739C /* GroupConstants.swift */, + 0E78179E21BE852200950C58 /* Reviewer.swift */, 0E05C5E320D1993C006EE732 /* SwiftGen+Strings.swift */, 0E4FD7ED20D539A0002221FF /* Utils.swift */, ); @@ -808,6 +811,7 @@ files = ( 0E5E5DDF215119AF00E318A3 /* VPNStatus.swift in Sources */, 0ECEE44E20E1122200A6BB43 /* TableModel.swift in Sources */, + 0E78179F21BE852200950C58 /* Reviewer.swift in Sources */, 0ED38AD9213F33150004D387 /* WizardHostViewController.swift in Sources */, 0EE3BBB2215ED3A900F30952 /* AboutViewController.swift in Sources */, 0EBE3A79213C4E5500BFA2F5 /* OrganizerViewController.swift in Sources */, diff --git a/Passepartout/Sources/Reviewer.swift b/Passepartout/Sources/Reviewer.swift new file mode 100644 index 00000000..78c2df09 --- /dev/null +++ b/Passepartout/Sources/Reviewer.swift @@ -0,0 +1,75 @@ +// +// Reviewer.swift +// Passepartout +// +// Created by Davide De Rosa on 12/10/18. +// Copyright (c) 2018 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import StoreKit +import SwiftyBeaver + +private let log = SwiftyBeaver.self + +class Reviewer { + private struct Keys { + static let eventCount = "ReviewerEventCount" + + static let lastVersion = "ReviewerLastVersion" + } + + static let shared = Reviewer() + + private let defaults: UserDefaults + + var eventCountBeforeRating = 3 + + private init() { + defaults = .standard + } + + func reportEvent() { + let currentVersion = GroupConstants.App.buildNumber + let lastVersion = defaults.integer(forKey: Keys.lastVersion) + if lastVersion > 0 { + log.debug("App last reviewed for version \(lastVersion)") + } else { + log.debug("App was never reviewed") + } + guard currentVersion != lastVersion else { + log.debug("App already reviewed for version \(currentVersion)") + return + } + + var count = defaults.integer(forKey: Keys.eventCount) + count += 1 + defaults.set(count, forKey: Keys.eventCount) + log.debug("Event reported for version \(currentVersion) (count: \(count), prompt: \(eventCountBeforeRating))") + + guard count >= eventCountBeforeRating else { + return + } + log.debug("Prompting for review...") + + SKStoreReviewController.requestReview() + defaults.removeObject(forKey: Keys.eventCount) + defaults.set(currentVersion, forKey: Keys.lastVersion) + } +} From d2186678de4c55cb2a399f70eae6eaf7200a11a9 Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Mon, 10 Dec 2018 12:42:50 +0100 Subject: [PATCH 2/4] Report reviewer event on successful connection --- Passepartout-iOS/Scenes/ServiceViewController.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Passepartout-iOS/Scenes/ServiceViewController.swift b/Passepartout-iOS/Scenes/ServiceViewController.swift index a225c1c5..3b6ef0ee 100644 --- a/Passepartout-iOS/Scenes/ServiceViewController.swift +++ b/Passepartout-iOS/Scenes/ServiceViewController.swift @@ -395,6 +395,10 @@ class ServiceViewController: UIViewController, TableModelHost { @objc private func vpnDidUpdate() { reloadVpnStatus() + + if vpn.status == .connected { + Reviewer.shared.reportEvent() + } } @objc private func applicationDidBecomeActive() { From 323807cfbf5677cb14045de4799442170f6c0460 Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Mon, 10 Dec 2018 12:53:01 +0100 Subject: [PATCH 3/4] Configure reviewer event count in AppConstants --- Passepartout-iOS/AppDelegate.swift | 1 + Passepartout/Sources/AppConstants.swift | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/Passepartout-iOS/AppDelegate.swift b/Passepartout-iOS/AppDelegate.swift index 714c60d4..21fea37f 100644 --- a/Passepartout-iOS/AppDelegate.swift +++ b/Passepartout-iOS/AppDelegate.swift @@ -39,6 +39,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { InfrastructureFactory.shared.loadCache() Theme.current.applyAppearance() + Reviewer.shared.eventCountBeforeRating = AppConstants.Rating.eventCount // Override point for customization after application launch. let splitViewController = window!.rootViewController as! UISplitViewController diff --git a/Passepartout/Sources/AppConstants.swift b/Passepartout/Sources/AppConstants.swift index e14cbf0d..328214bd 100644 --- a/Passepartout/Sources/AppConstants.swift +++ b/Passepartout/Sources/AppConstants.swift @@ -234,4 +234,8 @@ class AppConstants { ) ] } + + struct Rating { + static let eventCount = 3 + } } From a0e4a0b610fc1d01393822b932531f41cb38224e Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Mon, 10 Dec 2018 12:49:04 +0100 Subject: [PATCH 4/4] Update CHANGELOG --- CHANGELOG.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0b79246..86d1bffb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,14 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -### Fixed +### Added -- Infrastructures not refreshed. [#29](https://github.com/passepartoutvpn/passepartout-ios/issues/29) +- Automated app rating mechanism. ### Changed - Relocated API endpoints, better before first release. +### Fixed + +- Infrastructures not refreshed. [#29](https://github.com/passepartoutvpn/passepartout-ios/issues/29) + ## 1.0 RC4 1271 (2018-12-04) ### Changed