Skip to content

Commit

Permalink
Merge pull request #830 from Infomaniak/shareExtension
Browse files Browse the repository at this point in the history
Mail share extension
  • Loading branch information
PhilippeWeidmann committed Aug 4, 2023
2 parents e1202d2 + 2e3aeeb commit bf038f6
Show file tree
Hide file tree
Showing 91 changed files with 2,184 additions and 396 deletions.
2 changes: 1 addition & 1 deletion .package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/Infomaniak/ios-core",
"state" : {
"revision" : "4eaefd644f75d833d6b1009dd94a9d6d674ccb53"
"revision" : "d779a9f6619615a4b4a91fa9d3fbb48415a27470"
}
},
{
Expand Down
26 changes: 17 additions & 9 deletions Mail/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,27 @@
*/

import CocoaLumberjackSwift
import InfomaniakCore
import InfomaniakDI
import InfomaniakNotifications
import MailCore
import UIKit

class AppDelegate: UIResponder, UIApplicationDelegate {
@available(iOSApplicationExtension, unavailable)
final class AppDelegate: UIResponder, UIApplicationDelegate {
private let notificationCenterDelegate = NotificationCenterDelegate()
static var orientationLock = UIInterfaceOrientationMask.all

func application(
_ application: UIApplication,
willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
@LazyInjectService private var orientationManager: OrientationManageable
@LazyInjectService private var accountManager: AccountManager
@LazyInjectService private var applicationState: ApplicationStatable

/// Making sure the DI is registered at a very early stage of the app launch.
private let dependencyInjectionHook = EarlyDIHook()

func application(_ application: UIApplication,
willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
DDLogInfo("Application starting in foreground ? \(applicationState.applicationState != .background)")

UNUserNotificationCenter.current().delegate = notificationCenterDelegate
Task {
// Ask permission app launch
Expand All @@ -44,14 +52,14 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
@InjectService var notificationService: InfomaniakNotifications
@InjectService var tokenStore: TokenStore

for account in AccountManager.instance.accounts {
for account in accountManager.accounts {
Task {
/* Because of a backend issue we can't register the notification token directly after the creation or refresh of
an API token. We wait at least 15 seconds before trying to register. */
try? await Task.sleep(nanoseconds: 15_000_000_000)

guard let token = tokenStore.tokenFor(userId: account.userId) else { return }
let userApiFetcher = AccountManager.instance.getApiFetcher(for: token.userId, token: token)
let userApiFetcher = accountManager.getApiFetcher(for: token.userId, token: token)
await notificationService.updateRemoteNotificationsToken(tokenData: deviceToken,
userApiFetcher: userApiFetcher,
updatePolicy: .always)
Expand All @@ -65,6 +73,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {

func application(_ application: UIApplication,
supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return AppDelegate.orientationLock
return orientationManager.orientationLock
}
}
11 changes: 9 additions & 2 deletions Mail/Components/UnavailableMailboxListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import InfomaniakDI
import MailCore
import MailResources
import RealmSwift
Expand All @@ -27,14 +28,20 @@ struct UnavailableMailboxListView: View {
@ObservedResults(
Mailbox.self,
configuration: MailboxInfosManager.instance.realmConfiguration,
where: { $0.userId == AccountManager.instance.currentUserId && $0.isPasswordValid == false },
where: { mailbox in
@InjectService var accountManager: AccountManager
return mailbox.userId == accountManager.currentUserId && mailbox.isPasswordValid == false
},
sortDescriptor: SortDescriptor(keyPath: \Mailbox.mailboxId)
) private var passwordBlockedMailboxes

@ObservedResults(
Mailbox.self,
configuration: MailboxInfosManager.instance.realmConfiguration,
where: { $0.userId == AccountManager.instance.currentUserId && $0.isLocked == true },
where: { mailbox in
@InjectService var accountManager: AccountManager
return mailbox.userId == accountManager.currentUserId && mailbox.isLocked == true
},
sortDescriptor: SortDescriptor(keyPath: \Mailbox.mailboxId)
) private var lockedMailboxes

Expand Down
141 changes: 141 additions & 0 deletions Mail/Helpers/AppAssembly.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
Infomaniak Mail - iOS App
Copyright (C) 2022 Infomaniak Network SA
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import Foundation
import InfomaniakBugTracker
import InfomaniakCore
import InfomaniakCoreUI
import InfomaniakDI
import InfomaniakLogin
import InfomaniakNotifications
import MailCore

private let realmRootPath = "mailboxes"
private let appGroupIdentifier = "group.com.infomaniak.mail"

extension Array where Element == Factory {
func registerFactoriesInDI() {
forEach { SimpleResolver.sharedResolver.store(factory: $0) }
}
}

/// Something that prepares the application Dependency Injection
enum ApplicationAssembly {
static func setupDI() {
// Setup main servicies
setupMainServices()

// Setup proxy types necessary for the App code to work in Extension mode
setupProxyTypes()
}

private static func setupMainServices() {
let factories = [
Factory(type: InfomaniakNetworkLoginable.self) { _, _ in
InfomaniakNetworkLogin(clientId: MailApiFetcher.clientId)
},
Factory(type: InfomaniakLoginable.self) { _, _ in
InfomaniakLogin(clientId: MailApiFetcher.clientId)
},
Factory(type: KeychainHelper.self) { _, _ in
KeychainHelper(accessGroup: AccountManager.accessGroup)
},
Factory(type: InfomaniakNotifications.self) { _, _ in
InfomaniakNotifications(appGroup: AccountManager.appGroup)
},
Factory(type: AppLockHelper.self) { _, _ in
AppLockHelper()
},
Factory(type: BugTracker.self) { _, _ in
BugTracker(info: BugTrackerInfo(project: "app-mobile-mail", gitHubRepoName: "ios-mail", appReleaseType: .beta))
},
Factory(type: MatomoUtils.self) { _, _ in
MatomoUtils(siteId: Constants.matomoId, baseURL: URLConstants.matomo.url)
},
Factory(type: IKSnackBarAvoider.self) { _, _ in
IKSnackBarAvoider()
},
Factory(type: DraftManager.self) { _, _ in
DraftManager()
},
Factory(type: AccountManager.self) { _, _ in
AccountManager()
},
Factory(type: SnackBarPresentable.self) { _, _ in
SnackBarPresenter()
},
Factory(type: UserAlertDisplayable.self) { _, _ in
UserAlertDisplayer()
},
Factory(type: ApplicationStatable.self) { _, _ in
ApplicationState()
},
Factory(type: UserActivityController.self) { _, _ in
UserActivityController()
},
Factory(type: PlatformDetectable.self) { _, _ in
PlatformDetector()
},
Factory(type: AppGroupPathProvidable.self) { _, _ in
guard let provider = AppGroupPathProvider(
realmRootPath: realmRootPath,
appGroupIdentifier: appGroupIdentifier
) else {
fatalError("could not safely init AppGroupPathProvider")
}

return provider
},
Factory(type: TokenStore.self) { _, _ in
TokenStore()
}
]

factories.registerFactoriesInDI()
}

private static func setupProxyTypes() {
let factories = [
Factory(type: CacheManageable.self) { _, _ in
CacheManager()
},
Factory(type: OrientationManageable.self) { _, _ in
OrientationManager()
},
Factory(type: RemoteNotificationRegistrable.self) { _, _ in
RemoteNotificationRegistrer()
}
]

factories.registerFactoriesInDI()
}
}

/// Something that loads the DI on init
public struct EarlyDIHook {
public init() {
// Setup date encoding
ApiFetcher.decoder.dateDecodingStrategy = .iso8601

// setup DI ASAP
ApplicationAssembly.setupDI()

// Setup debug stack early, requires DI to be setup to work
Logging.initLogging()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/

import Foundation
import InfomaniakDI
import MailCore
import UIKit
import UserNotifications
Expand All @@ -26,24 +27,26 @@ public struct NotificationTappedPayload {
}

@MainActor
class NotificationCenterDelegate: NSObject, UNUserNotificationCenterDelegate {
final class NotificationCenterDelegate: NSObject, UNUserNotificationCenterDelegate {
@LazyInjectService private var accountManager: AccountManager

private func handleClickOnNotification(scene: UIScene?, content: UNNotificationContent) {
guard let mailboxId = content.userInfo[NotificationsHelper.UserInfoKeys.mailboxId] as? Int,
let userId = content.userInfo[NotificationsHelper.UserInfoKeys.userId] as? Int,
let mailbox = MailboxInfosManager.instance.getMailbox(id: mailboxId, userId: userId),
let mailboxManager = AccountManager.instance.getMailboxManager(for: mailbox) else {
let mailboxManager = accountManager.getMailboxManager(for: mailbox) else {
return
}

if AccountManager.instance.currentMailboxManager?.mailbox != mailboxManager.mailbox {
if AccountManager.instance.getCurrentAccount()?.userId != mailboxManager.mailbox.userId {
if let switchedAccount = AccountManager.instance.accounts.values
if accountManager.currentMailboxManager?.mailbox != mailboxManager.mailbox {
if accountManager.getCurrentAccount()?.userId != mailboxManager.mailbox.userId {
if let switchedAccount = accountManager.accounts.values
.first(where: { $0.userId == mailboxManager.mailbox.userId }) {
AccountManager.instance.switchAccount(newAccount: switchedAccount)
AccountManager.instance.switchMailbox(newMailbox: mailbox)
accountManager.switchAccount(newAccount: switchedAccount)
accountManager.switchMailbox(newMailbox: mailbox)
}
} else {
AccountManager.instance.switchMailbox(newMailbox: mailbox)
accountManager.switchMailbox(newMailbox: mailbox)
}
}

Expand Down
4 changes: 3 additions & 1 deletion Mail/Helpers/WorkInProgress.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@

import Foundation
import InfomaniakCoreUI
import InfomaniakDI
import MailCore
import MailResources

// To delete: alert to facilitate tests for beta version
@MainActor
func showWorkInProgressSnackBar() {
IKSnackBar.showSnackBar(message: MailResourcesStrings.Localizable.workInProgressTitle)
@InjectService var snackbarPresenter: SnackBarPresentable
snackbarPresenter.show(message: MailResourcesStrings.Localizable.workInProgressTitle)
}
65 changes: 4 additions & 61 deletions Mail/MailApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,67 +28,13 @@ import Sentry
import SwiftUI
import UIKit

public struct EarlyDIHook {
public init() {
// setup DI and logging ASAP
Logging.initLogging()
setupDI()
}

func setupDI() {
let networkLoginService = Factory(type: InfomaniakNetworkLoginable.self) { _, _ in
InfomaniakNetworkLogin(clientId: MailApiFetcher.clientId)
}
let loginService = Factory(type: InfomaniakLoginable.self) { _, _ in
InfomaniakLogin(clientId: MailApiFetcher.clientId)
}
let keychainHelper = Factory(type: KeychainHelper.self) { _, _ in
KeychainHelper(accessGroup: AccountManager.accessGroup)
}
let tokenStore = Factory(type: TokenStore.self) { _, _ in
TokenStore()
}
let notificationService = Factory(type: InfomaniakNotifications.self) { _, _ in
InfomaniakNotifications(appGroup: AccountManager.appGroup)
}
let appLockHelper = Factory(type: AppLockHelper.self) { _, _ in
AppLockHelper()
}
let bugTracker = Factory(type: BugTracker.self) { _, _ in
BugTracker(info: BugTrackerInfo(project: "app-mobile-mail", gitHubRepoName: "ios-mail", appReleaseType: .beta))
}
let matomoUtils = Factory(type: MatomoUtils.self) { _, _ in
MatomoUtils(siteId: Constants.matomoId, baseURL: URLConstants.matomo.url)
}
let avoider = Factory(type: SnackBarAvoider.self) { _, _ in
SnackBarAvoider()
}
let draftManager = Factory(type: DraftManager.self) { _, _ in
DraftManager()
}
let userActivityController = Factory(type: UserActivityController.self) { _, _ in
UserActivityController()
}

SimpleResolver.sharedResolver.store(factory: networkLoginService)
SimpleResolver.sharedResolver.store(factory: loginService)
SimpleResolver.sharedResolver.store(factory: notificationService)
SimpleResolver.sharedResolver.store(factory: keychainHelper)
SimpleResolver.sharedResolver.store(factory: tokenStore)
SimpleResolver.sharedResolver.store(factory: appLockHelper)
SimpleResolver.sharedResolver.store(factory: bugTracker)
SimpleResolver.sharedResolver.store(factory: matomoUtils)
SimpleResolver.sharedResolver.store(factory: avoider)
SimpleResolver.sharedResolver.store(factory: draftManager)
SimpleResolver.sharedResolver.store(factory: userActivityController)
}
}

@main
struct MailApp: App {
/// Making sure the DI is registered at a very early stage of the app launch.
private let dependencyInjectionHook = EarlyDIHook()
@LazyInjectService var appLockHelper: AppLockHelper

@LazyInjectService private var appLockHelper: AppLockHelper
@LazyInjectService private var accountManager: AccountManager

@UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate

Expand All @@ -99,11 +45,8 @@ struct MailApp: App {

@StateObject private var navigationState = NavigationState()

private let accountManager = AccountManager.instance

init() {
DDLogInfo("Application starting in foreground ? \(UIApplication.shared.applicationState != .background)")
ApiFetcher.decoder.dateDecodingStrategy = .iso8601
}

var body: some Scene {
Expand Down Expand Up @@ -161,7 +104,7 @@ struct MailApp: App {
try await accountManager.updateUser(for: account)
accountManager.enableBugTrackerIfAvailable()

try await accountManager.currentMailboxManager?.contactManager.fetchContactsAndAddressBooks()
try await accountManager.currentContactManager?.fetchContactsAndAddressBooks()
} catch {
DDLogError("Error while updating user account: \(error)")
}
Expand Down
Loading

0 comments on commit bf038f6

Please sign in to comment.