Skip to content

Commit

Permalink
Add azkar chapter and items screens
Browse files Browse the repository at this point in the history
  • Loading branch information
kosratdev committed Mar 25, 2024
1 parent 9ce71b7 commit c9d23b1
Show file tree
Hide file tree
Showing 11 changed files with 253 additions and 7 deletions.
48 changes: 48 additions & 0 deletions Example/MuslimDataExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
objects = {

/* Begin PBXBuildFile section */
2D9B68CA2BB190E30029E4D0 /* ChapterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D9B68C92BB190E30029E4D0 /* ChapterViewModel.swift */; };
2D9B68CD2BB191270029E4D0 /* ChapterRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D9B68CC2BB191270029E4D0 /* ChapterRow.swift */; };
2D9B68CF2BB1913A0029E4D0 /* AzkarChaptersScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D9B68CE2BB1913A0029E4D0 /* AzkarChaptersScreen.swift */; };
2D9B68D22BB195FF0029E4D0 /* AzkarItemsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D9B68D12BB195FF0029E4D0 /* AzkarItemsScreen.swift */; };
2D9B68D42BB19AFB0029E4D0 /* ItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D9B68D32BB19AFB0029E4D0 /* ItemViewModel.swift */; };
2D9B68D62BB19B0F0029E4D0 /* ItemRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D9B68D52BB19B0F0029E4D0 /* ItemRow.swift */; };
6A22480D2BAED7840094967B /* NamesScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A22480C2BAED7840094967B /* NamesScreen.swift */; };
6A22480F2BAED7960094967B /* NamesRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A22480E2BAED7960094967B /* NamesRowView.swift */; };
6A2248112BAEDAEE0094967B /* NamesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A2248102BAEDAED0094967B /* NamesViewModel.swift */; };
Expand All @@ -18,6 +24,12 @@
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
2D9B68C92BB190E30029E4D0 /* ChapterViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChapterViewModel.swift; sourceTree = "<group>"; };
2D9B68CC2BB191270029E4D0 /* ChapterRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChapterRow.swift; sourceTree = "<group>"; };
2D9B68CE2BB1913A0029E4D0 /* AzkarChaptersScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AzkarChaptersScreen.swift; sourceTree = "<group>"; };
2D9B68D12BB195FF0029E4D0 /* AzkarItemsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AzkarItemsScreen.swift; sourceTree = "<group>"; };
2D9B68D32BB19AFB0029E4D0 /* ItemViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemViewModel.swift; sourceTree = "<group>"; };
2D9B68D52BB19B0F0029E4D0 /* ItemRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemRow.swift; sourceTree = "<group>"; };
6A22480C2BAED7840094967B /* NamesScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NamesScreen.swift; sourceTree = "<group>"; };
6A22480E2BAED7960094967B /* NamesRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NamesRowView.swift; sourceTree = "<group>"; };
6A2248102BAEDAED0094967B /* NamesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NamesViewModel.swift; sourceTree = "<group>"; };
Expand All @@ -41,6 +53,35 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
2D9B68CB2BB190F30029E4D0 /* Azkars */ = {
isa = PBXGroup;
children = (
2D9B68D72BB1A3600029E4D0 /* AzkarChapters */,
2D9B68D02BB191870029E4D0 /* AzkarItems */,
);
path = Azkars;
sourceTree = "<group>";
};
2D9B68D02BB191870029E4D0 /* AzkarItems */ = {
isa = PBXGroup;
children = (
2D9B68D12BB195FF0029E4D0 /* AzkarItemsScreen.swift */,
2D9B68D52BB19B0F0029E4D0 /* ItemRow.swift */,
2D9B68D32BB19AFB0029E4D0 /* ItemViewModel.swift */,
);
path = AzkarItems;
sourceTree = "<group>";
};
2D9B68D72BB1A3600029E4D0 /* AzkarChapters */ = {
isa = PBXGroup;
children = (
2D9B68CE2BB1913A0029E4D0 /* AzkarChaptersScreen.swift */,
2D9B68CC2BB191270029E4D0 /* ChapterRow.swift */,
2D9B68C92BB190E30029E4D0 /* ChapterViewModel.swift */,
);
path = AzkarChapters;
sourceTree = "<group>";
};
6A22480B2BAED7730094967B /* Names */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -80,6 +121,7 @@
isa = PBXGroup;
children = (
6A22480B2BAED7730094967B /* Names */,
2D9B68CB2BB190F30029E4D0 /* Azkars */,
6A787B1B2BAECF6F00DA0107 /* MuslimDataExampleApp.swift */,
6A787B1D2BAECF6F00DA0107 /* ContentView.swift */,
6A787B1F2BAECF7200DA0107 /* Assets.xcassets */,
Expand Down Expand Up @@ -169,11 +211,17 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2D9B68CA2BB190E30029E4D0 /* ChapterViewModel.swift in Sources */,
2D9B68CF2BB1913A0029E4D0 /* AzkarChaptersScreen.swift in Sources */,
2D9B68CD2BB191270029E4D0 /* ChapterRow.swift in Sources */,
2D9B68D42BB19AFB0029E4D0 /* ItemViewModel.swift in Sources */,
6A22480F2BAED7960094967B /* NamesRowView.swift in Sources */,
6A22480D2BAED7840094967B /* NamesScreen.swift in Sources */,
6A787B1E2BAECF6F00DA0107 /* ContentView.swift in Sources */,
6A787B1C2BAECF6F00DA0107 /* MuslimDataExampleApp.swift in Sources */,
2D9B68D62BB19B0F0029E4D0 /* ItemRow.swift in Sources */,
6A2248112BAEDAEE0094967B /* NamesViewModel.swift in Sources */,
2D9B68D22BB195FF0029E4D0 /* AzkarItemsScreen.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// AzkarsScreen.swift
// Example
//
// Created by Kosrat Ahmed on 25/03/2024.
//

import SwiftUI

/// Display the azkar chapter list.
struct AzkarChaptersScreen: View {
private var azkarViewModel = ChapterViewModel()

var body: some View {
NavigationSplitView {
List {
ForEach(azkarViewModel.azkarChapters, id: \.id) { chapter in
NavigationLink {
AzkarItemsScreen(chapterId: chapter.id)
} label: {
ChapterRow(azkarChapter: chapter)
.frame(height: 36)
}
}
}
.navigationTitle("Azkars")
} detail: {
Text("Select an Azkar")
}
}
}

#Preview {
AzkarChaptersScreen()
}
28 changes: 28 additions & 0 deletions Example/MuslimDataExample/Azkars/AzkarChapters/ChapterRow.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// AzkarRow.swift
// Example
//
// Created by Kosrat Ahmed on 25/03/2024.
//

import SwiftUI
import MuslimData

/// Displays a single row that is representing an azkar chapter.
///
/// - Parameters:
/// - azkarChapter: the `AzkarChapter` instance that needs to be displayed in the row.
struct ChapterRow: View {
var azkarChapter: AzkarChapter

var body: some View {
VStack(alignment: .leading) {
Text(azkarChapter.name)
.font(.body)
}
}
}

#Preview {
ChapterRow(azkarChapter: AzkarChapter(id: 1, categoryId: 1, name: "Morning Azkars"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// AzkarViewModel.swift
// Example
//
// Created by Kosrat Ahmed on 25/03/2024.
//

import Foundation
import MuslimData

@Observable
/// Manages the state for the azkar chapters list and responsible for fetching data.
class ChapterViewModel {
private(set) var azkarChapters: [AzkarChapter] = []

init() {
getAzkarChapters()
}

/// Fetches the azkar chapters from the `MuslimRepository`.
private func getAzkarChapters() {
Task {
do {
azkarChapters = try await MuslimRepository().getAzkarChapters(language: .en) ?? []
} catch {
print("Error loading azkars: \(error.localizedDescription)")
}
}
}
}
33 changes: 33 additions & 0 deletions Example/MuslimDataExample/Azkars/AzkarItems/AzkarItemsScreen.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// AzkarDetailScreen.swift
// Example
//
// Created by Kosrat Ahmed on 25/03/2024.
//

import SwiftUI

/// Display the detail of the selected azkar chapter.
struct AzkarItemsScreen: View {
var chapterId: Int
var itemsViewModel: ItemViewModel

init(chapterId: Int) {
self.chapterId = chapterId
itemsViewModel = ItemViewModel(chapterId: chapterId)
}

var body: some View {
List {
ForEach(itemsViewModel.azkarItems, id: \.id) { item in
ItemRow(azkarItem: item)
}
}
.listRowSpacing(8)
.navigationTitle("Azkar Details")
}
}

#Preview {
AzkarItemsScreen(chapterId: 1)
}
41 changes: 41 additions & 0 deletions Example/MuslimDataExample/Azkars/AzkarItems/ItemRow.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// ItemRow.swift
// Example
//
// Created by Kosrat Ahmed on 25/03/2024.
//

import SwiftUI
import MuslimData

/// Displays a single row that is representing an Azkar Item. Includes the Arabic azkar, its tranlation,
/// and the azkar reference.
///
/// - Parameters:
/// - azkarItem: the `AzkarItem` instance that needs to be displayed in the row.
struct ItemRow: View {
var azkarItem: AzkarItem

var body: some View {
VStack(alignment: .leading) {
Text(azkarItem.item)
.font(.headline)
.padding(.bottom, 4)
Text(azkarItem.translation)
.font(.body)
.padding(.bottom, 8)
Text(azkarItem.reference)
.font(.caption)
}
}
}

#Preview {
ItemRow(azkarItem: AzkarItem(
id: 1,
chapterId: 1,
item: "Azkar detail in Arabic language",
translation: "translated azkar into user's language",
reference: "Azkar references")
)
}
32 changes: 32 additions & 0 deletions Example/MuslimDataExample/Azkars/AzkarItems/ItemViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// ItemViewModel.swift
// Example
//
// Created by Kosrat Ahmed on 25/03/2024.
//

import Foundation
import MuslimData

@Observable
/// Manages the state for the azkar item list and responsible for fetching data.
class ItemViewModel {
private(set) var azkarItems: [AzkarItem] = []
let chapterId: Int

init(chapterId: Int) {
self.chapterId = chapterId
getAzkarItems()
}

/// Fetches the azkar items from the `MuslimRepository`.
private func getAzkarItems() {
Task {
do {
azkarItems = try await MuslimRepository().getAzkarItems(chapterId: chapterId, language: .en) ?? []
} catch {
print("Error getting azkar items: \(error.localizedDescription)")
}
}
}
}
2 changes: 1 addition & 1 deletion Example/MuslimDataExample/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ struct ContentView: View {
Image("ic_nav_names")
Text("Names")
}.tag(AppTabs.names)
Text("Azkar")
AzkarChaptersScreen()
.tabItem {
Image("ic_nav_azkars")
Text("Azkar")
Expand Down
7 changes: 4 additions & 3 deletions Example/MuslimDataExample/Names/NamesRowView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@
import SwiftUI
import MuslimData

/// Displays a single row representing a Name of Allah. Includes the Arabic name and its translation.
/// Displays a single row which is representing a Name of Allah. Includes the Arabic name
/// and its translation.
///
/// - Parameter:
/// - name: The `Name` data to be displayed in the row.
/// - Parameters:
/// - name: The `Name` instance that needs to be displayed in the row.
struct NamesRowView: View {
let name: Name

Expand Down
1 change: 0 additions & 1 deletion Example/MuslimDataExample/Names/NamesScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ struct NamesScreen: View {
NamesRowView(name: name)
}
}
.listStyle(.plain)
.navigationTitle("Names of Allah")
}
}
Expand Down
3 changes: 1 addition & 2 deletions Example/MuslimDataExample/Names/NamesViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,11 @@
import Foundation
import MuslimData

/// Manages the state for a list of Names of Allah. Responsible for fetching data.
@Observable
/// Manages the state for a list of Names of Allah and responsible for fetching data.
class NamesViewModel {
private(set) var names: [Name] = []

/// Initializes the view model and starts fetching the Names of Allah.
init() {
getNamesOfAllah()
}
Expand Down

0 comments on commit c9d23b1

Please sign in to comment.