Skip to content
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

Merged
merged 21 commits into from
Jan 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
bd25e79
first draft of what´s new screen
hosy Oct 9, 2019
a440ed0
Autoplay Media / Show album artwork in the media player view (#566)
mneuwert Dec 3, 2019
c51f628
[fix/open-in-on-ipad] Share sheet not visible on iPad (#570)
hosy Dec 4, 2019
696aba0
Changed implementation for ReleaseNotes controller
hosy Dec 6, 2019
0508fa2
- moved release notes to new folder
hosy Dec 8, 2019
67081ab
Added task to update In-App changelog
hosy Dec 8, 2019
4e7b627
No longer needed, because code was moved
hosy Dec 8, 2019
3babefa
No longer needed, decided for other solution
hosy Dec 8, 2019
f842fb7
Merge branch 'milestone/1.2' into feature/whats-new-screen
hosy Dec 8, 2019
b3965f7
Merge branch 'feature/whats-new-screen' of github.com:owncloud/ios-ap…
hosy Dec 8, 2019
8d29fa6
code review fixes
hosy Dec 9, 2019
4a32767
fixed typo
hosy Dec 9, 2019
11a0bc0
Keyboard commands are available below iOS 13
hosy Dec 10, 2019
3de4e73
- no longer showing release notes after app install
hosy Jan 9, 2020
db724f5
Merge branch 'milestone/1.3' into feature/whats-new-screen
hosy Jan 13, 2020
190aa08
set correct short app version
hosy Jan 20, 2020
eff4f92
new check, if app was previously installed, with a key already exists…
hosy Jan 20, 2020
18e8408
- removed unneeded code
hosy Jan 20, 2020
6ee498d
if clause is needed, otherwise next else statement would be always true
hosy Jan 20, 2020
6af51be
changed fallback check, because .isBetaBuild always exists
hosy Jan 21, 2020
295e146
added support for customize app name
hosy Jan 21, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/release_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Release a new version
- [ ] [DEV] Update `APP_SHORT_VERSION` `[major].[minor].[patch]` in [ownCloud.xcodeproj/project.pbxproj](https://github.com/owncloud/ios-app/blob/master/ownCloud.xcodeproj/project.pbxproj)
- [ ] [TRFX] Update translations from transifex branch.
- [ ] [DIS] Update [changelog](https://github.com/owncloud/ios-app/blob/master/CHANGELOG.md)
- [ ] [DEV] Update In-App Release Notes (changelog) in ownCloud/Release Notes/ReleaseNotes.plist
- [ ] [QA] Design Test plan
- [ ] [QA] Regression Test plan
- [ ] [DOC] Update user manual with the new functionalities
Expand All @@ -21,7 +22,7 @@ Release a new version

If it is required to update the iOS-SDK version:

- [ ] [GIT] Create branch library `release/[major].[minor].[patch]`(freeze the code)
- [ ] [GIT] Create branch library `release/[major].[minor].[patch]`(freeze the code)
- [ ] [mail] inform #marketing about the new release.
- [ ] [DIS] Update README.md (version number, third party, supported versions of iOS, Xcode)
- [ ] [DIS] Update [changelog](https://github.com/owncloud/ios-sdk/blob/master/CHANGELOG.md)
Expand Down
64 changes: 38 additions & 26 deletions ownCloud.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions ownCloud/Client/Viewer/Media/MediaDisplayViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ class MediaDisplayViewController : DisplayViewController {
}

// Add handler for skip forward command
commandCenter.skipForwardCommand.isEnabled = true
commandCenter.skipForwardCommand.addTarget { [weak self] (_) -> MPRemoteCommandHandlerStatus in
if let player = self?.player {
let time = player.currentTime() + CMTime(seconds: 10.0, preferredTimescale: 1)
Expand All @@ -239,6 +240,7 @@ class MediaDisplayViewController : DisplayViewController {
}

// Add handler for skip backward command
commandCenter.skipBackwardCommand.isEnabled = true
commandCenter.skipBackwardCommand.addTarget { [weak self] (_) -> MPRemoteCommandHandlerStatus in
if let player = self?.player {
let time = player.currentTime() - CMTime(seconds: 10.0, preferredTimescale: 1)
Expand Down Expand Up @@ -314,6 +316,7 @@ class MediaDisplayViewController : DisplayViewController {

nowPlayingInfo[MPMediaItemPropertyTitle] = mediaItemTitle
nowPlayingInfo[MPMediaItemPropertyArtist] = mediaItemArtist
nowPlayingInfo[MPNowPlayingInfoPropertyCurrentPlaybackDate] = self.playerItem?.currentDate()
nowPlayingInfo[MPNowPlayingInfoPropertyAssetURL] = source
nowPlayingInfo[MPNowPlayingInfoPropertyCurrentPlaybackDate] = playerItem.currentDate()
nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = playerItem.currentTime().seconds
Expand Down
133 changes: 133 additions & 0 deletions ownCloud/Release Notes/ReleaseNotes.plist

Large diffs are not rendered by default.

227 changes: 227 additions & 0 deletions ownCloud/Release Notes/ReleaseNotesHostViewController.swift
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
Copy link
Contributor

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

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") {
Copy link
Contributor

Choose a reason for hiding this comment

The 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...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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
}
}
53 changes: 53 additions & 0 deletions ownCloud/Release Notes/ReleaseNotesTableViewController.swift
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)
}
}

}
5 changes: 5 additions & 0 deletions ownCloud/Resources/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,11 @@
"Save File" = "Save File";
"Choose an account and folder to import the file into.\n\nOnly one file can be imported at once." = "Choose an account and folder to import the file into.\n\nOnly one file can be imported at once.";

/* Release Notes */
"Proceed" = "Proceed";
"New in ownCloud" = "New in ownCloud";
"Thank you for using %@.\nIf you like our App, please leave an AppStore review.\n❤️" = "Thank you for using %@.\nIf you like our App, please leave an AppStore review.\n❤️";

/* Key Commands */
"Select Next" = "Select Next";
"Select Previous" = "Select Previous";
Expand Down
8 changes: 8 additions & 0 deletions ownCloud/Server List/ServerListTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ class ServerListTableViewController: UITableViewController, Themeable {
self.navigationItem.title = OCAppIdentity.shared.appName

NotificationCenter.default.addObserver(self, selector: #selector(considerAutoLogin), name: UIApplication.didBecomeActiveNotification, object: nil)

if ReleaseNotesDatasource().shouldShowReleaseNotes {
let releaseNotesHostController = ReleaseNotesHostViewController()
releaseNotesHostController.modalPresentationStyle = .formSheet
self.present(releaseNotesHostController, animated: true, completion: nil)
}

ReleaseNotesDatasource.setUserPreferenceValue(NSString(utf8String: VendorServices.shared.appVersion), forClassSettingsKey: .lastSeenAppVersion)
}

override func viewWillAppear(_ animated: Bool) {
Expand Down
2 changes: 1 addition & 1 deletion ownCloud/Theming/UI/ThemeButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class ThemeButton : UIButton {
}

private func styleButton() {
self.layer.cornerRadius = 5
self.layer.cornerRadius = 8
self.titleLabel?.font = UIFont.preferredFont(forTextStyle: .headline)
self.titleLabel?.adjustsFontForContentSizeCategory = true
}
Expand Down