tutorial101 is the one place for high quality web development, Web Design and software development tutorials and Resources programming. Learn cutting edge techniques in web development, design and software development, download source components and participate in the community.
article
Showing posts with label SwiftUI-iOS-Xcode. Show all posts
Showing posts with label SwiftUI-iOS-Xcode. Show all posts
//
// Model.swift
// SwiftUIProject
//
// Created by Cairocoders
//
import Foundation
struct Dessert: Identifiable, Hashable {
public var id: Int
public var image: String
public var name: String
public var price: String
public var description: String
}
var dessertData = [
Dessert(id: 0, image: "desert1", name: "Leche Flan", price: "$2.99", description: "Leche Flan is a dessert made-up of eggs and milk with a soft caramel on top. It resembles crรจme caramel and caramel custard."),
Dessert(id: 1, image: "desert2", name: "Maja Blanca", price: "$2.02", description: "Maja Blanca is a Filipino dessert made from coconut milk, cornstarch, and sugar. Often called Coconut Pudding, this luscious dessert is easy to make"),
Dessert(id: 2, image: "desert3", name: "Yema", price: "$1.00", description: "Yema is a type of Filipino candy named after the Spanish term for egg yolks. I don't see the reason as to why not because egg yolk is a major ingredient "),
Dessert(id: 3, image: "desert4", name: "Ube Halaya", price: "$3.99", description: "Ube Halaya or is a type of Filipino jam made from purple yam. It's commonly served as a midday snack or after-meal dessert"),
Dessert(id: 4, image: "desert5", name: "Buko Salad", price: "$1.99", description: "The Buko Salad Recipe is prepared with young shredded coconut, canned fruits, cream and sweetened milk. A very popular dessert in every parties or occasion."),
Dessert(id: 5, image: "desert6", name: "Polvoron", price: "$0.99", description: "Polvoron is a type of shortbread popular in Spain and its former colonies in Latin America and the Philippines."),
Dessert(id: 6, image: "desert7", name: "Pastillas", price: "$0.85", description: "Pastillas de leche are sweet milk candies that are usually served for dessert. An authentic recipe will require the use of Carabao's"),
Dessert(id: 7, image: "desert8", name: "Cassava Cake", price: "$1.99", description: "Cassava Cake is a classic Filipino dessert made from grated cassava (manioc). Cassava is also known as kamoteng kahoy and balinghoy"),
]
//
// ContentView.swift
// SwiftUIProject
//
// Created by Cairocoders
//
import Combine
import SwiftUI
struct ContentView: View {
@ObservedObject private var userViewModel = UserViewModel()
@State var columns = Array(repeating: GridItem(.flexible(), spacing: 15), count: 2)
var body: some View {
ScrollView(.vertical, showsIndicators: false) {
HStack{
Text("GitHub User")
.font(.title)
.fontWeight(.bold)
Spacer()
Button {
} label: {
Image(systemName: "rectangle.grid.1x2")
.font(.system(size: 24))
.foregroundColor(.black)
}
}
.padding(.horizontal)
.padding(.top,25)
LazyVGrid(columns: self.columns,spacing: 25){
ForEach(userViewModel.users, id: \.id) { user in
UserRow(user: user)
}
LoaderView(isFailed: userViewModel.isRequestFailed)
.onAppear(perform: fetchData)
.onTapGesture(perform: onTapLoadView)
}
.padding([.horizontal,.top])
}
.background(Color.black.opacity(0.05).edgesIgnoringSafeArea(.all))
}
private func fetchData() {
userViewModel.getUsers()
}
private func onTapLoadView() {
// tap to reload
if userViewModel.isRequestFailed {
userViewModel.isRequestFailed = false
fetchData()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
APIService.swift
//
// APIService.swift
// SwiftUIProject
//
// Created by Cairocoders
//
import Foundation
import Combine
class APIService {
static let shared = APIService()
func getUsers(perPage: Int = 30, sinceId: Int? = nil) -> AnyPublisher<[User], Error> {
var components = URLComponents(string: "https://api.github.com/users")!
components.queryItems = [
URLQueryItem(name: "per_page", value: "\(perPage)"),
URLQueryItem(name: "since", value: (sinceId != nil) ? "\(sinceId!)" : nil)
]
let request = URLRequest(url: components.url!, timeoutInterval: 5)
return URLSession.shared.dataTaskPublisher(for: request)
.map(\.data)
.decode(type: [User].self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
}
LoaderView.swift
//
// LoaderView.swift
// SwiftUIProject
//
// Created by Cairocoders
//
import SwiftUI
struct LoaderView: View {
let isFailed: Bool
var body: some View {
Text(isFailed ? "Failed. Tap to retry." : "Loading..")
.foregroundColor(isFailed ? .red : .green)
.padding()
.font(.title)
}
}
struct LoaderView_Previews: PreviewProvider {
static var previews: some View {
LoaderView(isFailed: false)
}
}
User.swift
//
// User.swift
// SwiftUIProject
//
// Created by Cairocoders
//
import Foundation
struct User: Decodable, Identifiable {
let id: Int
let name: String
let avatarUrl: String
enum CodingKeys: String, CodingKey {
case id
case name = "login"
case avatarUrl = "avatar_url"
}
}
UserRow.swift
//
// UserRow.swift
// SwiftUIProject
//
// Created by Cairocoders
//
import SwiftUI
import SDWebImageSwiftUI //https://github.com/SDWebImage/SDWebImageSwiftUI.git
struct UserRow: View {
let user: User
@State var show = false
var body: some View {
VStack(spacing: 15){
ZStack(alignment: Alignment(horizontal: .trailing, vertical: .top)) {
Button {
show.toggle()
} label: {
AnimatedImage(url: URL(string: user.avatarUrl)!)
.resizable()
.frame(height: 250)
.cornerRadius(15)
}
Button {
} label: {
Image(systemName: "heart.fill")
.foregroundColor(.red)
.padding(.all,10)
.background(Color.white)
.clipShape(Circle())
}
.padding(.all,10)
}
Text(user.name)
.fontWeight(.bold)
}
.sheet(isPresented: $show, content: {
DetailsView(user: User(id: user.id, name: user.name, avatarUrl: user.avatarUrl))
})
}
}
struct UserRow_Previews: PreviewProvider {
static var previews: some View {
let mockUser = User(id: 1, name: "cairocoders", avatarUrl: "")
UserRow(user: mockUser)
}
}
UserViewModel.swift
//
// UserViewModel.swift
// SwiftUIProject
//
// Created by Cairocoders
//
import Foundation
import Combine
class UserViewModel: ObservableObject {
@Published var users: [User] = []
@Published var isRequestFailed = false
private let pageLimit = 10
private var currentLastId: Int? = nil
private var cancellable: AnyCancellable?
func getUsers() {
cancellable = APIService.shared.getUsers(perPage: pageLimit, sinceId: currentLastId)
.receive(on: DispatchQueue.main)
.sink { completion in
switch completion {
case .failure(let error):
self.isRequestFailed = true
print(error)
case .finished:
print("finished loading")
}
} receiveValue: { users in
self.users.append(contentsOf: users)
self.currentLastId = users.last?.id
}
}
}
DetailsView.swift
//
// DetailsView.swift
// SwiftUIProject
//
// Created by Cairocoders
//
import SwiftUI
import SDWebImageSwiftUI
struct DetailsView: View {
var user: User
var body: some View {
VStack {
HStack {
AnimatedImage(url: URL(string: user.avatarUrl)!)
.resizable()
.frame(width: 250, height: 250)
.cornerRadius(15)
}
HStack {
Text("User Name :")
Text(user.name)
}
}
}
}
SwiftUI MVVM (Model View View Model) design pattern with ObservableObject — @Published — @ObservedObject fetch JSON data
ContentView.swift
//
// ContentView.swift
// SwiftUIProject
//
// Created by Cairocoders
//
import SwiftUI
struct ContentView: View {
@ObservedObject var viewModel = ContentViewModel()
var body: some View {
NavigationView {
VStack {
List(viewModel.items, id: \.id) { item in
VStack(alignment: .leading) {
Text(item.title)
Text(item.completed.description)
.font(.system(size: 11))
.foregroundColor(.gray)
}
}
.listStyle(GroupedListStyle())
}.onAppear(perform: {
viewModel.fetchData()
})
.navigationBarTitle("Fetch JSON Datas")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
ViewModel.swift
//
// ViewModel.swift
// SwiftUIProject
//
// Created by Cairocoders
//
import SwiftUI
class ContentViewModel: ObservableObject {
@Published var items = [Model]()
func fetchData() {
let api = "https://jsonplaceholder.typicode.com/todos"
guard let url = URL(string: api) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
do {
if let data = data {
let result = try JSONDecoder().decode([Model].self, from: data)
DispatchQueue.main.async {
self.items = result
}
} else {
print("No data")
}
} catch (let error) {
print(error.localizedDescription)
}
}.resume()
}
}
Model.swift
//
// Model.swift
// SwiftUIProject
//
// Created by Cairocoders
//
import SwiftUI
struct Model: Decodable {
let id: Int
let userId: Int
let title: String
let completed: Bool
}