Giter Club home page Giter Club logo

mvvm-and-design-pattern's Introduction

CMS with MVVM Design Patern

Xcode Version 13.0

SwiftUI, Firebase, Kingfisher

MVVM-and-Design-Pattern Project

MVVM-and-Design-Pattern show both MVVM patern and how to structure files as well as full flow of CMS and fronend for products which you can use is project to start your project.

MVVM pattern architecture

Model-View-ViewModel (MVVM) is a structural design pattern that separates objects into three distinct groups:

1. Model

The Model represents simple data. It simply holds the data and has nothing to do with any of the business logic. You can simply say it’s a plain structure of data that we are expecting from our API.

2. View

To receive data from ViewModel class we have link our ViewModel property inside the view controller class

3. ViewModel

ViewModel is the main component of this architecture pattern. ViewModel never knows what the view is or what the view does. This makes this architecture more testable and removes complexity from the view.

How to install

  1. Clone project to your Mac

  1. Setup firebase https://firebase.google.com/docs/ios/setup

  2. Delete "GoogleService-Info.plist" in App/ and import your own GoogleService-Info.plist

4. run pod install in Terminal
 run pod install
  1. Close project and open again

  1. ✨Well done, now you will be able to see the CMS screen.

| |

Folder Structure

Check these files

Pods for MVVM-and-Design-Pattern

Run open podfile, Only check what pods we use in the project.

 open podfile
  pod 'Firebase'
  pod 'Firebase/Firestore'


  # download the image from url
  pod 'Kingfisher', '~> 6.0'

MVVM_and_Design_PatternApp.swift

if you want to separate to difference Firebase for development and production so you can use this code otherwise you can just use FirebaseApp.configure()

    private func setupFirebaseApp() {
        
       guard let plistPath = Bundle.main.path(
        forResource: "GoogleService-Info", ofType: "plist"),
             let options =  FirebaseOptions(contentsOfFile: plistPath)
                      else { return }
        
          if FirebaseApp.app() == nil{
              FirebaseApp.configure(options: options)
          }
    }

Example for Config 2 difference Firebase.

     private func setupFirebaseApp() {
        #if DEBUG
            let kGoogleServiceInfoFileName = "DEVELOPMENT-GoogleService-Info"
        #else
            let kGoogleServiceInfoFileName = "GoogleService-Info"
        #endif
        
       guard let plistPath = Bundle.main.path(
        forResource: kGoogleServiceInfoFileName, ofType: "plist"),
             let options =  FirebaseOptions(contentsOfFile: plistPath)
                      else { return }
        
          if FirebaseApp.app() == nil{
              FirebaseApp.configure(options: options)
          }
    }

Constants.swift

The constants values that I use in the project.

public let kSafeAreaTop = UIApplication.shared.windows.first?.safeAreaInsets.top
public let kSafeAreaBottom = UIApplication.shared.windows.first?.safeAreaInsets.bottom
public let kScreen = UIScreen.main.bounds
public let kUserDefaults = UserDefaults.standard
public let kScreenBackground: String = "background"

let KCategories = ["ALL","MAN","WOMAN", "KIDS"] 

FCollectionReference.swift

Collections for firebase

enum FCollectionReference: String {
    case ProductGroup = "pia_productGroup"
    case Product = "pia_product"
    case ProductBundle = "pia_productBundle"
    
} 

func FirebaseReference(_ collectionReference: FCollectionReference) -> CollectionReference {
    
    return Firestore.firestore().collection(collectionReference.rawValue)
} 

How to use :

FirebaseReference(.Product).document(objectId).delete() { error in }

ProductModel.swift (Model)

struct ProductModel: Identifiable {
    var id: String
    var name: String
    var imageURL: String
    var category: String
    var description: String
    var price: Double
}

ProductModel.swift (View)

Example for View, program will receive data from ViewModel and present to the screen.

struct ProductFormView: View {
    // MARK: - Variable here
    
    var body: some View {
        
         // MARK: - View here
        
    } 
    
    // MARK: - HELPER FUNCTIONS
    func saveToFirebase(objectId: String){
        // Note: - Save to Firebase 
        let modelData = ProductModel(id: objectId,
                                     name: name,
                                     imageURL: imageURL,
                                     category: KCategories[tabCategory],
                                     description: description,
                                     price: Double(price)! )
        
        productVM.SaveRecord(objectId: objectId, modelData: modelData) { isCompleted in
            isSaved = true
        }
    }

    func resetFields(){
        name = ""
        imageURL = ""
        imageURL = ""
        category = ""
        description = ""
        price = "0.00"
    }
}```sh

ProductVM.swift (ViewModel)

All insert/update/delete processes.

class ProductVM: ObservableObject {
    @Published var contentRows: [ProductModel] = []
    @Published var countRow: Int = 0
    @Published var selectedRow: ProductModel?
    
    @State var contentRowsByCategory : [ProductModel] = []
    
    init() {
       getRecords()
    }
    
    func getRecords() {
        self.contentRows = []
        FirebaseReference(.Product).getDocuments { [self] (snapshot, error) in
            
            guard let snapshot = snapshot else { return }
            
            if !snapshot.isEmpty {
                for snapshot in snapshot.documents {
                    let rowData = snapshot.data()
                    let rowStructure = dictionaryToStructrue(rowData)
                    self.contentRows.append(rowStructure)
                }
                
                self.contentRowsByCategory = self.contentRows
            }
        }
         
    }
    
    func getSelectedRow(selectedRow: ProductModel) {
        self.selectedRow = selectedRow
    }
    
    // Note: - Create/Update Record
    func SaveRecord(objectId: String, modelData: ProductModel, completion: @escaping (_ isCompleted: Bool?) -> Void) {
        
        let dictionaryRowData = self.structureToDictionary(modelData)
        FirebaseReference(.Product).document(objectId).setData(dictionaryRowData) {
            error in
            DispatchQueue.main.async {
                if error != nil {
                    completion(false)
                }
                completion(true)
            }
        }
    }
    
    // Note: - Delete Record
    func removeRecord(objectId: String, completion: @escaping (_ isCompleted:Bool?) -> Void) {
        FirebaseReference(.Product).document(objectId).delete() { error in
            if let _ = error {
                completion(false)
            } else {
                completion(true)
            }
        }
    }
    
    
    func structureToDictionary(_ row : ProductModel) -> [String : Any] {
        return NSDictionary(
            objects:
                [row.id,
                 row.name,
                 row.imageURL,
                 row.category,
                 row.description,
                 row.price
                ],
            forKeys: [
                "id" as NSCopying,
                "name" as NSCopying,
                "imageURL" as NSCopying,
                "category" as NSCopying,
                "description" as NSCopying,
                "price" as NSCopying
            ]
        ) as! [String : Any]
    }
    
    func dictionaryToStructrue(_ dictionaryRow : [String : Any]) -> ProductModel {
        return ProductModel(id: dictionaryRow["id"] as? String ?? "",
                            name: dictionaryRow["name"] as? String ?? "",
                            imageURL: dictionaryRow["imageURL"] as? String ?? "",
                            category: dictionaryRow["category"] as? String ?? "",
                            description:dictionaryRow["description"] as? String ?? "",
                            price: dictionaryRow["price"] as? Double ?? 0.00)
    }
     
    
}

ButtonIconAction.swift

If you have same design buttons in your app it's good to use shared button action view.

struct ButtonWithCircleIconAction: View {
    var systemName:String
    
    var action: () -> Void
    var body: some View {
        Button(action: action , label: {
            Image(systemName: systemName)
                .foregroundColor(Color.white)
                .padding()
                .background(Color.accentColor.opacity(0.3))
                .clipShape(Circle())
        })
    }
}

When you use

ButtonWithCircleIconAction(systemName: "magnifyingglass", action: {
    // Your code here
 })

CommonModifier.swift

It's useful for style objects. it's similar to CSS for website.

struct ImageFullScreenModifier: ViewModifier {
    
    func body(content: Content) -> some View {
        content
            .frame(width: kScreen.width * 0.9, height: kScreen.height - (kSafeAreaTop! + kSafeAreaBottom!) - 200)
            .scaledToFit()
            .cornerRadius(10)
    }
}

If you can't run project

Note: The project at ‘/Users/lia/Documents/MVVM-and-Design-Pattern/MVVM-and-Design-Pattern.xcodeproj’ cannot be opened because it is in a future Xcode project file format. Adjust the project format using a compatible version of Xcode to allow it to be opened by this version of Xcode.

mvvm-and-design-pattern's People

Contributors

waleerat avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.