takasurazeem / QuranMajeed

This app will help you create Quiz for your students if you teach The Quran. This app will grow in features ان شاء اللہ تَعَالٰی
GNU General Public License v3.0
5 stars 1 forks source link

Add capability to change name of Masjid and class via a settings module. #55

Open takasurazeem opened 9 months ago

codeautopilot[bot] commented 9 months ago

Potential solution

The task involves adding the capability to change the name of the Masjid and class via a settings module. The solution requires updating the QuizPreferences structure to include new properties for Masjid and class names, modifying the PDFPreviewView to use these new properties, and ensuring that the Datastore implementations can save and load these new settings. Additionally, the QuizSettingsView will need to provide UI elements for user input, and the QuizViewModel will need to handle the logic for updating and persisting these settings.

How to implement

QuizPreferences.swift

Add new properties for Masjid and class names to the QuizPreferences structure and update the initializer to include these properties.

struct QuizPreferences {
    struct QuizHeader {
        var topRightText: String
        var topLeftText: String
        var masjidName: String
        var className: String
    }

    var quizHeader: QuizHeader
    var quizDate = Date.now

    init(topRightText: String = "Default Top Right",
         topLeftText: String = "Default Top Left",
         masjidName: String = "Default Masjid",
         className: String = "Default Class") {
        self.quizHeader = QuizHeader(topRightText: topRightText,
                                     topLeftText: topLeftText,
                                     masjidName: masjidName,
                                     className: className)
    }
}

PDFPreviewView.swift

Update the PDFPreviewView to use the new properties from QuizPreferences when generating the PDF.

PDFKitView(
    documentData: PDFGenerator(
        verses: viewModel.quizVerses,
        words: viewModel.wordsForWordsMeaning,
        preferences: viewModel.preferences
    ).generateQuiz()
)

QuizSettingsView.swift

Add TextField views for Masjid and class names and a Button to save the changes.

TextField("Enter Masjid Name", text: $masjidName)
TextField("Enter Class Name", text: $className)
Button("Save Changes", action: saveSettings)

QuizViewModel.swift

Add properties for Masjid and class names and methods to update and save these settings.

@Published var masjidName: String = ""
@Published var className: String = ""

func updateMasjidName(to newName: String) {
    masjidName = newName
    saveSettings()
}

func updateClassName(to newName: String) {
    className = newName
    saveSettings()
}

private func saveSettings() {
    // Save the settings using the Datastore implementation
}

FileDatastore.swift

Ensure that the FileDatastore class can handle saving and loading the new settings. Since the class is generic, no specific changes are needed here, but you may want to add error handling and logging.

let preferencesDatastore = FileDatastore<QuizPreferences>(purpose: "QuizSettings")
preferencesDatastore.save(preferences, forKey: "QuizPreferences")

Datastore.swift

Verify that the concrete implementations of the Datastore protocol can handle string values for Masjid and class names. If necessary, add methods to save and load these settings.

protocol Datastore {
    // Existing methods...
    func saveMasjidName(_ name: String)
    func loadMasjidName() -> String?
    func saveClassName(_ name: String)
    func loadClassName() -> String?
}

Ensure that the concrete classes or structs that conform to the Datastore protocol implement these methods.

Testing and Documentation

Test the changes to ensure that the Masjid and class names are correctly saved, loaded, and displayed. Update documentation to reflect the new functionality.

Click here to create a Pull Request with the proposed solution

Files used for this task:

Changes on QuranMajeed/Foundation/Datastore.swift The `Datastore` protocol in `QuranMajeed/Foundation/Datastore.swift` already provides a generic interface for saving, loading, and deleting data, as well as flushing the entire data store. To support the new feature of changing the name of the Masjid and class via a settings module, we need to ensure that the concrete implementations of this protocol can handle the specific data types for Masjid and class names. Since the `Datastore` protocol uses an associated type `T`, it can support any data type, including strings, which are likely the data type needed for Masjid and class names. Therefore, the protocol itself does not need to be modified to support the new feature. However, it is important to ensure that the concrete classes or structs that conform to the `Datastore` protocol in the application are capable of handling string values and that they are set up to save and retrieve the Masjid and class names using specific keys. The tasks for the concrete implementations, such as `FileDatastore`, will involve updating methods to include saving and loading the new settings for Masjid and class names. This will likely involve adding new keys for these settings and ensuring that the save and load methods can handle string values. In summary, the `Datastore` protocol itself does not require changes for this task, but the concrete implementations must be verified or updated to ensure they can handle the new settings. The focus should be on the classes or structs that conform to this protocol and their ability to persist and retrieve string values associated with the new feature.
Changes on QuranMajeed/Info.plist For the `Info.plist` file, there is no immediate need to add keys or strings related to permissions or usage descriptions for the task described. The task involves adding functionality to change the name of a Masjid and class via a settings module, which does not inherently require new permissions or usage descriptions. However, if the new settings involve accessing sensitive user data or integrating with other services that require permissions (e.g., cloud storage for syncing settings), then appropriate keys and strings would need to be added to the `Info.plist` file. Since the task description does not specify such requirements, the `Info.plist` file can remain unchanged for the scope of this task. If future requirements necessitate changes to this file, those can be addressed at that time.
Changes on QuranMajeed/Quiz/Main/View/Quiz/PDFPreviewView.swift To address the task of binding the Masjid and class names to the appropriate Text views in the `PDFPreviewView.swift` file, you will need to modify the `PDFPreviewView` struct to use the updated `QuizPreferences` structure that includes the new properties for Masjid and class names. Here's a practical proposal to solve the task: 1. Ensure that the `QuizPreferences` structure is updated to include properties for the Masjid and class names. This should be handled in the `QuizPreferences.swift` file by another agent. 2. Once the `QuizPreferences` structure is updated, modify the `PDFPreviewView` struct to use these new properties when generating the PDF. Specifically, you will need to update the `PDFGenerator` initializer call to pass the new Masjid and class names. 3. Remove the `@AppStorage` properties for `masjidName` and `className` if they are no longer needed because the names will be managed through the `QuizPreferences` structure. Here's an example of how you might modify the `PDFPreviewView` struct: ```swift struct PDFPreviewView: View { @ObservedObject var viewModel: QuizView.ViewModel var body: some View { NavigationLink { VStack { // ... (other code remains unchanged) // Update the PDFKitView initializer to use the updated QuizPreferences PDFKitView( documentData: PDFGenerator( verses: viewModel.quizVerses, words: viewModel.wordsForWordsMeaning, preferences: QuizPreferences( quizHeader: QuizPreferences.QuizHeader( topRightText: viewModel.preferences.className, // Updated to use viewModel topLeftText: viewModel.preferences.masjidName // Updated to use viewModel ) ) ) .generateQuiz() ) // ... (other code remains unchanged) } } label: { // ... (label code remains unchanged) } } } ``` In the above code, `viewModel.preferences.className` and `viewModel.preferences.masjidName` are placeholders for where you would access the updated class and Masjid names from the `QuizPreferences` structure. You will need to ensure that the `viewModel` has access to the updated `QuizPreferences` that includes these properties. Remember to test the changes to ensure that the Masjid and class names are correctly displayed in the PDF preview and that the PDF document is generated as expected with the new settings.
Changes on QuranMajeed/Quiz/QuizSettings/QuizPreferences.swift To solve the task for the `QuizPreferences.swift` file, we need to add properties to the `QuizPreferences` structure that will hold the new Masjid and class names. Here's a practical proposal for the changes: ```swift // // QuizPreferences.swift // Al-Tanzeel // // Created by Takasur Azeem on 16/02/2024. // Copyright © 2024 Islam. All rights reserved. // import Foundation struct QuizPreferences { struct QuizHeader { var topRightText: String var topLeftText: String var masjidName: String // New property for Masjid name var className: String // New property for class name } var quizHeader: QuizHeader var quizDate = Date.now // Initializer to set default values or load existing settings init(topRightText: String = "Default Top Right", topLeftText: String = "Default Top Left", masjidName: String = "Default Masjid", className: String = "Default Class") { self.quizHeader = QuizHeader(topRightText: topRightText, topLeftText: topLeftText, masjidName: masjidName, className: className) } } ``` With these changes, the `QuizPreferences` structure now includes properties for the Masjid and class names. The initializer is also updated to allow setting default values or loading existing settings for these new properties. This will facilitate the persistence and retrieval of the Masjid and class names in the data store, which will be handled in the `Datastore.swift` and `FileDatastore.swift` files by another agent.
Changes on QuranMajeed/Quiz/QuizSettings/QuizSettingsView.swift To solve the task of adding the capability to change the name of the Masjid and class via a settings module, we need to modify the `QuizSettingsView.swift` file to include TextFields for user input and a button to save the changes. Here's a practical proposal for the changes: 1. Add two `TextField` views to allow the user to input new names for the Masjid and the class. 2. Add a `Button` that will save the changes made by the user to the `AppStorage`. Here's the updated code for `QuizSettingsView.swift`: ```swift import SwiftUI struct QuizSettingsView: View { @AppStorage("MasjidName") private var masjidName: String = "" @AppStorage("ClassName") private var className: String = "" private let masjidNameLabel: String = "Masjid Name" private let classNameLabel: String = "Class Name" var body: some View { List { Section(header: Text("Settings")) { VStack(alignment: .leading) { Text(masjidNameLabel) .font(.headline) TextField("Enter Masjid Name", text: $masjidName) .textFieldStyle(RoundedBorderTextFieldStyle()) .padding(.bottom) Text(classNameLabel) .font(.headline) TextField("Enter Class Name", text: $className) .textFieldStyle(RoundedBorderTextFieldStyle()) .padding(.bottom) Button(action: saveSettings) { Text("Save Changes") .bold() .frame(maxWidth: .infinity) } .buttonStyle(RoundedRectangleButtonStyle()) } .padding() } } .navigationTitle("Quiz Settings") } private func saveSettings() { // Code to save the settings will be implemented here. // This could involve updating the ViewModel or directly saving to AppStorage if that's the chosen approach. } } struct RoundedRectangleButtonStyle: ButtonStyle { func makeBody(configuration: Configuration) -> some View { configuration.label .padding() .background(Color.blue) .foregroundColor(.white) .clipShape(RoundedRectangle(cornerRadius: 8)) .scaleEffect(configuration.isPressed ? 0.95 : 1) } } struct QuizSettingsView_Previews: PreviewProvider { static var previews: some View { NavigationStack { QuizSettingsView() } } } ``` In this updated code, we have: - Added `TextField` views for the Masjid and class names. - Included a `Button` with an action `saveSettings` that will be responsible for saving the changes. - Used `@AppStorage` property wrappers to bind the text fields to persistent storage. - Provided a `RoundedRectangleButtonStyle` to style the save button. The `saveSettings` function is where you would implement the logic to save the settings. Depending on the architecture of the app, this could involve updating a ViewModel, sending a message to a controller, or directly saving to `AppStorage`. The specifics of this function will depend on the rest of the app's code and architecture.
Changes on QuranMajeed/Quiz/Main/ViewModel/QuizViewModel.swift To implement the capability to change the name of the Masjid and class via a settings module in the `QuizViewModel.swift` file, you should follow these steps: 1. **Define Properties for Masjid and Class Names:** Add two new `@Published` properties to the `ViewModel` class to hold the current Masjid and class names. These properties will be observed by the view for changes. ```swift @Published var masjidName: String = "" @Published var className: String = "" ``` 2. **Create Methods to Update Names:** Implement methods within the `ViewModel` class to update the Masjid and class names. These methods will be called when the user submits the new names from the settings view. ```swift func updateMasjidName(to newName: String) { masjidName = newName saveSettings() } func updateClassName(to newName: String) { className = newName saveSettings() } ``` 3. **Persisting Changes:** Create a `saveSettings` method that will persist the changes to the data store. This method will interact with the `Datastore` class or any other persistence service you have in your application. ```swift private func saveSettings() { // Assuming Datastore has methods to save settings Datastore.shared.saveMasjidName(masjidName) Datastore.shared.saveClassName(className) } ``` 4. **Loading Initial Settings:** In the `init` method or a dedicated `loadSettings` method, load the initial Masjid and class names from the data store and assign them to the properties. ```swift init( theQuranRepository: QuranRepository ) { self.theQuranRepository = theQuranRepository // ... existing code ... loadSettings() } private func loadSettings() { masjidName = Datastore.shared.loadMasjidName() ?? "Default Masjid" className = Datastore.shared.loadClassName() ?? "Default Class" } ``` 5. **Error Handling:** Add error handling to the methods that interact with the data store. This will ensure that any issues with saving or loading settings are properly managed. ```swift private func saveSettings() { do { try Datastore.shared.saveMasjidName(masjidName) try Datastore.shared.saveClassName(className) } catch { // Handle the error, possibly by showing an alert to the user } } ``` 6. **Update the View:** Ensure that the view that displays the Masjid and class names is bound to the `masjidName` and `className` properties of the `ViewModel`. This way, any changes to these properties will be reflected in the UI. Remember to also update the `Datastore` class or the relevant persistence service to handle the new settings for Masjid and class names. This includes adding methods to save and load these settings, as well as updating any models or structures that represent the persisted data.
Changes on QuranMajeed/Foundation/FileDatastore.swift To update the `FileDatastore.swift` to include saving and loading the new Masjid and class name settings, you will need to ensure that the `FileDatastore` class can handle these new settings. Since the `FileDatastore` class is generic and supports `Codable` data, you can save and load any `Codable` structure, including the new settings. Here's a practical proposal for updating the `FileDatastore` class: 1. **Define the Settings Structure**: First, ensure that there is a `Codable` structure that represents the settings you want to save, including the Masjid and class names. This structure should be defined in a different file, likely `QuizPreferences.swift`. 2. **Update Save and Load Methods**: The `save` and `load` methods in `FileDatastore` are already generic and should work for any `Codable` data, including the new settings structure. No changes are required here unless you want to add specific error handling or logging for the new settings. 3. **Error Handling and Logging**: Consider improving error handling and logging within the `save`, `load`, `delete`, and `flush` methods to provide more detailed feedback, especially since you are adding new functionality that might require debugging. 4. **Testing**: After the new settings structure is defined and integrated into the app, write unit tests to ensure that the `FileDatastore` can save and load the new settings correctly. Test cases should include saving new settings, loading existing settings, handling errors or missing files, and ensuring that the flush method does not inadvertently delete the new settings. 5. **Documentation**: Update the documentation/comments within the `FileDatastore` class to reflect the new capability of handling Masjid and class name settings. Here is an example of how the settings structure might look in `QuizPreferences.swift`: ```swift struct QuizPreferences: Codable { var masjidName: String var className: String // ... other properties } ``` And here is how you might use the `FileDatastore` to save and load these settings: ```swift let preferencesDatastore = FileDatastore(purpose: "QuizSettings") // To save the settings let preferences = QuizPreferences(masjidName: "New Masjid", className: "New Class") preferencesDatastore.save(preferences, forKey: "QuizPreferences") // To load the settings if let loadedPreferences = preferencesDatastore.load(forKey: "QuizPreferences") { print("Loaded Masjid Name: \(loadedPreferences.masjidName)") print("Loaded Class Name: \(loadedPreferences.className)") } ``` Remember to handle the possibility of the settings not existing yet when the app is first launched or after a flush. You may want to provide default values or prompt the user to enter these details if they are not found.