diff --git a/ScribbleLab.xcodeproj/project.pbxproj b/ScribbleLab.xcodeproj/project.pbxproj index ef7865aa9..ba4059cc3 100644 --- a/ScribbleLab.xcodeproj/project.pbxproj +++ b/ScribbleLab.xcodeproj/project.pbxproj @@ -24,8 +24,6 @@ 381C1DF22B5EF4B200F73B5E /* SLPrivacySettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 381C1DF12B5EF4B200F73B5E /* SLPrivacySettingsView.swift */; }; 381C1DF52B5EFD1900F73B5E /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 381C1DF42B5EFD1900F73B5E /* SearchView.swift */; }; 381C1DF82B5EFF7B00F73B5E /* TrashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 381C1DF72B5EFF7B00F73B5E /* TrashView.swift */; }; - 381E0B362ADC136400A2A836 /* PomodoroModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 381E0B352ADC136400A2A836 /* PomodoroModel.swift */; }; - 381E0B382ADC14E300A2A836 /* SLStudyPomodoroTimerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 381E0B372ADC14E300A2A836 /* SLStudyPomodoroTimerView.swift */; }; 381F1F132AD72DD6001B3B10 /* TestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 381F1F122AD72DD6001B3B10 /* TestView.swift */; }; 3828B2432B1FA5BE00D66BD8 /* NotificationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3828B2422B1FA5BE00D66BD8 /* NotificationCell.swift */; }; 3828B2452B1FA7A400D66BD8 /* NotificationCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3828B2442B1FA7A400D66BD8 /* NotificationCellModel.swift */; }; @@ -91,6 +89,8 @@ 387CC3292BEE49A100B5B907 /* SCSNetworkMonitorAgentProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 387CC3282BEE49A100B5B907 /* SCSNetworkMonitorAgentProtocol.swift */; }; 387CC32B2BEE49A100B5B907 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 387CC32A2BEE49A100B5B907 /* main.swift */; }; 387CC3302BEE49A100B5B907 /* SCSNetworkMonitorAgent.xpc in Embed XPC Services */ = {isa = PBXBuildFile; fileRef = 387CC3242BEE49A000B5B907 /* SCSNetworkMonitorAgent.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 387CC3392BEFC43800B5B907 /* SCSLoggingAgent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 387CC3382BEFC43800B5B907 /* SCSLoggingAgent.swift */; }; + 387CC33B2BEFC96400B5B907 /* SCSNotificationAgent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 387CC33A2BEFC96400B5B907 /* SCSNotificationAgent.swift */; }; 387F7F882B12087E001CC150 /* Draw+PencilKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 387F7F872B12087E001CC150 /* Draw+PencilKit.swift */; }; 387F7F8A2B120948001CC150 /* DrawingTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 387F7F892B120948001CC150 /* DrawingTest.swift */; }; 387F7F8D2B122634001CC150 /* ColorPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 387F7F8C2B122634001CC150 /* ColorPickerView.swift */; }; @@ -125,7 +125,6 @@ 38AB46312B16524000DC9D1C /* Release.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 385F788C2AD5C4690096E504 /* Release.xcconfig */; }; 38AB46322B16524000DC9D1C /* Alpha.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 38355EFD2AD3DF9B00392674 /* Alpha.xcconfig */; }; 38AB46332B16524000DC9D1C /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 38355F032AD3DFED00392674 /* Debug.xcconfig */; }; - 38AD22322B10F6A100663C37 /* Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38AD22312B10F6A100663C37 /* Network.swift */; }; 38ADE8112B1D1253002229A2 /* SLTip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38ADE8102B1D1253002229A2 /* SLTip.swift */; }; 38ADE8172B1D1F44002229A2 /* NotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38ADE8162B1D1F44002229A2 /* NotificationSettings.swift */; }; 38AE9C9C2AD0750F00B761E8 /* ScribbleLabApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38AE9C9B2AD0750F00B761E8 /* ScribbleLabApp.swift */; }; @@ -247,8 +246,6 @@ 381C1DF12B5EF4B200F73B5E /* SLPrivacySettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SLPrivacySettingsView.swift; sourceTree = ""; }; 381C1DF42B5EFD1900F73B5E /* SearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchView.swift; sourceTree = ""; }; 381C1DF72B5EFF7B00F73B5E /* TrashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrashView.swift; sourceTree = ""; }; - 381E0B352ADC136400A2A836 /* PomodoroModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PomodoroModel.swift; sourceTree = ""; }; - 381E0B372ADC14E300A2A836 /* SLStudyPomodoroTimerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SLStudyPomodoroTimerView.swift; sourceTree = ""; }; 381F1F122AD72DD6001B3B10 /* TestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestView.swift; sourceTree = ""; }; 3828B2422B1FA5BE00D66BD8 /* NotificationCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationCell.swift; sourceTree = ""; }; 3828B2442B1FA7A400D66BD8 /* NotificationCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationCellModel.swift; sourceTree = ""; }; @@ -315,6 +312,8 @@ 387CC32A2BEE49A100B5B907 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 387CC32C2BEE49A100B5B907 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 387CC32D2BEE49A100B5B907 /* SCSNetworkMonitorAgent.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SCSNetworkMonitorAgent.entitlements; sourceTree = ""; }; + 387CC3382BEFC43800B5B907 /* SCSLoggingAgent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SCSLoggingAgent.swift; sourceTree = ""; }; + 387CC33A2BEFC96400B5B907 /* SCSNotificationAgent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SCSNotificationAgent.swift; sourceTree = ""; }; 387F7F872B12087E001CC150 /* Draw+PencilKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Draw+PencilKit.swift"; sourceTree = ""; }; 387F7F892B120948001CC150 /* DrawingTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DrawingTest.swift; sourceTree = ""; }; 387F7F8C2B122634001CC150 /* ColorPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerView.swift; sourceTree = ""; }; @@ -343,7 +342,6 @@ 38A5E9BA2B03D4E80037C668 /* SLOTP+2FAView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SLOTP+2FAView.swift"; sourceTree = ""; }; 38A5E9BC2B03D7730037C668 /* OTPTextFieldView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OTPTextFieldView.swift; sourceTree = ""; }; 38A5E9C42B03F09C0037C668 /* SLOTP+2FA_ConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SLOTP+2FA_ConfigView.swift"; sourceTree = ""; }; - 38AD22312B10F6A100663C37 /* Network.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = ""; }; 38ADE8102B1D1253002229A2 /* SLTip.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SLTip.swift; sourceTree = ""; }; 38ADE8162B1D1F44002229A2 /* NotificationSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettings.swift; sourceTree = ""; }; 38AE9C982AD0750F00B761E8 /* ScribbleLab.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ScribbleLab.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -469,22 +467,6 @@ path = Waiting; sourceTree = ""; }; - 380ADEA02B0E9030001832C6 /* Plug-Ins */ = { - isa = PBXGroup; - children = ( - 380ADEA12B0E9051001832C6 /* VocabularyLearning */, - 38D5C67E2AD1C0FA00D943A5 /* Timer */, - ); - path = "Plug-Ins"; - sourceTree = ""; - }; - 380ADEA12B0E9051001832C6 /* VocabularyLearning */ = { - isa = PBXGroup; - children = ( - ); - path = VocabularyLearning; - sourceTree = ""; - }; 380BC6442B260BA000DCF442 /* Shop */ = { isa = PBXGroup; children = ( @@ -505,7 +487,8 @@ isa = PBXGroup; children = ( 38140A682AE3F81900753FB6 /* UserService.swift */, - 38AD22312B10F6A100663C37 /* Network.swift */, + 387CC3382BEFC43800B5B907 /* SCSLoggingAgent.swift */, + 387CC33A2BEFC96400B5B907 /* SCSNotificationAgent.swift */, ); path = Service; sourceTree = ""; @@ -557,22 +540,6 @@ path = Trash; sourceTree = ""; }; - 381E0B332ADC134C00A2A836 /* Model */ = { - isa = PBXGroup; - children = ( - 381E0B352ADC136400A2A836 /* PomodoroModel.swift */, - ); - path = Model; - sourceTree = ""; - }; - 381E0B342ADC135200A2A836 /* View */ = { - isa = PBXGroup; - children = ( - 381E0B372ADC14E300A2A836 /* SLStudyPomodoroTimerView.swift */, - ); - path = View; - sourceTree = ""; - }; 381F1F112AD72DC2001B3B10 /* Editor */ = { isa = PBXGroup; children = ( @@ -752,7 +719,6 @@ 3858A7722AD14AC800FC6319 /* Features */, 3858A7712AD14AC200FC6319 /* Home */, 38A5E34F2BECFE72009A8885 /* Onboarding */, - 380ADEA02B0E9030001832C6 /* Plug-Ins */, 3858A7752AD14B5C00FC6319 /* Settings */, 3886B2DF2AD1ABA3002EF30E /* SideBar */, 380BC6442B260BA000DCF442 /* Shop */, @@ -1378,15 +1344,6 @@ path = Profile; sourceTree = ""; }; - 38D5C67E2AD1C0FA00D943A5 /* Timer */ = { - isa = PBXGroup; - children = ( - 381E0B342ADC135200A2A836 /* View */, - 381E0B332ADC134C00A2A836 /* Model */, - ); - path = Timer; - sourceTree = ""; - }; 38D5C6812AD2887000D943A5 /* Units */ = { isa = PBXGroup; children = ( @@ -1857,6 +1814,7 @@ files = ( 38D0CF592B67C1090051B356 /* CreateNotebookView.swift in Sources */, 3852D7212B054DBF007FAFF1 /* Particle.swift in Sources */, + 387CC3392BEFC43800B5B907 /* SCSLoggingAgent.swift in Sources */, 38B36C5E2B5D73D80009BA56 /* FavouriteView.swift in Sources */, 385DC5D72B53FB0C00D1FE6E /* NotificationSettingsModel.swift in Sources */, 38BAF7C52B5AF6EF00BEE6A5 /* IntegrationsView.swift in Sources */, @@ -1866,7 +1824,6 @@ 3889688B2AF143C700F67F08 /* SettingsViewModel.swift in Sources */, 3858A77E2AD15E8900FC6319 /* NotificationSheetView.swift in Sources */, 383588442AFEDB4000EEA1C3 /* PerformanceView.swift in Sources */, - 38AD22322B10F6A100663C37 /* Network.swift in Sources */, 387B79362ADEDD9B0067E08B /* SLOtherSettings.swift in Sources */, 38F59B8B2AEC4E0D00475B0B /* ResetPasswordView.swift in Sources */, 38B36C652B5D95FD0009BA56 /* ScribbleCloudOverviewView.swift in Sources */, @@ -1875,7 +1832,6 @@ 38EFBE232AD6E4EF00CF0ECD /* RestartAppView.swift in Sources */, 389FD4332B1BD22800C7DCC1 /* ResetPasswordModel.swift in Sources */, 3886B2DE2AD19F34002EF30E /* SLSettingsView.swift in Sources */, - 381E0B362ADC136400A2A836 /* PomodoroModel.swift in Sources */, 385F78BE2AD5ED720096E504 /* SLHelpView.swift in Sources */, 386845172B654AA800C375E1 /* LearningCenterView.swift in Sources */, 381C1DF22B5EF4B200F73B5E /* SLPrivacySettingsView.swift in Sources */, @@ -1950,7 +1906,6 @@ 38140A692AE3F81900753FB6 /* UserService.swift in Sources */, 3868A3DE2AD2DBA300D4CAEC /* ImageView.swift in Sources */, 380D93972AE42C6600277D2D /* CompleteRegistartionView.swift in Sources */, - 381E0B382ADC14E300A2A836 /* SLStudyPomodoroTimerView.swift in Sources */, 3852D71F2B054D18007FAFF1 /* ParticleEffect.swift in Sources */, 387F7F962B12387E001CC150 /* DrawingViewController.swift in Sources */, 38A5E9BB2B03D4E80037C668 /* SLOTP+2FAView.swift in Sources */, @@ -1961,6 +1916,7 @@ 381C1DE32B5E8BCA00F73B5E /* DocumentSortOptionFavourite.swift in Sources */, 38B36C5B2B5D47510009BA56 /* StoreView.swift in Sources */, 384079D02B600E7A0059523C /* CrashReportSheet.swift in Sources */, + 387CC33B2BEFC96400B5B907 /* SCSNotificationAgent.swift in Sources */, 385B8D2D2B9B7D5700DD4768 /* SettingsView.swift in Sources */, 38A5E3512BECFE9B009A8885 /* OnboardingView.swift in Sources */, 38CB09092B5411FA00E0C224 /* OnboardingFeature.swift in Sources */, diff --git a/ScribbleLab.xcodeproj/xcshareddata/xcschemes/ScribbleLab.xcscheme b/ScribbleLab.xcodeproj/xcshareddata/xcschemes/ScribbleLab.xcscheme index e054bf975..163b06517 100644 --- a/ScribbleLab.xcodeproj/xcshareddata/xcschemes/ScribbleLab.xcscheme +++ b/ScribbleLab.xcodeproj/xcshareddata/xcschemes/ScribbleLab.xcscheme @@ -73,6 +73,13 @@ ReferencedContainer = "container:ScribbleLab.xcodeproj"> + + + + EndingColumnNumber 0 EndingLineNumber - 55 + 52 StartingColumnNumber 0 StartingLineNumber - 54 + 51 Timestamp - 736952176.826629 + 737133869.1351219 rebasable-url diff --git a/ScribbleLab.xcworkspace/xcuserdata/neviohirani.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/ScribbleLab.xcworkspace/xcuserdata/neviohirani.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index f4b2a9d6d..accd280d1 100644 --- a/ScribbleLab.xcworkspace/xcuserdata/neviohirani.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/ScribbleLab.xcworkspace/xcuserdata/neviohirani.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -14,10 +14,10 @@ filePath = "ScribbleLab/Core/Onboarding/OnboardingData.swift" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "10" - endingLineNumber = "10" - landmarkName = "unknown" - landmarkType = "0"> + startingLineNumber = "24" + endingLineNumber = "24" + landmarkName = "load(_:)" + landmarkType = "9"> diff --git a/ScribbleLab/App/AppDelegate.swift b/ScribbleLab/App/AppDelegate.swift index 8174937f6..2ab85374f 100644 --- a/ScribbleLab/App/AppDelegate.swift +++ b/ScribbleLab/App/AppDelegate.swift @@ -30,17 +30,14 @@ import UIKit import SwiftUI import UserNotifications -import os.log +import ScribbleCoreServices import FirebaseCore import GoogleSignIn import FirebasePerformance import FirebaseCrashlytics -import ScribbleCoreServices class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate, ObservableObject { -// var notificationSettings = NotificationSettingsModel() - @Published var notificationAllowed: Bool = false func application(_ application: UIApplication, @@ -54,10 +51,10 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele UNUserNotificationCenter.current().delegate = self let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] + UNUserNotificationCenter.current().requestAuthorization( options: authOptions, completionHandler: { /*granted, _ in*/ [weak self] granted, _ in -// self.notificationSettings.notificationAllowed = granted DispatchQueue.main.async { self?.notificationAllowed = granted } @@ -77,10 +74,12 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele } // [START setting_up_scnLogger] + /* let scnLog = SCNLog(subsystem: "com.nhstudiios.ScribbleLab") + */ func applicationDidReceiveMemoryWarning(_ application: UIApplication) { - scnLog.memoryWarning("AppDelegate Received memory warning!") + SCNLoggingAgent.shared.logger.memoryWarning("AppDelegate Received memory warning!") } // [END setting_up_scnLogger] diff --git a/ScribbleLab/App/ScribbleLabApp.swift b/ScribbleLab/App/ScribbleLabApp.swift index c361bd3b6..1540e9078 100644 --- a/ScribbleLab/App/ScribbleLabApp.swift +++ b/ScribbleLab/App/ScribbleLabApp.swift @@ -27,25 +27,22 @@ // // // ===---------------------------------------------------------------------------------------=== // -import SwiftUI import TipKit - +import SwiftUI import ScribbleCoreServices - import FirebaseCore import GoogleSignIn - -#if os(iOS) import FirebasePerformance import FirebaseCrashlytics -#endif @main struct ScribbleLabApp: App { - // register app delegate for Firebase setup @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate - public let scnLog = SCNLog(subsystem: "com.nhstudiiios.ScribleLab") + init() { + _ = SCNLoggingAgent.shared + SCNLoggingAgent.shared.logger.log("SCNLoggingAgent: SCNLogStream successfully initialized") + } var body: some Scene { WindowGroup { @@ -57,13 +54,6 @@ struct ScribbleLabApp: App { .datastoreLocation(.applicationDefault) ]) } - #if os(macOS) - .frame(width: 500, height: 400) - #endif -// SignUpView() -// .environmentObject(RegistrationViewModel()) -// .environmentObject(SignInWithGoogleModel()) -// .preferredColorScheme(isDarkMode ? .dark : .light) } } } diff --git a/ScribbleLab/App/Service/Network.swift b/ScribbleLab/App/Service/Network.swift deleted file mode 100644 index 9a840a13c..000000000 --- a/ScribbleLab/App/Service/Network.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// Network.swift -// ScribbleLab Networking/Core -// -// Copyright (c) 2023 - 2024 ScribbleLabApp. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation -import Network - -/// A class responsible for monitoring the device's network connectivity. -/// -/// This class utilizes NWPathMonitor to observe changes in the network path -/// and updates the `isInternetConnected` property based on the current network status. -/// -class Network: ObservableObject { - /// A published property indicating whether the device is currently connected to the internet. - @Published var isInternetConnected = false - - private let monitor = NWPathMonitor() - - static let shared = Network() - - /// Initializes the network monitoring process and begins monitoring the network status. - init() { - startMonitoring() - } - - /// Starts monitoring the network status using NWPathMonitor. - func startMonitoring() { - monitor.pathUpdateHandler = { path in - DispatchQueue.main.async { - self.isInternetConnected = path.status == .satisfied - } - } - - let queue = DispatchQueue(label: "NetworkMonitor") - monitor.start(queue: queue) - } -} diff --git a/ScribbleLab/App/Service/SCSLoggingAgent.swift b/ScribbleLab/App/Service/SCSLoggingAgent.swift new file mode 100644 index 000000000..7da6c1c12 --- /dev/null +++ b/ScribbleLab/App/Service/SCSLoggingAgent.swift @@ -0,0 +1,39 @@ +// +// SCSLoggingAgent.swift +// ScribbleLab Core +// +// Copyright (c) 2023 - 2024 ScribbleLabApp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Authors: +// - NH: https://github.com/N3v1 +// + +import Foundation +import ScribbleCoreServices + +/// `SCNLoggingAgent` manages a shared instance of `SCNLog` for logging throughout the app. +class SCNLoggingAgent { + + /// Shared instance of `SCNLoggingAgent`. + static let shared = SCNLoggingAgent() + + /// The logger instance for logging messages. + let logger: SCNLog + + /// Initializes a new `SCNLoggingAgent` instance with a subsystem identifier. + private init() { + logger = SCNLog(subsystem: "com.nhsystems.ScribbleLab") + } +} diff --git a/ScribbleLab/App/Service/SCSNotificationAgent.swift b/ScribbleLab/App/Service/SCSNotificationAgent.swift new file mode 100644 index 000000000..837bc693b --- /dev/null +++ b/ScribbleLab/App/Service/SCSNotificationAgent.swift @@ -0,0 +1,83 @@ +// +// SCSNotificationAgent.swift +// ScribbleLab Core +// +// Copyright (c) 2023 - 2024 ScribbleLabApp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Authors: +// - NH: https://github.com/N3v1 +// + +import SwiftUI +import UserNotifications +import ScribbleCoreServices + +// NotificationAgent manages notification permissions and settings. +// +// NotificationAgent is a singleton class that provides functionality to check and request notification permissions, +// as well as monitor notification settings. It conforms to ObservableObject and UNUserNotificationCenterDelegate protocols. +// +// ```swift +// // Request notification permission +// NotificationAgent.shared.requestNotificationPermission() +// ``` +// +class NotificationAgent: NSObject, ObservableObject, UNUserNotificationCenterDelegate, SCSNotificationAgent { + + // The shared instance of NotificationAgent. + static let shared = NotificationAgent() + + // The current notification permission status. + @Published var notificationPermissionStatus: UNAuthorizationStatus = .notDetermined + + // Initializes a new instance of NotificationAgent. + // + // This method sets the delegate of the UNUserNotificationCenter to the instance of NotificationAgent + // and checks the current notification permission status. + private override init() { + super.init() + UNUserNotificationCenter.current().delegate = self + checkNotificationPermissionStatus() + } + + // Requests notification permission from the user. + // + // This method requests authorization to display alerts, badges, and play sounds for notifications. + // Upon user response, it updates the notificationPermissionStatus accordingly. + func requestNotificationPermission() { + UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { [weak self] granted, error in + guard let self = self else { return } + DispatchQueue.main.async { + if granted { + self.notificationPermissionStatus = .authorized + } else { + self.notificationPermissionStatus = .denied + } + } + } + } + + // Checks the current notification permission status. + // + // This method retrieves the notification settings and updates the notificationPermissionStatus accordingly. + private func checkNotificationPermissionStatus() { + UNUserNotificationCenter.current().getNotificationSettings { [weak self] settings in + guard let self = self else { return } + DispatchQueue.main.async { + self.notificationPermissionStatus = settings.authorizationStatus + } + } + } +} diff --git a/ScribbleLab/Core/Onboarding/FeatureCell.swift b/ScribbleLab/Core/Onboarding/FeatureCell.swift index e8f9b7091..38b6fd849 100644 --- a/ScribbleLab/Core/Onboarding/FeatureCell.swift +++ b/ScribbleLab/Core/Onboarding/FeatureCell.swift @@ -2,8 +2,22 @@ // FeatureCell.swift // ScribbleLab // -// Created by Nevio Hirani on 09.05.24. +// Copyright (c) 2023 - 2024 ScribbleLabApp. All rights reserved // +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Authors: +// - NH: https://github.com/N3v1 import Foundation diff --git a/ScribbleLab/Core/Onboarding/NotificationOnboardingCellView.swift b/ScribbleLab/Core/Onboarding/NotificationOnboardingCellView.swift index c8c559467..4f07df96e 100644 --- a/ScribbleLab/Core/Onboarding/NotificationOnboardingCellView.swift +++ b/ScribbleLab/Core/Onboarding/NotificationOnboardingCellView.swift @@ -30,7 +30,7 @@ struct NotificationOnboardingCellView: View { case message, collaboration_request, permission var id: Int { - switch self { // permission, collaboration_request, message + switch self { case .message: 0 case .collaboration_request: @@ -99,7 +99,7 @@ struct NotificationOnboardingCellView: View { } for notification in notifications { - var id: Int { + var id: Int { // FIXME: switch `notification.reverseId` with notification.id if notifications == Notification.allCases.reversed() { notification.reverseId } else { @@ -178,8 +178,7 @@ struct NotificationOnboardingCellView: View { struct ScrollOffsetPreferenceKey: PreferenceKey { static var defaultValue: CGPoint = .zero - static func reduce(value: inout CGPoint, nextValue: () -> CGPoint) { - } + static func reduce(value: inout CGPoint, nextValue: () -> CGPoint) { } } struct NotificationAlertView: View { diff --git a/ScribbleLab/Core/Onboarding/NotificationOnboardingView.swift b/ScribbleLab/Core/Onboarding/NotificationOnboardingView.swift index b9f064e07..419afeb34 100644 --- a/ScribbleLab/Core/Onboarding/NotificationOnboardingView.swift +++ b/ScribbleLab/Core/Onboarding/NotificationOnboardingView.swift @@ -2,10 +2,25 @@ // NotificationOnboardingView.swift // ScribbleLab // -// Created by Nevio Hirani on 10.05.24. +// Copyright (c) 2023 - 2024 ScribbleLabApp. All rights reserved // +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Authors: +// - NH: https://github.com/N3v1 import SwiftUI +import ScribbleCoreServices struct NotificationOnboardingView: View { @State private var isNotificationGranted: Bool = false diff --git a/ScribbleLab/Core/Onboarding/OnboardingData.swift b/ScribbleLab/Core/Onboarding/OnboardingData.swift index e4a6facbf..6124c5eb5 100644 --- a/ScribbleLab/Core/Onboarding/OnboardingData.swift +++ b/ScribbleLab/Core/Onboarding/OnboardingData.swift @@ -2,8 +2,22 @@ // OnboardingData.swift // ScribbleLab // -// Created by Nevio Hirani on 09.05.24. +// Copyright (c) 2023 - 2024 ScribbleLabApp. All rights reserved // +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Authors: +// - NH: https://github.com/N3v1 import Foundation diff --git a/ScribbleLab/Core/Onboarding/OnboardingFeatureCell.swift b/ScribbleLab/Core/Onboarding/OnboardingFeatureCell.swift index 2ac5c7fc0..de96a178c 100644 --- a/ScribbleLab/Core/Onboarding/OnboardingFeatureCell.swift +++ b/ScribbleLab/Core/Onboarding/OnboardingFeatureCell.swift @@ -2,8 +2,22 @@ // OnboardingFeatureCell.swift // ScribbleLab // -// Created by Nevio Hirani on 09.05.24. +// Copyright (c) 2023 - 2024 ScribbleLabApp. All rights reserved // +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Authors: +// - NH: https://github.com/N3v1 import SwiftUI diff --git a/ScribbleLab/Core/Onboarding/OnboardingView.swift b/ScribbleLab/Core/Onboarding/OnboardingView.swift index 724a59f4c..731c8760e 100644 --- a/ScribbleLab/Core/Onboarding/OnboardingView.swift +++ b/ScribbleLab/Core/Onboarding/OnboardingView.swift @@ -2,8 +2,22 @@ // OnboardingView.swift // ScribbleLab // -// Created by Nevio Hirani on 09.05.24. +// Copyright (c) 2023 - 2024 ScribbleLabApp. All rights reserved // +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Authors: +// - NH: https://github.com/N3v1 import SwiftUI import ScribbleCoreServices diff --git a/ScribbleLab/Core/Plug-Ins/Timer/Model/PomodoroModel.swift b/ScribbleLab/Core/Plug-Ins/Timer/Model/PomodoroModel.swift deleted file mode 100644 index 2c9ff9d20..000000000 --- a/ScribbleLab/Core/Plug-Ins/Timer/Model/PomodoroModel.swift +++ /dev/null @@ -1,141 +0,0 @@ -// -// PomodoroModel.swift -// ScribbleLab -// -// Created by Nevio Hirani on 15.10.23. -// - -import SwiftUI - -class PomodoroModel: NSObject, ObservableObject, UNUserNotificationCenterDelegate { - // MARK: - Timer properties - @Published var progress: CGFloat = 1 - @Published var timerStringValue: String = "00:00" - @Published var estimatedFinishedTime: String = "" - @Published var isStarted: Bool = false - @Published var addNewTimer: Bool = false - - @Published var hour: Int = 0 - @Published var minutes: Int = 0 - @Published var seconds: Int = 0 - - // MARK: - Total Seconds - @Published var totalSeconds: Int = 0 - @Published var staticTotalSeconds: Int = 0 - - // MARK: - Post Timer Properties - @Published var isFinished: Bool = false - - // NS Object stuff - override init() { - super.init() - self.authorizeNotifications() - } - - // MARK: - Authorize Notifications - // swiftlint:disable line_length - func authorizeNotifications() { - UNUserNotificationCenter.current().requestAuthorization(options: [.sound, .alert, .badge, .provisional, .criticalAlert]) { _, _ in - - } - - // MARK: In-app notification - UNUserNotificationCenter.current().delegate = self - } - // swiftlint:enable line_length - func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { - completionHandler([.sound, .banner]) - } - // MARK: - Start Timer - func startTimer() { - withAnimation(.easeInOut(duration: 0.25)) { isStarted = true } - // MARK: Time String Value - timerStringValue = "\(hour == 0 ? "" : "\(hour):")\(minutes >= 10 ? "\(minutes)" : "0\(minutes)"):\(seconds>=10 ? "\(seconds)" : "0\(seconds)")" - // MARK: Calculate Total Seconds - /// 1 hour = 3600 sec ยท 1 min = 60 sec - totalSeconds = (hour * 3600) + (minutes * 60) + seconds - staticTotalSeconds = totalSeconds - addNewTimer = false - notifyWhenTimerEnds() - } - // MARK: - Stop Timer - func stopTimer() { - withAnimation { - isStarted = false - hour = 0 - minutes = 0 - seconds = 0 - progress = 1 - } - totalSeconds = 0 - staticTotalSeconds = 0 - timerStringValue = "00:00" - } - - // MARK: - Update Timer - func upadateTimer() { - totalSeconds -= 1 - progress = CGFloat(totalSeconds) / CGFloat(staticTotalSeconds) - progress = (progress < 0 ? 0 : progress) - // 60 min * 60 sec - // 1 hr = 3600 sec - hour = totalSeconds / 3600 - minutes = (totalSeconds / 60) % 60 - seconds = (totalSeconds % 60) - - timerStringValue = "\(hour == 0 ? "" : "\(hour):")\(minutes >= 10 ? "\(minutes)" : "0\(minutes)"):\(seconds>=10 ? "\(seconds)" : "0\(seconds)")" - - if hour == 0 && seconds == 0 && minutes == 0 { - isStarted = false - print("DEBUG: Finished") - isFinished = true - } - } - - // MARK: notification - /// A function that returns an push notification - /// - /// To configure the push notification's payload, the `UNMutableNotificationContent()` function has to be called. - /// - `content.title`: The notification's title - /// - `content.body`: The notification's description Text - /// - `contnet.sound`: The notification's sound - /// - /// To make the text localozable a `NSString.localizedUserNotificationString(forKey: "key", arguments: nil)` has to be used - /// - /// Delivering a notification: - /// - `let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)`: Trigger's the notification to deliver within 1 second `timeInterval: 1`. - /// - `let request = UNNotificationRequest(identifier: "MSG", content: content, trigger: trigger)`: Schedule the notification with the notification's payload and it's trigger - /// - `let center = UNUserNotificationCenter.current()` - /// - func notifyWhenTimerEnds() { - // Configure the notification's payload. - let content = UNMutableNotificationContent() - content.title = NSString.localizedUserNotificationString(forKey: "ScribbleLab", arguments: nil) - content.body = NSString.localizedUserNotificationString(forKey: "Your study timer has expired ๐ŸŽ‰", arguments: nil) - content.sound = UNNotificationSound.default - - // Deliver the notification in five seconds. - let trigger = UNTimeIntervalNotificationTrigger(timeInterval: TimeInterval(staticTotalSeconds), repeats: false) - let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger) // Schedule the notification. - let center = UNUserNotificationCenter.current() - center.add(request) { (error : Error?) in - if error != nil { - // Handle any errors - } - } - } - - // MARK: Calculate estimated finish time - /// A function that calculates the estimated finish time - /// - func getCurrentTime() -> String { - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "mm:ss" - return dateFormatter.string(from: Date()) - } - - func calculateEstimatedTime() { - - } - // swiftlint:enable line_length -} diff --git a/ScribbleLab/Core/Plug-Ins/Timer/View/SLStudyPomodoroTimerView.swift b/ScribbleLab/Core/Plug-Ins/Timer/View/SLStudyPomodoroTimerView.swift deleted file mode 100644 index 586e12162..000000000 --- a/ScribbleLab/Core/Plug-Ins/Timer/View/SLStudyPomodoroTimerView.swift +++ /dev/null @@ -1,247 +0,0 @@ -// -// SLStudyPomodoroTimerView.swift -// ScribbleLab -// -// Created by Nevio Hirani on 15.10.23. -// - -import SwiftUI - -struct SLStudyPomodoroTimerView: View { - @EnvironmentObject var pomodoroModel: PomodoroModel - - var body: some View { - NavigationStack { - VStack { - GeometryReader { proxy in - VStack(spacing: 15) { - // MARK: - Timer ring - ZStack { - // background - Circle() - .trim(from: 0, to: 1) - .stroke( - Color.black.opacity(0.09), - style: StrokeStyle(lineWidth: 35, lineCap: .round) - ) - - // shadow - Circle() - .stroke( LinearGradient(colors: [.red, .orange, .yellow], startPoint: .top, endPoint: .bottom), style: StrokeStyle(lineWidth: 35, lineCap: .round)) - .blur(radius: 10) - .opacity(0.1) - - // ring - Circle() - .trim(from: 0, to: pomodoroModel.progress) - .stroke( - LinearGradient( - colors: [.red, .orange, .yellow], - startPoint: .top, - endPoint: .bottom - ), style: StrokeStyle(lineWidth: 35, lineCap: .round) - ) - - // ring blur - Circle() - .trim(from: 0, to: pomodoroModel.progress) - .stroke( - LinearGradient( - colors: [.red, .orange, .yellow], - startPoint: .top, endPoint: .bottom - ), style: StrokeStyle(lineWidth: 35, lineCap: .round) - ) - .blur(radius: 10) - - // Timer string value - Text(pomodoroModel.timerStringValue) - .font(.system(size: 50, weight: .light)) - .rotationEffect(.init(degrees: 90)) - .animation(.none, value: pomodoroModel.progress) - - // Estimated end time - Text(pomodoroModel.getCurrentTime()) - } - .padding(60) - .frame(height: proxy.size.width) - .rotationEffect(.init(degrees: -90)) - .animation(.easeInOut, value: pomodoroModel.progress) - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) - - Button { - if pomodoroModel.isStarted { - pomodoroModel.stopTimer() - // MARK: Cancel all notifications - UNUserNotificationCenter.current().removeAllPendingNotificationRequests() - } else { - pomodoroModel.addNewTimer = true - } - } label: { - Image(systemName: !pomodoroModel.isStarted ? "timer" : "stop.fill") - .font(.largeTitle.bold()) - .foregroundStyle(.white) - .frame(width: 80, height: 80) - .background { - Circle() - .fill(Color.black) - } - .shadow(color: .black,radius: 10) - } - } - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) - } - } - .padding() - .overlay { - ZStack { - Color.black - .opacity(pomodoroModel.addNewTimer ? 0.25 : 0) - .onTapGesture { - pomodoroModel.hour = 0 - pomodoroModel.minutes = 0 - pomodoroModel.seconds = 0 - - pomodoroModel.addNewTimer = false - } - - newTimerView() - .frame(maxHeight: .infinity, alignment: .bottom) - .offset(y: pomodoroModel.addNewTimer ? 0 : 400) - } - .animation(.easeInOut, value: pomodoroModel.addNewTimer) - } - .onReceive(Timer.publish(every: 1, on: .current, in: .common).autoconnect()) { _ in - if pomodoroModel.isStarted { - pomodoroModel.upadateTimer() - } - } - .alert("Your Study session is finished! ๐ŸŽ‰", isPresented: $pomodoroModel.isFinished) { - Button(role: .destructive) { - pomodoroModel.stopTimer() - } label: { - Text("Close") - .fontWeight(.semibold) - .foregroundStyle(.red) - } - - Button("Start new", role: .cancel) { - pomodoroModel.stopTimer() - pomodoroModel.addNewTimer = true - } - - } - .navigationTitle("Pomodoro Timer") - .navigationBarTitleDisplayMode(.inline) - } - } - - // MARK: New Timer Bottom Sheet - // swiftlint:disable function_body_length - @ViewBuilder - func newTimerView() -> some View { - VStack(spacing: 15) { - Text("Add New Timer") - .font(.title2.bold()) - .foregroundStyle(.black) - .padding(.top, 10) - - HStack(spacing: 15) { - Text("\(pomodoroModel.hour) hr") - .font(.title3) - .fontWeight(.semibold) - .foregroundStyle(.black.opacity(0.3)) - .padding(.horizontal, 20) - .padding(.vertical, 12) - .background { - Capsule() - .fill(.black.opacity(0.07)) - } - .contextMenu { - ContextMenuOptions(maxValue: 12, hint: "hr") { value in - pomodoroModel.hour = value - } - } - - Text("\(pomodoroModel.minutes) min") - .font(.title3) - .fontWeight(.semibold) - .foregroundStyle(.black.opacity(0.3)) - .padding(.horizontal, 20) - .padding(.vertical, 12) - .background { - Capsule() - .fill(.black.opacity(0.07)) - } - .contextMenu { - ContextMenuOptions(maxValue: 60, hint: "min") { value in - pomodoroModel.minutes = value - } - } - - Text("\(pomodoroModel.seconds) sec") - .font(.title3) - .fontWeight(.semibold) - .foregroundStyle(.black.opacity(0.3)) - .padding(.horizontal, 20) - .padding(.vertical, 12) - .background { - Capsule() - .fill(.black.opacity(0.07)) - } - .contextMenu { - ContextMenuOptions(maxValue: 60, hint: "sec") { value in - pomodoroModel.seconds = value - } - } - } - .padding(.top, 20) - - Button { - pomodoroModel.startTimer() - } label: { - Text("Save") - .font(.title3) - .fontWeight(.semibold) - .foregroundStyle(.white) - .padding(.horizontal, 100) - .padding(.vertical) - .background { - Capsule() - .foregroundStyle(.black) - } - } - .disabled(pomodoroModel.seconds == 0) - .opacity(pomodoroModel.seconds == 0 ? 0.5 : 1) - .padding(.top) - } - .padding() - .frame(maxWidth: .infinity) - .background { - RoundedRectangle(cornerRadius: 10, style: .continuous) - .fill(Color.white) - .ignoresSafeArea() - } - } - // swiftlint:enable function_body_length - - // MARK: Reusable Context Menu Options - // swiftlint:disable identifier_name - // swiftlint:disable void_return - // swiftlint:disable return_arrow_whitespace - @ViewBuilder - func ContextMenuOptions(maxValue: Int, hint: String, onClick: @escaping (Int)->()) -> some View { - ForEach(0...maxValue, id: \.self) { value in - Button("\(value) \(hint)") { - onClick(value) - } - } - } - // swiftlint:enable identifier_name - // swiftlint:enable void_return - // swiftlint:enable return_arrow_whitespace -} - -#Preview { - SLStudyPomodoroTimerView() - .environmentObject(PomodoroModel()) -} diff --git a/ScribbleLab/Ressources/Localizable.xcstrings b/ScribbleLab/Ressources/Localizable.xcstrings index 0d3709aca..c5c8e2f1e 100644 --- a/ScribbleLab/Ressources/Localizable.xcstrings +++ b/ScribbleLab/Ressources/Localizable.xcstrings @@ -193,6 +193,7 @@ } }, "%lld %@" : { + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -215,6 +216,7 @@ } }, "%lld hr" : { + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -231,6 +233,7 @@ } }, "%lld min" : { + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -247,6 +250,7 @@ } }, "%lld sec" : { + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -505,9 +509,6 @@ } } } - }, - "Add New Timer" : { - }, "Allow document syncing" : { "localizations" : { @@ -787,9 +788,6 @@ }, "Click below to complete registration and start using ScribbleLab" : { - }, - "Close" : { - }, "Cloud Storage & Backup" : { @@ -1602,9 +1600,6 @@ }, "Photo Libary" : { - }, - "Pomodoro Timer" : { - }, "Pre-Releases & Dev-Builds" : { @@ -1723,9 +1718,6 @@ }, "Restart Application" : { - }, - "Save" : { - }, "Scan document" : { @@ -1860,9 +1852,6 @@ }, "Sort By" : { - }, - "Start new" : { - }, "Status" : { @@ -2276,9 +2265,6 @@ }, "Your ScribbleLab Account information is used to enable services when you sign in, including other features like live collaboration, ... [**See how your data is managed...**](https://github.com/ScribbleLabApp/ScribbleLab)" : { - }, - "Your Study session is finished! ๐ŸŽ‰" : { - } }, "version" : "1.0"