article

Thursday, September 16, 2021

SwiftUI Simple Blog App

SwiftUI Simple Blog App

ContentView.swift
 
//
//  ContentView.swift
//  swiftuidev
//
//  Created by Cairocoders
//

import SwiftUI

struct ContentView: View {
    
    var body: some View {
        
        TabView {
            MainView()
                .tabItem {
                    Image(systemName: "house.fill")
                    Text("Home")
                }
            AllPosts()
                .tabItem {
                    Image(systemName: "list.dash")
                    Text("See all")
                }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()  
    }
}
Creating the data model
BlogPosts.swift
 
//
//  BlogPosts.swift
//  swiftuidev
//
//  Created by Cairocoders
//

import Foundation

struct BlogPosts : Identifiable {
     
    var id : Int
    var name : String
    var image : String
    var details : String
}
 
var latestpost = [
 
    BlogPosts(id: 0, name: "Bistek Tagalog", image: "0", details: "A dish made of strips of salted and peppered sirloin beef, usually flattened with a meat tenderizing tool, slowly cooked in soy sauce, calamansi juice, garlic and onions, a specialty of the Tagalog region"),
    BlogPosts(id: 1, name: "Boogie flight", image: "1", details: "A boodle fight is a meal that dispenses with cutlery and dishes. Diners instead practice kamayan, Filipino for eating with the hands"),
    BlogPosts(id: 2, name: "Sinigang Na Baboy", image: "2", details: "Sinigang na baboy with Gabi is a Filipino pork soup with taro cooked in a sour broth."),
    BlogPosts(id: 3, name: "Ginisang Togue", image: "3", details: "Ginisang Togue is basically Sauteed Mung Bean Sprout with carrots, bell pepper, shrimp, and tofu."),
    BlogPosts(id: 4, name: "Ginisang Munggo (Monggo)", image: "4", details: "Munggo or Mung bean (or even green bean to some) is a seed of Vigna radiata, a plant native to India and Pakistan. Since the plant originated in Asia, it was easy to spread along the nearby countries. This seed became a hit when it reached the Philippines."),
    BlogPosts(id: 5, name: "Pork Estofado (Sweet Pork Stew)", image: "5", details: "Pork Estofado with saba bananas, carrots, Chinese sausage, and a sweet and savory sauce. Perfect with steamed rice!"),
    BlogPosts(id: 6, name: "Pata Tim", image: "6", details: "Brimming in a pork stew infused with aromatic peppercorn, sesame oil and soy sauce, Pata Tim is a classic Filipino dish with traces in Chinese cuisine"),
    BlogPosts(id: 7, name: "Pancit Palabok", image: "7", details: "Pancit Palabok is a noodle dish with shrimp sauce and topped with several ingredients such as cooked shrimp, boiled pork, crushed chicharon, tinapa flakes, fried tofu, scallions, and fried garlic. "),
]

var featuredpost = [
 
    BlogPosts(id: 0, name: "Adobong Manok", image: "0", details: "A dish made of strips of salted and peppered sirloin beef, usually flattened with a meat tenderizing tool, slowly cooked in soy sauce, calamansi juice, garlic and onions, a specialty of the Tagalog region"),
    BlogPosts(id: 1, name: "Boogie flight", image: "1", details: "A boodle fight is a meal that dispenses with cutlery and dishes. Diners instead practice kamayan, Filipino for eating with the hands"),
]
MainView.swift
 
//
//  MainView.swift
//  swiftuidev
//
//  Created by Cairocoders
//

import SwiftUI

struct MainView: View {
    
    var body: some View {
        
        NavigationView {
            ScrollView {
                // featured article
                VStack {
                    HStack {
                        Text("Featured posts")
                            .font(.title.bold())
                        Spacer()
                    }
                    LazyVStack {
                        ForEach(featuredpost){post in
                            //Text(store.name)
                            NavigationLink(destination: BlogPostView(blogPost: post)) {
                              BlogPostCardMain(blogPost: post)
                            }
                        }
                    }
                }
                .padding(.horizontal, 15)
                .padding(.vertical, 30)
                
                // latest articles
                VStack {
                    HStack {
                        Text("Latest posts")
                            .font(.title.bold())
                        Spacer()
                    }
                    .padding(.horizontal, 15)
                    
                    ScrollView(.horizontal, showsIndicators: false) {
                        LazyHStack(spacing: 15) {
                            
                            if latestpost.count >= 3 {
                                ForEach(latestpost[0...2]) { post in
                                    NavigationLink(destination: BlogPostView(blogPost: post)) {
                                        BlogPostCardMain(blogPost: post)
                                    }
                                }
                                
                            }else {
                                ForEach(latestpost[0..<latestpost.count]) { post in
                                    NavigationLink(destination: BlogPostView(blogPost: post)) {
                                        BlogPostCardMain(blogPost: post)
                                    }
                                }
                            }
                        }
                        .padding(.leading, 15)
                        .padding(.trailing, 30)
                    }
                    .frame(height: 420)
                    
                    Spacer()
                }
                .padding(.bottom, 40)
                
            }
            .navigationBarTitle("Home")
            .navigationBarItems(
                trailing: Button(action: {}) { Image(systemName: "arrow.clockwise.circle.fill")
                    .resizable()
                    .frame(width: 30, height: 30)
            })
        }
    }
}
BlogPostCardMain.swift
 
//
//  BlogPostCardMain.swift
//  swiftuidev
//
//  Created by Cairocoders
//

import SwiftUI

struct BlogPostCardMain: View {
    
    @Environment(\.colorScheme) var colorScheme
    var blogPost: BlogPosts
    
    var body: some View {
        VStack(alignment: .leading) {
            Image(blogPost.image)
                .resizable()
                .aspectRatio(contentMode: .fill)
                .frame(height: 220)
                .frame(maxWidth: UIScreen.main.bounds.width - 80)
                .clipped()
                .clipShape(RoundedRectangle(cornerRadius: 20, style: .continuous))
            VStack(spacing: 6) {
                HStack {
                    Text(blogPost.name)
                        .multilineTextAlignment(.leading)
                        .fixedSize(horizontal: false, vertical: true)
                        .lineLimit(3)
                        .font(Font.title2.bold())
                        .foregroundColor(.primary)
                    Spacer()
                }
                HStack {
                    Text(blogPost.details)
                        .multilineTextAlignment(.leading)
                        .fixedSize(horizontal: false, vertical: true)
                        .lineLimit(3)
                        .font(.subheadline)
                        .foregroundColor(.secondary)
                    Spacer()
                }
            }
            .frame(height: 110)
        }
        .padding(15)
        .background(colorScheme == .dark ? Color(hex: "#121212") : Color.white)
        .frame(maxWidth: UIScreen.main.bounds.width - 50, alignment: .leading)
        .clipShape(RoundedRectangle(cornerRadius: 20, style: .continuous))
        .shadow(color: colorScheme == .dark ? .white.opacity(0.01) : .black.opacity(0.1), radius: 15, x: 0, y: 5)
    }
}

struct BlogPostCardMain_Previews: PreviewProvider {
    static var previews: some View {
        BlogPostCardMain(blogPost: BlogPosts(id: 1, name: "Adobo", image: "1", details: "sample"))
    }
}
AllPosts.swift
 
//
//  AllPosts.swift
//  swiftuidev
//
//  Created by Cairocoders
//

import SwiftUI

struct AllPosts: View {
    var body: some View {
        NavigationView {
            List {
                ForEach(latestpost) {post in
                    NavigationLink(destination: BlogPostView(blogPost: post)) {
                    BlogPostCardList(blogPost: post)
                    }
                }
            }
            .navigationTitle("All blog posts")
            .listStyle(InsetListStyle())
        }
    }
}

struct AllPosts_Previews: PreviewProvider {
    static var previews: some View {
        AllPosts()
    }
}
BlogPostCardList.swift
 
//
//  BlogPostCardList.swift
//  swiftuidev
//
//  Created by Cairocoders
//

import SwiftUI

struct BlogPostCardList: View {
    
    var blogPost: BlogPosts
    
    var body: some View {
        VStack(alignment: .leading) {
            Image(blogPost.image)
                .resizable()
                .aspectRatio(contentMode: .fill)
                .frame(maxWidth: .infinity)
                .frame(height: 180)
                .frame(maxWidth: UIScreen.main.bounds.width - 60)
                .clipped()
                .clipShape(RoundedRectangle(cornerRadius: 20, style: .continuous))
            VStack(spacing: 6) {
                HStack {
                    Text(blogPost.name)
                        .multilineTextAlignment(.leading)
                        .fixedSize(horizontal: false, vertical: true)
                        .lineLimit(3)
                        .font(Font.title2.bold())
                        .foregroundColor(.primary)
                    Spacer()
                }

                HStack {
                    Text(blogPost.details)
                        .multilineTextAlignment(.leading)
                        .fixedSize(horizontal: false, vertical: true)
                        .lineLimit(3)
                        .font(.subheadline)
                        .foregroundColor(.secondary)
                    Spacer()
                }
            }
        }
        .frame(maxWidth: UIScreen.main.bounds.width - 60, alignment: .leading)
        .padding()
    }
}

struct BlogPostCardList_Previews: PreviewProvider {
    static var previews: some View {
        BlogPostCardList(blogPost: BlogPosts(id: 1, name: "Adobo", image: "1", details: "Sample Details"))
    }
}
BlogPostView.swift
 
//
//  BlogPostView.swift
//  swiftuidev
//
//  Created by Cairocoders
//

import SwiftUI

struct BlogPostView: View {
    var blogPost: BlogPosts
    
    var body: some View {
        ZStack {
            ScrollView {
                VStack {
                    Image(blogPost.image)
                        .renderingMode(.original)
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                        .frame(height: 310)
                        .frame(maxWidth: UIScreen.main.bounds.width)
                        .clipped()
                    
                    VStack {
                        HStack {
                            Text(blogPost.name)
                                .font(.title3)
                                .fontWeight(.heavy)
                                .foregroundColor(.primary)
                                .lineLimit(3)
                                .padding(.vertical, 15)
                            Spacer()
                        }
                        .frame(maxWidth: .infinity)
                        
                        Text(blogPost.details)
                            .multilineTextAlignment(.leading)
                            .font(.body)
                            .foregroundColor(Color.primary.opacity(0.9))
                            .padding(.bottom, 25)
                            .frame(maxWidth: .infinity)
                    }
                    .padding(.horizontal, 20)

                    Spacer()
                }
                .frame(maxWidth: .infinity)
                
            }
            .navigationBarTitleDisplayMode(.inline)
        }
    }
}

struct BlogPostView_Previews: PreviewProvider {
    static var previews: some View {
        BlogPostView(blogPost: BlogPosts(id: 1, name: "Adobo", image: "1", details: "Sample Details"))
    }
}
HexColorExtension.swift
 
//
//  HexColorExtension.swift
//  swiftuidev
//
//  Created by Cairocoders
//

import Foundation
import SwiftUI

extension Color {
    init(hex: String) {
        let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
        var int: UInt64 = 0
        Scanner(string: hex).scanHexInt64(&int)
        let a, r, g, b: UInt64
        switch hex.count {
        case 3: // RGB (12-bit)
            (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
        case 6: // RGB (24-bit)
            (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
        case 8: // ARGB (32-bit)
            (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
        default:
            (a, r, g, b) = (1, 1, 1, 0)
        }

        self.init(
            .sRGB,
            red: Double(r) / 255,
            green: Double(g) / 255,
            blue:  Double(b) / 255,
            opacity: Double(a) / 255
        )
    }
}

Related Post