From 8c82cd4a3b173bc55b6b4b283966af896e8b8b3c Mon Sep 17 00:00:00 2001 From: "Kosrat D. Ahmed" Date: Wed, 20 Mar 2024 22:57:14 +0300 Subject: [PATCH 1/7] Add repository pattern to the codebase --- Example/MuslimData.xcodeproj/project.pbxproj | 20 -- .../AzkarChaptersViewController.swift | 6 +- .../AzkarDetailViewController.swift | 8 +- .../MuslimData/LocationViewController.swift | 6 +- Example/MuslimData/NamesViewController.swift | 7 +- .../MuslimData/PrayersViewController.swift | 18 +- Example/Pods/Pods.xcodeproj/project.pbxproj | 52 ++-- Example/Tests/AzkarTests.swift | 256 +++++++----------- .../CityMapperTests/IQCityMapperTests.swift | 165 ----------- .../CityMapperTests/IRCityMapperTests.swift | 34 --- .../CityMapperTests/KWCityMapperTests.swift | 95 ------- Example/Tests/LocationTests.swift | 133 +++++---- Example/Tests/NamesTest.swift | 66 ++--- Example/Tests/PrayerTests.swift | 114 ++------ .../Azkars/AzkarCategory.swift | 0 .../Azkars/AzkarChapter.swift | 0 .../Classes => Models}/Azkars/AzkarItem.swift | 0 .../Location/Location.swift | 0 .../Classes => Models}/Names/Language.swift | 0 .../Classes => Models}/Names/Name.swift | 0 .../Prayer Times/Prayer.swift | 22 ++ .../Prayer Times/PrayerAttribute.swift | 0 .../Prayer Times/PrayerTime.swift | 70 +---- .../Prayer Times/TimeFormat.swift | 0 MuslimData/Classes/Azkars/Azkars.swift | 68 ----- MuslimData/Classes/DB Helper/DBHelper.swift | 255 +++++++++++------ .../Classes/Extensions/DateExtensions.swift | 11 + .../Extensions/String+Extensions.swift | 26 -- .../Classes/Location/LocationHelper.swift | 130 --------- MuslimData/Classes/Names/Names.swift | 29 -- README.md | 2 +- Repository/MuslimRepository.swift | 106 ++++++++ 32 files changed, 577 insertions(+), 1122 deletions(-) delete mode 100644 Example/Tests/CityMapperTests/IQCityMapperTests.swift delete mode 100644 Example/Tests/CityMapperTests/IRCityMapperTests.swift delete mode 100644 Example/Tests/CityMapperTests/KWCityMapperTests.swift rename {MuslimData/Classes => Models}/Azkars/AzkarCategory.swift (100%) rename {MuslimData/Classes => Models}/Azkars/AzkarChapter.swift (100%) rename {MuslimData/Classes => Models}/Azkars/AzkarItem.swift (100%) rename {MuslimData/Classes => Models}/Location/Location.swift (100%) rename {MuslimData/Classes => Models}/Names/Language.swift (100%) rename {MuslimData/Classes => Models}/Names/Name.swift (100%) rename {MuslimData/Classes => Models}/Prayer Times/Prayer.swift (94%) rename {MuslimData/Classes => Models}/Prayer Times/PrayerAttribute.swift (100%) rename {MuslimData/Classes => Models}/Prayer Times/PrayerTime.swift (50%) rename {MuslimData/Classes => Models}/Prayer Times/TimeFormat.swift (100%) delete mode 100755 MuslimData/Classes/Azkars/Azkars.swift delete mode 100755 MuslimData/Classes/Location/LocationHelper.swift delete mode 100755 MuslimData/Classes/Names/Names.swift create mode 100644 Repository/MuslimRepository.swift diff --git a/Example/MuslimData.xcodeproj/project.pbxproj b/Example/MuslimData.xcodeproj/project.pbxproj index 96d43d0..a1ffbce 100755 --- a/Example/MuslimData.xcodeproj/project.pbxproj +++ b/Example/MuslimData.xcodeproj/project.pbxproj @@ -11,9 +11,6 @@ 2D1D63A32B9CCF2100DBC74B /* MIGRATION_GUIDE.md in Resources */ = {isa = PBXBuildFile; fileRef = 2D1D63A22B9CCF2100DBC74B /* MIGRATION_GUIDE.md */; }; 2D27AC4B2188E621004722BD /* LocationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D27AC4A2188E621004722BD /* LocationViewController.swift */; }; 2D4558BA21694A5200A08DAF /* LocationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D4558B921694A5200A08DAF /* LocationTests.swift */; }; - 2D4EC4D42B835D7C00F08DCB /* IQCityMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D4EC4D32B835D7C00F08DCB /* IQCityMapperTests.swift */; }; - 2D4EC4D72B83637A00F08DCB /* IRCityMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D4EC4D62B83637A00F08DCB /* IRCityMapperTests.swift */; }; - 2D4EC4D92B83639E00F08DCB /* KWCityMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D4EC4D82B83639E00F08DCB /* KWCityMapperTests.swift */; }; 2D6B21C421708D600054F8C0 /* NamesTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D6B21C321708D600054F8C0 /* NamesTest.swift */; }; 2D9FC355217278E0003EF074 /* AzkarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D9FC354217278E0003EF074 /* AzkarTests.swift */; }; 2DBD7E7B218E01AF00B6595B /* AzkarChaptersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DBD7E7A218E01AF00B6595B /* AzkarChaptersViewController.swift */; }; @@ -45,9 +42,6 @@ 2D1D63A22B9CCF2100DBC74B /* MIGRATION_GUIDE.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = MIGRATION_GUIDE.md; path = ../MIGRATION_GUIDE.md; sourceTree = ""; }; 2D27AC4A2188E621004722BD /* LocationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationViewController.swift; sourceTree = ""; }; 2D4558B921694A5200A08DAF /* LocationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationTests.swift; sourceTree = ""; }; - 2D4EC4D32B835D7C00F08DCB /* IQCityMapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IQCityMapperTests.swift; sourceTree = ""; }; - 2D4EC4D62B83637A00F08DCB /* IRCityMapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IRCityMapperTests.swift; sourceTree = ""; }; - 2D4EC4D82B83639E00F08DCB /* KWCityMapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KWCityMapperTests.swift; sourceTree = ""; }; 2D6B21C321708D600054F8C0 /* NamesTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NamesTest.swift; sourceTree = ""; }; 2D9FC354217278E0003EF074 /* AzkarTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AzkarTests.swift; sourceTree = ""; }; 2DBD7E7A218E01AF00B6595B /* AzkarChaptersViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AzkarChaptersViewController.swift; sourceTree = ""; }; @@ -104,16 +98,6 @@ name = Pods; sourceTree = ""; }; - 2D4EC4D52B83634200F08DCB /* CityMapperTests */ = { - isa = PBXGroup; - children = ( - 2D4EC4D32B835D7C00F08DCB /* IQCityMapperTests.swift */, - 2D4EC4D62B83637A00F08DCB /* IRCityMapperTests.swift */, - 2D4EC4D82B83639E00F08DCB /* KWCityMapperTests.swift */, - ); - path = CityMapperTests; - sourceTree = ""; - }; 2DBD7E7C218E01BF00B6595B /* Azkars */ = { isa = PBXGroup; children = ( @@ -214,7 +198,6 @@ 607FACE81AFB9204008FA782 /* Tests */ = { isa = PBXGroup; children = ( - 2D4EC4D52B83634200F08DCB /* CityMapperTests */, 2D9FC354217278E0003EF074 /* AzkarTests.swift */, 2D6B21C321708D600054F8C0 /* NamesTest.swift */, 2D110EDD216BE7FB002035FA /* PrayerTests.swift */, @@ -466,12 +449,9 @@ buildActionMask = 2147483647; files = ( 2D110EDE216BE7FB002035FA /* PrayerTests.swift in Sources */, - 2D4EC4D92B83639E00F08DCB /* KWCityMapperTests.swift in Sources */, 2D6B21C421708D600054F8C0 /* NamesTest.swift in Sources */, 2D4558BA21694A5200A08DAF /* LocationTests.swift in Sources */, 2D9FC355217278E0003EF074 /* AzkarTests.swift in Sources */, - 2D4EC4D72B83637A00F08DCB /* IRCityMapperTests.swift in Sources */, - 2D4EC4D42B835D7C00F08DCB /* IQCityMapperTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Example/MuslimData/AzkarChaptersViewController.swift b/Example/MuslimData/AzkarChaptersViewController.swift index db4c8dd..c52cb5b 100755 --- a/Example/MuslimData/AzkarChaptersViewController.swift +++ b/Example/MuslimData/AzkarChaptersViewController.swift @@ -27,10 +27,8 @@ class AzkarChaptersViewController: UIViewController { chaptersTable.dataSource = self // Get azkar chapters from MuslimData library. - Azkars.azkarChapters(language: .en) { chapters, error in - guard error == nil else { - return - } + Task.init { + let chapters = try! await MuslimRepository().getAzkarChapters(language: .en) self.chapters = chapters! self.chaptersTable.reloadData() } diff --git a/Example/MuslimData/AzkarDetailViewController.swift b/Example/MuslimData/AzkarDetailViewController.swift index 4a2f245..883a466 100755 --- a/Example/MuslimData/AzkarDetailViewController.swift +++ b/Example/MuslimData/AzkarDetailViewController.swift @@ -30,11 +30,9 @@ class AzkarDetailViewController: UIViewController { azkarTable.tableFooterView = UIView() // Get azkar items from MuslimData library. - Azkars.azkarItems(language: .en, chapterId: azkarChapter!.id) { azkars, error in - guard error == nil else { - return - } - self.azkars = azkars! + Task.init { + let items = try! await MuslimRepository().getAzkarItems(language: .en, chapterId: azkarChapter!.id) + self.azkars = items! self.azkarTable.reloadData() } } diff --git a/Example/MuslimData/LocationViewController.swift b/Example/MuslimData/LocationViewController.swift index bd0d1e1..f9e9d3b 100755 --- a/Example/MuslimData/LocationViewController.swift +++ b/Example/MuslimData/LocationViewController.swift @@ -70,10 +70,8 @@ extension LocationViewController: UISearchBarDelegate { locations.removeAll() return } - LocationHelper.shared.citySearch(searchBar.text!) { locations, error in - guard error == nil else { - return - } + Task.init { + let locations = try! await MuslimRepository().searchLocation(searchBar.text!) if let locations = locations { self.locations = locations } diff --git a/Example/MuslimData/NamesViewController.swift b/Example/MuslimData/NamesViewController.swift index 5a229a4..480d8b8 100755 --- a/Example/MuslimData/NamesViewController.swift +++ b/Example/MuslimData/NamesViewController.swift @@ -25,11 +25,8 @@ class NamesViewController: UIViewController { namesTable.dataSource = self - // Get names of allah from MuslimData. - Names.names(language: .en) { names, error in - guard error == nil else { - return - } + Task.init { + let names = try! await MuslimRepository().getNamesOfAllah(language: .en) self.names = names! self.namesTable.reloadData() } diff --git a/Example/MuslimData/PrayersViewController.swift b/Example/MuslimData/PrayersViewController.swift index f9e18e4..0e31a44 100755 --- a/Example/MuslimData/PrayersViewController.swift +++ b/Example/MuslimData/PrayersViewController.swift @@ -33,24 +33,22 @@ class PrayersViewController: UIViewController { super.viewWillAppear(animated) // Get prayer times - getPrayers() + Task.init { + try! await getPrayers() + } } // MARK: - Helper Methods /// Get prayer times from the MuslimData library - func getPrayers() { + func getPrayers() async throws { let offsets = [Double](repeating: 0, count: 6) let location = Location.loadSavedLocation() let attributes = PrayerAttribute(method: .makkah, asrMethod: .shafii, adjustAngle: .angleBased, offsets: offsets) - PrayerTime.getPrayerTimes(location: location, date: Date(), - attributes: attributes) { prayerTime, error in - guard error == nil else { - return - } - self.prayerTimes = prayerTime!.formatPrayers(.time12) - self.prayerTable.reloadData() - } + + let prayer = try await MuslimRepository().getPrayerTimes(location: location, date: Date(), attributes: attributes) + prayerTimes = prayer!.formatPrayers(.time12) + prayerTable.reloadData() let dateFormatter = DateFormatter() dateFormatter.dateFormat = "dd MMM yyyy" diff --git a/Example/Pods/Pods.xcodeproj/project.pbxproj b/Example/Pods/Pods.xcodeproj/project.pbxproj index 19ce00d..a5817f7 100755 --- a/Example/Pods/Pods.xcodeproj/project.pbxproj +++ b/Example/Pods/Pods.xcodeproj/project.pbxproj @@ -18,7 +18,6 @@ 11AAE1599E6093A219A889D2DAE80ECA /* StatementColumnConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD5F36FEF53D52328747380C3D59D187 /* StatementColumnConvertible.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; 121E4E7A4C0459415A9B883D506D3FBC /* ValueObservation+DatabaseValueConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E8F40C80B8B85C4393ED5F43C8ED116 /* ValueObservation+DatabaseValueConvertible.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; 13F6B7CE384A0A2CE2A7E12616535089 /* SQLExpressible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7093F7382D260704506C5464AFBC16F5 /* SQLExpressible.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 1423967A16BCB379BE339E4C573082CF /* Azkars.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D8F486496B9633B4BBEBB8F8AC33399 /* Azkars.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; 15BFA9419F7B8F44B90DB2A0685D8416 /* SQLGenerationContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33E1BA72AB090848D099FDE15FFCD602 /* SQLGenerationContext.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; 1958078CF71CEA9143902886C5B9C310 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A49D0B537A24E7B6779BDF2FF4BF1376 /* UIKit.framework */; }; 19EAAEBC608AA44323ABEE5E5C433F82 /* GRDB-Bridging.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C3DE7F469BC348F7C1DDC5196499B58 /* GRDB-Bridging.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -38,6 +37,7 @@ 2D0F97A52B813E8B003D46C5 /* CHANGELOG.md in Resources */ = {isa = PBXBuildFile; fileRef = 2D0F97A42B813E8B003D46C5 /* CHANGELOG.md */; }; 2D6CD44729CC5BF2009B527C /* muslim_db_v2.0.0.db in Resources */ = {isa = PBXBuildFile; fileRef = 2D6CD44629CC5BF2009B527C /* muslim_db_v2.0.0.db */; }; 2DAF0C709FAF6D288751DB00EB06B40C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FD7232797ACF3F6F7685B58BCDC00C7 /* Foundation.framework */; }; + 2DE6E95C2BA8D8010082A3CE /* MuslimRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DE6E95B2BA8D8010082A3CE /* MuslimRepository.swift */; }; 318B2D4FBE83F08BB67C2AA6A52977AB /* FTS5+QueryInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5779BFB97BB16F7C257E39CD28630594 /* FTS5+QueryInterface.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; 33FDF2697ECE2E34513CACBC1EDFDB51 /* DatabaseValueConvertible+RawRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1585FD241A9AC0D79B3E084E1A8B7B77 /* DatabaseValueConvertible+RawRepresentable.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; 35A9B68C8D7AC42A8187DC1F8AEC095A /* FTS3TokenizerDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C9ECD60B68221B76E253AA39B4B52E /* FTS3TokenizerDescriptor.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; @@ -99,7 +99,6 @@ 8691CEE725ED2C7C06E086770DB7757B /* Column.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E4B190F2E830A1BB55FBA48ACEA7E86 /* Column.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; 889F226413C21D59F2BFFBC2C92DB9EA /* SQLFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291780A00DC00211D75FBDEA9B09E764 /* SQLFunctions.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; 8C8DDF01955D5FB72AE73979CD218F36 /* AssociationAggregate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98583347F707576BCEA189427FC47A69 /* AssociationAggregate.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 8D172DEA8CB15655BCF753F343BABDA0 /* LocationHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A76849C47F3395C7AD6455AB2B7634D /* LocationHelper.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; 8F776D68D6DEFD38CCF85B4276D968E0 /* FTS3+QueryInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CD278A63004131343ECCF5C78B29392 /* FTS3+QueryInterface.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; 90DF4F4E9630E63609F3CF6642505E25 /* Record.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25DF833796CBC2D0F008C6638CF48BD2 /* Record.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; 91F28A0A35BA0F4F8FB3F005D7253C45 /* FTS5CustomTokenizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87F53F41F8B38930F8E492305ADD4866 /* FTS5CustomTokenizer.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; @@ -128,7 +127,6 @@ BA76D4525CC0A4865E2AAA90336118D8 /* SQLForeignKeyRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = F27BA0AAB3F0B8F0F6FBFD49B7969EA9 /* SQLForeignKeyRequest.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; BD802C1DC1B139EDAB311C7709A00CB0 /* DatabaseValueConvertible+Encodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A48FA30EC31431A33C17FAE91902EE /* DatabaseValueConvertible+Encodable.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; BE5A72CE583F45FF74F5334921FF9968 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FD7232797ACF3F6F7685B58BCDC00C7 /* Foundation.framework */; }; - C0B657B41E3B2EFEBF0C340107759317 /* Names.swift in Sources */ = {isa = PBXBuildFile; fileRef = 707CD218A0DD160B3BF52677AA016730 /* Names.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; C184186D7F480467C879626B3D8BF92A /* grdb_config.h in Headers */ = {isa = PBXBuildFile; fileRef = F4E91BB21A1925C004A070AB895D6B14 /* grdb_config.h */; settings = {ATTRIBUTES = (Public, ); }; }; C31B69B2E5A6B91C7202FCE6A3B6A1E4 /* FTS5TokenizerDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0938A7247E2982B82482760B0AC6123F /* FTS5TokenizerDescriptor.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; C4E2B1658AC3663D15AA9F2531B7BFD6 /* FetchableRecord+QueryInterfaceRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED2B193D223BFC78855A3B1DE8CED395 /* FetchableRecord+QueryInterfaceRequest.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; @@ -230,6 +228,7 @@ 2D0F97A42B813E8B003D46C5 /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = CHANGELOG.md; path = MuslimData/Assets/CHANGELOG.md; sourceTree = ""; }; 2D6CD44629CC5BF2009B527C /* muslim_db_v2.0.0.db */ = {isa = PBXFileReference; lastKnownFileType = file; name = muslim_db_v2.0.0.db; path = MuslimData/Assets/muslim_db_v2.0.0.db; sourceTree = ""; }; 2DC6A83C7FE2580E3F2A1AFBB2B117E6 /* PrayerAttribute.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PrayerAttribute.swift; sourceTree = ""; }; + 2DE6E95B2BA8D8010082A3CE /* MuslimRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MuslimRepository.swift; sourceTree = ""; }; 2E88CF46329DBA47B53B98F005E11EE3 /* MuslimData.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MuslimData.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 2F75C56ED8BD1951FC8172C608B20303 /* Pods-MuslimData_Example-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-MuslimData_Example-acknowledgements.plist"; sourceTree = ""; }; 2FFBDBD6E148D8CD2D3E5D40636ABE46 /* AzkarItem.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AzkarItem.swift; sourceTree = ""; }; @@ -266,7 +265,6 @@ 59FBE42988DD91F3D3C2B74D31996523 /* ValueObservation+CompactMap.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ValueObservation+CompactMap.swift"; path = "GRDB/ValueObservation/ValueObservation+CompactMap.swift"; sourceTree = ""; }; 5A02DA8BFACEE9E07FBD62D157FED96B /* SQLSpecificExpressible+QueryInterface.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SQLSpecificExpressible+QueryInterface.swift"; path = "GRDB/QueryInterface/SQL/SQLSpecificExpressible+QueryInterface.swift"; sourceTree = ""; }; 5A2F3326B33A6BC66E13954DF736BEAA /* GRDB.swift-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "GRDB.swift-dummy.m"; sourceTree = ""; }; - 5D8F486496B9633B4BBEBB8F8AC33399 /* Azkars.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = Azkars.swift; sourceTree = ""; }; 5E166D7E44FE057A6E248D6B423B0C81 /* DatabaseMigrator.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DatabaseMigrator.swift; path = GRDB/Migration/DatabaseMigrator.swift; sourceTree = ""; }; 5F5B13B296896404F68B81BDDB33598A /* SQLSelectable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SQLSelectable.swift; path = GRDB/QueryInterface/SQL/SQLSelectable.swift; sourceTree = ""; }; 5F997529A98C052DA7C12591E52C94D6 /* FetchedRecordsController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = FetchedRecordsController.swift; path = GRDB/Record/FetchedRecordsController.swift; sourceTree = ""; }; @@ -285,7 +283,6 @@ 6DE2E8EEA85B8FB4DB536F2DDA9089D0 /* DatabaseRegionObservation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DatabaseRegionObservation.swift; path = GRDB/Core/DatabaseRegionObservation.swift; sourceTree = ""; }; 6E4B190F2E830A1BB55FBA48ACEA7E86 /* Column.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Column.swift; path = GRDB/QueryInterface/SQL/Column.swift; sourceTree = ""; }; 6F74C3288A30C090F9DAE356D7F8CEF9 /* HasOneAssociation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HasOneAssociation.swift; path = GRDB/QueryInterface/Request/Association/HasOneAssociation.swift; sourceTree = ""; }; - 707CD218A0DD160B3BF52677AA016730 /* Names.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = Names.swift; sourceTree = ""; }; 7093F7382D260704506C5464AFBC16F5 /* SQLExpressible.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SQLExpressible.swift; path = GRDB/QueryInterface/SQL/SQLExpressible.swift; sourceTree = ""; }; 720E3E47CB7DDE45FA7550A02D097ACD /* MuslimData.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; path = MuslimData.podspec; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 730FF805483A83B2584256EEDC5D2639 /* Language.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = Language.swift; sourceTree = ""; }; @@ -313,7 +310,6 @@ 98583347F707576BCEA189427FC47A69 /* AssociationAggregate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AssociationAggregate.swift; path = GRDB/QueryInterface/Request/Association/AssociationAggregate.swift; sourceTree = ""; }; 988514746A18BB7288E7AE2B074B7196 /* SQLExpression.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SQLExpression.swift; path = GRDB/QueryInterface/SQL/SQLExpression.swift; sourceTree = ""; }; 9A0D52E8D92DD8E648D19B837936563A /* Pods_MuslimData_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MuslimData_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 9A76849C47F3395C7AD6455AB2B7634D /* LocationHelper.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LocationHelper.swift; sourceTree = ""; }; 9AC1744C057858332AA73845B0CE26D7 /* DatabaseValueConvertible+Decodable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "DatabaseValueConvertible+Decodable.swift"; path = "GRDB/Core/Support/StandardLibrary/DatabaseValueConvertible+Decodable.swift"; sourceTree = ""; }; 9B99EBD21496FBA605E3A375E86ED829 /* DatabaseValueConversion.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DatabaseValueConversion.swift; path = GRDB/Core/DatabaseValueConversion.swift; sourceTree = ""; }; 9C3DE7F469BC348F7C1DDC5196499B58 /* GRDB-Bridging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GRDB-Bridging.h"; path = "Support/GRDB-Bridging.h"; sourceTree = ""; }; @@ -477,10 +473,8 @@ isa = PBXGroup; children = ( 35291486FD48076A204DF52CCD6A72AC /* Location.swift */, - 9A76849C47F3395C7AD6455AB2B7634D /* LocationHelper.swift */, ); - name = Location; - path = MuslimData/Classes/Location; + path = Location; sourceTree = ""; }; 2B81C12C52C5CB2D888908B65FF9D6DD /* GRDB.swift */ = { @@ -492,6 +486,25 @@ path = GRDB.swift; sourceTree = ""; }; + 2DE6E95A2BA8D75D0082A3CE /* Repository */ = { + isa = PBXGroup; + children = ( + 2DE6E95B2BA8D8010082A3CE /* MuslimRepository.swift */, + ); + path = Repository; + sourceTree = ""; + }; + 2DE6E95D2BA8F1F30082A3CE /* Models */ = { + isa = PBXGroup; + children = ( + 5B32A0A6C3385773AA423D017A5BFE73 /* Azkars */, + 8D92D353CC7766D3072B3133A23D2705 /* Names */, + 2817A6C16C274658D2455BB0739C199E /* Location */, + F45771AD65677FDC2506D34994A89145 /* Prayer Times */, + ); + path = Models; + sourceTree = ""; + }; 4022D06EB0FD32BF668EE12AF2306B41 /* standard */ = { isa = PBXGroup; children = ( @@ -643,10 +656,8 @@ BB2B3F9D2BF7D6132661A531E7BB2F12 /* AzkarCategory.swift */, 94586B16D5D2DCA4B4E22C167DD17B61 /* AzkarChapter.swift */, 2FFBDBD6E148D8CD2D3E5D40636ABE46 /* AzkarItem.swift */, - 5D8F486496B9633B4BBEBB8F8AC33399 /* Azkars.swift */, ); - name = Azkars; - path = MuslimData/Classes/Azkars; + path = Azkars; sourceTree = ""; }; 6A7E60A4A85B5746C77AA59AF4549B00 /* Development Pods */ = { @@ -697,10 +708,8 @@ children = ( 730FF805483A83B2584256EEDC5D2639 /* Language.swift */, 401A16EADAEB6FE46A4F5411CCD2A9F3 /* Name.swift */, - 707CD218A0DD160B3BF52677AA016730 /* Names.swift */, ); - name = Names; - path = MuslimData/Classes/Names; + path = Names; sourceTree = ""; }; A08711B133A02CDCC7C1F09A0D69CB4A /* Products */ = { @@ -772,13 +781,11 @@ D6987B66A5B198235A8BB606A32FC336 /* MuslimData */ = { isa = PBXGroup; children = ( - 5B32A0A6C3385773AA423D017A5BFE73 /* Azkars */, 0540E1C8A51BDA08F9803F4F5C81C4A9 /* DB Helper */, 068C7933E1034C5E720F2FEE596A2051 /* Extensions */, - 2817A6C16C274658D2455BB0739C199E /* Location */, - 8D92D353CC7766D3072B3133A23D2705 /* Names */, + 2DE6E95D2BA8F1F30082A3CE /* Models */, + 2DE6E95A2BA8D75D0082A3CE /* Repository */, 6C85BC022E11396A542DB08BF82032BE /* Pod */, - F45771AD65677FDC2506D34994A89145 /* Prayer Times */, CF862A95B5D3FFC023257833F1193CE5 /* Resources */, 176ED022F62840DFBB6098DE94236B35 /* Support Files */, ); @@ -794,8 +801,7 @@ 6368FFE5512AD8AC9D36EB8427AFA109 /* PrayerTime.swift */, 65F554C03188A6F204B2036E5CF4B82D /* TimeFormat.swift */, ); - name = "Prayer Times"; - path = "MuslimData/Classes/Prayer Times"; + path = "Prayer Times"; sourceTree = ""; }; /* End PBXGroup section */ @@ -985,15 +991,13 @@ A2C07BA2D862B7CFEE16E632B97EF68C /* AzkarCategory.swift in Sources */, 4F3B7D7E1C44ECB7A2EBEC681ACE4090 /* AzkarChapter.swift in Sources */, 5301D3C1ECA5E2D47002FBE7724941FF /* AzkarItem.swift in Sources */, - 1423967A16BCB379BE339E4C573082CF /* Azkars.swift in Sources */, E4B3988CB85F30F8B1539CDFFC777DE8 /* DateExtensions.swift in Sources */, 567C4757D6C8959A805420C387798D94 /* DBHelper.swift in Sources */, 3A22C174B394CB9AF865557B3EA0D761 /* Language.swift in Sources */, 5B889DD74524BF47702D94225C8676BF /* Location.swift in Sources */, - 8D172DEA8CB15655BCF753F343BABDA0 /* LocationHelper.swift in Sources */, + 2DE6E95C2BA8D8010082A3CE /* MuslimRepository.swift in Sources */, A7D645073A4902CE19144733BD3B1D6B /* MuslimData-dummy.m in Sources */, FF616834C38743D535B62B7886C74F07 /* Name.swift in Sources */, - C0B657B41E3B2EFEBF0C340107759317 /* Names.swift in Sources */, EA0BC2897FF6BE975F969C15629840CB /* Prayer.swift in Sources */, 0AD24AEB225F135FE242003EA86E7039 /* PrayerAttribute.swift in Sources */, 4232F4B0DC26B878201F9523CEF8F761 /* PrayerTime.swift in Sources */, diff --git a/Example/Tests/AzkarTests.swift b/Example/Tests/AzkarTests.swift index a7430d1..6a887af 100755 --- a/Example/Tests/AzkarTests.swift +++ b/Example/Tests/AzkarTests.swift @@ -18,184 +18,138 @@ class AzkarTests: XCTestCase { // Put teardown code here. This method is called after the invocation of each test method in the class. } - func testAzkarCategories() { - // Test English azkar categories - Azkars.azkarCategories(language: .en) { categories, error in - XCTAssertNil(error) - XCTAssertNotNil(categories) - XCTAssertEqual(categories!.count, 11) - XCTAssertNotNil(categories![5].name) - } - - // Test Arabic azkar categories - Azkars.azkarCategories(language: .ar) { categories, error in - XCTAssertNil(error) - XCTAssertNotNil(categories) - XCTAssertEqual(categories!.count, 11) - XCTAssertNotNil(categories![10].name) - } - - // Test Central Kurdish azkar categories - Azkars.azkarCategories(language: .ckb) { categories, error in - XCTAssertNil(error) - XCTAssertNotNil(categories) - XCTAssertEqual(categories!.count, 11) - XCTAssertNotNil(categories![3].name) - } - - // Test Farsi azkar categories - Azkars.azkarCategories(language: .fa) { categories, error in - XCTAssertNil(error) - XCTAssertNotNil(categories) - XCTAssertEqual(categories!.count, 11) - XCTAssertNotNil(categories![1].name) - } - - // Test Russian azkar categories - Azkars.azkarCategories(language: .ru) { categories, error in - XCTAssertNil(error) - XCTAssertNotNil(categories) - XCTAssertEqual(categories!.count, 11) - XCTAssertNotNil(categories![7].name) - } - } - - func testAzkarChapters() { - // Test English azkar chapters - Azkars.azkarChapters(language: .en) { chapters, error in - XCTAssertNil(error) - XCTAssertNotNil(chapters) - XCTAssertEqual(chapters!.count, 133) - } - - // Test Arabic azkar chapters - Azkars.azkarChapters(language: .ar) { chapters, error in - XCTAssertNil(error) - XCTAssertNotNil(chapters) - XCTAssertEqual(chapters!.count, 133) - } - - // Test Central Kurdish azkar chapters - Azkars.azkarChapters(language: .ckb) { chapters, error in - XCTAssertNil(error) - XCTAssertNotNil(chapters) - XCTAssertEqual(chapters!.count, 133) - } - - // Test Farsi azkar chapters - Azkars.azkarChapters(language: .fa) { chapters, error in - XCTAssertNil(error) - XCTAssertNotNil(chapters) - XCTAssertEqual(chapters!.count, 133) - } - - // Test Russian azkar chapters - Azkars.azkarChapters(language: .ru) { chapters, error in - XCTAssertNil(error) - XCTAssertNotNil(chapters) - XCTAssertEqual(chapters!.count, 133) - } - } - - func testAzkarChaptersByCategory() { + func testEnAzkarCategories() async throws { + let categories = try await MuslimRepository().getAzkarCategories(language: .en) + assesAzkarCategories(categories: categories) + } + + func testArAzkarCategories() async throws { + let categories = try await MuslimRepository().getAzkarCategories(language: .ar) + assesAzkarCategories(categories: categories) + } + + func testCkbAzkarCategories() async throws { + let categories = try await MuslimRepository().getAzkarCategories(language: .ckb) + assesAzkarCategories(categories: categories) + } + + func testFaAzkarCategories() async throws { + let categories = try await MuslimRepository().getAzkarCategories(language: .fa) + assesAzkarCategories(categories: categories) + } + + func testRuAzkarCategories() async throws { + let categories = try await MuslimRepository().getAzkarCategories(language: .ru) + assesAzkarCategories(categories: categories) + } + + private func assesAzkarCategories(categories: [AzkarCategory]?) { + XCTAssertNotNil(categories) + XCTAssertEqual(categories!.count, 11) + XCTAssertNotNil(categories![Int.random(in: 0 ..< 11)].name) + } + + func testEnAzkarChapters() async throws { + let chapters = try await MuslimRepository().getAzkarChapters(language: .en) + assesAzkarChapters(chapters: chapters) + } + + func testArAzkarChapters() async throws { + let chapters = try await MuslimRepository().getAzkarChapters(language: .ar) + assesAzkarChapters(chapters: chapters) + } + + func testCkbAzkarChapters() async throws { + let chapters = try await MuslimRepository().getAzkarChapters(language: .ckb) + assesAzkarChapters(chapters: chapters) + } + + func testFaAzkarChapters() async throws { + let chapters = try await MuslimRepository().getAzkarChapters(language: .fa) + assesAzkarChapters(chapters: chapters) + } + + func testRuAzkarChapters() async throws { + let chapters = try await MuslimRepository().getAzkarChapters(language: .ru) + assesAzkarChapters(chapters: chapters) + } + + private func assesAzkarChapters(chapters: [AzkarChapter]?) { + XCTAssertNotNil(chapters) + XCTAssertEqual(chapters!.count, 133) + } + + func testAzkarChaptersByCategory() async throws { // Test English azkar chapters for category id = 1 - Azkars.azkarChapters(language: .en, categoryId: 1) { chapters, error in - XCTAssertNil(error) - XCTAssertNotNil(chapters) - XCTAssertEqual(chapters!.count, 7) - } + var chapters = try await MuslimRepository().getAzkarChapters(language: .en, categoryId: 1) + XCTAssertNotNil(chapters) + XCTAssertEqual(chapters!.count, 7) // Test English azkar chapters for category id = 2 - Azkars.azkarChapters(language: .en, categoryId: 2) { chapters, error in - XCTAssertNil(error) - XCTAssertNotNil(chapters) - XCTAssertEqual(chapters!.count, 14) - } + chapters = try await MuslimRepository().getAzkarChapters(language: .en, categoryId: 2) + XCTAssertNotNil(chapters) + XCTAssertEqual(chapters!.count, 14) // Test English azkar chapters for category id = 3 - Azkars.azkarChapters(language: .en, categoryId: 3) { chapters, error in - XCTAssertNil(error) - XCTAssertNotNil(chapters) - XCTAssertEqual(chapters!.count, 7) - } + chapters = try await MuslimRepository().getAzkarChapters(language: .en, categoryId: 3) + XCTAssertNotNil(chapters) + XCTAssertEqual(chapters!.count, 7) // Test English azkar chapters for category id = 4 - Azkars.azkarChapters(language: .en, categoryId: 4) { chapters, error in - XCTAssertNil(error) - XCTAssertNotNil(chapters) - XCTAssertEqual(chapters!.count, 15) - } + chapters = try await MuslimRepository().getAzkarChapters(language: .en, categoryId: 4) + XCTAssertNotNil(chapters) + XCTAssertEqual(chapters!.count, 15) // Test English azkar chapters for category id = 5 - Azkars.azkarChapters(language: .en, categoryId: 5) { chapters, error in - XCTAssertNil(error) - XCTAssertNotNil(chapters) - XCTAssertEqual(chapters!.count, 11) - } + chapters = try await MuslimRepository().getAzkarChapters(language: .en, categoryId: 5) + XCTAssertNotNil(chapters) + XCTAssertEqual(chapters!.count, 11) // Test English azkar chapters for category id = 6 - Azkars.azkarChapters(language: .en, categoryId: 6) { chapters, error in - XCTAssertNil(error) - XCTAssertNotNil(chapters) - XCTAssertEqual(chapters!.count, 19) - } + chapters = try await MuslimRepository().getAzkarChapters(language: .en, categoryId: 6) + XCTAssertNotNil(chapters) + XCTAssertEqual(chapters!.count, 19) // Test English azkar chapters for category id = 7 - Azkars.azkarChapters(language: .en, categoryId: 7) { chapters, error in - XCTAssertNil(error) - XCTAssertNotNil(chapters) - XCTAssertEqual(chapters!.count, 9) - } + chapters = try await MuslimRepository().getAzkarChapters(language: .en, categoryId: 7) + XCTAssertNotNil(chapters) + XCTAssertEqual(chapters!.count, 9) // Test English azkar chapters for category id = 8 - Azkars.azkarChapters(language: .en, categoryId: 8) { chapters, error in - XCTAssertNil(error) - XCTAssertNotNil(chapters) - XCTAssertEqual(chapters!.count, 8) - } + chapters = try await MuslimRepository().getAzkarChapters(language: .en, categoryId: 8) + XCTAssertNotNil(chapters) + XCTAssertEqual(chapters!.count, 8) // Test English azkar chapters for category id = 9 - Azkars.azkarChapters(language: .en, categoryId: 9) { chapters, error in - XCTAssertNil(error) - XCTAssertNotNil(chapters) - XCTAssertEqual(chapters!.count, 20) - } + chapters = try await MuslimRepository().getAzkarChapters(language: .en, categoryId: 9) + XCTAssertNotNil(chapters) + XCTAssertEqual(chapters!.count, 20) // Test English azkar chapters for category id = 10 - Azkars.azkarChapters(language: .en, categoryId: 10) { chapters, error in - XCTAssertNil(error) - XCTAssertNotNil(chapters) - XCTAssertEqual(chapters!.count, 10) - } + chapters = try await MuslimRepository().getAzkarChapters(language: .en, categoryId: 10) + XCTAssertNotNil(chapters) + XCTAssertEqual(chapters!.count, 10) // Test English azkar chapters for category id = 11 - Azkars.azkarChapters(language: .en, categoryId: 11) { chapters, error in - XCTAssertNil(error) - XCTAssertNotNil(chapters) - XCTAssertEqual(chapters!.count, 13) - } + chapters = try await MuslimRepository().getAzkarChapters(language: .en, categoryId: 11) + XCTAssertNotNil(chapters) + XCTAssertEqual(chapters!.count, 13) } - func testAzkarItems() { + func testAzkarItems() async throws { // Test English azkar items for chapter id = 1 - Azkars.azkarItems(language: .en, chapterId: 1) { items, error in - XCTAssertNil(error) - XCTAssertNotNil(items) - XCTAssertEqual(items!.count, 4) - } + var items = try await MuslimRepository().getAzkarItems(language: .en, chapterId: 1) + XCTAssertNotNil(items) + XCTAssertEqual(items!.count, 4) // Test English azkar items for chapter id = 10 - Azkars.azkarItems(language: .en, chapterId: 10) { items, error in - XCTAssertNil(error) - XCTAssertNotNil(items) - XCTAssertEqual(items!.count, 2) - } + items = try await MuslimRepository().getAzkarItems(language: .en, chapterId: 10) + XCTAssertNotNil(items) + XCTAssertEqual(items!.count, 2) // Test English azkar items for chapter id = 100 - Azkars.azkarItems(language: .en, chapterId: 100) { items, error in - XCTAssertNil(error) - XCTAssertNotNil(items) - XCTAssertEqual(items!.count, 1) - } + items = try await MuslimRepository().getAzkarItems(language: .en, chapterId: 100) + XCTAssertNotNil(items) + XCTAssertEqual(items!.count, 1) } } diff --git a/Example/Tests/CityMapperTests/IQCityMapperTests.swift b/Example/Tests/CityMapperTests/IQCityMapperTests.swift deleted file mode 100644 index 2ce6246..0000000 --- a/Example/Tests/CityMapperTests/IQCityMapperTests.swift +++ /dev/null @@ -1,165 +0,0 @@ -// -// IQCityMapperTests.swift -// MuslimData_Tests -// -// Created by Kosrat Ahmed on 19/02/2024. -// Copyright © 2024 CocoaPods. All rights reserved. -// - -@testable import MuslimData -import XCTest - -class IQCityMapperTests: XCTestCase { - override func setUp() { - super.setUp() - } - - override func tearDown() { - super.tearDown() - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testDuhokCityMapper() { - // TODO: Update city mapper test. -// XCTAssertEqual("Sumel".mapper(countryCode: "IQ"), "Duhok") -// XCTAssertEqual("Zawita".mapper(countryCode: "IQ"), "Duhok") -// XCTAssertEqual("Atrish".mapper(countryCode: "IQ"), "Duhok") -// XCTAssertEqual("Sharya".mapper(countryCode: "IQ"), "Duhok") -// XCTAssertEqual("Mrebah".mapper(countryCode: "IQ"), "Duhok") - } - - func testAkreCityMapper() { - // TODO: Update city mapper test. -// XCTAssertEqual("Amedi".mapper(countryCode: "IQ"), "Akre") -// XCTAssertEqual("Sulav".mapper(countryCode: "IQ"), "Akre") -// XCTAssertEqual("Kani".mapper(countryCode: "IQ"), "Akre") -// XCTAssertEqual("Sheladiz".mapper(countryCode: "IQ"), "Akre") -// XCTAssertEqual("Barzan".mapper(countryCode: "IQ"), "Akre") -// XCTAssertEqual("Bele".mapper(countryCode: "IQ"), "Akre") -// XCTAssertEqual("Shanidar".mapper(countryCode: "IQ"), "Akre") -// XCTAssertEqual("Bujal".mapper(countryCode: "IQ"), "Akre") -// XCTAssertEqual("Mergin".mapper(countryCode: "IQ"), "Akre") -// XCTAssertEqual("Susna".mapper(countryCode: "IQ"), "Akre") -// XCTAssertEqual("Sersink".mapper(countryCode: "IQ"), "Akre") - } - - func testBardarashCityMapper() { - // TODO: Update city mapper test. -// XCTAssertEqual("Mamuzin".mapper(countryCode: "IQ"), "Bardarash") - } - - func testErbilCityMapper() { - // TODO: Update city mapper test. -// XCTAssertEqual("Kalak".mapper(countryCode: "IQ"), "Erbil") -// XCTAssertEqual("Pirmam".mapper(countryCode: "IQ"), "Erbil") -// XCTAssertEqual("Shaqlawa".mapper(countryCode: "IQ"), "Erbil") -// XCTAssertEqual("Harir".mapper(countryCode: "IQ"), "Erbil") -// XCTAssertEqual("Khalifan".mapper(countryCode: "IQ"), "Erbil") -// XCTAssertEqual("Rawanduz".mapper(countryCode: "IQ"), "Erbil") -// XCTAssertEqual("Soran".mapper(countryCode: "IQ"), "Erbil") -// XCTAssertEqual("Mergasur".mapper(countryCode: "IQ"), "Erbil") -// XCTAssertEqual("Galala".mapper(countryCode: "IQ"), "Erbil") -// XCTAssertEqual("Choman".mapper(countryCode: "IQ"), "Erbil") -// XCTAssertEqual("Hiran".mapper(countryCode: "IQ"), "Erbil") -// XCTAssertEqual("Qushtapa".mapper(countryCode: "IQ"), "Erbil") -// XCTAssertEqual("Kasnazan".mapper(countryCode: "IQ"), "Erbil") - } - - func testQasreCityMapper() { - // TODO: Update city mapper test. -// XCTAssertEqual("Wallze".mapper(countryCode: "IQ"), "Qasre") -// XCTAssertEqual("Soraban".mapper(countryCode: "IQ"), "Qasre") -// XCTAssertEqual("Shnawa".mapper(countryCode: "IQ"), "Qasre") -// XCTAssertEqual("Rashdur".mapper(countryCode: "IQ"), "Qasre") -// XCTAssertEqual("Makosan".mapper(countryCode: "IQ"), "Qasre") -// XCTAssertEqual("Saya".mapper(countryCode: "IQ"), "Qasre") -// XCTAssertEqual("Walash".mapper(countryCode: "IQ"), "Qasre") -// XCTAssertEqual("Eskawa".mapper(countryCode: "IQ"), "Qasre") -// XCTAssertEqual("Xazena".mapper(countryCode: "IQ"), "Qasre") -// XCTAssertEqual("Dilman".mapper(countryCode: "IQ"), "Qasre") -// XCTAssertEqual("Sarkan".mapper(countryCode: "IQ"), "Qasre") -// XCTAssertEqual("Chomsak".mapper(countryCode: "IQ"), "Qasre") -// XCTAssertEqual("Qalat".mapper(countryCode: "IQ"), "Qasre") -// XCTAssertEqual("Koila".mapper(countryCode: "IQ"), "Qasre") -// XCTAssertEqual("Mawnan".mapper(countryCode: "IQ"), "Qasre") -// XCTAssertEqual("Wasan".mapper(countryCode: "IQ"), "Qasre") -// XCTAssertEqual("Choma".mapper(countryCode: "IQ"), "Qasre") -// XCTAssertEqual("Mergay Khwaru".mapper(countryCode: "IQ"), "Qasre") -// XCTAssertEqual("Kani bast".mapper(countryCode: "IQ"), "Qasre") - } - - func testKirkukCityMapper() { - // TODO: Update city mapper test. -// XCTAssertEqual("Taza Khurmatu".mapper(countryCode: "IQ"), "Kirkuk") - } - - func testSulaymaniyahCityMapper() { - // TODO: Update city mapper test. -// XCTAssertEqual("Mawat".mapper(countryCode: "IQ"), "Sulaymaniyah") -// XCTAssertEqual("Arbat".mapper(countryCode: "IQ"), "Sulaymaniyah") - } - - func testQaladizaCityMapper() { - // TODO: Update city mapper test. -// XCTAssertEqual("Halsho".mapper(countryCode: "IQ"), "Qaladiza") -// XCTAssertEqual("Nawdasht".mapper(countryCode: "IQ"), "Qaladiza") -// XCTAssertEqual("Tasluja".mapper(countryCode: "IQ"), "Qaladiza") -// XCTAssertEqual("Bazian".mapper(countryCode: "IQ"), "Qaladiza") -// XCTAssertEqual("Sangasar".mapper(countryCode: "IQ"), "Qaladiza") -// XCTAssertEqual("Zharawa".mapper(countryCode: "IQ"), "Qaladiza") -// XCTAssertEqual("Bngrd".mapper(countryCode: "IQ"), "Qaladiza") -// XCTAssertEqual("Hero".mapper(countryCode: "IQ"), "Qaladiza") - } - - func testDokanCityMapper() { - // TODO: Update city mapper test. -// XCTAssertEqual("Piramagroon".mapper(countryCode: "IQ"), "Dokan") - } - - func testRanyaCityMapper() { - // TODO: Update city mapper test. -// XCTAssertEqual("Hajiawa".mapper(countryCode: "IQ"), "Ranya") -// XCTAssertEqual("Sarkapkan".mapper(countryCode: "IQ"), "Ranya") -// XCTAssertEqual("Khalakan".mapper(countryCode: "IQ"), "Ranya") -// XCTAssertEqual("Taqtaq".mapper(countryCode: "IQ"), "Ranya") -// XCTAssertEqual("Hizop".mapper(countryCode: "IQ"), "Ranya") -// XCTAssertEqual("Chwarqurna".mapper(countryCode: "IQ"), "Ranya") - } - - func testChamchamalCityMapper() { - // TODO: Update city mapper test. -// XCTAssertEqual("Takiya".mapper(countryCode: "IQ"), "Chamchamal") -// XCTAssertEqual("Takiay Jabari".mapper(countryCode: "IQ"), "Chamchamal") -// XCTAssertEqual("Shorsh".mapper(countryCode: "IQ"), "Chamchamal") -// XCTAssertEqual("Aghjalar".mapper(countryCode: "IQ"), "Chamchamal") -// XCTAssertEqual("Sangaw".mapper(countryCode: "IQ"), "Chamchamal") - } - - func testDarbandikhanCityMapper() { - // TODO: Update city mapper test. -// XCTAssertEqual("Zalan".mapper(countryCode: "IQ"), "Darbandikhan") -// XCTAssertEqual("Gapilon".mapper(countryCode: "IQ"), "Darbandikhan") -// XCTAssertEqual("Chwarta".mapper(countryCode: "IQ"), "Darbandikhan") -// XCTAssertEqual("Barzinjah".mapper(countryCode: "IQ"), "Darbandikhan") -// XCTAssertEqual("Zarayan".mapper(countryCode: "IQ"), "Darbandikhan") -// XCTAssertEqual("Halebjai Taza".mapper(countryCode: "IQ"), "Darbandikhan") -// XCTAssertEqual("Qara Dagh".mapper(countryCode: "IQ"), "Darbandikhan") - } - - func testPenjwenCityMapper() { - // TODO: Update city mapper test. -// XCTAssertEqual("Garmk".mapper(countryCode: "IQ"), "Penjwen") -// XCTAssertEqual("Nalparez".mapper(countryCode: "IQ"), "Penjwen") -// XCTAssertEqual("Said Sadiq".mapper(countryCode: "IQ"), "Penjwen") -// XCTAssertEqual("Pshta".mapper(countryCode: "IQ"), "Penjwen") - } - - func testHalabjaCityMapper() { - // TODO: Update city mapper test. -// XCTAssertEqual("Sirwan".mapper(countryCode: "IQ"), "Halabja") -// XCTAssertEqual("Byara".mapper(countryCode: "IQ"), "Halabja") -// XCTAssertEqual("Tawella".mapper(countryCode: "IQ"), "Halabja") -// XCTAssertEqual("Balkha".mapper(countryCode: "IQ"), "Halabja") -// XCTAssertEqual("Khurmal".mapper(countryCode: "IQ"), "Halabja") - } -} diff --git a/Example/Tests/CityMapperTests/IRCityMapperTests.swift b/Example/Tests/CityMapperTests/IRCityMapperTests.swift deleted file mode 100644 index 247c730..0000000 --- a/Example/Tests/CityMapperTests/IRCityMapperTests.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// IRCityMapperTests.swift -// MuslimData_Tests -// -// Created by Kosrat Ahmed on 19/02/2024. -// Copyright © 2024 CocoaPods. All rights reserved. -// - -@testable import MuslimData -import XCTest - -class IRCityMapperTests: XCTestCase { - override func setUp() { - super.setUp() - } - - override func tearDown() { - super.tearDown() - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testSanandajCityMapper() { - // TODO: Update city mapper test. -// XCTAssertEqual("Kamyaran".mapper(countryCode: "IR"), "Sanandaj") -// XCTAssertEqual("Divandarreh".mapper(countryCode: "IR"), "Sanandaj") -// XCTAssertEqual("Dehgolan".mapper(countryCode: "IR"), "Sanandaj") -// XCTAssertEqual("Qorveh".mapper(countryCode: "IR"), "Sanandaj") - } - - func testUrmiaCityMapper() { - // TODO: Update city mapper test. -// XCTAssertEqual("Orumiyeh".mapper(countryCode: "IR"), "Urmia") - } -} diff --git a/Example/Tests/CityMapperTests/KWCityMapperTests.swift b/Example/Tests/CityMapperTests/KWCityMapperTests.swift deleted file mode 100644 index 0ccf8d9..0000000 --- a/Example/Tests/CityMapperTests/KWCityMapperTests.swift +++ /dev/null @@ -1,95 +0,0 @@ -// -// KWCityMapperTests.swift -// MuslimData_Tests -// -// Created by Kosrat Ahmed on 19/02/2024. -// Copyright © 2024 CocoaPods. All rights reserved. -// - -@testable import MuslimData -import XCTest - -class KWCityMapperTests: XCTestCase { - override func setUp() { - super.setUp() - } - - override func tearDown() { - super.tearDown() - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testAlAsimahCityMapper() { - // TODO: Update city mapper test. -// XCTAssertEqual("Kuwait City".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Dasman Palace".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Sharq".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Mirqab".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Jibla".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Dasma".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Daiya".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Salhia".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Bneid Al Qar".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Kaifan".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Mansouriya".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Abdullah al-Salem".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Nuzha".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Faiha".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Shamiya".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Rawda".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Adailiya".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Khaldiya".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Qadsiya".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Qortuba".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Surra".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Yarmouk".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Shuwaikh Industrial".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Rai".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Granada".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Sulaibikhat".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Doha".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Nahdha".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Jaber Al Ahmad".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Qairawan".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Ahmadi".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Al Wafrah".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Sabah Al Salem".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Messila".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Al-Masayel".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Adan".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Fnaitees".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Qusor".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Qurain".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Abu Fatira".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Mubarak Al Kabeer".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Jeleeb Al-Shuyoukh".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Eqaila".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Fintas".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Dahar".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Mahboula".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Hadiya".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Al-Riqqa".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Abu Halifa".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Fahad Al Ahmad".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Assabahiyah".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Mangaf".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Fahaheel".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("South Sabahiya".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Ali Sabah Al Salem".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Shalayhat Mina Abdullah".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Zour".mapper(countryCode: "KW"), "Al Asimah") -// XCTAssertEqual("Al Khiran".mapper(countryCode: "KW"), "Al Asimah") - } - - func testFailakaIslandCityMapper() { - // TODO: Update city mapper test. -// XCTAssertEqual("Zoor".mapper(countryCode: "KW"), "Failaka Island") -// XCTAssertEqual("Kubbar Island".mapper(countryCode: "KW"), "Failaka Island") -// XCTAssertEqual("Al-Nuwaiseeb".mapper(countryCode: "KW"), "Failaka Island") - } - - func testAbdaliCityMapper() { - // TODO: Update city mapper test. -// XCTAssertEqual("Jahra".mapper(countryCode: "KW"), "Abdali") - } -} diff --git a/Example/Tests/LocationTests.swift b/Example/Tests/LocationTests.swift index 81193de..dc9414f 100755 --- a/Example/Tests/LocationTests.swift +++ b/Example/Tests/LocationTests.swift @@ -10,94 +10,93 @@ import XCTest class LocationTests: XCTestCase { - var locationHelper: LocationHelper! - override func setUp() { super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. - locationHelper = LocationHelper.shared } override func tearDown() { - locationHelper = nil super.tearDown() - // Put teardown code here. This method is called after the invocation of each test method in the class. } - func testGeocoderName() { + func testLondonGBGeocod() async throws { // Test (London, GB) which has fixed prayer times. - locationHelper.geocoder(countryCode: "GB", locationName: "London") { location in - XCTAssertNotNil(location) - XCTAssertEqual(location!.latitude, 51.50853) - XCTAssertEqual(location!.longitude, -0.12574) - XCTAssertEqual(location!.hasFixedPrayerTime, true) - } + let location = try await MuslimRepository().geocoder(countryCode: "GB", locationName: "London") + XCTAssertNotNil(location) + XCTAssertEqual(location!.latitude, 51.50853) + XCTAssertEqual(location!.longitude, -0.12574) + XCTAssertEqual(location!.hasFixedPrayerTime, true) + } + func testUnknownGeocode() async throws { // Test Nil. - locationHelper.geocoder(countryCode: "abc", locationName: "Unknown") { location in - XCTAssertNil(location) - } + let location = try await MuslimRepository().geocoder(countryCode: "abc", locationName: "Unknown") + XCTAssertNil(location) + } + func testTehranIRGeocode() async throws { // Test (Tahran, IR) which hasn't fixed prayer times. - locationHelper.geocoder(countryCode: "IR", locationName: "Tehran") { location in - XCTAssertNotNil(location) - XCTAssertEqual(location!.latitude, 35.69439) - XCTAssertEqual(location!.longitude, 51.42151) - XCTAssertEqual(location!.hasFixedPrayerTime, false) - } + let location = try await MuslimRepository().geocoder(countryCode: "IR", locationName: "Tehran") + XCTAssertNotNil(location) + XCTAssertEqual(location!.latitude, 35.69439) + XCTAssertEqual(location!.longitude, 51.42151) + XCTAssertEqual(location!.hasFixedPrayerTime, false) + } - // Test (Soran, IQ) which has fixed prayer times by city mapper. - locationHelper.geocoder(countryCode: "IQ", locationName: "Soran") { location in - XCTAssertNotNil(location) - XCTAssertEqual(location!.latitude, 36.652686) - XCTAssertEqual(location!.longitude, 44.541427) - XCTAssertEqual(location!.hasFixedPrayerTime, true) - } + func testSoranIQGeocode() async throws { + // Test (Soran, IQ) which has fixed prayer times. + let location = try await MuslimRepository().geocoder(countryCode: "IQ", locationName: "Soran") + XCTAssertNotNil(location) + XCTAssertEqual(location!.latitude, 36.652686) + XCTAssertEqual(location!.longitude, 44.541427) + XCTAssertEqual(location!.hasFixedPrayerTime, true) + } - // Test (Qasre, IQ) which has fixed prayer times by city mapper. - locationHelper.geocoder(countryCode: "IQ", locationName: "Qasre") { location in - XCTAssertNotNil(location) - XCTAssertEqual(location!.latitude, 36.557804) - XCTAssertEqual(location!.longitude, 44.827805) - XCTAssertEqual(location!.hasFixedPrayerTime, true) - } + func testQasreIQGeocode() async throws { + // Test (Qasre, IQ) which has fixed prayer times. + let location = try await MuslimRepository().geocoder(countryCode: "IQ", locationName: "Qasre") + XCTAssertNotNil(location) + XCTAssertEqual(location!.latitude, 36.557804) + XCTAssertEqual(location!.longitude, 44.827805) + XCTAssertEqual(location!.hasFixedPrayerTime, true) } - func testGeocoderLocation() { + func testLondonGBReverseGeocode() async throws { // Test (London, GB) which has fixed prayer times. - locationHelper.reverseGeocoder(latitude: 51.50853, longitude: -0.12574) { location in - XCTAssertNotNil(location) - XCTAssertEqual(location!.name, "London") - XCTAssertEqual(location!.countryCode, "GB") - XCTAssertEqual(location!.countryName, "United Kingdom") - XCTAssertEqual(location!.hasFixedPrayerTime, true) - } + let location = try await MuslimRepository().reverseGeocoder(latitude: 51.50853, longitude: -0.12574) + XCTAssertNotNil(location) + XCTAssertEqual(location!.name, "London") + XCTAssertEqual(location!.countryCode, "GB") + XCTAssertEqual(location!.countryName, "United Kingdom") + XCTAssertEqual(location!.hasFixedPrayerTime, true) + } + func testTehranIRReverseGeocode() async throws { // Test (Tahran, IR) which hasn't fixed prayer times. - locationHelper.reverseGeocoder(latitude: 35.69439, longitude: 51.42151) { location in - XCTAssertNotNil(location) - XCTAssertEqual(location!.name, "Tehran") - XCTAssertEqual(location!.countryCode, "IR") - XCTAssertEqual(location!.countryName, "Iran") - XCTAssertEqual(location!.hasFixedPrayerTime, false) - } + let location = try await MuslimRepository().reverseGeocoder(latitude: 35.69439, longitude: 51.42151) + XCTAssertNotNil(location) + XCTAssertEqual(location!.name, "Tehran") + XCTAssertEqual(location!.countryCode, "IR") + XCTAssertEqual(location!.countryName, "Iran") + XCTAssertEqual(location!.hasFixedPrayerTime, false) + } - // Test (Soran, IQ) which has fixed prayer times by city mapper. - locationHelper.reverseGeocoder(latitude: 36.652686, longitude: 44.541427) { location in - XCTAssertNotNil(location) - XCTAssertEqual(location!.name, "Soran") - XCTAssertEqual(location!.countryCode, "IQ") - XCTAssertEqual(location!.countryName, "Iraq") - XCTAssertEqual(location!.hasFixedPrayerTime, true) - } + func testSoranIQReverseGeocode() async throws { + // Test (Soran, IQ) which has fixed prayer times. + let location = try await MuslimRepository().reverseGeocoder(latitude: 36.652686, longitude: 44.541427) + XCTAssertNotNil(location) + XCTAssertEqual(location!.name, "Soran") + XCTAssertEqual(location!.countryCode, "IQ") + XCTAssertEqual(location!.countryName, "Iraq") + XCTAssertEqual(location!.hasFixedPrayerTime, true) + } - // Test (Qasre, IQ) which has fixed prayer times by city mapper. - locationHelper.reverseGeocoder(latitude: 36.557804, longitude: 44.827805) { location in - XCTAssertNotNil(location) - XCTAssertEqual(location!.name, "Qasre") - XCTAssertEqual(location!.countryCode, "IQ") - XCTAssertEqual(location!.countryName, "Iraq") - XCTAssertEqual(location!.hasFixedPrayerTime, true) - } + func testQasreIQReverseGeocode() async throws { + // Test (Qasre, IQ) which has fixed prayer times. + let location = try await MuslimRepository().reverseGeocoder(latitude: 36.557804, longitude: 44.827805) + XCTAssertNotNil(location) + XCTAssertEqual(location!.name, "Qasre") + XCTAssertEqual(location!.countryCode, "IQ") + XCTAssertEqual(location!.countryName, "Iraq") + XCTAssertEqual(location!.hasFixedPrayerTime, true) } } diff --git a/Example/Tests/NamesTest.swift b/Example/Tests/NamesTest.swift index 2d88034..4e245b1 100755 --- a/Example/Tests/NamesTest.swift +++ b/Example/Tests/NamesTest.swift @@ -18,43 +18,33 @@ class NamesTest: XCTestCase { // Put teardown code here. This method is called after the invocation of each test method in the class. } - func testEnglishNames() { - Names.names(language: .en) { names, error in - XCTAssertNil(error) - XCTAssertNotNil(names) - XCTAssertEqual(names!.count, 99) - } - } - - func testArabicNames() { - Names.names(language: .ar) { names, error in - XCTAssertNil(error) - XCTAssertNotNil(names) - XCTAssertEqual(names!.count, 99) - } - } - - func testKurdishNames() { - Names.names(language: .ckb) { names, error in - XCTAssertNil(error) - XCTAssertNotNil(names) - XCTAssertEqual(names!.count, 99) - } - } - - func testFarsiNames() { - Names.names(language: .fa) { names, error in - XCTAssertNil(error) - XCTAssertNotNil(names) - XCTAssertEqual(names!.count, 99) - } - } - - func testRussianNames() { - Names.names(language: .ru) { names, error in - XCTAssertNil(error) - XCTAssertNotNil(names) - XCTAssertEqual(names!.count, 99) - } + func testEnglishNames() async throws { + let names = try await MuslimRepository().getNamesOfAllah(language: .en) + assesNames(names: names) + } + + func testArabicNames() async throws { + let names = try await MuslimRepository().getNamesOfAllah(language: .ar) + assesNames(names: names) + } + + func testKurdishNames() async throws { + let names = try await MuslimRepository().getNamesOfAllah(language: .ckb) + assesNames(names: names) + } + + func testFarsiNames() async throws { + let names = try await MuslimRepository().getNamesOfAllah(language: .fa) + assesNames(names: names) + } + + func testRussianNames() async throws { + let names = try await MuslimRepository().getNamesOfAllah(language: .ru) + assesNames(names: names) + } + + private func assesNames(names: [Name]?) { + XCTAssertNotNil(names) + XCTAssertEqual(names!.count, 99) } } diff --git a/Example/Tests/PrayerTests.swift b/Example/Tests/PrayerTests.swift index 0d778b4..bd2d23b 100755 --- a/Example/Tests/PrayerTests.swift +++ b/Example/Tests/PrayerTests.swift @@ -29,111 +29,29 @@ class PrayerTests: XCTestCase { // Put teardown code here. This method is called after the invocation of each test method in the class. } - func testAllFixedPrayerTimes() { - let locations = LocationHelper.shared.fixedPrayerTimesList() + func testAllFixedPrayerTimes() async throws { + let locations = try await MuslimRepository().getAllFixedPrayerLocations() let date = Date(timeIntervalSince1970: 1_709_206_718) // 2024/02/29 - locations!.forEach { location in + for location in locations! { print(location) - print(date) - PrayerTime.getPrayerTimes(location: location, date: date, attributes: self.attributes) { prayer, error in - XCTAssertNil(error) - XCTAssertNotNil(prayer) - } + let prayerTimes = try await MuslimRepository().getPrayerTimes(location: location, date: date, attributes: attributes) + XCTAssertNotNil(prayerTimes) } } - func testFixedPrayer() { - // Test fixed prayer times for Sulav, Iraq - let sulav = Location(id: 77342, name: "Sulav", latitude: 0.0, longitude: 0.0, countryCode: "IQ", - countryName: "Iraq", hasFixedPrayerTime: true, prayerDependentId: 77349) - PrayerTime.getPrayerTimes(location: sulav, date: date, attributes: attributes) { prayer, error in - XCTAssertNil(error) - XCTAssertNotNil(prayer) - let stringPrayer = prayer!.formatPrayers(.time24) - XCTAssertEqual(stringPrayer[0], "04:46") - XCTAssertEqual(stringPrayer[1], "06:11") - XCTAssertEqual(stringPrayer[2], "11:59") - XCTAssertEqual(stringPrayer[3], "15:13") - XCTAssertEqual(stringPrayer[4], "17:43") - XCTAssertEqual(stringPrayer[5], "18:58") - } - - // Test fixed prayer times for Erbil, Iraq - let erbil = Location(id: 77359, name: "Erbil", latitude: 0.0, longitude: 0.0, countryCode: "IQ", - countryName: "Iraq", hasFixedPrayerTime: true, prayerDependentId: nil) - PrayerTime.getPrayerTimes(location: erbil, date: date, attributes: attributes) { prayer, error in - XCTAssertNil(error) - XCTAssertNotNil(prayer) - let stringPrayer = prayer!.formatPrayers(.time24) - XCTAssertEqual(stringPrayer[0], "04:42") - XCTAssertEqual(stringPrayer[1], "06:10") - XCTAssertEqual(stringPrayer[2], "12:02") - XCTAssertEqual(stringPrayer[3], "15:10") - XCTAssertEqual(stringPrayer[4], "17:41") - XCTAssertEqual(stringPrayer[5], "18:56") - } - - // Test fixed prayer times for Baghdad, Iraq - let baghdad = Location(id: 77452, name: "Baghdad", latitude: 0.0, longitude: 0.0, countryCode: "IQ", - countryName: "Iraq", hasFixedPrayerTime: true, prayerDependentId: nil) - PrayerTime.getPrayerTimes(location: baghdad, date: date, attributes: attributes) { prayer, error in - XCTAssertNil(error) - XCTAssertNotNil(prayer) - let stringPrayer = prayer!.formatPrayers(.time24) -// 04:39 06:01 11:55 15:11 17:41 18:55 - XCTAssertEqual(stringPrayer[0], "04:40") - XCTAssertEqual(stringPrayer[1], "06:02") - XCTAssertEqual(stringPrayer[2], "11:56") - XCTAssertEqual(stringPrayer[3], "15:10") - XCTAssertEqual(stringPrayer[4], "17:40") - XCTAssertEqual(stringPrayer[5], "18:54") - } - - // Test fixed prayer times for Sanandaj, Iran - let sanandaj = Location(id: 154_907, name: "Sanandaj", latitude: 0.0, longitude: 0.0, countryCode: "IR", - countryName: "Iran", hasFixedPrayerTime: true, prayerDependentId: nil) - PrayerTime.getPrayerTimes(location: sanandaj, date: date, attributes: attributes) { prayer, error in - XCTAssertNil(error) - XCTAssertNotNil(prayer) - let stringPrayer = prayer!.formatPrayers(.time24) - XCTAssertEqual(stringPrayer[0], "05:04") - XCTAssertEqual(stringPrayer[1], "06:23") - XCTAssertEqual(stringPrayer[2], "12:29") - XCTAssertEqual(stringPrayer[3], "15:27") - XCTAssertEqual(stringPrayer[4], "18:04") - XCTAssertEqual(stringPrayer[5], "19:19") - } - - // Test fixed prayer times for Qasre, Iraq - let qasre = Location(id: 166_502, name: "Qasre", latitude: 0.0, longitude: 0.0, countryCode: "IQ", - countryName: "Iraq", hasFixedPrayerTime: true, prayerDependentId: nil) - PrayerTime.getPrayerTimes(location: qasre, date: date, attributes: attributes) { prayer, error in - XCTAssertNil(error) - XCTAssertNotNil(prayer) - let stringPrayer = prayer!.formatPrayers(.time24) - XCTAssertEqual(stringPrayer[0], "04:37") - XCTAssertEqual(stringPrayer[1], "06:05") - XCTAssertEqual(stringPrayer[2], "12:00") - XCTAssertEqual(stringPrayer[3], "15:06") - XCTAssertEqual(stringPrayer[4], "17:40") - XCTAssertEqual(stringPrayer[5], "18:55") - } - } - - func testCalculatedPrayer() { + func testCalculatedPrayer() async throws { // Test calculated prayer times for Mecca, Saudi Arabia let mecca = Location(id: 119_496, name: "Mecca", latitude: 21.42664, longitude: 39.82563, countryCode: "SA", countryName: "Saudi Arabia", hasFixedPrayerTime: false, prayerDependentId: nil) - PrayerTime.getPrayerTimes(location: mecca, date: date, attributes: attributes) { prayer, error in - XCTAssertNil(error) - XCTAssertNotNil(prayer) - let stringPrayer = prayer!.formatPrayers(.time24) - XCTAssertEqual(stringPrayer[0], "04:59") - XCTAssertEqual(stringPrayer[1], "06:15") - XCTAssertEqual(stringPrayer[2], "12:09") - XCTAssertEqual(stringPrayer[3], "15:30") - XCTAssertEqual(stringPrayer[4], "18:01") - XCTAssertEqual(stringPrayer[5], "19:31") - } + let prayer = try await MuslimRepository().getPrayerTimes(location: mecca, date: date, attributes: attributes) + + XCTAssertNotNil(prayer) + let stringPrayer = prayer!.formatPrayers(.time24) + XCTAssertEqual(stringPrayer[0], "04:59") + XCTAssertEqual(stringPrayer[1], "06:15") + XCTAssertEqual(stringPrayer[2], "12:09") + XCTAssertEqual(stringPrayer[3], "15:30") + XCTAssertEqual(stringPrayer[4], "18:01") + XCTAssertEqual(stringPrayer[5], "19:31") } } diff --git a/MuslimData/Classes/Azkars/AzkarCategory.swift b/Models/Azkars/AzkarCategory.swift similarity index 100% rename from MuslimData/Classes/Azkars/AzkarCategory.swift rename to Models/Azkars/AzkarCategory.swift diff --git a/MuslimData/Classes/Azkars/AzkarChapter.swift b/Models/Azkars/AzkarChapter.swift similarity index 100% rename from MuslimData/Classes/Azkars/AzkarChapter.swift rename to Models/Azkars/AzkarChapter.swift diff --git a/MuslimData/Classes/Azkars/AzkarItem.swift b/Models/Azkars/AzkarItem.swift similarity index 100% rename from MuslimData/Classes/Azkars/AzkarItem.swift rename to Models/Azkars/AzkarItem.swift diff --git a/MuslimData/Classes/Location/Location.swift b/Models/Location/Location.swift similarity index 100% rename from MuslimData/Classes/Location/Location.swift rename to Models/Location/Location.swift diff --git a/MuslimData/Classes/Names/Language.swift b/Models/Names/Language.swift similarity index 100% rename from MuslimData/Classes/Names/Language.swift rename to Models/Names/Language.swift diff --git a/MuslimData/Classes/Names/Name.swift b/Models/Names/Name.swift similarity index 100% rename from MuslimData/Classes/Names/Name.swift rename to Models/Names/Name.swift diff --git a/MuslimData/Classes/Prayer Times/Prayer.swift b/Models/Prayer Times/Prayer.swift similarity index 94% rename from MuslimData/Classes/Prayer Times/Prayer.swift rename to Models/Prayer Times/Prayer.swift index 95d782f..c3d6f9f 100755 --- a/MuslimData/Classes/Prayer Times/Prayer.swift +++ b/Models/Prayer Times/Prayer.swift @@ -214,6 +214,28 @@ open class Prayer { let tZone = Double(TimeZone.current.secondsFromGMT()) / 60.0 / 60.0 return getDatePrayerTimes(year, month: month, day: day, latitude: latitude, longitude: longitude, tZone: tZone) } + + static func getPrayerTimes(location: Location, date: Date, attributes: PrayerAttribute) -> PrayerTime? { + let prayers = Prayer(method: attributes.method, asrJuristic: attributes.asrMethod, + adjustHighLats: attributes.adjustAngle, timeFormat: .time24) + + let calculatedTimes = prayers.getPrayerTimes(date, latitude: location.latitude, + longitude: location.longitude) + // Check calculated prayer times for nullability. + guard let fajr = calculatedTimes["Fajr"], let sunrise = calculatedTimes["Sunrise"], + let dhuhr = calculatedTimes["Dhuhr"], let asr = calculatedTimes["Asr"], + let maghrib = calculatedTimes["Maghrib"], let isha = calculatedTimes["Isha"] + else { + return nil + } + + return PrayerTime(fajr: fajr.toDate(date), + sunrise: sunrise.toDate(date), + dhuhr: dhuhr.toDate(date), + asr: asr.toDate(date), + maghrib: maghrib.toDate(date), + isha: isha.toDate(date)) + } // set custom values for calculation parameters open func setCustomParams(_ params: [Double]) { diff --git a/MuslimData/Classes/Prayer Times/PrayerAttribute.swift b/Models/Prayer Times/PrayerAttribute.swift similarity index 100% rename from MuslimData/Classes/Prayer Times/PrayerAttribute.swift rename to Models/Prayer Times/PrayerAttribute.swift diff --git a/MuslimData/Classes/Prayer Times/PrayerTime.swift b/Models/Prayer Times/PrayerTime.swift similarity index 50% rename from MuslimData/Classes/Prayer Times/PrayerTime.swift rename to Models/Prayer Times/PrayerTime.swift index d7dede3..653f017 100755 --- a/MuslimData/Classes/Prayer Times/PrayerTime.swift +++ b/Models/Prayer Times/PrayerTime.swift @@ -18,12 +18,12 @@ public struct PrayerTime { public var maghrib: Date public var isha: Date - // MARK: - Private Methods + // MARK: - Internal Methods /// Apply offests to the current prayer times. /// /// - Parameter offsets: List of double values as prayer offsets. - private mutating func applyOffsets(_ offsets: [Double]) { + internal mutating func applyOffsets(_ offsets: [Double]) { fajr = fajr.addMinutes(offsets[0]) sunrise = sunrise.addMinutes(offsets[1]) dhuhr = dhuhr.addMinutes(offsets[2]) @@ -33,8 +33,7 @@ public struct PrayerTime { } /// Apply daylight saving time to the current prayer times. - private mutating func applyDST() { - + internal mutating func applyDST() { let isDST = TimeZone.current.isDaylightSavingTime() if isDST { @@ -49,69 +48,6 @@ public struct PrayerTime { // MARK: - Public Methods - /// Get prayer times from the prayer database. - /// - /// - Parameters: - /// - city: City name - /// - date: Prayer times date - /// - callback: Callback that will returen the prayer time when it has been found in the database. - public static func getPrayerTimes(location: Location, date: Date, attributes: PrayerAttribute, - callback: @escaping (PrayerTime?, String?) -> Void) { - if !location.hasFixedPrayerTime { - let prayers = Prayer(method: attributes.method, asrJuristic: attributes.asrMethod, - adjustHighLats: attributes.adjustAngle, timeFormat: .time24) - let calculatedTimes = prayers.getPrayerTimes(date, latitude: location.latitude, - longitude: location.longitude) - // Check calculated prayer times for nullability. - guard let fajr = calculatedTimes["Fajr"], let sunrise = calculatedTimes["Sunrise"], - let dhuhr = calculatedTimes["Dhuhr"], let asr = calculatedTimes["Asr"], - let maghrib = calculatedTimes["Maghrib"], let isha = calculatedTimes["Isha"] - else { - callback(nil, "") - return - } - - var prayerTime = PrayerTime(fajr: fajr.toDate(date), - sunrise: sunrise.toDate(date), - dhuhr: dhuhr.toDate(date), - asr: asr.toDate(date), - maghrib: maghrib.toDate(date), - isha: isha.toDate(date)) - prayerTime.applyOffsets(attributes.offsets) - callback(prayerTime, nil) - return - } - - DBHelper.shared.prayerTimes(location: location, date: date) { row, error in - guard error == nil else { - callback(nil, error) - return - } - // Getting data from columns - guard let fajr = row?["fajr"] as? String, - let sunrise = row?["sunrise"] as? String, - let dhuhr = row?["dhuhr"] as? String, - let asr = row?["asr"] as? String, - let maghrib = row?["maghrib"] as? String, - let isha = row?["isha"] as? String - else { - callback(nil, "All columns are not found in the row.") - return - } - - // Create PrayerTime object. - var prayerTime = PrayerTime(fajr: fajr.toDate(date), - sunrise: sunrise.toDate(date), - dhuhr: dhuhr.toDate(date), - asr: asr.toDate(date), - maghrib: maghrib.toDate(date), - isha: isha.toDate(date)) - prayerTime.applyOffsets(attributes.offsets) - prayerTime.applyDST() - callback(prayerTime, nil) - } - } - /// Format prayer times from Date object to String by "HH:mm" or "hh:mm a" pattern which /// depends on the given time format. /// diff --git a/MuslimData/Classes/Prayer Times/TimeFormat.swift b/Models/Prayer Times/TimeFormat.swift similarity index 100% rename from MuslimData/Classes/Prayer Times/TimeFormat.swift rename to Models/Prayer Times/TimeFormat.swift diff --git a/MuslimData/Classes/Azkars/Azkars.swift b/MuslimData/Classes/Azkars/Azkars.swift deleted file mode 100755 index 0ffae50..0000000 --- a/MuslimData/Classes/Azkars/Azkars.swift +++ /dev/null @@ -1,68 +0,0 @@ -// -// Azkars.swift -// MuslimData -// -// Created by Kosrat D. Ahmad on 10/13/18. -// - -import Foundation - -public enum Azkars { - // MARK: - Public Methods - - /// Get list of azkar categories which is localized by given language. - /// - /// - Parameters: - /// - language: Language of the azkar categories. - /// - callback: Callback that will return list of AzkarCategory object that contains - /// azkar category data or error message. - public static func azkarCategories(language: Language, callback: @escaping ([AzkarCategory]?, String?) -> Void) { - DBHelper.shared.azkarCategories(language: language) { categories, error in - guard error == nil else { - callback(nil, error) - return - } - - callback(categories, nil) - } - } - - /// Get list of azkar chapters which is localized by given language. - /// - /// - Parameters: - /// - language: Language of the azkar chapters. - /// - callback: Callback that will return list of AzkarChapter object that contains - /// azkar chapter data or error message. - public static func azkarChapters(language: Language, - categoryId: Int? = nil, - callback: @escaping ([AzkarChapter]?, String?) -> Void) { - DBHelper.shared.azkarChapters(language: language, categoryId: categoryId) { chapters, error in - guard error == nil else { - callback(nil, error) - return - } - - callback(chapters, nil) - } - } - - /// Get azkar items for specific azkar chapter from database which is localized by given language. - /// - /// - Parameters: - /// - language: Language of the chapter. - /// - chapterId: Chapter id for the azkar items. - /// - callback: Callback that will return list of AzkarItem object that contains azkar items data - /// or error message. - public static func azkarItems(language: Language, - chapterId: Int, - callback: @escaping ([AzkarItem]?, String?) -> Void) { - DBHelper.shared.azkarItems(language: language, chapterId: chapterId) { items, error in - guard error == nil else { - callback(nil, error) - return - } - - callback(items, nil) - } - } -} diff --git a/MuslimData/Classes/DB Helper/DBHelper.swift b/MuslimData/Classes/DB Helper/DBHelper.swift index 694c8b6..9a040e5 100755 --- a/MuslimData/Classes/DB Helper/DBHelper.swift +++ b/MuslimData/Classes/DB Helper/DBHelper.swift @@ -28,144 +28,237 @@ class DBHelper { } // MARK: - Public Methods - - func prayerTimes(location: Location, date: Date, callback: @escaping (Row?, String?) -> Void) { + + /// Get fixed prayer times from Muslim database. + /// - Parameters: + /// - location: Location object + /// - date: Prayer date + /// - Returns: PrayerTime instance. + func prayerTimes(location: Location, date: String) async throws -> PrayerTime? { do { - try dbPool?.read { dbConnect in + return try dbPool?.read { dbConnect in let result = try Row.fetchOne(dbConnect, sql: """ SELECT * FROM prayer_time - WHERE location_id = "\(location.prayerDependentId ?? location.id)" - and date = "\(formatPrayerDate(date))" + WHERE location_id = '\(location.prayerDependentId ?? location.id)' + and date = '\(date)' """) + guard let row = result else { - callback(nil, "Found nil while unwrapping result.") - return + print("Found nil while unwrapping result.") + return nil + } + + // Getting data from columns + guard let fajr = row["fajr"] as? String, + let sunrise = row["sunrise"] as? String, + let dhuhr = row["dhuhr"] as? String, + let asr = row["asr"] as? String, + let maghrib = row["maghrib"] as? String, + let isha = row["isha"] as? String + else { + print("All columns are not found in the row.") + return nil } - callback(row, nil) + + // Create PrayerTime object. + return PrayerTime(fajr: fajr.toDate(date), + sunrise: sunrise.toDate(date), + dhuhr: dhuhr.toDate(date), + asr: asr.toDate(date), + maghrib: maghrib.toDate(date), + isha: isha.toDate(date)) } } catch { - callback(nil, "Error: \(error.localizedDescription)") + print("Error: \(error.localizedDescription)") + return nil } } - /// Get 99 names of allah from database. + /// Get 99 names of Allah from database for the given language. /// /// - Parameters: /// - language: Language of the translated names. - /// - callback: Callback that will return list of names object or error message. - func names(language: Language, callback: @escaping ([Name]?, String?) -> Void) { + /// - Returns: List of [name]? of Allah + func names(language: Language) async throws -> [Name]? { do { - try dbPool?.read { dbConnect in - let result = try Name.fetchAll(dbConnect, sql: """ - SELECT org.name , tr.name as translated - FROM name as org - INNER JOIN name_translation as tr on tr.name_id = org._id and tr.language = "\(language)" + return try dbPool?.read { dbConnect in + let names = try Name.fetchAll(dbConnect, sql: """ + SELECT name.name , transl.name as translated + FROM name + INNER JOIN name_translation as transl on transl.name_id = name._id and transl.language = '\(language)' """) - guard result.count > 0 else { - callback(nil, "No row found") - return - } - callback(result, nil) + return names } } catch { - callback(nil, "Error: \(error.localizedDescription)") + print("Error: \(error.localizedDescription)") + return nil } } - /// Get azkar categories from database which is localized by given language. + /// Get azkar categories from database which is localized by the given language. /// /// - Parameters: /// - language: Language of the category. - /// - callback: Callback that will return list of AzkarCategory or error message. - func azkarCategories(language: Language, callback: @escaping ([AzkarCategory]?, String?) -> Void) { + /// - Returns: List of [AzkarCategory]? + func azkarCategories(language: Language) async throws -> [AzkarCategory]? { do { - try dbPool?.read { dbConnect in - let result = try AzkarCategory.fetchAll(dbConnect, sql: """ - SELECT org._id, category_name - FROM azkar_category as org - INNER JOIN azkar_category_translation as tr on tr.category_id = org._id - and language = "\(language)" + return try dbPool?.read { dbConnect in + let categories = try AzkarCategory.fetchAll(dbConnect, sql: """ + SELECT category._id, category_name + FROM azkar_category as category + INNER JOIN azkar_category_translation as transl on transl.category_id = category._id + and language = '\(language)' """) - guard result.count > 0 else { - callback(nil, "No row found") - return - } - callback(result, nil) + return categories } } catch { - callback(nil, "Error: \(error.localizedDescription)") + print("Error: \(error.localizedDescription)") + return nil } } /// Get azkar chapters from database which is localized by given language. - /// + /// /// - Parameters: /// - language: Language of the chapter. - /// - callback: Callback that will return list of AzkarChapter or error message. - func azkarChapters(language: Language, categoryId: Int? = nil, - callback: @escaping ([AzkarChapter]?, String?) -> Void) { + /// - categoryId: Optional category id + /// - Returns: List of [AzkarChapter]? + func azkarChapters(language: Language, categoryId: Int? = nil) async throws -> [AzkarChapter]? { var category = "" if let categoryId = categoryId { category = " and category_id = \(categoryId)" } do { - try dbPool?.read { dbConnect in - let result = try AzkarChapter.fetchAll(dbConnect, sql: """ - SELECT org._id, category_id, chapter_name - FROM azkar_chapter as org - INNER JOIN azkar_chapter_translation as tr on tr.chapter_id = org._id and language = "\(language)" - \(category) + return try dbPool?.read { dbConnect in + let chapters = try AzkarChapter.fetchAll(dbConnect, sql: """ + SELECT chapter._id, category_id, chapter_name + FROM azkar_chapter as chapter + INNER JOIN azkar_chapter_translation as transl on transl.chapter_id = chapter._id + and language = '\(language)' \(category) """) - guard result.count > 0 else { - callback(nil, "No row found") - return - } - callback(result, nil) + return chapters } } catch { - callback(nil, "Error: \(error.localizedDescription)") + print("Error: \(error.localizedDescription)") + return nil } } /// Get azkar items for specific azkar chapter from database which is localized by given language. - /// + /// /// - Parameters: /// - language: Language of the chapter. /// - chapterId: Chapter id for the azkar items. - /// - callback: Callback that will return list of AzkarItem or error message. - func azkarItems(language: Language, chapterId: Int, callback: @escaping ([AzkarItem]?, String?) -> Void) { + /// - Returns: List of [AskarItem]? + func azkarItems(language: Language, chapterId: Int) async throws -> [AzkarItem]? { do { - try dbPool?.read { dbConnect in - let result = try AzkarItem.fetchAll(dbConnect, sql: """ - SELECT org._id, org.chapter_id, org.item, tr.item_translation, rtr.reference - FROM azkar_item as org - INNER JOIN azkar_item_translation as tr on tr.item_id = org._id and tr.language = "\(language)" - and org.chapter_id = \(chapterId) - INNER JOIN azkar_reference as ref on ref.item_id = org._id - INNER JOIN azkar_reference_translation as rtr on rtr.reference_id = ref._id - and rtr.language = "\(language)" + return try dbPool?.read { dbConnect in + let items = try AzkarItem.fetchAll(dbConnect, sql: """ + SELECT item._id, item.chapter_id, item.item, transl.item_translation, ref_transl.reference + FROM azkar_item as item + INNER JOIN azkar_item_translation as transl on transl.item_id = item._id + and transl.language = '\(language)' and item.chapter_id = \(chapterId) + INNER JOIN azkar_reference as ref on ref.item_id = item._id + INNER JOIN azkar_reference_translation as ref_transl on ref_transl.reference_id = ref._id + and ref_transl.language = '\(language)' """) - guard result.count > 0 else { - callback(nil, "No row found") - return + return items + } + } catch { + print("Error: \(error.localizedDescription)") + return nil + } + } + + /// Search for a location in the database + /// + /// - Parameters: + /// - locationName: location name + /// - callback: Callback that returns a Location object. + /// - Returns: List of found locations + public func searchLocation(_ locationName: String) async throws -> [Location]? { + do { + return try dbPool?.read { dbConnect in + let locations = try Location.fetchAll(dbConnect, sql: """ + SELECT location._id as _id, country.code as country_code, country.name as country_name, + location.name as name, latitude, longitude, has_fixed_prayer_time, prayer_dependent_id + FROM location + INNER JOIN country on country._id = location.country_id + WHERE location.name like '\(locationName)%' + """) + return locations } - callback(result, nil) + } catch { + print("Error: \(error.localizedDescription)") + return nil + } + } + + /// Geocoder to find location by it's name. + /// + /// - Parameters: + /// - countryCode: Country code + /// - locationName: location name + /// - Returns: geocoded location + public func geocoder(countryCode: String, locationName: String) async throws -> Location? { + do { + return try dbPool?.read { dbConnect in + let location = try Location.fetchOne(dbConnect, sql: """ + SELECT location._id as _id, country.code as country_code, country.name as country_name, + location.name as name, latitude, longitude, has_fixed_prayer_time, prayer_dependent_id + FROM location + INNER JOIN country on country._id = location.country_id + WHERE country.code = '\(countryCode)' COLLATE NOCASE and location.name = '\(locationName)' COLLATE NOCASE + """) + return location } } catch { - callback(nil, "Error: \(error.localizedDescription)") + print("Error: \(error.localizedDescription)") + return nil } } - // MARK: - Private Methods + /// Reverse geocoder to find location by it's latitude and longitude. + /// + /// - Parameters: + /// - latitude: Location latitude. + /// - longitude: Location longitude. + /// - Returns: reverse geocoded location + public func reverseGeocoder(latitude: Double, longitude: Double) async throws -> Location? { + do { + return try dbPool?.read { dbConnect in + let location = try Location.fetchOne(dbConnect, sql: """ + SELECT location._id as _id, country.code as country_code, country.name as country_name, + location.name as name, latitude, longitude, has_fixed_prayer_time, prayer_dependent_id + FROM location + INNER JOIN country on country._id = location.country_id + ORDER BY abs(latitude - (\(latitude))) + abs(longitude - (\(longitude))) + LIMIT 1 + """) + return location + } + } catch { + print("Error: \(error.localizedDescription)") + return nil + } + } - /// Format date to "MM-dd" pattern which will be used to get prayers fro this date in the prayer database. - /// - /// - Parameter date: Date instance. - /// - Returns: Formatted date by "MM-dd" pattern. - private func formatPrayerDate(_ date: Date) -> String { - let formatter = DateFormatter() - formatter.locale = Locale(identifier: "us") - formatter.dateFormat = "MM-dd" - return formatter.string(from: date) + /// Get all the locations that has fixed prayer times. + /// - Returns: Location list + public func fixedPrayerTimesList() -> [Location]? { + do { + return try dbPool?.read { dbConnect in + let locations = try Location.fetchAll(dbConnect, sql: """ + SELECT location._id as _id, country.code as country_code, country.name as country_name, + location.name as name, latitude, longitude, has_fixed_prayer_time, prayer_dependent_id + FROM location + INNER JOIN country on country._id = location.country_id + WHERE has_fixed_prayer_time=1 + """) + return locations + } + } catch { + return nil + } } } diff --git a/MuslimData/Classes/Extensions/DateExtensions.swift b/MuslimData/Classes/Extensions/DateExtensions.swift index 8c6d149..7a31b4a 100755 --- a/MuslimData/Classes/Extensions/DateExtensions.swift +++ b/MuslimData/Classes/Extensions/DateExtensions.swift @@ -10,6 +10,17 @@ import Foundation // MARK: - Date Extensions public extension Date { + + /// Format date to "MM-dd" pattern which will be used to get prayers fro this date in the prayer database. + /// + /// - Returns: Formatted date by "MM-dd" pattern. + func toDBDate() -> String { + let formatter = DateFormatter() + formatter.locale = Locale(identifier: "us") + formatter.dateFormat = "MM-dd" + return formatter.string(from: self) + } + /// Convert date to string time by given time format. /// /// - Parameter format: TimeFormat object. diff --git a/MuslimData/Classes/Extensions/String+Extensions.swift b/MuslimData/Classes/Extensions/String+Extensions.swift index 3ce8376..fda8c0e 100755 --- a/MuslimData/Classes/Extensions/String+Extensions.swift +++ b/MuslimData/Classes/Extensions/String+Extensions.swift @@ -28,30 +28,4 @@ extension String { return calendar.date(from: dateComponents)! } - - /// City mapper that finds parent city if it has and it is used in the fixed prayers. - /// - /// - Parameter countryCode: Country code - /// - Returns: Parent city if available else the city it self. - func mapper(countryCode: String) -> String { - let city = self - var parentCity: String? - if let path = Bundle(for: DBHelper.self).path(forResource: "cityMapper", ofType: "json") { - do { - let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe) - let jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableLeaves) as? [String: Any] - if let jsonResult = jsonResult, let cities = jsonResult[countryCode] as? [String: [String]] { - cities.forEach { key, values in - if values.contains(city) { - parentCity = key - } - } - } - - } catch { - return city - } - } - return parentCity ?? city - } } diff --git a/MuslimData/Classes/Location/LocationHelper.swift b/MuslimData/Classes/Location/LocationHelper.swift deleted file mode 100755 index 257f875..0000000 --- a/MuslimData/Classes/Location/LocationHelper.swift +++ /dev/null @@ -1,130 +0,0 @@ -// -// LocationHelper.swift -// MuslimData -// -// Created by Kosrat D. Ahmad on 10/3/18. -// - -import Foundation - -/// Location helper model that holds some helper methods about locations that we may need it in the MuslimData. -public struct LocationHelper { - // MARK: - Properties - - let dbHelper: DBHelper - public static let shared = LocationHelper() - - // MARK: - Constructor - - private init() { - dbHelper = DBHelper.shared - } - - // MARK: - Public Methods - - /// Search for a city in the database - /// - /// - Parameters: - /// - locationName: location name - /// - callback: Callback that returns a Location object. - public func citySearch(_ locationName: String, callback: @escaping ([Location]?, String?) -> Void) { - DispatchQueue.global(qos: .background).async { - do { - try self.dbHelper.dbPool?.read { dbConnect in - let locations = try Location.fetchAll(dbConnect, sql: """ - SELECT location._id as _id, country.code as country_code, country.name as country_name, - location.name as name, latitude, longitude, has_fixed_prayer_time, prayer_dependent_id - FROM location - INNER JOIN country on country._id = location.country_id - WHERE location.name like "\(locationName)%" - """) - DispatchQueue.main.async { - callback(locations, nil) - } - } - } catch { - DispatchQueue.main.async { - callback(nil, "Error: \(error.localizedDescription)") - } - } - } - } - - /// Geocoder to find city location by it's name. - /// - /// - Parameters: - /// - countryCode: Country code - /// - city: City name - /// - callback: Callback that returns a Location object. - public func geocoder(countryCode: String, locationName: String, callback: @escaping (Location?) -> Void) { - do { - try dbHelper.dbPool?.read { dbConnect in - let result = try Location.fetchOne(dbConnect, sql: """ - SELECT location._id as _id, country.code as country_code, country.name as country_name, - location.name as name, latitude, longitude, has_fixed_prayer_time, prayer_dependent_id - FROM location - INNER JOIN country on country._id = location.country_id - WHERE country.code="\(countryCode)" COLLATE NOCASE and location.name="\(locationName)" COLLATE NOCASE - """) - - guard var location = result else { - callback(nil) - return - } - - callback(location) - } - } catch { - callback(nil) - } - } - - /// Reverse geocoder to find city by it's latitude and longitude. - /// - /// - Parameters: - /// - latitude: City latitude. - /// - longitude: City longitude. - /// - callback: Callback that returns a Location object. - public func reverseGeocoder(latitude: Double, longitude: Double, callback: @escaping (Location?) -> Void) { - do { - try dbHelper.dbPool?.read { dbConnect in - let result = try Location.fetchOne(dbConnect, sql: """ - SELECT location._id as _id, country.code as country_code, country.name as country_name, - location.name as name, latitude, longitude, has_fixed_prayer_time, prayer_dependent_id - FROM location - INNER JOIN country on country._id = location.country_id - ORDER BY abs(latitude - (\(latitude))) + abs(longitude - (\(longitude))) - LIMIT 1 - """) - - guard var location = result else { - callback(nil) - return - } - - callback(location) - } - } catch { - callback(nil) - } - } - - /// Get all the locations that has fixed prayer times. - /// - Returns: Location list - public func fixedPrayerTimesList() -> [Location]? { - do { - return try self.dbHelper.dbPool?.read { dbConnect in - let locations = try Location.fetchAll(dbConnect, sql: """ - SELECT location._id as _id, country.code as country_code, country.name as country_name, - location.name as name, latitude, longitude, has_fixed_prayer_time, prayer_dependent_id - FROM location - INNER JOIN country on country._id = location.country_id - WHERE has_fixed_prayer_time=1 - """) - return locations - } - } catch { - return nil - } - } -} diff --git a/MuslimData/Classes/Names/Names.swift b/MuslimData/Classes/Names/Names.swift deleted file mode 100755 index c526563..0000000 --- a/MuslimData/Classes/Names/Names.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// Names.swift -// MuslimData -// -// Created by Kosrat D. Ahmad on 10/11/18. -// - -import Foundation - -/// Names class that has a helper method to return a list of Names. -public enum Names { - // MARK: - Public Methods - - /// Get list of names of allah with translation for given language. - /// - /// - Parameters: - /// - language: Language for translating names. - /// - callback: Callback that return list of names or an error message - public static func names(language: Language, callback: @escaping ([Name]?, String?) -> Void) { - DBHelper.shared.names(language: language) { names, error in - guard error == nil else { - callback(nil, error) - return - } - - callback(names, nil) - } - } -} diff --git a/README.md b/README.md index 8e9fa7e..5ea9fcd 100755 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ pod 'MuslimData' ### Location Helper -There are some location helper methods that provides **offline** Location Search, Geocoder, Reverse Geocoder, and check a city for fixed prayer times. +There are some location helper methods that provides **offline** Location Search, Geocoder, Reverse Geocoder, and check a location for fixed prayer times. #### Search for location diff --git a/Repository/MuslimRepository.swift b/Repository/MuslimRepository.swift new file mode 100644 index 0000000..8e1b115 --- /dev/null +++ b/Repository/MuslimRepository.swift @@ -0,0 +1,106 @@ +// +// MuslimRepository.swift +// MuslimData +// +// Created by Kosrat Ahmed on 18/03/2024. +// + +import Foundation + +public class MuslimRepository { + + public init () {} + + /// Search for locations in the database by location name and it will return a list of Location object. + /// + /// - Parameters: + /// - locationName: location name + /// - Returns: List of [Location]? + public func searchLocation(_ locationName: String) async throws -> [Location]? { + return try await DBHelper.shared.searchLocation(locationName) + } + + /// Geocoding location information based on the provided country code and location name. + /// + /// - Parameters: + /// - countryCode: Country code + /// - locationName: Location name + /// - Returns: Geocoded location + public func geocoder(countryCode: String, locationName: String) async throws -> Location? { + return try await DBHelper.shared.geocoder(countryCode: countryCode, locationName: locationName) + } + + /// Reverse geocoding location information based on the provided latitude and longitude. + /// + /// - Parameters: + /// - latitude: Location's latitude. + /// - longitude: Location's longitude. + /// - Returns: Reverse geocoded location + public func reverseGeocoder(latitude: Double, longitude: Double) async throws -> Location? { + return try await DBHelper.shared.reverseGeocoder(latitude: latitude, longitude: longitude) + } + + /// Get prayer times for the specified location, date, and prayer attribute. + /// + /// - Parameters: + /// - location: Location object + /// - date: Prayer times date + /// - attribute: Prayer times' attribute + /// - attributes: Prayer attribute + /// - Returns: PrayerTime + public func getPrayerTimes(location: Location, date: Date, attributes: PrayerAttribute) async throws -> PrayerTime? { + var prayerTime: PrayerTime? + if location.hasFixedPrayerTime { + prayerTime = try await DBHelper.shared.prayerTimes(location: location, date: date.toDBDate()) + prayerTime?.applyDST() + } else { + prayerTime = Prayer.getPrayerTimes(location: location, date: date, attributes: attributes) + } + + prayerTime?.applyOffsets(attributes.offsets) + return prayerTime + } + + /// Get names of Allah for the specified language. + /// + /// - Parameters: + /// - language: Language for translating names. + /// - Returns: List of [Name]? of Allah + public func getNamesOfAllah(language: Language) async throws -> [Name]? { + return try await DBHelper.shared.names(language: language) + } + + /// Get azkar categories for the specified language. + /// + /// - Parameters: + /// - language: Language of the azkar categories. + /// - Returns: List of [AzkarCategory]? + public func getAzkarCategories(language: Language) async throws -> [AzkarCategory]? { + return try await DBHelper.shared.azkarCategories(language: language) + } + + /// Get azkar chapters from the database for the specified language and category id. + /// + /// - Parameters: + /// - language: Language of the azkar chapters. + /// - categoryId: Optional category id + /// - Returns: List of [AzkarChapter]? + public func getAzkarChapters(language: Language, categoryId: Int? = nil) async throws -> [AzkarChapter]? { + return try await DBHelper.shared.azkarChapters(language: language, categoryId: categoryId) + } + + /// Get azkar items for specific azkar chapter from database which is localized by the given language. + /// + /// - Parameters: + /// - language: Language of the chapter. + /// - chapterId: Chapter id for the azkar items. + /// - Returns: List of [AzkarItem]? + public func getAzkarItems(language: Language, chapterId: Int) async throws -> [AzkarItem]? { + return try await DBHelper.shared.azkarItems(language: language, chapterId: chapterId) + } + + // TODO: it needs to be deleted when the tests migrated to the package itself. + public func getAllFixedPrayerLocations() async throws -> [Location]? { + return try await DBHelper.shared.fixedPrayerTimesList() + } +} From d177bfa01b6e5acd7743022db3ec85adcd4b603e Mon Sep 17 00:00:00 2001 From: "Kosrat D. Ahmed" Date: Wed, 20 Mar 2024 23:11:22 +0300 Subject: [PATCH 2/7] Fix a date type issue --- MuslimData/Classes/DB Helper/DBHelper.swift | 9 +++++---- MuslimData/Classes/Extensions/DateExtensions.swift | 2 +- Repository/MuslimRepository.swift | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/MuslimData/Classes/DB Helper/DBHelper.swift b/MuslimData/Classes/DB Helper/DBHelper.swift index 9a040e5..fabe807 100755 --- a/MuslimData/Classes/DB Helper/DBHelper.swift +++ b/MuslimData/Classes/DB Helper/DBHelper.swift @@ -28,19 +28,19 @@ class DBHelper { } // MARK: - Public Methods - + /// Get fixed prayer times from Muslim database. /// - Parameters: /// - location: Location object /// - date: Prayer date /// - Returns: PrayerTime instance. - func prayerTimes(location: Location, date: String) async throws -> PrayerTime? { + func prayerTimes(location: Location, date: Date) async throws -> PrayerTime? { do { return try dbPool?.read { dbConnect in let result = try Row.fetchOne(dbConnect, sql: """ SELECT * FROM prayer_time WHERE location_id = '\(location.prayerDependentId ?? location.id)' - and date = '\(date)' + and date = '\(date.toDBDate())' """) guard let row = result else { @@ -208,7 +208,8 @@ class DBHelper { location.name as name, latitude, longitude, has_fixed_prayer_time, prayer_dependent_id FROM location INNER JOIN country on country._id = location.country_id - WHERE country.code = '\(countryCode)' COLLATE NOCASE and location.name = '\(locationName)' COLLATE NOCASE + WHERE country.code = '\(countryCode)' COLLATE NOCASE + and location.name = '\(locationName)' COLLATE NOCASE """) return location } diff --git a/MuslimData/Classes/Extensions/DateExtensions.swift b/MuslimData/Classes/Extensions/DateExtensions.swift index 7a31b4a..0c3c794 100755 --- a/MuslimData/Classes/Extensions/DateExtensions.swift +++ b/MuslimData/Classes/Extensions/DateExtensions.swift @@ -10,7 +10,7 @@ import Foundation // MARK: - Date Extensions public extension Date { - + /// Format date to "MM-dd" pattern which will be used to get prayers fro this date in the prayer database. /// /// - Returns: Formatted date by "MM-dd" pattern. diff --git a/Repository/MuslimRepository.swift b/Repository/MuslimRepository.swift index 8e1b115..1169b14 100644 --- a/Repository/MuslimRepository.swift +++ b/Repository/MuslimRepository.swift @@ -51,7 +51,7 @@ public class MuslimRepository { public func getPrayerTimes(location: Location, date: Date, attributes: PrayerAttribute) async throws -> PrayerTime? { var prayerTime: PrayerTime? if location.hasFixedPrayerTime { - prayerTime = try await DBHelper.shared.prayerTimes(location: location, date: date.toDBDate()) + prayerTime = try await DBHelper.shared.prayerTimes(location: location, date: date) prayerTime?.applyDST() } else { prayerTime = Prayer.getPrayerTimes(location: location, date: date, attributes: attributes) From db2aff4b542e5dd7f133961c8d6dbc1519e76e7b Mon Sep 17 00:00:00 2001 From: "Kosrat D. Ahmed" Date: Wed, 20 Mar 2024 23:39:58 +0300 Subject: [PATCH 3/7] Update readme and license files --- .../MuslimData/LocationViewController.swift | 2 +- LICENSE | 220 ++++++++++++++++-- README.md | 131 ++++------- Repository/MuslimRepository.swift | 2 +- 4 files changed, 243 insertions(+), 112 deletions(-) diff --git a/Example/MuslimData/LocationViewController.swift b/Example/MuslimData/LocationViewController.swift index f9e9d3b..80b7b60 100755 --- a/Example/MuslimData/LocationViewController.swift +++ b/Example/MuslimData/LocationViewController.swift @@ -71,7 +71,7 @@ extension LocationViewController: UISearchBarDelegate { return } Task.init { - let locations = try! await MuslimRepository().searchLocation(searchBar.text!) + let locations = try! await MuslimRepository().searchLocation(locationName: searchBar.text!) if let locations = locations { self.locations = locations } diff --git a/LICENSE b/LICENSE index 9130600..4c9ad98 100755 --- a/LICENSE +++ b/LICENSE @@ -1,19 +1,201 @@ -Copyright (c) 2018 Kosrat D. Ahmad - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/README.md b/README.md index 5ea9fcd..655576f 100755 --- a/README.md +++ b/README.md @@ -44,61 +44,40 @@ There are some location helper methods that provides **offline** Location Search You can search for any cities or places around the world and this is useful when a use doesn't have internet connection or user's location is turned off so you can search here: ```swift -LocationHelper.shared.citySearch(city: "London") { locations, error in - guard let locations = locations, locations.count > 0 else { - print("City could not be found!") - return - } - print("locations: \(locations)") -} -``` -`Important Note`: Search results always return **false** for **hasFixedPrayerTimes** property in the **Location** object so you need manualy check selected location in the search result like the following example -```swift -// Check the selected location to know that it has fixed prayer times or not. -LocationHelper.shared.cityHasFixedPrayerTimes(countryCode: location.countryCode, city: location.city) { hasFixed in - location.hasFixedPrayerTimes = hasFixed +let locations = try! await MuslimData().searchLocation(locationName: "London") +guard let locations = locations, locations.count > 0 else { + print("Location could not be found!") + return } +print("locations: \(locations)") ``` #### Geocoder -Use geocoder to find city location by name. +Use geocoder to find a location by name. ```swift -// Use geocoder to find city location by name. -LocationHelper.shared.geocoder(countryCode: "GB", city: "London") { location in - guard let location = location else { - print("City name can not be geocode") - return - } - print("location: \(location)") +// Use geocoder to find a location by name. +let location = try! await MuslimRepository().geocoder(countryCode: "GB", locationName: "London") +guard let location = location else { + print("Location name can not be geocoded") + return } +print("location: \(location)") ``` #### Reverse Geocoder -Use reverse geocoder to find city name by latitude and longitude. +Use reverse geocoder to find a location by latitude and longitude. ```swift -// Use reverse geocoder to find city name by latitude and longitude. -LocationHelper.shared.geocoder(latitude: 36.654090, longitude: 44.541278) { location in - guard let location = location else { - print("City name can nnot be geocode by latitude and longitude") - return - } - print("location: \(location)") -} -``` - -#### Has Fixed Prayer Times - -Check a city to know that it has fixed prayer times or not - -```swift -// Check a city to know that it has fixed prayer times or not -LocationHelper.shared.cityHasFixedPrayerTimes(countryCode: "IQ", city: "Duhok") { hasFixed in - print("City has fixed prayer times: \(hasFixed)") +// Use reverse geocoder to find a location by its latitude and longitude. +let location = try! await MuslimRepository().reverseGeocoder(latitude: 36.654090, longitude: 44.541278) +guard let location = location else { + print("Location name can not be geocoded by latitude and longitude") + return } +print("location: \(location)") ``` ### Prayer Times @@ -107,25 +86,20 @@ You can easily get a location prayer times just by passing (`Location`, `PrayerA ```swift // Create location object. -let location = Location(latitude: 36.123, longitude: 44.123, city: "Erbil", countryCode: "IQ", - countryName: "Iraq", hasFixedPrayerTimes: true) +let location = // it should be retrieved from geocoder, reverseGeocoder, or searchLocation methods. // Crate prayer attributes object. let attributes = PrayerAttribute(method: .makkah, asrMethod: .shafii, adjustAngle: .angleBased) // Get prayer times -PrayerTime.getPrayerTimes(location: location, date: Date(), attributes: attributes) { prayerTime, error in - guard error == nil else { - print("Prayer tims didn't found for the specified properties.") - return - } - print("prayer times: \(prayerTime!)") - print("Fromat prayer times: \(prayerTime!.formatPrayers(.time12))") - print("Format one prayer time: \(prayerTime!.isha.toTime(format: .time24))") - print("next prayer index: \(prayerTime!.nextPrayerIndex())") - print("next prayer interval: \(prayerTime!.nextPrayerInterval())") - print("next prayer time remaining: \(prayerTime!.nextPrayerTimeRemaining())") -} +let prayerTime = try! await MuslimRepository().getPrayerTimes(location: location, date: Date(), attributes: attributes) + +print("prayer times: \(prayerTime!)") +print("Fromat prayer times: \(prayerTime!.formatPrayers(.time12))") +print("Format one prayer time: \(prayerTime!.isha.toTime(format: .time24))") +print("next prayer index: \(prayerTime!.nextPrayerIndex())") +print("next prayer interval: \(prayerTime!.nextPrayerInterval())") +print("next prayer time remaining: \(prayerTime!.nextPrayerTimeRemaining())") ``` ### Azkars (Hisnul Muslim) @@ -138,13 +112,8 @@ Get all azkar categories and it is localized for the given language. ```swift // Get azkar categories from MuslimData library -Azkars.azkarCategories(language: .en) { azkarCategories, error in - guard error == nil else { - print("Azkar categories didn't find: \(error!)") - return - } - print("Azkar Categories: \(azkarCategories!)") -} +let azkarCategories = try! await MuslimRepository().getAzkarCategories(language: .en) +print("Azkar Categories: \(azkarCategories!)") ``` #### Azkar Chapters @@ -153,26 +122,16 @@ Get azkar chapters and it is localized for the given language. ```swift // Get azkar chapters from MuslimData library -Azkars.azkarChapters(language: .en) { azkarChapters, error in - guard error == nil else { - print("Azkar chapters didn't found: \(error!)") - return - } - print("Azkar Chapters: \(azkarChapters!)") -} +let azkarChapters = try! await MuslimRepository().getAzkarChapters(language: .en) +print("Azkar Chapters: \(azkarChapters!)") ``` Get azkar chapters for a specific category and it is localized for the given language. ```swift // Get azkar chapters for a specific category from MuslimData library -Azkars.azkarChapters(language: .en, categoryId: 2) { azkarChapters, error in - guard error == nil else { - print("Azkar chapters didn't found: \(error!)") - return - } - print("Azkar Chapters for a category: \(azkarChapters!)") -} +let azkarChapters = try! await MuslimRepository().getAzkarChapters(language: .en, categoryId: 2) +print("Azkar Chapters for a category: \(azkarChapters!)") ``` #### Azkar Items @@ -180,13 +139,8 @@ Azkars.azkarChapters(language: .en, categoryId: 2) { azkarChapters, error in Get azkar items for a specific chapter and it is localized for the given language. ```swift // Get azkar items for a specific chapter from MuslimData library -Azkars.azkarItems(language: .en, chapterId: 2) { azkarItems, error in - guard error == nil else { - print("Azkar items didn't found: \(error!)") - return - } - print("azkar items: \(azkarItems!)") -} +let azkarItems = try! await MuslimRepository().getAzkarItems(language: .en, chapterId: 2) +print("azkar items: \(azkarItems!)") ``` ### Names of Allah @@ -195,18 +149,13 @@ Get 99 Names of Allah with it's translation and now it is available for these la ```swift // Get 99 names of allah from MuslimData library -Names.names(language: .en) { names, error in - guard error == nil else { - print("Names of Allah didn't found: \(error!)") - return - } - print("Names of Allah: \(names)") -} +let namesOfAllah = try! await MuslimRepository().getNamesOfAllah(language: .en) +print("Names of Allah: \(namesOfAllah)") ``` ## Author -Kosrat D. Ahmad, kosrat.d.ahmad@gmail.com +Kosrat D. Ahmed, kosrat.d.ahmad@gmail.com ## License -MuslimData is available under the MIT license. See the [LICENSE](LICENSE) file for more info. +MuslimData is available under the Apache license. See the [LICENSE](LICENSE) file for more info. diff --git a/Repository/MuslimRepository.swift b/Repository/MuslimRepository.swift index 1169b14..b42e14e 100644 --- a/Repository/MuslimRepository.swift +++ b/Repository/MuslimRepository.swift @@ -16,7 +16,7 @@ public class MuslimRepository { /// - Parameters: /// - locationName: location name /// - Returns: List of [Location]? - public func searchLocation(_ locationName: String) async throws -> [Location]? { + public func searchLocation(locationName: String) async throws -> [Location]? { return try await DBHelper.shared.searchLocation(locationName) } From fc4f2bf8bba8ba1e764981c57d09f942285a4f0d Mon Sep 17 00:00:00 2001 From: "Kosrat D. Ahmed" Date: Wed, 20 Mar 2024 23:47:50 +0300 Subject: [PATCH 4/7] Add repository protocal for the MuslimRepository --- Example/Pods/Pods.xcodeproj/project.pbxproj | 4 +++ Repository/MuslimRepository.swift | 2 +- Repository/Repository.swift | 28 +++++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 Repository/Repository.swift diff --git a/Example/Pods/Pods.xcodeproj/project.pbxproj b/Example/Pods/Pods.xcodeproj/project.pbxproj index a5817f7..8c5072b 100755 --- a/Example/Pods/Pods.xcodeproj/project.pbxproj +++ b/Example/Pods/Pods.xcodeproj/project.pbxproj @@ -38,6 +38,7 @@ 2D6CD44729CC5BF2009B527C /* muslim_db_v2.0.0.db in Resources */ = {isa = PBXBuildFile; fileRef = 2D6CD44629CC5BF2009B527C /* muslim_db_v2.0.0.db */; }; 2DAF0C709FAF6D288751DB00EB06B40C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FD7232797ACF3F6F7685B58BCDC00C7 /* Foundation.framework */; }; 2DE6E95C2BA8D8010082A3CE /* MuslimRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DE6E95B2BA8D8010082A3CE /* MuslimRepository.swift */; }; + 2DFE19682BAB81E900665C6B /* Repository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DFE19672BAB81E900665C6B /* Repository.swift */; }; 318B2D4FBE83F08BB67C2AA6A52977AB /* FTS5+QueryInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5779BFB97BB16F7C257E39CD28630594 /* FTS5+QueryInterface.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; 33FDF2697ECE2E34513CACBC1EDFDB51 /* DatabaseValueConvertible+RawRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1585FD241A9AC0D79B3E084E1A8B7B77 /* DatabaseValueConvertible+RawRepresentable.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; 35A9B68C8D7AC42A8187DC1F8AEC095A /* FTS3TokenizerDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C9ECD60B68221B76E253AA39B4B52E /* FTS3TokenizerDescriptor.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; @@ -229,6 +230,7 @@ 2D6CD44629CC5BF2009B527C /* muslim_db_v2.0.0.db */ = {isa = PBXFileReference; lastKnownFileType = file; name = muslim_db_v2.0.0.db; path = MuslimData/Assets/muslim_db_v2.0.0.db; sourceTree = ""; }; 2DC6A83C7FE2580E3F2A1AFBB2B117E6 /* PrayerAttribute.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PrayerAttribute.swift; sourceTree = ""; }; 2DE6E95B2BA8D8010082A3CE /* MuslimRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MuslimRepository.swift; sourceTree = ""; }; + 2DFE19672BAB81E900665C6B /* Repository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Repository.swift; sourceTree = ""; }; 2E88CF46329DBA47B53B98F005E11EE3 /* MuslimData.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MuslimData.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 2F75C56ED8BD1951FC8172C608B20303 /* Pods-MuslimData_Example-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-MuslimData_Example-acknowledgements.plist"; sourceTree = ""; }; 2FFBDBD6E148D8CD2D3E5D40636ABE46 /* AzkarItem.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AzkarItem.swift; sourceTree = ""; }; @@ -489,6 +491,7 @@ 2DE6E95A2BA8D75D0082A3CE /* Repository */ = { isa = PBXGroup; children = ( + 2DFE19672BAB81E900665C6B /* Repository.swift */, 2DE6E95B2BA8D8010082A3CE /* MuslimRepository.swift */, ); path = Repository; @@ -999,6 +1002,7 @@ A7D645073A4902CE19144733BD3B1D6B /* MuslimData-dummy.m in Sources */, FF616834C38743D535B62B7886C74F07 /* Name.swift in Sources */, EA0BC2897FF6BE975F969C15629840CB /* Prayer.swift in Sources */, + 2DFE19682BAB81E900665C6B /* Repository.swift in Sources */, 0AD24AEB225F135FE242003EA86E7039 /* PrayerAttribute.swift in Sources */, 4232F4B0DC26B878201F9523CEF8F761 /* PrayerTime.swift in Sources */, E746EBB44033C7F5ECE664C2A2862C8D /* String+Extensions.swift in Sources */, diff --git a/Repository/MuslimRepository.swift b/Repository/MuslimRepository.swift index b42e14e..042d69f 100644 --- a/Repository/MuslimRepository.swift +++ b/Repository/MuslimRepository.swift @@ -7,7 +7,7 @@ import Foundation -public class MuslimRepository { +public class MuslimRepository: Repository { public init () {} diff --git a/Repository/Repository.swift b/Repository/Repository.swift new file mode 100644 index 0000000..94e875d --- /dev/null +++ b/Repository/Repository.swift @@ -0,0 +1,28 @@ +// +// Repository.swift +// MuslimData +// +// Created by Kosrat Ahmed on 20/03/2024. +// + +import Foundation + +public protocol Repository { + func searchLocation(locationName: String) async throws -> [Location]? + + func geocoder(countryCode: String, locationName: String) async throws -> Location? + + func reverseGeocoder(latitude: Double, longitude: Double) async throws -> Location? + + func getPrayerTimes(location: Location, date: Date, attributes: PrayerAttribute) async throws -> PrayerTime? + + func getNamesOfAllah(language: Language) async throws -> [Name]? + + func getAzkarCategories(language: Language) async throws -> [AzkarCategory]? + + func getAzkarChapters(language: Language, categoryId: Int?) async throws -> [AzkarChapter]? + + func getAzkarItems(language: Language, chapterId: Int) async throws -> [AzkarItem]? + + func getAllFixedPrayerLocations() async throws -> [Location]? +} From f4e84222a93fc17b9b72461e35bccd08b47e2d2c Mon Sep 17 00:00:00 2001 From: "Kosrat D. Ahmed" Date: Thu, 21 Mar 2024 00:38:52 +0300 Subject: [PATCH 5/7] Fix class pathes --- Example/.swiftlint.yml | 2 +- Example/Pods/Pods.xcodeproj/project.pbxproj | 12 +++++---- MuslimData/.swiftlint.yml | 2 +- .../Models}/Azkars/AzkarCategory.swift | 0 .../Classes/Models}/Azkars/AzkarChapter.swift | 0 .../Classes/Models}/Azkars/AzkarItem.swift | 0 .../Classes/Models}/Location/Location.swift | 0 .../Classes/Models}/Names/Language.swift | 0 .../Classes/Models}/Names/Name.swift | 0 .../Classes/Models/PrayerTimes}/Prayer.swift | 0 .../Models/PrayerTimes}/PrayerAttribute.swift | 0 .../Models/PrayerTimes}/PrayerTime.swift | 0 .../Models/PrayerTimes}/TimeFormat.swift | 0 .../Repository}/MuslimRepository.swift | 26 ++++++++++--------- .../Classes/Repository}/Repository.swift | 0 15 files changed, 23 insertions(+), 19 deletions(-) rename {Models => MuslimData/Classes/Models}/Azkars/AzkarCategory.swift (100%) rename {Models => MuslimData/Classes/Models}/Azkars/AzkarChapter.swift (100%) rename {Models => MuslimData/Classes/Models}/Azkars/AzkarItem.swift (100%) rename {Models => MuslimData/Classes/Models}/Location/Location.swift (100%) rename {Models => MuslimData/Classes/Models}/Names/Language.swift (100%) rename {Models => MuslimData/Classes/Models}/Names/Name.swift (100%) rename {Models/Prayer Times => MuslimData/Classes/Models/PrayerTimes}/Prayer.swift (100%) rename {Models/Prayer Times => MuslimData/Classes/Models/PrayerTimes}/PrayerAttribute.swift (100%) rename {Models/Prayer Times => MuslimData/Classes/Models/PrayerTimes}/PrayerTime.swift (100%) rename {Models/Prayer Times => MuslimData/Classes/Models/PrayerTimes}/TimeFormat.swift (100%) rename {Repository => MuslimData/Classes/Repository}/MuslimRepository.swift (95%) rename {Repository => MuslimData/Classes/Repository}/Repository.swift (100%) diff --git a/Example/.swiftlint.yml b/Example/.swiftlint.yml index ab3d979..8a425c0 100755 --- a/Example/.swiftlint.yml +++ b/Example/.swiftlint.yml @@ -1,6 +1,6 @@ excluded: - Pods - - ../MuslimData/Classes/Prayer Times/Prayer.swift + - ../MuslimData/Classes/Models/PrayerTimes/Prayer.swift included: - ../MuslimData identifier_name: diff --git a/Example/Pods/Pods.xcodeproj/project.pbxproj b/Example/Pods/Pods.xcodeproj/project.pbxproj index 8c5072b..ee7cf57 100755 --- a/Example/Pods/Pods.xcodeproj/project.pbxproj +++ b/Example/Pods/Pods.xcodeproj/project.pbxproj @@ -494,7 +494,8 @@ 2DFE19672BAB81E900665C6B /* Repository.swift */, 2DE6E95B2BA8D8010082A3CE /* MuslimRepository.swift */, ); - path = Repository; + name = Repository; + path = MuslimData/Classes/Repository; sourceTree = ""; }; 2DE6E95D2BA8F1F30082A3CE /* Models */ = { @@ -503,9 +504,10 @@ 5B32A0A6C3385773AA423D017A5BFE73 /* Azkars */, 8D92D353CC7766D3072B3133A23D2705 /* Names */, 2817A6C16C274658D2455BB0739C199E /* Location */, - F45771AD65677FDC2506D34994A89145 /* Prayer Times */, + F45771AD65677FDC2506D34994A89145 /* PrayerTimes */, ); - path = Models; + name = Models; + path = MuslimData/Classes/Models; sourceTree = ""; }; 4022D06EB0FD32BF668EE12AF2306B41 /* standard */ = { @@ -796,7 +798,7 @@ path = ../..; sourceTree = ""; }; - F45771AD65677FDC2506D34994A89145 /* Prayer Times */ = { + F45771AD65677FDC2506D34994A89145 /* PrayerTimes */ = { isa = PBXGroup; children = ( B85117D4C9BE4B6480B1C89933815E58 /* Prayer.swift */, @@ -804,7 +806,7 @@ 6368FFE5512AD8AC9D36EB8427AFA109 /* PrayerTime.swift */, 65F554C03188A6F204B2036E5CF4B82D /* TimeFormat.swift */, ); - path = "Prayer Times"; + path = PrayerTimes; sourceTree = ""; }; /* End PBXGroup section */ diff --git a/MuslimData/.swiftlint.yml b/MuslimData/.swiftlint.yml index ab3d979..8a425c0 100755 --- a/MuslimData/.swiftlint.yml +++ b/MuslimData/.swiftlint.yml @@ -1,6 +1,6 @@ excluded: - Pods - - ../MuslimData/Classes/Prayer Times/Prayer.swift + - ../MuslimData/Classes/Models/PrayerTimes/Prayer.swift included: - ../MuslimData identifier_name: diff --git a/Models/Azkars/AzkarCategory.swift b/MuslimData/Classes/Models/Azkars/AzkarCategory.swift similarity index 100% rename from Models/Azkars/AzkarCategory.swift rename to MuslimData/Classes/Models/Azkars/AzkarCategory.swift diff --git a/Models/Azkars/AzkarChapter.swift b/MuslimData/Classes/Models/Azkars/AzkarChapter.swift similarity index 100% rename from Models/Azkars/AzkarChapter.swift rename to MuslimData/Classes/Models/Azkars/AzkarChapter.swift diff --git a/Models/Azkars/AzkarItem.swift b/MuslimData/Classes/Models/Azkars/AzkarItem.swift similarity index 100% rename from Models/Azkars/AzkarItem.swift rename to MuslimData/Classes/Models/Azkars/AzkarItem.swift diff --git a/Models/Location/Location.swift b/MuslimData/Classes/Models/Location/Location.swift similarity index 100% rename from Models/Location/Location.swift rename to MuslimData/Classes/Models/Location/Location.swift diff --git a/Models/Names/Language.swift b/MuslimData/Classes/Models/Names/Language.swift similarity index 100% rename from Models/Names/Language.swift rename to MuslimData/Classes/Models/Names/Language.swift diff --git a/Models/Names/Name.swift b/MuslimData/Classes/Models/Names/Name.swift similarity index 100% rename from Models/Names/Name.swift rename to MuslimData/Classes/Models/Names/Name.swift diff --git a/Models/Prayer Times/Prayer.swift b/MuslimData/Classes/Models/PrayerTimes/Prayer.swift similarity index 100% rename from Models/Prayer Times/Prayer.swift rename to MuslimData/Classes/Models/PrayerTimes/Prayer.swift diff --git a/Models/Prayer Times/PrayerAttribute.swift b/MuslimData/Classes/Models/PrayerTimes/PrayerAttribute.swift similarity index 100% rename from Models/Prayer Times/PrayerAttribute.swift rename to MuslimData/Classes/Models/PrayerTimes/PrayerAttribute.swift diff --git a/Models/Prayer Times/PrayerTime.swift b/MuslimData/Classes/Models/PrayerTimes/PrayerTime.swift similarity index 100% rename from Models/Prayer Times/PrayerTime.swift rename to MuslimData/Classes/Models/PrayerTimes/PrayerTime.swift diff --git a/Models/Prayer Times/TimeFormat.swift b/MuslimData/Classes/Models/PrayerTimes/TimeFormat.swift similarity index 100% rename from Models/Prayer Times/TimeFormat.swift rename to MuslimData/Classes/Models/PrayerTimes/TimeFormat.swift diff --git a/Repository/MuslimRepository.swift b/MuslimData/Classes/Repository/MuslimRepository.swift similarity index 95% rename from Repository/MuslimRepository.swift rename to MuslimData/Classes/Repository/MuslimRepository.swift index 042d69f..c18b162 100644 --- a/Repository/MuslimRepository.swift +++ b/MuslimData/Classes/Repository/MuslimRepository.swift @@ -8,9 +8,9 @@ import Foundation public class MuslimRepository: Repository { - + public init () {} - + /// Search for locations in the database by location name and it will return a list of Location object. /// /// - Parameters: @@ -19,7 +19,7 @@ public class MuslimRepository: Repository { public func searchLocation(locationName: String) async throws -> [Location]? { return try await DBHelper.shared.searchLocation(locationName) } - + /// Geocoding location information based on the provided country code and location name. /// /// - Parameters: @@ -29,7 +29,7 @@ public class MuslimRepository: Repository { public func geocoder(countryCode: String, locationName: String) async throws -> Location? { return try await DBHelper.shared.geocoder(countryCode: countryCode, locationName: locationName) } - + /// Reverse geocoding location information based on the provided latitude and longitude. /// /// - Parameters: @@ -39,7 +39,7 @@ public class MuslimRepository: Repository { public func reverseGeocoder(latitude: Double, longitude: Double) async throws -> Location? { return try await DBHelper.shared.reverseGeocoder(latitude: latitude, longitude: longitude) } - + /// Get prayer times for the specified location, date, and prayer attribute. /// /// - Parameters: @@ -48,7 +48,9 @@ public class MuslimRepository: Repository { /// - attribute: Prayer times' attribute /// - attributes: Prayer attribute /// - Returns: PrayerTime - public func getPrayerTimes(location: Location, date: Date, attributes: PrayerAttribute) async throws -> PrayerTime? { + public func getPrayerTimes(location: Location, + date: Date, + attributes: PrayerAttribute) async throws -> PrayerTime? { var prayerTime: PrayerTime? if location.hasFixedPrayerTime { prayerTime = try await DBHelper.shared.prayerTimes(location: location, date: date) @@ -56,11 +58,11 @@ public class MuslimRepository: Repository { } else { prayerTime = Prayer.getPrayerTimes(location: location, date: date, attributes: attributes) } - + prayerTime?.applyOffsets(attributes.offsets) return prayerTime } - + /// Get names of Allah for the specified language. /// /// - Parameters: @@ -69,7 +71,7 @@ public class MuslimRepository: Repository { public func getNamesOfAllah(language: Language) async throws -> [Name]? { return try await DBHelper.shared.names(language: language) } - + /// Get azkar categories for the specified language. /// /// - Parameters: @@ -78,7 +80,7 @@ public class MuslimRepository: Repository { public func getAzkarCategories(language: Language) async throws -> [AzkarCategory]? { return try await DBHelper.shared.azkarCategories(language: language) } - + /// Get azkar chapters from the database for the specified language and category id. /// /// - Parameters: @@ -88,7 +90,7 @@ public class MuslimRepository: Repository { public func getAzkarChapters(language: Language, categoryId: Int? = nil) async throws -> [AzkarChapter]? { return try await DBHelper.shared.azkarChapters(language: language, categoryId: categoryId) } - + /// Get azkar items for specific azkar chapter from database which is localized by the given language. /// /// - Parameters: @@ -98,7 +100,7 @@ public class MuslimRepository: Repository { public func getAzkarItems(language: Language, chapterId: Int) async throws -> [AzkarItem]? { return try await DBHelper.shared.azkarItems(language: language, chapterId: chapterId) } - + // TODO: it needs to be deleted when the tests migrated to the package itself. public func getAllFixedPrayerLocations() async throws -> [Location]? { return try await DBHelper.shared.fixedPrayerTimesList() diff --git a/Repository/Repository.swift b/MuslimData/Classes/Repository/Repository.swift similarity index 100% rename from Repository/Repository.swift rename to MuslimData/Classes/Repository/Repository.swift From fb11a288c9b5f61cb521651a3985ddaadc77d64a Mon Sep 17 00:00:00 2001 From: "Kosrat D. Ahmed" Date: Thu, 21 Mar 2024 10:32:55 +0300 Subject: [PATCH 6/7] Update ios deployment target to 13.0 --- Example/MuslimData.xcodeproj/project.pbxproj | 6 ++++-- Example/Pods/Pods.xcodeproj/project.pbxproj | 4 ++-- MuslimData.podspec | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Example/MuslimData.xcodeproj/project.pbxproj b/Example/MuslimData.xcodeproj/project.pbxproj index a1ffbce..2918e82 100755 --- a/Example/MuslimData.xcodeproj/project.pbxproj +++ b/Example/MuslimData.xcodeproj/project.pbxproj @@ -534,11 +534,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -584,11 +585,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/Example/Pods/Pods.xcodeproj/project.pbxproj b/Example/Pods/Pods.xcodeproj/project.pbxproj index ee7cf57..9c346df 100755 --- a/Example/Pods/Pods.xcodeproj/project.pbxproj +++ b/Example/Pods/Pods.xcodeproj/project.pbxproj @@ -1276,7 +1276,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1373,7 +1373,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; diff --git a/MuslimData.podspec b/MuslimData.podspec index 20bb3cc..c60f3bb 100755 --- a/MuslimData.podspec +++ b/MuslimData.podspec @@ -31,7 +31,7 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/KosratDAhmad/MuslimData.git', :tag => s.version.to_s } # s.social_media_url = 'https://twitter.com/' - s.ios.deployment_target = '12.0' + s.ios.deployment_target = '13.0' s.source_files = 'MuslimData/Classes/**/*' From 053ae156ab4c0476bac7a3308f096460a8387017 Mon Sep 17 00:00:00 2001 From: "Kosrat D. Ahmed" Date: Thu, 21 Mar 2024 10:54:30 +0300 Subject: [PATCH 7/7] Fix load location id for first lunch --- Example/MuslimData/Location.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Example/MuslimData/Location.swift b/Example/MuslimData/Location.swift index 0ff741d..c2e8c51 100755 --- a/Example/MuslimData/Location.swift +++ b/Example/MuslimData/Location.swift @@ -30,7 +30,7 @@ extension Location { /// - Returns: Location object. static func loadSavedLocation() -> Location { let defaults = UserDefaults.standard - let id = defaults.integer(forKey: "id") + let id = defaults.object(forKey: "id") as? Int ?? 77359 let name = defaults.string(forKey: "name") ?? "Erbil" var latitude = defaults.double(forKey: "latitude") latitude = latitude == 0.0 ? 36.188204 : latitude