Added cellular data permission warning

Fixed people nearby initial opening
Fixed 3rd apps opening from group's location view screen
This commit is contained in:
Ilya Laktyushin 2019-06-25 23:58:11 +02:00
parent dfd1808d04
commit 3227b51ff8
13 changed files with 99 additions and 54 deletions

View File

@ -179,11 +179,11 @@ public final class DeviceAccess {
func statusForCellularState(_ state: CTCellularDataRestrictedState) -> AccessType? {
switch state {
case .restricted:
return .denied
return .allowed
case .notRestricted:
return .allowed
default:
return nil
return .allowed
}
}
let cellState = CTCellularData.init()
@ -196,7 +196,7 @@ public final class DeviceAccess {
}
}
} else {
subscriber.putNext(.notDetermined)
subscriber.putNext(.allowed)
subscriber.putCompletion()
}
return EmptyDisposable
@ -446,8 +446,12 @@ public final class DeviceAccess {
completion(result)
}
}
default:
break
case .cellularData:
if let presentationData = presentationData {
present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: presentationData.strings.Permissions_CellularDataTitle_v0, text: presentationData.strings.Permissions_CellularDataText_v0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_NotNow, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.AccessDenied_Settings, action: {
openSettings()
})]), nil)
}
}
}
}

View File

@ -590,6 +590,9 @@ final class SharedApplicationContext {
}, requestSetAlternateIconName: { name, completion in
if #available(iOS 10.3, *) {
application.setAlternateIconName(name, completionHandler: { error in
if let error = error {
Logger.shared.log("App \(self.episodeId)", "failed to set alternate icon with error \(error.localizedDescription)")
}
completion(error == nil)
})
} else {

View File

@ -148,14 +148,7 @@ final class AuthorizedApplicationContext {
context.keyShortcutsController = keyShortcutsController
}
/*self.applicationInForegroundDisposable = context.sharedContext.applicationBindings.applicationInForeground.start(next: { [weak self] value in
Queue.mainQueue().async {
self?.notificationManager.isApplicationInForeground = value
}
})*/
let previousPasscodeState = Atomic<PasscodeState?>(value: nil)
let passcodeStatusData = combineLatest(queue: Queue.mainQueue(), context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationPasscodeSettings]), context.sharedContext.accountManager.accessChallengeData(), context.sharedContext.applicationBindings.applicationIsActive)
let passcodeState = passcodeStatusData
|> map { sharedData, accessChallengeDataView, isActive -> PasscodeState in
@ -281,7 +274,7 @@ final class AuthorizedApplicationContext {
if #available(iOS 10.0, *) {
} else {
DeviceAccess.authorizeAccess(to: .contacts, presentationData: strongSelf.context.sharedContext.currentPresentationData.with { $0 }, present: { c, a in
}, openSettings: {}, { _ in })
})
}
if let passcodeController = strongSelf.passcodeController {
@ -520,23 +513,27 @@ final class AuthorizedApplicationContext {
if #available(iOS 10.0, *) {
let permissionsPosition = ValuePromise(0, ignoreRepeated: true)
self.permissionsDisposable.set((combineLatest(queue: .mainQueue(), requiredPermissions(context: context), permissionUISplitTest(postbox: context.account.postbox), permissionsPosition.get(), context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.contactsPermissionWarningKey()), context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.notificationsPermissionWarningKey()))
|> deliverOnMainQueue).start(next: { [weak self] required, splitTest, position, contactsPermissionWarningNotice, notificationsPermissionWarningNotice in
self.permissionsDisposable.set((combineLatest(queue: .mainQueue(), requiredPermissions(context: context), permissionUISplitTest(postbox: context.account.postbox), permissionsPosition.get(), context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.permissionWarningKey(permission: .contacts)!), context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.permissionWarningKey(permission: .notifications)!), context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.permissionWarningKey(permission: .cellularData)!))
|> deliverOnMainQueue).start(next: { [weak self] required, splitTest, position, contactsPermissionWarningNotice, notificationsPermissionWarningNotice, cellularDataPermissionWarningNotice in
guard let strongSelf = self else {
return
}
let contactsTimestamp = contactsPermissionWarningNotice.value.flatMap({ ApplicationSpecificNotice.getTimestampValue($0) })
let notificationsTimestamp = notificationsPermissionWarningNotice.value.flatMap({ ApplicationSpecificNotice.getTimestampValue($0) })
let cellularDataTimestamp = cellularDataPermissionWarningNotice.value.flatMap({ ApplicationSpecificNotice.getTimestampValue($0) })
if contactsTimestamp == nil, case .requestable = required.0.status {
ApplicationSpecificNotice.setContactsPermissionWarning(accountManager: context.sharedContext.accountManager, value: 1)
ApplicationSpecificNotice.setPermissionWarning(accountManager: context.sharedContext.accountManager, permission: .contacts, value: 1)
}
if notificationsTimestamp == nil, case .requestable = required.1.status {
ApplicationSpecificNotice.setNotificationsPermissionWarning(accountManager: context.sharedContext.accountManager, value: 1)
ApplicationSpecificNotice.setPermissionWarning(accountManager: context.sharedContext.accountManager, permission: .notifications, value: 1)
}
let config = splitTest.configuration
var order = config.order
if !order.contains(.cellularData) {
order.append(.cellularData)
}
if !order.contains(.siri) {
order.append(.siri)
}
@ -563,9 +560,13 @@ final class AuthorizedApplicationContext {
if case .requestable = required.1.status, notificationsTimestamp != 0 {
requestedPermissions.append((required.1, modal))
}
case .cellularData:
if case .denied = required.2.status, cellularDataTimestamp != 0 {
requestedPermissions.append((required.2, true))
}
case .siri:
if case .requestable = required.2.status {
requestedPermissions.append((required.2, false))
if case .requestable = required.3.status {
requestedPermissions.append((required.3, false))
}
default:
break
@ -590,9 +591,11 @@ final class AuthorizedApplicationContext {
permissionsPosition.set(position + 1)
switch state {
case .contacts:
ApplicationSpecificNotice.setContactsPermissionWarning(accountManager: context.sharedContext.accountManager, value: 0)
ApplicationSpecificNotice.setPermissionWarning(accountManager: context.sharedContext.accountManager, permission: .contacts, value: 0)
case .notifications:
ApplicationSpecificNotice.setNotificationsPermissionWarning(accountManager: context.sharedContext.accountManager, value: 0)
ApplicationSpecificNotice.setPermissionWarning(accountManager: context.sharedContext.accountManager, permission: .notifications, value: 0)
case .cellularData:
ApplicationSpecificNotice.setPermissionWarning(accountManager: context.sharedContext.accountManager, permission: .cellularData, value: 0)
default:
break
}
@ -616,7 +619,7 @@ final class AuthorizedApplicationContext {
splitTest.addEvent(.ContactsDenied)
}
permissionsPosition.set(position + 1)
ApplicationSpecificNotice.setContactsPermissionWarning(accountManager: context.sharedContext.accountManager, value: 0)
ApplicationSpecificNotice.setPermissionWarning(accountManager: context.sharedContext.accountManager, permission: .contacts, value: 0)
}
case .notifications:
splitTest.addEvent(.NotificationsRequest)
@ -629,8 +632,19 @@ final class AuthorizedApplicationContext {
splitTest.addEvent(.NotificationsDenied)
}
permissionsPosition.set(position + 1)
ApplicationSpecificNotice.setNotificationsPermissionWarning(accountManager: context.sharedContext.accountManager, value: 0)
ApplicationSpecificNotice.setPermissionWarning(accountManager: context.sharedContext.accountManager, permission: .notifications, value: 0)
}
case .cellularData:
DeviceAccess.authorizeAccess(to: .cellularData, presentationData: context.sharedContext.currentPresentationData.with { $0 }, present: { [weak self] c, a in
if let strongSelf = self {
(strongSelf.rootController.viewControllers.last as? ViewController)?.present(c, in: .window(.root))
}
}, openSettings: {
context.sharedContext.applicationBindings.openSettings()
}, { result in
permissionsPosition.set(position + 1)
ApplicationSpecificNotice.setPermissionWarning(accountManager: context.sharedContext.accountManager, permission: .cellularData, value: 0)
})
case .siri:
DeviceAccess.authorizeAccess(to: .siri, requestSiriAuthorization: { completion in
return context.sharedContext.applicationBindings.requestSiriAuthorization(completion)

View File

@ -849,7 +849,7 @@ final class ContactListNode: ASDisplayNode {
let contactsWarningSuppressed = Promise<(Bool, Bool)>()
contactsWarningSuppressed.set(.single((false, false))
|> then(
combineLatest(context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.contactsPermissionWarningKey()), context.account.postbox.preferencesView(keys: [PreferencesKeys.contactsSettings]))
combineLatest(context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.permissionWarningKey(permission: .contacts)!), context.account.postbox.preferencesView(keys: [PreferencesKeys.contactsSettings]))
|> map { noticeView, preferences -> (Bool, Bool) in
let settings: ContactsSettings = preferences.values[PreferencesKeys.contactsSettings] as? ContactsSettings ?? ContactsSettings.defaultSettings
let synchronizeDeviceContacts: Bool = settings.synchronizeContacts

View File

@ -132,7 +132,7 @@ public class ContactsController: ViewController {
})
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
self.authorizationDisposable = (combineLatest(DeviceAccess.authorizationStatus(subject: .contacts), combineLatest(context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.contactsPermissionWarningKey()), context.account.postbox.preferencesView(keys: [PreferencesKeys.contactsSettings]), context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.contactSynchronizationSettings]))
self.authorizationDisposable = (combineLatest(DeviceAccess.authorizationStatus(subject: .contacts), combineLatest(context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.permissionWarningKey(permission: .contacts)!), context.account.postbox.preferencesView(keys: [PreferencesKeys.contactsSettings]), context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.contactSynchronizationSettings]))
|> map { noticeView, preferences, sharedData -> (Bool, ContactsSortOrder) in
let settings: ContactsSettings = preferences.values[PreferencesKeys.contactsSettings] as? ContactsSettings ?? ContactsSettings.defaultSettings
let synchronizeDeviceContacts: Bool = settings.synchronizeContacts

View File

@ -2001,7 +2001,9 @@ public func groupInfoController(context: AccountContext, peerId originalPeerId:
return
}
let mapMedia = TelegramMediaMap(latitude: location.latitude, longitude: location.longitude, geoPlace: nil, venue: MapVenue(title: peer.displayTitle, address: location.address, provider: nil, id: nil, type: nil), liveBroadcastingTimeout: nil)
let controller = legacyLocationController(message: nil, mapMedia: mapMedia, context: context, isModal: false, openPeer: { _ in }, sendLiveLocation: { _, _ in }, stopLiveLocation: {}, openUrl: { _ in })
let controller = legacyLocationController(message: nil, mapMedia: mapMedia, context: context, isModal: false, openPeer: { _ in }, sendLiveLocation: { _, _ in }, stopLiveLocation: {}, openUrl: { url in
context.sharedContext.applicationBindings.openUrl(url)
})
pushControllerImpl?(controller)
})
}, changeLocation: {

View File

@ -129,6 +129,7 @@ private enum ApplicationSpecificGlobalNotice: Int32 {
case archiveChatTips = 10
case archiveIntroDismissed = 11
case callsTabTip = 12
case cellularDataPermissionWarning = 13
var key: ValueBoxKey {
let v = ValueBoxKey(length: 4)
@ -137,6 +138,21 @@ private enum ApplicationSpecificGlobalNotice: Int32 {
}
}
private extension PermissionKind {
var noticeKey: NoticeEntryKey? {
switch self {
case .contacts:
return ApplicationSpecificNoticeKeys.contactsPermissionWarning()
case .notifications:
return ApplicationSpecificNoticeKeys.notificationsPermissionWarning()
case .cellularData:
return ApplicationSpecificNoticeKeys.cellularDataPermissionWarning()
default:
return nil
}
}
}
private struct ApplicationSpecificNoticeKeys {
private static let botPaymentLiabilityNamespace: Int32 = 1
private static let globalNamespace: Int32 = 2
@ -195,6 +211,10 @@ private struct ApplicationSpecificNoticeKeys {
return NoticeEntryKey(namespace: noticeNamespace(namespace: permissionsNamespace), key: ApplicationSpecificGlobalNotice.notificationsPermissionWarning.key)
}
static func cellularDataPermissionWarning() -> NoticeEntryKey {
return NoticeEntryKey(namespace: noticeNamespace(namespace: permissionsNamespace), key: ApplicationSpecificGlobalNotice.cellularDataPermissionWarning.key)
}
static func volumeButtonToUnmuteTip() -> NoticeEntryKey {
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.volumeButtonToUnmuteTip.key)
}
@ -408,20 +428,19 @@ public struct ApplicationSpecificNotice {
}
}
public static func contactsPermissionWarningKey() -> NoticeEntryKey {
return ApplicationSpecificNoticeKeys.contactsPermissionWarning()
public static func permissionWarningKey(permission: PermissionKind) -> NoticeEntryKey? {
return permission.noticeKey
}
public static func setContactsPermissionWarning(accountManager: AccountManager, value: Int32) {
public static func setPermissionWarning(accountManager: AccountManager, permission: PermissionKind, value: Int32) {
guard let noticeKey = permission.noticeKey else {
return
}
let _ = accountManager.transaction { transaction -> Void in
transaction.setNotice(ApplicationSpecificNoticeKeys.contactsPermissionWarning(), ApplicationSpecificTimestampNotice(value: value))
transaction.setNotice(noticeKey, ApplicationSpecificTimestampNotice(value: value))
}.start()
}
public static func notificationsPermissionWarningKey() -> NoticeEntryKey {
return ApplicationSpecificNoticeKeys.notificationsPermissionWarning()
}
public static func getTimestampValue(_ entry: NoticeEntry) -> Int32? {
if let value = entry as? ApplicationSpecificTimestampNotice {
return value.value
@ -430,12 +449,6 @@ public struct ApplicationSpecificNotice {
}
}
public static func setNotificationsPermissionWarning(accountManager: AccountManager, value: Int32) {
let _ = accountManager.transaction { transaction -> Void in
transaction.setNotice(ApplicationSpecificNoticeKeys.notificationsPermissionWarning(), ApplicationSpecificTimestampNotice(value: value))
}.start()
}
static func getVolumeButtonToUnmute(accountManager: AccountManager) -> Signal<Bool, NoError> {
return accountManager.transaction { transaction -> Bool in
if let _ = transaction.getNotice(ApplicationSpecificNoticeKeys.volumeButtonToUnmuteTip()) as? ApplicationSpecificBoolNotice {

View File

@ -836,7 +836,7 @@ public func notificationsAndSoundsController(context: AccountContext, exceptions
case .denied, .restricted:
context.sharedContext.applicationBindings.openSettings()
case .unreachable:
ApplicationSpecificNotice.setNotificationsPermissionWarning(accountManager: context.sharedContext.accountManager, value: Int32(Date().timeIntervalSince1970))
ApplicationSpecificNotice.setPermissionWarning(accountManager: context.sharedContext.accountManager, permission: .notifications, value: Int32(Date().timeIntervalSince1970))
context.sharedContext.applicationBindings.openSettings()
default:
break
@ -845,7 +845,7 @@ public func notificationsAndSoundsController(context: AccountContext, exceptions
}, suppressWarning: {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
presentControllerImpl?(textAlertController(context: context, title: presentationData.strings.Notifications_PermissionsSuppressWarningTitle, text: presentationData.strings.Notifications_PermissionsSuppressWarningText, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Notifications_PermissionsKeepDisabled, action: {
ApplicationSpecificNotice.setNotificationsPermissionWarning(accountManager: context.sharedContext.accountManager, value: Int32(Date().timeIntervalSince1970))
ApplicationSpecificNotice.setPermissionWarning(accountManager: context.sharedContext.accountManager, permission: .notifications, value: Int32(Date().timeIntervalSince1970))
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Notifications_PermissionsEnable, action: {
context.sharedContext.applicationBindings.openSettings()
})]), nil)
@ -1051,7 +1051,7 @@ public func notificationsAndSoundsController(context: AccountContext, exceptions
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
notificationsWarningSuppressed.set(.single(true)
|> then(
context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.notificationsPermissionWarningKey())
context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.permissionWarningKey(permission: .notifications)!)
|> map { noticeView -> Bool in
let timestamp = noticeView.value.flatMap({ ApplicationSpecificNotice.getTimestampValue($0) })
if let timestamp = timestamp, timestamp > 0 {

View File

@ -5,7 +5,7 @@ import TelegramCore
import MobileCoreServices
private func rtfStringWithAppliedEntities(_ text: String, entities: [MessageTextEntity]) -> String {
let test = stringWithAppliedEntities(text, entities: entities, baseColor: .black, linkColor: .black, baseFont: Font.regular(14.0), linkFont: Font.regular(14.0), boldFont: Font.semibold(14.0), italicFont: Font.italic(14.0), fixedFont: Font.monospace(14.0), underlineLinks: false, external: true)
let test = stringWithAppliedEntities(text, entities: entities, baseColor: .black, linkColor: .black, baseFont: Font.regular(14.0), linkFont: Font.regular(14.0), boldFont: Font.semibold(14.0), italicFont: Font.italic(14.0), boldItalicFont: Font.semiboldItalic(14.0), fixedFont: Font.monospace(14.0), underlineLinks: false, external: true)
if let data = try? test.data(from: NSRange(location: 0, length: test.length), documentAttributes: [NSAttributedString.DocumentAttributeKey.documentType: NSAttributedString.DocumentType.rtf]) {
if var rtf = String(data: data, encoding: .windowsCP1252) {

View File

@ -389,7 +389,7 @@ public func peersNearbyController(context: AccountContext) -> ViewController {
}
}
}
dataPromise.set(dataSignal)
dataPromise.set(.single(nil) |> then(dataSignal))
let previousData = Atomic<PeersNearbyData?>(value: nil)
let displayLoading: Signal<Bool, NoError> = .single(false)

View File

@ -36,7 +36,7 @@ public enum PermissionState: Equatable {
case contacts(status: PermissionRequestStatus)
case notifications(status: PermissionRequestStatus)
case siri(status: PermissionRequestStatus)
case cellularData
case cellularData(status: PermissionRequestStatus)
case nearbyLocation(status: PermissionRequestStatus)
var kind: PermissionKind {
@ -62,19 +62,21 @@ public enum PermissionState: Equatable {
return status
case let .siri(status):
return status
case .cellularData:
return .unreachable
case let .cellularData(status):
return status
case let .nearbyLocation(status):
return status
}
}
}
public func requiredPermissions(context: AccountContext) -> Signal<(PermissionState, PermissionState, PermissionState), NoError> {
public func requiredPermissions(context: AccountContext) -> Signal<(contacts: PermissionState, notifications: PermissionState, cellularData: PermissionState, siri: PermissionState), NoError> {
return combineLatest(DeviceAccess.authorizationStatus(subject: .contacts), DeviceAccess.authorizationStatus(applicationInForeground: context.sharedContext.applicationBindings.applicationInForeground, subject: .notifications), DeviceAccess.authorizationStatus(siriAuthorization: {
return context.sharedContext.applicationBindings.siriAuthorization()
}, subject: .cellularData), DeviceAccess.authorizationStatus(siriAuthorization: {
return context.sharedContext.applicationBindings.siriAuthorization()
}, subject: .siri))
|> map { contactsStatus, notificationsStatus, siriStatus in
return (.contacts(status: PermissionRequestStatus(accessType: contactsStatus)), .notifications(status: PermissionRequestStatus(accessType: notificationsStatus)), .siri(status: PermissionRequestStatus(accessType: siriStatus)))
|> map { contactsStatus, notificationsStatus, cellularDataStatus, siriStatus in
return (.contacts(status: PermissionRequestStatus(accessType: contactsStatus)), .notifications(status: PermissionRequestStatus(accessType: notificationsStatus)), .cellularData(status: PermissionRequestStatus(accessType: cellularDataStatus)), .siri(status: PermissionRequestStatus(accessType: siriStatus)))
}
}

View File

@ -108,6 +108,11 @@ public final class PermissionController : ViewController {
self.state = state
if case let .permission(permission) = state, let state = permission {
if case .nearbyLocation = state {
} else {
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Permissions_Skip, style: .plain, target: self, action: #selector(PermissionController.nextPressed))
}
switch state {
case let .contacts(status):
self.splitTest?.addEvent(.ContactsModalRequest)
@ -170,11 +175,13 @@ public final class PermissionController : ViewController {
}
case .cellularData:
self.allow = { [weak self] in
self?.proceed?(true)
if let strongSelf = self {
strongSelf.openAppSettings()
strongSelf.proceed?(true)
}
}
case let .nearbyLocation(status):
self.title = self.presentationData.strings.Permissions_PeopleNearbyTitle_v0
self.navigationItem.rightBarButtonItem = nil
self.allow = { [weak self] in
if let strongSelf = self {

View File

@ -1052,7 +1052,7 @@ public func settingsController(context: AccountContext, accountManager: AccountM
|> then(
contextValue.get()
|> mapToSignal { context -> Signal<Bool, NoError> in
return context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.notificationsPermissionWarningKey())
return context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.permissionWarningKey(permission: .notifications)!)
|> map { noticeView -> Bool in
let timestamp = noticeView.value.flatMap({ ApplicationSpecificNotice.getTimestampValue($0) })
if let timestamp = timestamp, timestamp > 0 {