Proyectos de Subversion Iphone Microlearning - Inconcert

Rev

Rev 19 | Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |

//
//  LoginView.swift
//  twogetskills
//
//  Created by Efrain Yanez Recanatini on 1/27/22.
//

import SwiftUI
import AudioToolbox
import Network
import Alamofire
import SwiftyJSON
import SafariServices
import RNCryptor





struct SigninView: View {

    @EnvironmentObject var networkMonitor : NetworkMonitor
    @EnvironmentObject var appNavigation : AppNavigation
    
    @State private var keyboardHeight : CGFloat = 0
    
    private var appData = AppData.sharedInstance

    
    @State private var email: String = "" {
        didSet {
            if email.count > 250 {
                email = String(email.prefix(250))
                AudioServicesPlayAlertSoundWithCompletion(SystemSoundID(kSystemSoundID_Vibrate)) { return }
            }
        }
    }
    
    @State private var isProcessing : Bool = false
    
    @State private var isValidEmail : Bool = true
    @State private var isEditingEmail : Bool = false
    
    @State private var password: String = ""  {
        didSet {
            if password.count > 25 {
                password = String(password.prefix(25))
                AudioServicesPlayAlertSoundWithCompletion(SystemSoundID(kSystemSoundID_Vibrate)) { return }
            }
        }
    }
        
    @State private var isValidPassword : Bool = true
    @State private var isEditingPassword : Bool = false
    
    @State private var isPasswordShow: Bool = false
    @State private var showProgressView : Bool = false
    
    @State private var presentAlert : Bool = false
    @State private var titleAlert : String = ""
    @State private var messageAlert : String = ""
    

    
    @State private var openForgotPassword : Bool = false
    @State private var openSignup : Bool = false

    var body: some View {
        ZStack {
            
            Color("color_window_background")
                    .edgesIgnoringSafeArea(.all)
            
            if self.showProgressView {
                ProgressView()
                    .progressViewStyle(CircularProgressViewStyle(tint: Color("color_progress_view_foreground")))
                    .scaleEffect(3, anchor: .center).zIndex(100000)
            }
                
            VStack(spacing: 0) {
                
                if networkMonitor.status == .disconnected {
                    HStack {
                        
                        
                        Text(Config.LANG_ERROR_NETWORK_MESSAGE_SHORT)
                        .font(Font.custom(Config.FONT_NAME_REGULAR, size: Config.FONT_SIZE_APP_BAR_HEAD1 ))
                            .foregroundColor(Color("color_network_disconnected_foreground"))
                            .padding(.leading, 16)

                        
                        Spacer()
                    }
                    .edgesIgnoringSafeArea(.top)
                    .frame(height: 50)
                    .background(Color("color_network_disconnected_background"))


                    Divider().background(Color("color_network_disconnected_background"))
                }
                    
                HeaderGroupView()
                
                EmailTextFieldGroup(email: self.$email, isEditingEmail: self.$isEditingEmail, isValidEmail: self.$isValidEmail, password: self.$password, isEditingPassword: self.$isEditingPassword, isValidPassword: self.$isValidPassword)
                
                PasswordTextFieldGroup(
                    password: self.$password,
                    isEditingPassword: self.$isEditingPassword,
                    isValidPassword: self.$isValidPassword,
                    isPasswordShow: self.$isPasswordShow
                ).padding(.top, isValidEmail ? 10 : 2)
                
                                   
                
                Button(action: {
                    if(validate()) {
                        signin()
                    }
                }, label: {
                    Text(Config.LANG_SIGNIN_BUTTON_SIGNIN)
                    .font(Font.custom(Config.FONT_NAME_REGULAR, size: 13))
                    .frame(width: UIScreen.main.bounds.width - 32, height: 35)
                    .foregroundColor(Color("color_button_foreground"))
                    .background(Color("color_button_background"))
                    .border(Color("color_button_border"), width: Config.BUTTON_BORDER_SIZE)
                                           .cornerRadius(Config.BUTTON_BORDER_RADIUS)
                                       
                                   })
                                   
                                   .padding(.top, 16)
                                   .padding(.leading, 16)
                                   .padding(.trailing, 16)
                                   
                         
                ButtonSignUpGroup(openSignup: self.$openSignup)
                                   
                                   
                
                Spacer()
                
                ButtonForgotPasswordGroup(openForgotPassword: self.$openForgotPassword)
               
   
            }
            
         
        }
      
        //}.offset(y : CGFloat(-(self.keyboardHeight / 2)))
        
        .onAppear {
    /*
            NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { (notification) in
                let keyboardHeight: CGFloat = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height ?? 0
                
         
                self.keyboardHeight = keyboardHeight
                //print("keyboardHeightShow = \(keyboardHeight)")
                
            }*/
            
            NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main) { (notification) in
            
          
               // print("keyboardHeightHide ")
                
            }
        }.popover(isPresented: self.$openSignup, content: {

            SafariView(sURL: Config.URL_SIGNUP_ENDPOINT)
  
        }).popover(isPresented: self.$openForgotPassword, content: {
            
            SafariView(sURL: Config.URL_FORGOT_PASSWORD_ENDPOINT)
   
        }).alert(isPresented: $presentAlert) {
            Alert(
                title: Text(self.titleAlert),
                message: Text(self.messageAlert),
                dismissButton: .default(Text(Config.LANG_COMMON_OK))
            )
        }

    }
        
    private func signin() -> Void
    {
        if isProcessing {
            self.titleAlert = Config.LANG_ERROR_SIGNIN_IN_PROGRESS_TITLE
            self.messageAlert = Config.LANG_ERROR_SIGNIN_IN_PROGRESS_MESSAGE
            self.presentAlert = true

            return
        }
        
        
        self.isEditingEmail = false
        self.isValidEmail = Validator.checkEmail(email: self.email)
        self.isEditingPassword = false
        self.isValidPassword = Validator.checkPassword(password: self.password)
        
        if !self.isValidEmail || !self.isValidPassword {
            return
        }
        
        
        let device_uuid = appData.deviceUuid
        let emailTrimming = email.trimmingCharacters(in: .whitespaces)
        let passwordTrimming = password.trimmingCharacters(in: .whitespaces)
        
        //print("signin")
        //print(" aes  = \(appData.deviceAes) " )
        //print(" email  = \(self.email) " )
        //print(" password  = \(self.password) " )
        

        let syncDao = SyncDao()
        if appData.deviceAes.isEmpty  {
            
            let syncRecord = syncDao.selectOneByType(type: Constants.SYNC_ADAPTER_TYPE_DEVICE)
                    
            if syncRecord.id > 0 {
                let syncAdapter = SyncAdapter()
                syncAdapter.sync(isForeground: true){
                    success in
                }
            }
            
            self.titleAlert = Config.LANG_ERROR_DEVICE_NOT_REGISTER_TITLE
            self.messageAlert = Config.LANG_ERROR_DEVICE_NOT_REGISTER_MESSAGE
            self.presentAlert = true

            return
        }
        

        
        if networkMonitor.status == .disconnected {
            self.titleAlert = Config.LANG_ERROR_NETWORK_TITLE
            self.messageAlert = Config.LANG_ERROR_NETWORK_MESSAGE_SHORT
            self.presentAlert = true
            
            return
        }
        
        self.showProgressView = true;

        let emailData = emailTrimming.data(using: .utf8)!
        let emailCipherData = RNCryptor.encrypt(data: emailData, withPassword: appData.deviceAes)
        let emailEncrypted = emailCipherData.base64EncodedString()
                  
        let passwordData = passwordTrimming.data(using: .utf8)!
        let passwordCipherData = RNCryptor.encrypt(data: passwordData, withPassword: appData.deviceAes)
        let passwordEncrypted = passwordCipherData.base64EncodedString()
                   

        //print(" email encrypted = \(emailEncrypted) " )
        //print(" password encrypted = \(passwordEncrypted) " )

        let parameters = [
            Constants.POST_SIGNIN_FIELD_APPLICATION_ID: "\(Config.APPLICATION_ID)",
            Constants.POST_SIGNIN_FIELD_VARIANT_ID: "\(Config.VARIANT_ID)",
            Constants.POST_SYNC_FIELD_DEVICE_UUID: device_uuid,
            Constants.POST_SIGNIN_FIELD_EMAIL: emailEncrypted,
            Constants.POST_SIGNIN_FIELD_PASSWORD: passwordEncrypted,
            Constants.POST_SIGNIN_FIELD_ENCRYPTER: Constants.GLOBAL_ENCRYPTER
        ]
        
        let headers: HTTPHeaders = [
            .accept(Constants.HTTP_HEADER_ACCEPT)
        ]
        
        //print("URL signin : \(Config.URL_SIGNIN)")
        
        self.showProgressView = true
        AF.request(Config.URL_SIGNIN, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers).responseJSON{(response) in
            self.showProgressView = false
            
            switch response.result {
                case .success:
                    let json = try? JSON(data: response.data!)
                    
                    //print("json : \(json)")
                    
                    if json?["success"] ?? "" != false {
                        let dataService = DataService()
                        
                        if dataService.syncFromServer(json : json) {
                            
                            
                            let userinfo = [
                                "title" : Config.LANG_TITLE_NOTIFICATION_SIGNIN_PUSH,
                                "body" : Config.LANG_BODY_NOTIFICATION_SIGNIN_PUSH,
                                "url" : ""
                            ]
                            
                            
                            NotificationCenter.default.post(name: Constants.NOTIFICATION_NAME_PUSH , object: self, userInfo: userinfo)
                            
                            let now = Date()
                            let dateFormatter = DateFormatter()
                            dateFormatter.dateFormat = Constants.FORMAT_DATETIME_SERVICE
                            let dateOn = dateFormatter.string(from: now)
                            
                            
                            
                            
                            
                            var userLog = UserLogModel()
                            userLog.userUuid = appData.userUuid
                            userLog.activity = Constants.USER_LOG_ACTIVITY_SIGNIN
                            userLog.addedOn = dateOn
                            
                            let userLogDao = UserLogDao()
                            userLogDao.insert(record: userLog)
                            
                            var sync = SyncModel()
                            
                            var json = userLog.toJson()
                            json[Constants.SYNC_ADAPTER_DATA_TYPE_FIELD_NAME] = Constants.SYNC_ADAPTER_DATA_TYPE_USER_LOG
                                    
                            sync = SyncModel();
                            sync.type = Constants.SYNC_ADAPTER_TYPE_SYNC
                            if let theJSONData = try?  JSONSerialization.data(withJSONObject: json, options: .prettyPrinted),
                                let data = String(data: theJSONData, encoding: String.Encoding.ascii) {
                                    sync.data = data
                                }
                                      
                            syncDao.insert(record : sync);
                            
                            
                            appNavigation.subpageActive = AppMainSubPage.mycapsules
                            appNavigation.pageActive = AppMainPage.home
        
  
                            
                            //self.goToMain = true
                        }
                    } else {
                        let message = json?["data"].string ?? ""
                        if !message.isEmpty {
                            self.titleAlert = Config.LANG_ERROR_GENERIC_TITLE
                            self.messageAlert = message
                            self.presentAlert = true
                        }
                    }
                    
                   return
                            
                case .failure :
                    self.titleAlert = Config.LANG_ERROR_COMMUNICATION_TITLE
                    self.messageAlert = Config.LANG_ERROR_COMMUNICATION_MESSAGE
                    self.presentAlert = true
                    
                    return
            }
            

           
         
         
        }
    }

    
    private func validate() -> Bool
    {

        //print("validate - email : \(email)")
        //print("validate - password : \(password)")
        

        if email.isEmpty {
            self.isValidEmail = false
        } else  if !Validator.checkEmail(email: email) {
            self.isValidEmail = false
        } else {
            self.isValidEmail = true
        }
        
     
        
        if password.isEmpty {
            self.isValidPassword = false
        } else if(!Validator.checkPassword(password: password)) {
            self.isValidPassword = false
           
        } else {
            self.isValidPassword = true
        }
        
        return  self.isValidEmail &&  self.isValidPassword
    }
    

   
    
    
       

}



struct SigninView_Previews: PreviewProvider {
    static var previews: some View {
        SigninView()
    }
}



struct HeaderGroupView: View {

    
    var body: some View {
        //Inicio Logo
        HStack {
            Image("logo")
            .resizable()
            .frame(width: 50, height: 50)
                      
            Text(Config.LANG_SIGNIN_APP_NAME)
            .font(Font.custom(Config.FONT_NAME_BOLD, size: 24))
            .foregroundColor(Color("color_textview_foreground"))
                      
            Spacer()
        }
        .padding(.leading, 16)
        .padding(.top, 66)
        //Fin logo
        
        //Inicio Saludo
        HStack {
            Text(Config.LANG_SIGNIN_GREATING)
            .font(Font.custom(Config.FONT_NAME_BOLD, size: 32))
            .foregroundColor(Color("color_textview_foreground"))
            Spacer()
        }
        .padding(.leading, 16)
        .padding(.top, 10)
        //Fin Saludo
        
        //Inicio Encabezado
        HStack {
            Text(Config.LANG_SIGNIN_HEAD_LINE1)
            .font(Font.custom(Config.FONT_NAME_REGULAR, size: 16))
            .foregroundColor(Color("color_textview_foreground"))
            Spacer()
        }
        .padding(.leading, 16)
        .padding(.top, 10)
        //Fin Encabezado
    }
}

struct EmailTextFieldGroup : View {

    
    
    @Binding var email: String
    @Binding var isEditingEmail : Bool
    @Binding var isValidEmail : Bool
    
    @Binding var password: String
    @Binding var isEditingPassword: Bool
    @Binding var isValidPassword: Bool

    
    var body : some View {
        //Inicio Label Email
        HStack {
            Text(Config.LANG_SIGNIN_TITLE_EMAIL_FIELD)
            .font(Font.custom(Config  .FONT_NAME_REGULAR, size: Config.FONT_SIZE_TEXTFIELD_LABEL))
            .foregroundColor(Color("color_textview_foreground"))
            Spacer()
        }
        .padding(.leading, 16)
        .padding(.top, 10)
        //Fin Label Email
        
        //Inicio TextField  Email
        
        Group {
            HStack {
                /*
                Image("ui_mail")
                .resizable()
                .frame(width: 24, height: 24)
                         .padding(.horizontal, 4)
                */
                
  
                TextField("",
                    text: self.$email,
                    onEditingChanged: { (changed) in
                        
                        if changed {
                            
                            if self.isEditingPassword {
                                self.isValidPassword = Validator.checkPassword(password: self.password)
                                self.isEditingPassword = false
                            }
                            
                            
                            self.isEditingEmail = true
                        } else {
                            self.isEditingEmail = false
                            self.isValidEmail = Validator.checkEmail(email: self.email)
                        }
                        
                    }, onCommit: {
                        self.isEditingEmail = false
                        self.isValidEmail = Validator.checkEmail(email: self.email)
                    }
                )
            
                .font(Font.custom(Config.FONT_NAME_REGULAR, size: Config.FONT_SIZE_TEXTFIELD))
                .textFieldStyle(PlainTextFieldStyle())
                .frame(height: 32)
                .keyboardType(.emailAddress)
                .autocapitalization(.none)
                //.foregroundColor(Color("color_textfield_foreground"))
                //.background(Color("color_textfield_background"))
                .padding(.leading, 4)
                Spacer()
           
            }
        }

        .foregroundColor(Color("color_textfield_foreground"))
        .background(Color("color_textfield_background"))
        .overlay(RoundedRectangle(cornerRadius: 5).stroke(
            Color(self.isEditingEmail ? "color_textfield_border_active" : self.isValidEmail ? "color_textfield_border" : "color_textfield_border_error" )
        ))
        .padding(.leading, 16)
        .padding(.trailing, 16)
        .padding(.top, self.isValidEmail ? 10 : 2)


        if !self.isValidEmail {
            HStack {
                Spacer()
             
                Text(Config.LANG_SIGNIN_ERROR_EMAIL_FIELD)
                .foregroundColor(.red)
                .font(Font.custom(Config.FONT_NAME_REGULAR, size: Config.FONT_SIZE_TEXTFIELD_ERROR))
             
            }
            .padding(.top, 5)
            .padding(.trailing, 16)
        }
        
        //Fin TextField Email
    }
    
}



struct PasswordTextFieldGroup : View {
    @Binding var password: String
    @Binding var isEditingPassword: Bool
    @Binding var isValidPassword: Bool
    @Binding var isPasswordShow: Bool

    var body : some View {
        //Inicio Label Password
        HStack {
            Text(Config.LANG_SIGNIN_TITLE_PASSWORD_FIELD)
                .font(Font.custom(Config  .FONT_NAME_REGULAR, size: Config.FONT_SIZE_TEXTFIELD_LABEL))
            .foregroundColor(Color("color_textview_foreground"))
            Spacer()
        }
        .padding(.leading, 16)
        //Fin Label Password
        
        
        //Inicio TextField  Password
        
        Group {
            HStack {
                /*
                Image("ui_key")
                .resizable()
                .frame(width: 24, height: 24)
                         .padding(.horizontal, 4)
                 */
                if isPasswordShow {
                
                    TextField("",
                        text: self.$password,
                        onEditingChanged: { (changed) in
                            
                            if changed {
                                self.isEditingPassword = true
                            } else {
                                self.isEditingPassword = false
                                self.isValidPassword = Validator.checkPassword(password: self.password)
                            }
                            
                        }, onCommit: {
                            self.isEditingPassword = false
                            self.isValidPassword = Validator.checkPassword(password:  self.password)
                        }
                    )
                    .font(Font.custom(Config.FONT_NAME_REGULAR, size: Config.FONT_SIZE_TEXTFIELD))
                    .textFieldStyle(PlainTextFieldStyle())
                    .frame(height: 32)
                        .keyboardType(.default)
                    .autocapitalization(.none)
                    /*
                    .foregroundColor(Color("color_textfield_foreground"))
                    .background(Color("color_textfield_background"))
 */
                    .padding(.leading, 4)
                    Spacer()
                    
                    Button(action: {
                        self.isPasswordShow.toggle()
                    }, label: {
                        Image("ui_visibility_off")
                        .resizable()
                        .frame(width: 24, height: 24)
                                 .padding(.horizontal, 4)
                    })
                } else {
     
                    SecureField("", text: self.$password, onCommit: {
                        self.isEditingPassword = false
                        self.isValidPassword = Validator.checkPassword(password: self.password)
                    })
                    .onTapGesture {
                        self.isEditingPassword = true
                    }
                    .font(Font.custom(Config.FONT_NAME_REGULAR, size: Config.FONT_SIZE_TEXTFIELD))
                    .textFieldStyle(PlainTextFieldStyle())
                    .frame(height: 32)
                        .keyboardType(.default)
                    .autocapitalization(.none)
                    /*
                    .foregroundColor(Color("color_textfield_foreground"))
                    .background(Color("color_textfield_background"))*/
                        .padding(.leading, 4)
                    Spacer()
                    
                    Button(action: {
                        self.isPasswordShow.toggle()
                    }, label: {
                        Image("ui_visibility")
                        .resizable()
                        .frame(width: 24, height: 24)
                                 .padding(.horizontal, 4)
                        
                    })
                    
                }
                
                //
                //ui_visibility
           
            }
        }
        .foregroundColor(Color("color_textfield_foreground"))
        .background(Color("color_textfield_background"))
        .overlay(RoundedRectangle(cornerRadius: 5).stroke(
            Color(self.isEditingPassword ? "color_textfield_border_active" : self.isValidPassword ? "color_textfield_border" : "color_textfield_border_error" )
        ))
        .padding(.leading, 16)
        .padding(.trailing, 16)
        .padding(.top, 2)

        if !self.isValidPassword {
            HStack {
                Spacer()
             
                Text(Config.LANG_SIGNIN_ERROR_PASSWORD_FIELD)
                .foregroundColor(.red)
                .font(Font.custom(Config.FONT_NAME_REGULAR, size: Config.FONT_SIZE_TEXTFIELD_ERROR))
             
            }
            .padding(.top, 5)
            .padding(.trailing, 16)
        }
        
        //Fin TextField Password
        
        
    }
    
    

}

struct ButtonSignUpGroup : View {
    @Binding var openSignup : Bool
    
    
    
    var body : some View {
        Button(action: {
            openSignup = true
            
        }, label: {
            Text(Config.LANG_SIGNIN_BUTTON_SIGNUP)
             .font(Font.custom(Config.FONT_NAME_REGULAR, size: 13))
             .frame(width: UIScreen.main.bounds.width - 32, height: 35)
                .foregroundColor(Color("color_button_foreground"))
                .background(Color("color_button_background"))
                .border(Color("color_button_border"), width: Config.BUTTON_BORDER_SIZE)
                .cornerRadius(Config.BUTTON_BORDER_RADIUS)
            
        })
        .padding(.top, 16)
        .padding(.leading, 16)
        .padding(.trailing, 16)
    }
}

struct ButtonForgotPasswordGroup : View {
    @Binding var openForgotPassword : Bool

    var body : some View {
        Button(action: {
            openForgotPassword = true
            
        }, label: {
            Text(Config.LANG_SIGNIN_BUTTON_FORGOT_PASSWORD)
             .font(Font.custom(Config.FONT_NAME_REGULAR, size: 13))

                .foregroundColor(Color("color_button_foreground"))

               
            
        })
        .padding(.vertical, 16)
    }
}