Skip to content

Commit

Permalink
Merge branch 'feature/Notifications' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
RealBonus committed Mar 9, 2018
2 parents 1e1e264 + dd8e4b8 commit 84e8a87
Show file tree
Hide file tree
Showing 24 changed files with 865 additions and 325 deletions.
26 changes: 26 additions & 0 deletions Adamant.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@
E9256F7E2039B29D00DE86E9 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = E9256F802039B29D00DE86E9 /* InfoPlist.strings */; };
E93B0D742028B21400126346 /* ChatsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93B0D732028B21400126346 /* ChatsProvider.swift */; };
E93B0D762028B28E00126346 /* AdamantChatsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93B0D752028B28E00126346 /* AdamantChatsProvider.swift */; };
E93D7ABE2052CEE1005D19DC /* NotificationsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93D7ABD2052CEE1005D19DC /* NotificationsService.swift */; };
E93D7AC02052CF63005D19DC /* AdamantNotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93D7ABF2052CF63005D19DC /* AdamantNotificationService.swift */; };
E93D7AC22052EE21005D19DC /* SettingsViewController+StayIn.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93D7AC12052EE21005D19DC /* SettingsViewController+StayIn.swift */; };
E93D7AC520530F76005D19DC /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = E93D7AC720530F76005D19DC /* Localizable.stringsdict */; };
E93EFE13200D1156000BB482 /* ChatViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93EFE12200D1156000BB482 /* ChatViewController.swift */; };
E9452A4C20344834005BA34C /* Account.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E9452A4E20344834005BA34C /* Account.storyboard */; };
E94883E7203F07CD00F6E1B0 /* PassphraseValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = E94883E6203F07CD00F6E1B0 /* PassphraseValidation.swift */; };
Expand Down Expand Up @@ -209,6 +213,11 @@
E9256F7F2039B29D00DE86E9 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/InfoPlist.strings; sourceTree = "<group>"; };
E93B0D732028B21400126346 /* ChatsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatsProvider.swift; sourceTree = "<group>"; };
E93B0D752028B28E00126346 /* AdamantChatsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdamantChatsProvider.swift; sourceTree = "<group>"; };
E93D7ABD2052CEE1005D19DC /* NotificationsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsService.swift; sourceTree = "<group>"; };
E93D7ABF2052CF63005D19DC /* AdamantNotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdamantNotificationService.swift; sourceTree = "<group>"; };
E93D7AC12052EE21005D19DC /* SettingsViewController+StayIn.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SettingsViewController+StayIn.swift"; sourceTree = "<group>"; };
E93D7AC620530F76005D19DC /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ru; path = ru.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
E93D7AC920530F8E005D19DC /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = Base; path = Base.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
E93EFE12200D1156000BB482 /* ChatViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatViewController.swift; sourceTree = "<group>"; };
E9452A4D20344834005BA34C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Account.storyboard; sourceTree = "<group>"; };
E94883E6203F07CD00F6E1B0 /* PassphraseValidation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PassphraseValidation.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -398,6 +407,7 @@
E9E7CDAE2002B8A100DFC4DB /* Router.swift */,
E905D39C204C13B900DDB504 /* SecuredStore.swift */,
E90A494C204DA932009F6A65 /* LocalAuthentication.swift */,
E93D7ABD2052CEE1005D19DC /* NotificationsService.swift */,
);
path = ServiceProtocols;
sourceTree = "<group>";
Expand All @@ -410,6 +420,7 @@
E9E7CD922002740500DFC4DB /* AdamantAccountService.swift */,
E9E7CDBF2003AF6D00DFC4DB /* AdamantCellFactory.swift */,
E9E7CD8E20026CD300DFC4DB /* AdamantDialogService.swift */,
E93D7ABF2052CF63005D19DC /* AdamantNotificationService.swift */,
E913C9161FFFAF76001A83F7 /* JSAdamantCore.swift */,
E9E7CDB42002BA6900DFC4DB /* SwinjectedRouter.swift */,
E950273F202E257E002C1098 /* RepeaterService.swift */,
Expand Down Expand Up @@ -456,6 +467,7 @@
E913C8F81FFFA51D001A83F7 /* Assets.xcassets */,
E9256F802039B29D00DE86E9 /* InfoPlist.strings */,
E9256F7B2039B29A00DE86E9 /* Localizable.strings */,
E93D7AC720530F76005D19DC /* Localizable.stringsdict */,
E9256F752039A9A200DE86E9 /* LaunchScreen.storyboard */,
E9C51EEC2011416E00385EB7 /* adamant-core.js */,
);
Expand Down Expand Up @@ -564,6 +576,7 @@
E948E04D20278D5600975D6B /* SettingsDependencies.swift */,
E948E03A20235E2300975D6B /* SettingsRoutes.swift */,
E982F69B20235B4D00566AC7 /* SettingsViewController.swift */,
E93D7AC12052EE21005D19DC /* SettingsViewController+StayIn.swift */,
E9942B7F203C058C00C163AF /* QRGeneratorViewController.swift */,
);
path = Settings;
Expand Down Expand Up @@ -789,6 +802,7 @@
E9256F632034E7DE00DE86E9 /* Settings.storyboard in Resources */,
E9EC341C200524CA00C0E546 /* Roboto_400_italic.ttf in Resources */,
E9256F792039B29A00DE86E9 /* Localizable.strings in Resources */,
E93D7AC520530F76005D19DC /* Localizable.stringsdict in Resources */,
E9EC3415200524CA00C0E546 /* Exo+2_100_normal.ttf in Resources */,
E9EC341A200524CA00C0E546 /* Exo+2_700_normal.ttf in Resources */,
E9EC341D200524CA00C0E546 /* Roboto_400_normal.ttf in Resources */,
Expand Down Expand Up @@ -903,6 +917,7 @@
E9E7CD8D20026B6600DFC4DB /* DialogService.swift in Sources */,
E9E7CDB72003994E00DFC4DB /* AdamantUtilities.swift in Sources */,
E9147B6320505C7500145913 /* QRCodeReader+adamant.swift in Sources */,
E93D7AC22052EE21005D19DC /* SettingsViewController+StayIn.swift in Sources */,
E9942B80203C058C00C163AF /* QRGeneratorViewController.swift in Sources */,
E948E0462024DAE800975D6B /* AdamantUserInfoKeys.swift in Sources */,
E9E7CD9120026FA100DFC4DB /* SwinjectDependencies.swift in Sources */,
Expand Down Expand Up @@ -968,12 +983,14 @@
E9CE7789202B9DC2009CF70D /* ChatTransaction+CoreDataClass.swift in Sources */,
E9E7CDBE2003AEFB00DFC4DB /* CellFactory.swift in Sources */,
E9CAE8D62018AC5300345E76 /* AdamantApi+Transactions.swift in Sources */,
E93D7ABE2052CEE1005D19DC /* NotificationsService.swift in Sources */,
E972206B201F44CA004F2AAD /* TransfersProvider.swift in Sources */,
E9722068201F42CC004F2AAD /* InMemoryCoreDataStack.swift in Sources */,
E9C51EF12013F18000385EB7 /* NewChatViewController.swift in Sources */,
E913C9171FFFAF76001A83F7 /* JSAdamantCore.swift in Sources */,
E95F856520067A030070534A /* GlobalConstants.swift in Sources */,
E9502740202E257E002C1098 /* RepeaterService.swift in Sources */,
E93D7AC02052CF63005D19DC /* AdamantNotificationService.swift in Sources */,
E93B0D762028B28E00126346 /* AdamantChatsProvider.swift in Sources */,
E90A4943204C5ED6009F6A65 /* EurekaPassphraseRow.swift in Sources */,
E95F8589200900B10070534A /* ChatType.swift in Sources */,
Expand Down Expand Up @@ -1060,6 +1077,15 @@
name = InfoPlist.strings;
sourceTree = "<group>";
};
E93D7AC720530F76005D19DC /* Localizable.stringsdict */ = {
isa = PBXVariantGroup;
children = (
E93D7AC620530F76005D19DC /* ru */,
E93D7AC920530F8E005D19DC /* Base */,
);
name = Localizable.stringsdict;
sourceTree = "<group>";
};
E9452A4E20344834005BA34C /* Account.storyboard */ = {
isa = PBXVariantGroup;
children = (
Expand Down
74 changes: 64 additions & 10 deletions Adamant/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?
var repeater: RepeaterService!

weak var accountService: AccountService?
weak var notificationService: NotificationsService?

// MARK: - Lifecycle

Expand All @@ -28,6 +31,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
container.registerAdamantChatsStory()
container.registerAdamantSettingsStory()

accountService = container.resolve(AccountService.self)
notificationService = container.resolve(NotificationsService.self)


// MARK: 2. Prepare UI
self.window = UIWindow(frame: UIScreen.main.bounds)
Expand Down Expand Up @@ -64,16 +70,26 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
repeater.registerForegroundCall(label: "chatsProvider", interval: 3, queue: DispatchQueue.global(qos: .utility), callback: chatsProvider.update)


// MARK: 4. Login / Logut
NotificationCenter.default.addObserver(forName: Notification.Name.adamantUserLoggedIn, object: nil, queue: OperationQueue.main) { _ in
// Background Fetch
UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalMinimum)
// MARK: 4. Notifications
if let service = container.resolve(NotificationsService.self) {
if service.notificationsEnabled {
UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalMinimum)
} else {
UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalNever)
}

NotificationCenter.default.addObserver(forName: Notification.Name.adamantShowNotificationsChanged, object: service, queue: OperationQueue.main) { _ in
if service.notificationsEnabled {
UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalMinimum)
} else {
UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalNever)
}
}
}


// MARK: 5. Logout reset
NotificationCenter.default.addObserver(forName: Notification.Name.adamantUserLoggedOut, object: nil, queue: OperationQueue.main) { [weak self] _ in
// Background Fetch
UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalNever)

// On logout, pop all navigators to root.
guard let tbc = self?.window?.rootViewController as? UITabBarController, let vcs = tbc.viewControllers else {
return
Expand All @@ -99,6 +115,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate {

func applicationDidBecomeActive(_ application: UIApplication) {
repeater.resumeAll()

if accountService?.account != nil {
notificationService?.removeAllDeliveredNotifications()
}
}

// MARK: Background fetch
Expand All @@ -107,22 +127,56 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
let container = Container()
container.registerAdamantBackgroundFetchServices()

guard let securedStore = container.resolve(SecuredStore.self), let apiService = container.resolve(ApiService.self) else {
guard let securedStore = container.resolve(SecuredStore.self),
let apiService = container.resolve(ApiService.self),
let notificationsService = container.resolve(NotificationsService.self) else {
UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalNever)
completionHandler(.failed)
return
}

guard let address = securedStore.get(StoreKey.chatProvider.address), let lastHeightRaw = securedStore.get(StoreKey.chatProvider.lastHeight), let lastHeight = Int64(lastHeightRaw) else {
guard let address = securedStore.get(StoreKey.chatProvider.address) else {
UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalNever)
completionHandler(.failed)
return
}

var lastHeight: Int64?
if let raw = securedStore.get(StoreKey.chatProvider.receivedLastHeight) {
lastHeight = Int64(raw)
} else {
lastHeight = nil
}

var notifiedCount = 0
if let raw = securedStore.get(StoreKey.chatProvider.notifiedLastHeight), let notifiedHeight = Int64(raw), let h = lastHeight {
if h < notifiedHeight {
lastHeight = notifiedHeight

if let raw = securedStore.get(StoreKey.chatProvider.notifiedMessagesCount), let count = Int(raw) {
notifiedCount = count
}
}
}


apiService.getChatTransactions(address: address, height: lastHeight, offset: nil) { result in
switch result {
case .success(let transactions):
completionHandler(transactions.count > 0 ? .newData : .noData)
if transactions.count > 0 {
let total = transactions.count + notifiedCount
securedStore.set(String(total), for: StoreKey.chatProvider.notifiedMessagesCount)

if let newLastHeight = transactions.map({$0.height}).sorted().last {
securedStore.set(String(newLastHeight), for: StoreKey.chatProvider.notifiedLastHeight)
}


notificationsService.showNotification(title: String.adamantLocalized.notifications.newMessageTitle, body: String.localizedStringWithFormat(String.adamantLocalized.notifications.newMessageBody, total), type: .newMessages(count: total))
completionHandler(.newData)
} else {
completionHandler(.noData)
}

case .failure(_):
completionHandler(.failed)
Expand Down
22 changes: 22 additions & 0 deletions Adamant/Assets/Base.lproj/Localizable.stringsdict
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>You have %d new message(s)</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@messages@</string>
<key>messages</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>You have %d new message</string>
<key>other</key>
<string>You have %d new messages</string>
</dict>
</dict>
</dict>
</plist>
51 changes: 28 additions & 23 deletions Adamant/Assets/ru.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@
/* Config: Application Info section */
"Application info" = "Приложение";

/* Config: Biometry authorization reason for turning on/off biometry usage to log in */
"Authorize yourself" = "Для внесения изменений необходимо авторизироваться";

/* Transfer: logged user balance.
Wallet page: Balance row title */
"Balance" = "Баланс";
Expand All @@ -57,6 +54,9 @@
/* Config: turn off 'Stay Logged In' confirmation */
"Do not stay logged in" = "Выходить из системы при выходе из приложения";

/* Config: Authorization reason for turning biometry off */
"Do not use biometry to log in" = "Отключить вход с биометрией";

/* Shared alert Done message. Used anywhere */
"Done" = "Готово";

Expand Down Expand Up @@ -134,7 +134,8 @@
/* Login: Create new account section */
"New account" = "Новый аккаунт";

/* Chat: message input placeholder */
/* Chat: message input placeholder
Notifications: New message notification title */
"New message" = "Новое сообщение";

/* ApiService: No connection message. Generally bad network. */
Expand All @@ -143,14 +144,24 @@
/* Login: No network error. */
"No connection with The Internet" = "Нет соединения с сетью";

/* Config: Show notifications */
"Notifications" = "Уведомления";

/* Notifications: User has disabled notifications. Head him into settings */
"Notifications disabled. You can reenable notifications in Settings" = "Уведомления отключены. Вы можете включить их в Настройках";

/* Shared alert 'Ok' button. Used anywhere */
"Ok" = "Ок";

/* Transaction details: 'Open transaction in explorer' row. */
"Open in Explorer" = "Открыть в Explorer";

/* Login: Passphrase placeholder
QRGenerator: Passphrase textview placeholder */
"Passphrase" = "Пароль";

/* Login: Login with pincode button */
"Pin" = "Войти с pin-кодом";
"Login with Pincode" = "Войти с pin-кодом";

/* Transfer: Address validation error */
"Please enter a valid recipient address" = "Введите корректный адрес получателя";
Expand All @@ -159,7 +170,7 @@
"Please specify valid recipient address" = "Неверный адрес";

/* Login: Login with QR button. */
"QR" = "Войти с QR-кодом";
"Login with QR" = "Войти с QR-кодом";

/* New Chat: Notify user that scanned QR doesn't contains an address */
"QR code does not contains a valid adamant address" = "QR код не содержит адреса";
Expand Down Expand Up @@ -198,22 +209,19 @@
/* Transfer: Processing message */
"Sending funds..." = "Отправляем токены...";

/* Shared alert 'Settings' button. Used to go to system Settings app, on application settings page. Should be same as Settings application title.
Config: Settings section */
/* Config: Settings section
Shared alert 'Settings' button. Used to go to system Settings app, on application settings page. Should be same as Settings application title. */
"Settings" = "Настройки";

/* Wallet page: 'Transfer not allowed' alert title */
"Sorry!" = "Ой!";

/* Shared alert 'Share' button. Used anywhere for presenting standart iOS 'Share' menu. */
"Share" = "Поделиться";

/* Wallet page: 'Transfer not allowed' alert title */
"Sorry!" = "Ой!";

/* Config: Stay logged option */
"Stay Logged in" = "Оставаться в сети";

/* Config: Authorization reason for turning biometry off */
"Do not use biometry to log in" = "Отключить вход с биометрией";

/* Export transaction: 'Share transaction summary' button */
"Summary" = "Сводка";

Expand All @@ -236,14 +244,15 @@
/* Export transaction: 'Share transaction URL' button */
"URL" = "URL";

/* Unknown internal error */
"Unknown error" = "Неизвестная ошибка";

/* Config: Authorization reason for turning biometry on */
"Use biometry to log in" = "Использовать биометрию для входа в систему";

/* Login: user not logged error */
"User not logged!" = "Не выполнен вход";

/* Unknown internal error */
"Unknown error" = "Неизвестная ошибка";
/* ApiService: User not logged error
Login: user not logged error */
"User not logged" = "Не выполнен вход";

/* Config: Utilities section */
"Utilities" = "Утилиты";
Expand Down Expand Up @@ -287,10 +296,6 @@
/* Transfer: recipient address placeholder */
"of the recipient" = "получателя";

/* Login: Passphrase placeholder
QRGenerator: Passphrase textview placeholder */
"Passphrase" = "Пароль";

/* Transfer: transfer amount placeholder */
"to send" = "для перевода";

24 changes: 24 additions & 0 deletions Adamant/Assets/ru.lproj/Localizable.stringsdict
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>You have %d new message(s)</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@messages@</string>
<key>messages</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>У вас %d новое сообщение</string>
<key>many</key>
<string>У вас %d новых сообщений</string>
<key>other</key>
<string>У вас %d новых сообщения</string>
</dict>
</dict>
</dict>
</plist>
Loading

0 comments on commit 84e8a87

Please sign in to comment.