In this tutorial i'm going to create a simple Tinder App Using Firebase With SwiftUI.
ContentView.swift
//
// ContentView.swift
// DevSwiftUI
//
// Created by Cairocoders
//
import SwiftUI
import Firebase
import SDWebImageSwiftUI
struct ContentView: View {
@ObservedObject var obs = observer()
@State var showLiked = false
var body: some View {
ZStack{
Color(.white).edgesIgnoringSafeArea(.all)
if obs.users.isEmpty{
Loader()
}
VStack{
TopView(show: $showLiked)
swipeView()
}
}
.sheet(isPresented: $showLiked) {
LikedPeople()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
observer.swift
//
// observer.swift
// DevSwiftUI
//
// Created by Cairocoders
//
import SwiftUI
import Firebase
class observer : ObservableObject{
@Published var users = [datatype]()
@Published var last = -1
init() {
let db = Firestore.firestore()
db.collection("users").getDocuments { (snap, err) in
if err != nil{
print((err?.localizedDescription)!)
return
}
for i in snap!.documents{
let name = i.get("name") as! String
let age = i.get("age") as! String
let image = i.get("image") as! String
let id = i.documentID
let status = i.get("status") as! String
if status == ""{
self.users.append(datatype(id: id, name: name, image: image, age: age, swipe: 0, degree: 0))
}
}
}
} //End init()
func update(id : datatype,value : CGFloat,degree : Double){
print("update \(id.id)")
for i in 0..<self.users.count{
if self.users[i].id == id.id{
self.users[i].swipe = value
self.users[i].degree = degree
self.last = i
}
}
}
func updateDB(id : datatype,status : String){
let db = Firestore.firestore()
db.collection("users").document(id.id).updateData(["status":status]) { (err) in
if err != nil{
print(err!.localizedDescription)
return
}
print("success \(id.id)")
for i in 0..<self.users.count{
if self.users[i].id == id.id{
if status == "liked"{
self.users[i].swipe = 500
}else if status == "dislike"{
self.users[i].swipe = -500
}else{
self.users[i].swipe = 0
}
}
}
if status == "liked" {
db.collection("liked").document(id.id).setData(["name":id.name,"age":id.age,"image":id.image]) { (err) in
if err != nil{
print((err?.localizedDescription)!)
return
}
}
}
}
}// End updateDB
}
datatypes.swift
//
// datatypes.swift
// DevSwiftUI
//
// Created by Cairocoders
//
import Foundation
import SwiftUI
struct datatype : Identifiable {
var id : String
var name : String
var image : String
var age : String
var swipe : CGFloat
var degree : Double
}
struct datatype1 : Identifiable {
var id : String
var name : String
var age : String
var image : String
}
TopView.swift
//
// TopView.swift
// DevSwiftUI
//
// Created by Cairocoders
//
import SwiftUI
struct TopView : View {
@Binding var show : Bool
var body : some View{
HStack(alignment: .top){
Button(action: {
//No action
}) {
Image("photo1").resizable().frame(width: 35, height: 35)
}.foregroundColor(.gray)
Spacer()
Button(action: {
//No action
}) {
Image(systemName: "flame.fill").resizable().frame(width: 30, height: 35)
}.foregroundColor(.red)
Spacer()
Button(action: {
self.show.toggle()
}) {
Image(systemName: "message").resizable().frame(width: 35, height: 35)
}.foregroundColor(.gray)
}.padding()
}
}
swipeView.swift
//
// swipeView.swift
// DevSwiftUI
//
// Created by Cairocoders
//
import SwiftUI
import SDWebImageSwiftUI
struct swipeView: View {
@ObservedObject var obser = observer()
var body : some View{
VStack {
GeometryReader{geo in
ZStack{
ForEach(self.obser.users){i in
SwipeDetailsView(name: i.name, age: i.age, image: i.image, height: geo.size.height - 100).gesture(DragGesture()
.onChanged({ (value) in
if value.translation.width > 0{
self.obser.update(id: i, value: value.translation.width, degree: 8)
}
else{
self.obser.update(id: i, value: value.translation.width, degree: -8)
}
}).onEnded({ (value) in
if i.swipe > 0{
if i.swipe > geo.size.width / 2 - 80{
self.obser.update(id: i, value: 500, degree: 0)
}
else{
self.obser.update(id: i, value: 0, degree: 0)
}
}
else{
if -i.swipe > geo.size.width / 2 - 80{
self.obser.update(id: i, value: -500, degree: 0)
}
else{
self.obser.update(id: i, value: 0, degree: 0)
}
}
})
).offset(x: i.swipe)
.rotationEffect(.init(degrees: i.degree))
.animation(.spring())
} //End Foreach
}//End ZStack
}// End GeometryReader
HStack{
Button(action: {
//No action
}) {
Image(systemName: "arrow.clockwise.circle").resizable().frame(width: 25, height: 25).padding()
}.foregroundColor(.yellow)
.background(Color.white)
.shadow(radius: 25)
.clipShape(Circle())
//dislike
Button(action: {
if self.obser.last == -1{
self.obser.updateDB(id: self.obser.users[self.obser.users.count - 1], status: "dislike")
}
else{
self.obser.updateDB(id: self.obser.users[self.obser.last - 1], status: "dislike")
}
}) {
Image(systemName: "xmark.circle").resizable().frame(width: 30, height: 30).padding()
}.foregroundColor(.pink)
.background(Color.white)
.shadow(radius: 25)
.clipShape(Circle())
Button(action: {
//no action
}) {
Image(systemName: "star").resizable().frame(width: 25, height: 25).padding()
}.foregroundColor(.blue)
.background(Color.white)
.shadow(radius: 25)
.clipShape(Circle())
Button(action: {
if self.obser.last == -1{
self.obser.updateDB(id: self.obser.users[self.obser.users.count - 1], status: "liked")
}
else{
self.obser.updateDB(id: self.obser.users[self.obser.last - 1], status: "liked")
}
}) {
Image(systemName: "heart").resizable().frame(width: 35, height: 35).padding()
}.foregroundColor(.blue)
.background(Color.white)
.shadow(radius: 25)
.clipShape(Circle())
Button(action: {
//no action
}) {
Image(systemName: "rectangle.dashed.badge.record").resizable().frame(width: 25, height: 25).padding()
}.foregroundColor(.purple)
.background(Color.white)
.shadow(radius: 25)
.clipShape(Circle())
}
}
}
}
struct swipeView_Previews: PreviewProvider {
static var previews: some View {
swipeView()
}
}
Loader.swift
//
// Loader.swift
// DevSwiftUI
//
// Created by Cairocoders
//
import SwiftUI
struct Loader : UIViewRepresentable {
func makeUIView(context: UIViewRepresentableContext<Loader>) -> UIActivityIndicatorView {
let indicator = UIActivityIndicatorView(style: .large)
indicator.startAnimating()
return indicator
}
func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext<Loader>) {
}
}
//
// SwipeDetailsView.swift
// DevSwiftUI
//
// Created by Cairocoders
//
import SwiftUI
import SDWebImageSwiftUI
struct SwipeDetailsView: View {
var name = ""
var age = ""
var image = ""
var height : CGFloat = 0
var body: some View {
ZStack {
AnimatedImage(url: URL(string: image)!).resizable().cornerRadius(20).padding(.horizontal, 15)
VStack {
Spacer()
HStack {
VStack(alignment: .leading, content: {
Text(name).fontWeight(.heavy).font(.system(size: 25)).foregroundColor(.white)
Text(age).foregroundColor(.white)
})
Spacer()
}
}.padding([.bottom, .leading], 35)
}.frame(height:height)
}
}
struct SwipeDetailsView_Previews: PreviewProvider {
static var previews: some View {
SwipeDetailsView()
}
}
likedPeople.swift
//
// likedPeople.swift
// DevSwiftUI
//
// Created by Cairocoders
//
import SwiftUI
import SDWebImageSwiftUI
import Firebase
struct LikedPeople: View {
@ObservedObject var datas = observer1()
var body: some View {
VStack{
if datas.data.isEmpty{
Text("No Liked People")
}
else{
NavigationView {
List(datas.data){i in
NavigationLink(destination : Details(userItem: i)) {
cards(name: i.name, image: i.image)
}
}.navigationBarTitle("Like Users")
}
}
}
}
}
struct cards : View {
var name = ""
var image = ""
var body : some View{
HStack{
AnimatedImage(url: URL(string: image)!).resizable().frame(width: 65, height: 65).clipShape(Circle())
Text(name).fontWeight(.heavy)
}
}
}
class observer1 : ObservableObject{
@Published var data = [datatype1]()
init() {
let db = Firestore.firestore()
db.collection("liked").getDocuments { (snap, err) in
if err != nil{
print((err?.localizedDescription)!)
return
}
for i in snap!.documents{
let name = i.get("name") as! String
let age = i.get("age") as! String
let image = i.get("image") as! String
self.data.append(datatype1(id: UUID().uuidString, name: name, age: age, image: image))
}
}
}
}
Details.swift
//
// Details.swift
// DevSwiftUI
//
// Created by Cairocoders
//
import SwiftUI
import SDWebImageSwiftUI
struct Details: View {
let userItem : datatype1
var body: some View {
GeometryReader{geo in
//Text(userItem.name)
VStack {
Text("Username : \(userItem.name)")
.font(.title2)
AnimatedImage(url: URL(string: userItem.image))
.resizable().frame(height: geo.size.height - 100)
.padding(.horizontal, 15)
.cornerRadius(20)
}
}
}
}
DevSwiftUIApp.swift
//
// DevSwiftUIApp.swift
// DevSwiftUI
//
// Created by Cairocoders
//
import SwiftUI
import Firebase
@main
struct DevSwiftUIApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
class AppDelegate: NSObject,UIApplicationDelegate{
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
FirebaseApp.configure()
return true
}
}
