article

Wednesday, November 3, 2021

SwiftUI Firebase Twitter Clone Design and Functionalities

SwiftUI Firebase Twitter Clone Design and Functionalities

https://github.com/firebase/firebase-ios-sdk.git
https://github.com/SDWebImage/SDWebImageSwiftUI.git

ContentView.swift
 
//
//  ContentView.swift
//  DevSwiftUI
//
//  Created by Cairocoders
//

import SwiftUI

struct ContentView: View {
    
    @State var show = false
    @State var showMenu = false
    
    var body: some View {
        
        let drag = DragGesture() //swipe to close menu
            .onEnded {
                if $0.translation.width < -100 {
                    withAnimation {
                        self.showMenu = false
                    }
                }
            }
        return NavigationView {
            //geometry property to adjust the frame of our Home View to fill the entire screen.
            GeometryReader { geometry in
                ZStack(alignment: .leading) {
                    TabView{
                        Home().tabItem {
                            Image(systemName: "house")
                        }.tag(0)
                        
                        Search().tabItem {
                            Image(systemName: "magnifyingglass.circle.fill")
                        }.tag(1)
                        
                        Text("Notifications").tabItem {
                            Image(systemName: "bell")
                        }.tag(2)
                        
                        Text("Messages").tabItem {
                            Image(systemName: "envelope")
                        }.tag(3)
                        
                    }.accentColor(.blue)
                    .edgesIgnoringSafeArea(.top)
                    
                    VStack{
                        Spacer()
                        HStack{
                            Spacer()
                            Button(action: {
                                self.show.toggle()
                            }) {
                                Image("addtwit").resizable().frame(width: 20, height: 20).padding()
                            }.background(Color("bg"))
                            .foregroundColor(.white)
                            .clipShape(Circle())
                        }.padding()
                    }.padding(.bottom,65)
                    
                    if self.showMenu {
                        MenuView()
                            .frame(width: geometry.size.width/1.5)
                            .transition(.move(edge: .leading)) //slide in transition
                    }
                    
                } //ZStack
                .sheet(isPresented: $show) {
                   CreateTweet(show: self.$show)
                }
                .gesture(drag) //swipe to the left the menu collapse
            }
            .navigationBarTitle(Text(""), displayMode: .inline)
            .navigationBarItems(leading:
                HStack {
                    Button(action: {
                        withAnimation {
                           self.showMenu.toggle()
                        }
                        print("Open the side menu")
                    }) {
                        Image("photo1").resizable().frame(width: 35, height: 35).clipShape(Circle())
                    }
                
                    Image("tweet")
                        .resizable()
                        .foregroundColor(.white)
                        .aspectRatio(contentMode: .fit)
                        .frame(width: 60, height: 40, alignment: .center)
                    .padding(UIScreen.main.bounds.size.width/4+30)
                }
                ,trailing:
                HStack {
                    Button(action: {
                    }) {
                        Image(systemName: "sparkles")
                    }
                }
            )
        }// End Navigation
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
Home.swift
//
//  Home.swift
//  DevSwiftUI
//
//  Created by Cairocoders
//

import SwiftUI
import SDWebImageSwiftUI

struct Home: View {
    
    @ObservedObject var viewModel = TweetModel()
    
    var body : some View{
        ScrollView(.vertical, showsIndicators: false) {
            VStack(alignment: .leading){
                ForEach(viewModel.data){i in
                    
                    twitPost(name: i.name, id: i.tagId, pic: i.pic, image: i.url, msg: i.msg)
                    
                    if i.pic != ""{
                        AnimatedImage(url: URL(string: i.pic)!).resizable().frame(height: 300).cornerRadius(20).padding()
                    }
                    twitButton(like: i.likes, retwit: i.retwetts).offset(x: UIScreen.main.bounds.width / 4)
                }
            }
            
        }.padding(.bottom, 15)
    }
  }

struct Home_Previews: PreviewProvider {
    
    //@State static var showMenu = false
    
    static var previews: some View {
        //Home(showMenu: $showMenu)
        Home()
    }
}


struct twitPost : View {
  
  var name = ""
  var id = ""
  var pic = ""
  var image = ""
  var msg = ""
    
  var body : some View{
      
      HStack(alignment: .top){
          VStack{
              AnimatedImage(url: URL(string: image)!).resizable().frame(width: 50, height: 50).clipShape(Circle())

          }
          VStack(alignment: .leading){
              Text(name).fontWeight(.heavy)
              Text(id)
              Text(msg).padding(.top, 8)
          }
      }.padding()
  }
}

struct twitButton : View {
  
  var like = ""
  var retwit = ""
    
  var body : some View{
      
      HStack(spacing : 40){
          Button(action: {
              
          }) {
              Image(systemName: "message.and.waveform").resizable().frame(width: 20, height: 20)
              Text(like)
          }.foregroundColor(.gray)
          
          Button(action: {
              
          }) {
              Image(systemName: "crop.rotate").resizable().frame(width: 20, height: 20)
              Text(retwit)
          }.foregroundColor(.gray)
          
          Button(action: {
              
          }) {
              Image(systemName: "heart").resizable().frame(width: 20, height: 17)
          }.foregroundColor(.gray)
          
          Button(action: {
              
          }) {
              Image(systemName: "square.and.arrow.up").resizable().frame(width: 20, height: 20)
          }.foregroundColor(.gray)
      }
  }
}
Search.swift
//
//  Search.swift
//  DevSwiftUI
//
//  Created by Cairocoders
//

import SwiftUI

struct Search: View {
    var body: some View {
        Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
    }
}

struct Search_Previews: PreviewProvider {
    static var previews: some View {
        Search()
    }
}
Datatypes.swift
//
//  Datatypes.swift
//  DevSwiftUI
//
//  Created by Cairocoders
//

import Foundation

struct datatype : Identifiable {
  
  var id : String
  var name : String
  var msg : String
  var retwetts : String
  var likes : String
  var pic : String
  var url : String
  var tagId : String
}
TweetModel.swift
//
//  TweetModel.swift
//  DevSwiftUI
//
//  Created by Cairocoders
//

import Foundation
import FirebaseFirestore

class TweetModel : ObservableObject{
  
  @Published var data = [datatype]()
    
    init() {
        
        let db = Firestore.firestore()
        
        db.collection("tweets").addSnapshotListener { (snap, err) in
            
            if err != nil{
                print((err?.localizedDescription)!)
                return
            }
            
            for i in snap!.documentChanges{
                
                if i.type == .added{
                    
                    print("hello world")
                    
                    let id = i.document.documentID
                    let name = i.document.get("name") as! String
                    let msg = i.document.get("msg") as! String
                    let pic = i.document.get("pic") as! String
                    let url = i.document.get("url") as! String
                    let retweets = i.document.get("retweet") as! String?
                    let likes = i.document.get("likes") as! String
                    let tagID = i.document.get("id") as! String?
                    
                    DispatchQueue.main.async {
                        self.data.append(datatype(id: id, name: name, msg: msg, retwetts: retweets ?? "0", likes: likes, pic: pic, url: url, tagId: tagID ?? "cairocoders"))
                    }
                }
            }// End ForEach
        } //End db.collection
    } //End init()
}

func postTweet(msg : String){
  
  let db = Firestore.firestore()
  
  db.collection("tweets").document().setData(["name" : "Cairocoders","id":"@cairocoders","msg":msg,"retweet":"0","likes":"0","pic":"","url":"https://images.pexels.com/photos/3981337/pexels-photo-3981337.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"]) { (err) in
      
      if err != nil{
          
          print((err?.localizedDescription)!)
          
          return
      }
      print("success")
  }
}
CreateTweet.swift
//
//  CreateTweet.swift
//  DevSwiftUI
//
//  Created by Cairocoders
//

import SwiftUI

struct CreateTweet: View {
    
    @Binding var show : Bool
    @State var txt = ""
    
    var body : some View{
        VStack{
            HStack{
                Button(action: {
                    self.show.toggle()
                }) {
                    Text("Cancel")
                }
                
                Spacer()
                
                Button(action: {
                    postTweet(msg: self.txt)
                    self.show.toggle()
                }) {
                    Text("Tweet").padding()
                }.background(Color("bg"))
                .foregroundColor(.white)
                .clipShape(Capsule())
            }
            multilineTextField(txt: $txt)
        }.padding()
    }
  }
multilineTextField.swift
//
//  multilineTextField.swift
//  DevSwiftUI
//
//  Created by Cairocoders
//

import SwiftUI

struct multilineTextField : UIViewRepresentable {
  
  
  @Binding var txt : String
  
  func makeCoordinator() -> multilineTextField.Coordinator {
      return multilineTextField.Coordinator(parent1 : self)
  }
  func makeUIView(context: UIViewRepresentableContext<multilineTextField>) -> UITextView {
      let text = UITextView()
      text.isEditable = true
      text.isUserInteractionEnabled = true
      text.text = "Type Something"
      text.textColor = .gray
      text.font = .systemFont(ofSize: 20)
      text.delegate = context.coordinator
      return text
  }
  
  func updateUIView(_ uiView: UITextView, context: UIViewRepresentableContext<multilineTextField>) {
      
  }
  
  class Coordinator : NSObject,UITextViewDelegate{
      var parent : multilineTextField
      init(parent1 : multilineTextField) {
          parent = parent1
      }
      func textViewDidBeginEditing(_ textView: UITextView) {
          textView.text = ""
          textView.textColor = .black
      }
      func textViewDidChange(_ textView: UITextView) {
          self.parent.txt = textView.text
      }
  }
}
MenuView.swift
//
//  MenuView.swift
//  DevSwiftUI
//
//  Created by Cairocoders
//

import SwiftUI

struct MenuView: View {
    var body: some View {
        VStack(alignment: .leading) {
            HStack {
                VStack(alignment: .leading) {
                    Text("Cairocoders")
                        .foregroundColor(.black)
                    Text("@Cairocoders")
                        .foregroundColor(.black)
                    Text("239 Following 93 Followers")
                        .foregroundColor(.black)
                }
            }
            .padding(.top, 100)
            
            HStack {
                Image(systemName: "person")
                    .foregroundColor(.black)
                    .imageScale(.large)
                Text("Profile")
                    .foregroundColor(.black)
                    .font(.headline)
            }
            .padding(.top, 30)
             
            HStack {
                Image(systemName: "list.bullet.rectangle")
                    .foregroundColor(.black)
                    .imageScale(.large)
                Text("List")
                    .foregroundColor(.black)
                    .font(.headline)
            }
            .padding(.top, 30)
             
            HStack {
                Image(systemName: "message.and.waveform")
                    .foregroundColor(.black)
                    .imageScale(.large)
                Text("Topics")
                    .foregroundColor(.black)
                    .font(.headline)
            }
            .padding(.top, 30)
             
            HStack {
                Image(systemName: "bookmark")
                    .foregroundColor(.black)
                    .imageScale(.large)
                Text("Bookmarks")
                    .foregroundColor(.black)
                    .font(.headline)
            }
            .padding(.top, 30)
             
            Divider()
            
            HStack {
                Text("Setting and privacy")
                    .foregroundColor(.black)
                    .font(.headline)
            }
            .padding(.top, 30)
            
            HStack {
                Text("Help Center")
                    .foregroundColor(.black)
                    .font(.headline)
            }
            .padding(.top, 30)
            
            Spacer()
        }
        .padding()
        .frame(maxWidth: .infinity, alignment: .leading)
        .background(Color("1"))
        .edgesIgnoringSafeArea(.all)
    }
}

struct MenuView_Previews: PreviewProvider {
    static var previews: some View {
        MenuView()
    }
}
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
    }
}

Related Post