Introducción al curso

1

Construyamos una app para iOS

2

Introducción a la arquitectura MVVM

3

Planeando nuestra app

Creando las primeras pantallas de la app

4

Programando la primera pantalla en módulos

5

Escribiendo la lógica para mostrar dos pantallas

6

Pantalla de inicio de sesión con SecureField y Scroll

7

Completando nuestra pantalla de inicio de sesión

8

Pantalla de registro de usuario

9

Comprobando el funcionamiento de nuestras pantallas

10

Estructura de las pantallas con TabView

11

Creando nuestra pantalla home

12

Pantalla home: logo y barra de b√ļsqueda

13

Pantalla home: programación de interfaces estáticas

14

Pantalla home: carruseles

Aplicando arquitectura MVVM

15

Creando estructura para arquitectura MVVM

16

Modelando nuestro JSON

17

Peticiones al servidor

18

Mostrar información de un servidor de manera dinámica

19

Mostrar im√°genes de forma din√°mica y eficiente con LazyVGrid

Reproductor y b√ļsqueda de video

20

Pasar datos entre pantallas

21

Darle datos de inicio a un Canvas

22

Reproducir videos din√°micamente de un servidor

23

Mostrar im√°genes din√°micamente de un servidor

24

Mostrar alertas

25

Programar clase de b√ļsqueda

26

Programar m√©todo de b√ļsqueda

√öltimas pantallas de la app

27

Pantalla de favoritos

28

Pantalla de perfil de usuario

29

Módulo de ajustes de perfil con Toggle

30

Pantalla de edición de perfil

31

Módulo de edición de perfil

32

Guardado interno de datos

Utilizando la c√°mara y fotos del iPhone

33

Captura de foto de perfil: ImagePicker y vista Sheet

34

Captura de foto de perfil con la cámara: modificar librerías de terceros

35

Captura de foto de perfil con la c√°mara: recuperar im√°genes guardadas

¬ŅQu√© m√°s posibilidades tiene SwiftUI?

36

Mejoremos nuestra app

No tienes acceso a esta clase

¬°Contin√ļa aprendiendo! √önete y comienza a potenciar tu carrera

Mostrar alertas

24/36
Recursos

Aportes 2

Preguntas 0

Ordenar por:

¬ŅQuieres ver m√°s aportes, preguntas y respuestas de la comunidad?

o inicia sesión.

Creo que como parte de la clase tambi√©n seria bueno que mostraran como refactorizar correctamente el c√≥digo en vistas individuales ‚úĆÔłŹ

//
//  ScreenHomeTab.swift
//  GameStream
//
//  Created by Jonathan Ixcayau on 16/09/21.
//

import SwiftUI
import AVKit

struct ScreenHomeTab: View {
    @State var searchText: String = ""
    @State var isPlayerActive = false
    @State var url : String = "https://cdn.cloudflare.steamstatic.com/steam/apps/256658589/movie480.mp4"
    @State var isGameInfoEmpty = false
    
    let  urlVideos: [String] = [
        "https://cdn.cloudflare.steamstatic.com/steam/apps/256658589/movie480.mp4",
        "https://cdn.cloudflare.steamstatic.com/steam/apps/256671638/movie480.mp4",
        "https://cdn.cloudflare.steamstatic.com/steam/apps/256720061/movie480.mp4",
        "https://cdn.cloudflare.steamstatic.com/steam/apps/256814567/movie480.mp4",
        "https://cdn.cloudflare.steamstatic.com/steam/apps/256705156/movie480.mp4",
        "https://cdn.cloudflare.steamstatic.com/steam/apps/256801252/movie480.mp4",
        "https://cdn.cloudflare.steamstatic.com/steam/apps/256757119/movie480.mp4"
    ]
    
    
    var body: some View {
        ZStack{
            Color("backgroundColor")
                .ignoresSafeArea()
            
            ScrollView{
                VStack {
                    GameStreamLogo()
                        .padding(.bottom)
                    
                    HStack{
                        Button(
                            action: search,
                            label: {
                                Image(systemName: "magnifyingglass")
                                    .foregroundColor(
                                        searchText.isEmpty ? Color(.yellow) : Color("darkCianColor"))
                            }
                        )
                            .alert(isPresented: $isGameInfoEmpty){
                                Alert(
                                    title: Text("Error"),
                                    message: Text("No se encontro el juego"),
                                    dismissButton: .default(Text("Entendido"))
                                )
                            }
                        
                        
                        ZStack(alignment: .leading){
                            CommonInput(content: $searchText, hint: "Buscar un video", hasBottomPadding: false)
                        }
                    }
                    .padding([.top, .bottom], 11)
                    .padding([.leading, .trailing], 18)
                    .background(Color("tabBarColor"))
                    .clipShape(Capsule())
                    
                    PopularsView(urlPlayer: $url, isPlayerActive: $isPlayerActive, url: urlVideos[0] )
                    SuggestedCategories()
                    RecommendedForYou(urlPlayer: $url, isPlayerActive: $isPlayerActive, urlVideos: urlVideos)
                    
                }
                .padding(.horizontal, 24)
            }
            
            NavigationLink(
                destination: VideoPlayer(player: AVPlayer(url: URL(string: url)!))
                    .frame(width: 400, height: 300),
                isActive: $isPlayerActive,
                label: {
                    EmptyView()
                }
            )
        }
        .navigationBarHidden(true)
        .navigationBarBackButtonHidden(true)
    }
    
    func search() {
        print("Searching \(searchText)")
        isGameInfoEmpty = searchText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
    }
}

struct PopularsView: View {
    @Binding var urlPlayer: String
    @Binding var isPlayerActive: Bool
    
    let url: String
    
    var body: some View {
        VStack  {
            HomeBaseTitle(title: "LOS M√ĀS POPULARES")
            
            ZStack{
                Button(
                    action: {
                        urlPlayer = url
                        isPlayerActive = true
                    },
                    label: {
                        VStack(spacing:0){
                            ZStack{
                                Image("thewitcher")
                                    .resizable()
                                    .scaledToFit()
                                    .frame(minWidth: 0,  maxWidth: .infinity, minHeight: 200, maxHeight: 200)
                                
                                Image(systemName: "play.circle.fill")
                                    .resizable()
                                    .foregroundColor(.white)
                                    .frame(width: 42, height: 42)
                            }
                            .padding(.bottom, 4)
                            
                            Text("The Witcher 3")
                                .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
                        }
                    }
                )
                    .frame(minWidth: 0, maxWidth: .infinity, alignment: .center)
                    .background(Color("tabBarColor"))
            }
        }
    }
}

struct SuggestedCategories:View {
    
    var body: some View {
        VStack{
            HomeBaseTitle(title:"CATEGOR√ćAS SUGERIDAS PARA TI")
            
            ScrollView(.horizontal, showsIndicators: false){
                HStack{
                    HomeCategoryButton(imagePath: "category")
                    HomeCategoryButton(imagePath: "fps")
                    HomeCategoryButton(imagePath: "rpg")
                    HomeCategoryButton(imagePath: "world")
                }
            }
        }
    }
}

struct RecommendedForYou:View {
    @Binding var urlPlayer: String
    @Binding var isPlayerActive: Bool
    
    let urlVideos: [String]
    
    var body: some View {
        VStack{
            HomeBaseTitle(title:"RECOMENDADO PARA TI")
            
            ScrollView(.horizontal, showsIndicators: false){
                HStack{
                    RecommendedForYouButton(
                        imagePath: "Abzu",
                        action: {
                            urlPlayer = urlVideos[1]
                            isPlayerActive = true
                        }
                    )
                    RecommendedForYouButton(
                        imagePath: "Crash Bandicoot",
                        action: {
                            urlPlayer = urlVideos[2]
                            isPlayerActive = true
                        }
                    )
                    RecommendedForYouButton(
                        imagePath: "DEATH STRANDING",
                        action: {
                            urlPlayer = urlVideos[3]
                            isPlayerActive = true
                        }
                    )
                }
            }
        }
        .padding(.bottom, 20)
    }
}

struct HomeBaseTitle:View {
    let title : String
    
    var body: some View {
        Text(title)
            .font(.title3)
            .foregroundColor(.white)
            .bold()
            .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
            .padding(.top)
    }
}

struct ScreenHomeTab_Previews: PreviewProvider {
    static var previews: some View {
        HomeView()
    }
}

Si quieren tener un teclado con el boton aceptar y que cuando terminen de escribir y presionen aceptar (para no tener que presionar siempre el icono de lupa y mejorar la UX) ejecute la función de buscar la palabra que acaba de escribir, escriban el siguiente código al final del textfield