Skip to content

Commit

Permalink
Terms of service (#3234)
Browse files Browse the repository at this point in the history
Signed-off-by: Marino Faggiana <[email protected]>
  • Loading branch information
marinofaggiana authored Dec 11, 2024
1 parent 2f69aef commit a2767a2
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 6 deletions.
2 changes: 1 addition & 1 deletion Brand/NCBrand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ let userAgent: String = {
var textCopyrightNextcloudiOS: String = "Nextcloud Hydrogen for iOS %@ © 2024"
var textCopyrightNextcloudServer: String = "Nextcloud Server %@"
var loginBaseUrl: String = "https://cloud.nextcloud.com"
@objc var pushNotificationServerProxy: String = "https://push-notifications.nextcloud.com"
var pushNotificationServerProxy: String = "https://push-notifications.nextcloud.com"
var linkLoginHost: String = "https://nextcloud.com/install"
var linkloginPreferredProviders: String = "https://nextcloud.com/signup-ios"
var webLoginAutenticationProtocol: String = "nc://" // example "abc://"
Expand Down
20 changes: 18 additions & 2 deletions Nextcloud.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@
F711A4EB2AF9327D00095DD8 /* UIImage+animatedGIF.m in Sources */ = {isa = PBXBuildFile; fileRef = F713FEFF2472764100214AF6 /* UIImage+animatedGIF.m */; };
F711A4EF2AF932B900095DD8 /* SVGKitSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F711A4EE2AF932B900095DD8 /* SVGKitSwift */; };
F711D63128F44801003F43C8 /* IntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C9739428F17131002C43E2 /* IntentHandler.swift */; };
F7132C722D085AD200B42D6A /* NCTermOfServiceModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7132C6B2D085AD200B42D6A /* NCTermOfServiceModel.swift */; };
F7132C732D085AD200B42D6A /* NCTermOfServiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7132C6C2D085AD200B42D6A /* NCTermOfServiceView.swift */; };
F713FBE52C31645200F10760 /* NCNetworking+AsyncAwait.swift in Sources */ = {isa = PBXBuildFile; fileRef = F713FBE42C31645200F10760 /* NCNetworking+AsyncAwait.swift */; };
F713FBE62C31646400F10760 /* NCNetworking+AsyncAwait.swift in Sources */ = {isa = PBXBuildFile; fileRef = F713FBE42C31645200F10760 /* NCNetworking+AsyncAwait.swift */; };
F713FBE72C31646500F10760 /* NCNetworking+AsyncAwait.swift in Sources */ = {isa = PBXBuildFile; fileRef = F713FBE42C31645200F10760 /* NCNetworking+AsyncAwait.swift */; };
Expand Down Expand Up @@ -1258,6 +1260,8 @@
F710D1F42405770F00A6033D /* NCViewerPDF.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCViewerPDF.swift; sourceTree = "<group>"; };
F710D2012405826100A6033D /* NCViewer+Menu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCViewer+Menu.swift"; sourceTree = "<group>"; };
F711A4DB2AF92CAD00095DD8 /* NCUtility+Date.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCUtility+Date.swift"; sourceTree = "<group>"; };
F7132C6B2D085AD200B42D6A /* NCTermOfServiceModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCTermOfServiceModel.swift; sourceTree = "<group>"; };
F7132C6C2D085AD200B42D6A /* NCTermOfServiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCTermOfServiceView.swift; sourceTree = "<group>"; };
F713FBE42C31645200F10760 /* NCNetworking+AsyncAwait.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCNetworking+AsyncAwait.swift"; sourceTree = "<group>"; };
F713FEFE2472764000214AF6 /* UIImage+animatedGIF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+animatedGIF.h"; sourceTree = "<group>"; };
F713FEFF2472764100214AF6 /* UIImage+animatedGIF.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+animatedGIF.m"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2095,6 +2099,15 @@
path = Color;
sourceTree = "<group>";
};
F7132C6D2D085AD200B42D6A /* Terms of service */ = {
isa = PBXGroup;
children = (
F7132C6B2D085AD200B42D6A /* NCTermOfServiceModel.swift */,
F7132C6C2D085AD200B42D6A /* NCTermOfServiceView.swift */,
);
path = "Terms of service";
sourceTree = "<group>";
};
F713418B2597513800768D21 /* PushNotification */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -3091,6 +3104,7 @@
F79A65C12191D8DC00FF6DCC /* Select */,
F728CE741BF6322C00E69702 /* Share */,
F7169A161EE590930086BD69 /* Shares */,
F7132C6D2D085AD200B42D6A /* Terms of service */,
F7E9C41320F4CA870040CF18 /* Transfers */,
F78F74322163753B00C2ADAD /* Trash */,
F7EFC0CB256BF89300461AAD /* UserStatus */,
Expand Down Expand Up @@ -4367,6 +4381,8 @@
F7CBC1252BAC8B0000EC1D55 /* NCSectionFirstHeaderEmptyData.swift in Sources */,
F7D4BF3D2CA2E8D800A5E746 /* TOPasscodeKeypadView.m in Sources */,
F7D4BF3E2CA2E8D800A5E746 /* TOPasscodeSettingsKeypadView.m in Sources */,
F7132C722D085AD200B42D6A /* NCTermOfServiceModel.swift in Sources */,
F7132C732D085AD200B42D6A /* NCTermOfServiceView.swift in Sources */,
F7D4BF3F2CA2E8D800A5E746 /* TOPasscodeFixedInputView.m in Sources */,
F7D4BF402CA2E8D800A5E746 /* TOPasscodeButtonLabel.m in Sources */,
F7D4BF412CA2E8D800A5E746 /* TOPasscodeViewControllerAnimatedTransitioning.m in Sources */,
Expand Down Expand Up @@ -5487,7 +5503,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 2;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = NKUJUXUJ3B;
ENABLE_STRICT_OBJC_MSGSEND = YES;
Expand Down Expand Up @@ -5553,7 +5569,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = NKUJUXUJ3B;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
Expand Down
9 changes: 6 additions & 3 deletions iOSClient/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -279,14 +279,17 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
}

func nextcloudPushNotificationAction(data: [String: AnyObject]) {
guard let data = NCApplicationHandle().nextcloudPushNotificationAction(data: data),
let account = data["account"] as? String
guard let data = NCApplicationHandle().nextcloudPushNotificationAction(data: data)
else {
return
}
let account = data["account"] as? String ?? "unavailable"
let app = data["app"] as? String

func openNotification(controller: NCMainTabBarController) {
if let viewController = UIStoryboard(name: "NCNotification", bundle: nil).instantiateInitialViewController() as? NCNotification {
if app == NCGlobal.shared.termsOfServiceName {
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterGetServerData, second: 0.5)
} else if let viewController = UIStoryboard(name: "NCNotification", bundle: nil).instantiateInitialViewController() as? NCNotification {
viewController.session = NCSession.shared.getSession(account: account)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
let navigationController = UINavigationController(rootViewController: viewController)
Expand Down
14 changes: 14 additions & 0 deletions iOSClient/Files/NCFiles.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import UIKit
import NextcloudKit
import RealmSwift
import SwiftUI

class NCFiles: NCCollectionViewCommon {
internal var isRoot: Bool = true
Expand Down Expand Up @@ -192,6 +193,19 @@ class NCFiles: NCCollectionViewCommon {
NCNetworking.shared.downloadQueue.addOperation(NCOperationDownload(metadata: metadata, selector: NCGlobal.shared.selectorDownloadFile))
}
}
} else if error.errorCode == self.global.errorForbidden {
DispatchQueue.main.async {
if self.presentedViewController == nil {
NextcloudKit.shared.getTermsOfService(account: self.session.account) { _, tos, _, error in
if error == .success, let tos {
let termOfServiceModel = NCTermOfServiceModel(controller: self.controller, tos: tos)
let termOfServiceView = NCTermOfServiceModelView(model: termOfServiceModel)
let termOfServiceController = UIHostingController(rootView: termOfServiceView)
self.present(termOfServiceController, animated: true, completion: nil)
}
}
}
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions iOSClient/NCGlobal.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class NCGlobal: NSObject {
let talkName = "talk-message"
let spreedName = "spreed"
let twoFactorNotificatioName = "twofactor_nextcloud_notification"
let termsOfServiceName = "terms_of_service"

// Nextcloud version
//
Expand Down
3 changes: 3 additions & 0 deletions iOSClient/Supporting Files/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,9 @@
"_offline_not_allowed_" = "This operation is not allowed in offline mode";
"_Upload_native_format_yes_"= "Upload in native format: yes";
"_Upload_native_format_no_" = "Upload in native format: no";
"_terms_of_service_" = "Terms of service";
"_terms_accept_" = "I acknowledge that I have read and agree to the above terms of service";
"_terms_accepted_" = "Terms accepted";

// Tip
"_tip_pdf_thumbnails_" = "Swipe left from the right edge of the screen to show the thumbnails.";
Expand Down
70 changes: 70 additions & 0 deletions iOSClient/Terms of service/NCTermOfServiceModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// SPDX-FileCopyrightText: Nextcloud GmbH
// SPDX-FileCopyrightText: 2024 Marino Faggiana
// SPDX-License-Identifier: GPL-3.0-or-later

import Foundation
import NextcloudKit

/// A model that allows the user to configure the account
class NCTermOfServiceModel: ObservableObject {
/// Root View Controller
var controller: NCMainTabBarController?
/// Set true for dismiss the view
@Published var dismissView = false
// Data
@Published var languages: [String: String] = [:]
@Published var terms: [String: String] = [:]
@Published var termsId: [String: Int] = [:]
@Published var hasUserSigned: Bool = false

/// Initialization code
init(controller: NCMainTabBarController?, tos: NKTermsOfService?) {
self.controller = controller

if let terms = tos?.getTerms() {
for term in terms {
self.terms[term.languageCode] = term.body
self.termsId[term.languageCode] = term.id
}
} else {
languages = ["en": "English", "de": "Deutsch", "it": "Italiano"]
}

if let languages = tos?.getLanguages() {
for language in languages {
if self.terms[language.key] != nil {
self.languages[language.key] = language.value
}
}
} else {
terms = [
"en": "These are the Terms of Service.",
"de": "Dies sind die Allgemeinen Geschäftsbedingungen.",
"it": "Questi sono i Termini di servizio."
]
}

if let hasUserSigned = tos?.hasUserSigned() {
self.hasUserSigned = hasUserSigned
}
}

func signTermsOfService(termId: Int?) {
guard let termId,
let controller
else {
return
}

NextcloudKit.shared.signTermsOfService(termId: "\(termId)", account: controller.account) { _, _, error in
if error == .success {
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterGetServerData)
self.dismissView = true
} else {
NCContentPresenter().showError(error: error)
}
}
}

deinit { }
}
79 changes: 79 additions & 0 deletions iOSClient/Terms of service/NCTermOfServiceView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// SPDX-FileCopyrightText: Nextcloud GmbH
// SPDX-FileCopyrightText: 2024 Marino Faggiana
// SPDX-License-Identifier: GPL-3.0-or-later

import SwiftUI

struct NCTermOfServiceModelView: View {
@State private var selectedLanguage = Locale.preferredLanguages.first?.components(separatedBy: "-").first ?? "en"
@State private var termsText = "Loading terms..."
@ObservedObject var model: NCTermOfServiceModel

@Environment(\.presentationMode) var presentationMode

var body: some View {
VStack {
HStack {
Text(NSLocalizedString("_terms_of_service_", comment: "Terms of Service"))
.font(.headline)
.frame(maxWidth: .infinity, alignment: .leading)

Picker("Select Language", selection: $selectedLanguage) {
ForEach(model.languages.keys.sorted(), id: \.self) { key in
Text(model.languages[key] ?? "").tag(key)
}
}
.pickerStyle(MenuPickerStyle())
.frame(maxWidth: .infinity, alignment: .trailing)
.onChange(of: selectedLanguage) { newLanguage in
if let terms = model.terms[newLanguage] {
termsText = terms
} else {
selectedLanguage = model.languages.first?.key ?? "en"
termsText = model.terms[selectedLanguage] ?? "Terms not available in selected language."
}
}
}
.padding(.horizontal)

ScrollView {
Text(termsText)
.font(.body)
.foregroundColor(.primary)
.frame(maxWidth: .infinity)
.padding(.horizontal)
}
.padding(.top)

Button(action: {
model.signTermsOfService(termId: model.termsId[selectedLanguage])
}) {
Text(model.hasUserSigned ? NSLocalizedString("_terms_accepted_", comment: "Accepted terms") : NSLocalizedString("_terms_accept_", comment: "Accept terms"))
.foregroundColor(.white)
.padding()
.background(model.hasUserSigned ? Color.green : Color.blue)
.cornerRadius(10)
.padding(.bottom)
}
.disabled(model.hasUserSigned)
}
.padding()
.onAppear {
if let item = model.terms[selectedLanguage] {
termsText = item
} else {
selectedLanguage = model.languages.first?.key ?? "en"
termsText = model.terms[selectedLanguage] ?? "Terms not available in selected language."
}
}
.onReceive(model.$dismissView) { newValue in
if newValue {
presentationMode.wrappedValue.dismiss()
}
}
}
}

#Preview {
NCTermOfServiceModelView(model: NCTermOfServiceModel(controller: nil, tos: nil))
}

0 comments on commit a2767a2

Please sign in to comment.