-
Notifications
You must be signed in to change notification settings - Fork 131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[feature/whats new screen] In-App changelog "What´s new screen" #572
Changes from all commits
bd25e79
a440ed0
c51f628
696aba0
0508fa2
67081ab
4e7b627
3babefa
f842fb7
b3965f7
8d29fa6
4a32767
11a0bc0
3de4e73
db724f5
190aa08
eff4f92
18e8408
6ee498d
6af51be
295e146
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,227 @@ | ||
// | ||
// ReleaseNotesHostViewController.swift | ||
// ownCloud | ||
// | ||
// Created by Matthias Hühne on 04.12.19. | ||
// Copyright © 2019 ownCloud GmbH. All rights reserved. | ||
// | ||
|
||
/* | ||
* Copyright (C) 2019, ownCloud GmbH. | ||
* | ||
* This code is covered by the GNU Public License Version 3. | ||
* | ||
* For distribution utilizing Apple mechanisms please see https://owncloud.org/contribute/iOS-license-exception/ | ||
* You should have received a copy of this license along with this program. If not, see <http://www.gnu.org/licenses/gpl-3.0.en.html>. | ||
* | ||
*/ | ||
|
||
import UIKit | ||
import ownCloudSDK | ||
import StoreKit | ||
|
||
class ReleaseNotesHostViewController: UIViewController { | ||
|
||
// MARK: - Constants | ||
private let cornerRadius : CGFloat = 8.0 | ||
private let padding : CGFloat = 20.0 | ||
private let smallPadding : CGFloat = 10.0 | ||
private let buttonHeight : CGFloat = 44.0 | ||
private let headerHeight : CGFloat = 60.0 | ||
|
||
// MARK: - Instance Variables | ||
var titleLabel = UILabel() | ||
var proceedButton = ThemeButton() | ||
var footerButton = UIButton() | ||
|
||
override func viewDidLoad() { | ||
super.viewDidLoad() | ||
|
||
Theme.shared.register(client: self) | ||
|
||
ReleaseNotesDatasource.setUserPreferenceValue(NSString(utf8String: VendorServices.shared.appVersion), forClassSettingsKey: .lastSeenReleaseNotesVersion) | ||
|
||
let headerView = UIView() | ||
headerView.backgroundColor = .clear | ||
headerView.translatesAutoresizingMaskIntoConstraints = false | ||
view.addSubview(headerView) | ||
NSLayoutConstraint.activate([ | ||
headerView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), | ||
headerView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), | ||
headerView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), | ||
headerView.heightAnchor.constraint(equalToConstant: headerHeight) | ||
]) | ||
|
||
titleLabel.translatesAutoresizingMaskIntoConstraints = false | ||
titleLabel.setContentHuggingPriority(UILayoutPriority.defaultLow, for: NSLayoutConstraint.Axis.horizontal) | ||
|
||
titleLabel.text = "New in ownCloud".localized | ||
titleLabel.textAlignment = .center | ||
titleLabel.numberOfLines = 0 | ||
titleLabel.font = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.headline) | ||
titleLabel.adjustsFontForContentSizeCategory = true | ||
headerView.addSubview(titleLabel) | ||
|
||
NSLayoutConstraint.activate([ | ||
titleLabel.leftAnchor.constraint(greaterThanOrEqualTo: headerView.safeAreaLayoutGuide.leftAnchor, constant: padding), | ||
titleLabel.rightAnchor.constraint(lessThanOrEqualTo: headerView.safeAreaLayoutGuide.rightAnchor, constant: padding * -1), | ||
titleLabel.centerXAnchor.constraint(equalTo: headerView.safeAreaLayoutGuide.centerXAnchor), | ||
|
||
titleLabel.topAnchor.constraint(equalTo: headerView.safeAreaLayoutGuide.topAnchor, constant: padding) | ||
]) | ||
|
||
let releaseNotesController = ReleaseNotesTableViewController(style: .plain) | ||
if let containerView = releaseNotesController.view { | ||
containerView.backgroundColor = .clear | ||
containerView.translatesAutoresizingMaskIntoConstraints = false | ||
view.addSubview(containerView) | ||
|
||
let bottomView = UIView() | ||
bottomView.backgroundColor = .clear | ||
bottomView.translatesAutoresizingMaskIntoConstraints = false | ||
view.addSubview(bottomView) | ||
NSLayoutConstraint.activate([ | ||
bottomView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), | ||
bottomView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), | ||
bottomView.topAnchor.constraint(equalTo: containerView.bottomAnchor), | ||
bottomView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) | ||
]) | ||
|
||
proceedButton.setTitle("Proceed".localized, for: .normal) | ||
proceedButton.translatesAutoresizingMaskIntoConstraints = false | ||
proceedButton.addTarget(self, action: #selector(dismissView), for: .touchUpInside) | ||
bottomView.addSubview(proceedButton) | ||
|
||
let appName = OCAppIdentity.shared.appName ?? "ownCloud" | ||
footerButton.setTitle(String(format:"Thank you for using %@.\nIf you like our App, please leave an AppStore review.\n❤️".localized, appName), for: .normal) | ||
footerButton.titleLabel?.font = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.footnote) | ||
footerButton.titleLabel?.adjustsFontForContentSizeCategory = true | ||
footerButton.titleLabel?.numberOfLines = 0 | ||
footerButton.titleLabel?.textAlignment = .center | ||
footerButton.translatesAutoresizingMaskIntoConstraints = false | ||
footerButton.addTarget(self, action: #selector(rateApp), for: .touchUpInside) | ||
bottomView.addSubview(footerButton) | ||
|
||
NSLayoutConstraint.activate([ | ||
footerButton.leadingAnchor.constraint(equalTo: bottomView.leadingAnchor, constant: padding), | ||
footerButton.trailingAnchor.constraint(equalTo: bottomView.trailingAnchor, constant: padding * -1), | ||
footerButton.topAnchor.constraint(equalTo: bottomView.topAnchor, constant: smallPadding), | ||
footerButton.bottomAnchor.constraint(equalTo: proceedButton.topAnchor, constant: padding * -1) | ||
]) | ||
|
||
NSLayoutConstraint.activate([ | ||
proceedButton.leadingAnchor.constraint(equalTo: bottomView.leadingAnchor, constant: padding), | ||
proceedButton.trailingAnchor.constraint(equalTo: bottomView.trailingAnchor, constant: padding * -1), | ||
proceedButton.heightAnchor.constraint(equalToConstant: buttonHeight), | ||
proceedButton.bottomAnchor.constraint(equalTo: bottomView.bottomAnchor, constant: smallPadding * -1) | ||
]) | ||
|
||
NSLayoutConstraint.activate([ | ||
containerView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), | ||
containerView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), | ||
containerView.topAnchor.constraint(equalTo: headerView.bottomAnchor), | ||
containerView.bottomAnchor.constraint(equalTo: bottomView.topAnchor) | ||
]) | ||
} | ||
} | ||
|
||
deinit { | ||
Theme.shared.unregister(client: self) | ||
} | ||
|
||
@objc func dismissView() { | ||
self.dismiss(animated: true, completion: nil) | ||
} | ||
|
||
@objc func rateApp() { | ||
SKStoreReviewController.requestReview() | ||
} | ||
} | ||
|
||
// MARK: - Themeable implementation | ||
extension ReleaseNotesHostViewController : Themeable { | ||
func applyThemeCollection(theme: Theme, collection: ThemeCollection, event: ThemeEvent) { | ||
|
||
self.view.backgroundColor = collection.tableBackgroundColor | ||
titleLabel.applyThemeCollection(collection, itemStyle: .logo) | ||
proceedButton.backgroundColor = collection.neutralColors.normal.background | ||
proceedButton.setTitleColor(collection.neutralColors.normal.foreground, for: .normal) | ||
footerButton.titleLabel?.textColor = collection.tableRowColors.labelColor | ||
} | ||
} | ||
|
||
class ReleaseNotesDatasource : NSObject, OCClassSettingsUserPreferencesSupport { | ||
|
||
var shouldShowReleaseNotes: Bool { | ||
if let lastSeenReleaseNotesVersion = self.classSetting(forOCClassSettingsKey: .lastSeenReleaseNotesVersion) as? String { | ||
|
||
if lastSeenReleaseNotesVersion.compare(VendorServices.shared.appVersion, options: .numeric) == .orderedDescending || lastSeenReleaseNotesVersion.compare(VendorServices.shared.appVersion, options: .numeric) == .orderedSame { | ||
return false | ||
} | ||
|
||
if let path = Bundle.main.path(forResource: "ReleaseNotes", ofType: "plist"), let releaseNotesValues = NSDictionary(contentsOfFile: path), let versionsValues = releaseNotesValues["Versions"] as? NSArray { | ||
|
||
let relevantReleaseNotes = versionsValues.filter { | ||
if let version = ($0 as AnyObject)["Version"] as? String, version.compare(VendorServices.shared.appVersion, options: .numeric) == .orderedDescending { | ||
return false | ||
} | ||
|
||
return true | ||
} | ||
|
||
if relevantReleaseNotes.count > 0 { | ||
return true | ||
} | ||
} | ||
|
||
return false | ||
} else if self.classSetting(forOCClassSettingsKey: .lastSeenAppVersion) != nil { | ||
if self.classSetting(forOCClassSettingsKey: .lastSeenAppVersion) as? String != VendorServices.shared.appVersion { | ||
return true | ||
} | ||
return false | ||
} else if OCBookmarkManager.shared.bookmarks.count > 0 { | ||
// Fallback, if app was previously installed, because we cannot check for an user defaults key, we have to check if accounts was previously configured | ||
return true | ||
} | ||
|
||
return false | ||
} | ||
|
||
func releaseNotes(for version: String) -> [[String:Any]]? { | ||
if let path = Bundle.main.path(forResource: "ReleaseNotes", ofType: "plist") { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @hosy Looking at code in lines 154-172, I think there is some potential to reduce code duplication... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removed one if statement |
||
if let releaseNotesValues = NSDictionary(contentsOfFile: path), let versionsValues = releaseNotesValues["Versions"] as? NSArray { | ||
|
||
let relevantReleaseNotes = versionsValues.filter { | ||
if let version = ($0 as AnyObject)["Version"] as? String, version.compare(VendorServices.shared.appVersion, options: .numeric) == .orderedAscending { | ||
return false | ||
} | ||
|
||
return true | ||
} | ||
|
||
return relevantReleaseNotes as? [[String:Any]] | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
} | ||
|
||
extension OCClassSettingsKey { | ||
// Available since version 1.3.0 | ||
static let lastSeenReleaseNotesVersion = OCClassSettingsKey("lastSeenReleaseNotesVersion") | ||
static let lastSeenAppVersion = OCClassSettingsKey("lastSeenAppVersion") | ||
} | ||
|
||
extension ReleaseNotesDatasource : OCClassSettingsSupport { | ||
static let classSettingsIdentifier : OCClassSettingsIdentifier = .app | ||
|
||
static func defaultSettings(forIdentifier identifier: OCClassSettingsIdentifier) -> [OCClassSettingsKey : Any]? { | ||
if identifier == .app { | ||
return nil | ||
} | ||
|
||
return nil | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// | ||
// ReleaseNotesTableViewController.swift | ||
// ownCloud | ||
// | ||
// Created by Matthias Hühne on 09.10.19. | ||
// Copyright © 2019 ownCloud GmbH. All rights reserved. | ||
// | ||
|
||
/* | ||
* Copyright (C) 2019, ownCloud GmbH. | ||
* | ||
* This code is covered by the GNU Public License Version 3. | ||
* | ||
* For distribution utilizing Apple mechanisms please see https://owncloud.org/contribute/iOS-license-exception/ | ||
* You should have received a copy of this license along with this program. If not, see <http://www.gnu.org/licenses/gpl-3.0.en.html>. | ||
* | ||
*/ | ||
|
||
import UIKit | ||
|
||
class ReleaseNotesTableViewController: StaticTableViewController { | ||
|
||
override func viewDidLoad() { | ||
super.viewDidLoad() | ||
|
||
tableView.separatorColor = .clear | ||
prepareReleaseNotes() | ||
} | ||
|
||
func prepareReleaseNotes() { | ||
if let relevantReleaseNotes = ReleaseNotesDatasource().releaseNotes(for: VendorServices.shared.appVersion) { | ||
let section = StaticTableViewSection() | ||
|
||
for aDict in relevantReleaseNotes { | ||
if let notes = aDict["ReleaseNotes"] as? NSArray { | ||
for releaseNote in (notes as? [[String:String]])! { | ||
if let title = releaseNote["Title"], let subtitle = releaseNote["Subtitle"], let strBase64 = releaseNote["ImageData"] { | ||
let dataDecoded : Data = Data(base64Encoded: strBase64, options: .ignoreUnknownCharacters)! | ||
if let decodedimage = UIImage(data: dataDecoded)?.tinted(with: .white)?.scaledImageFitting(in: CGSize(width: 50.0, height: 44.0)) { | ||
let row = StaticTableViewRow(rowWithAction: { (_, _) in | ||
self.dismissAnimated() | ||
}, title: title, subtitle: subtitle, image: decodedimage, imageWidth:50.0, alignment: .left, accessoryType: .none) | ||
section.add(row: row) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
self.addSection(section) | ||
} | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ownCloud
word should be brandable