💄 - finish views

main
DJYohann 2 years ago
parent d507d327c6
commit 947969a248

@ -18,6 +18,7 @@
1E92BCEF2A14319D0026C641 /* PodcastListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E92BCEE2A14319D0026C641 /* PodcastListView.swift */; };
1E92BCF12A1439000026C641 /* PodcastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E92BCF02A1439000026C641 /* PodcastView.swift */; };
1E92BCF32A1440B20026C641 /* LibraryMenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E92BCF22A1440B20026C641 /* LibraryMenuItem.swift */; };
1EE5D3E72A196A7C00F92680 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EE5D3E62A196A7C00F92680 /* Extensions.swift */; };
1EFF14972A10E76A0018278E /* PodcastsAppApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EFF14962A10E76A0018278E /* PodcastsAppApp.swift */; };
1EFF14992A10E76A0018278E /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EFF14982A10E76A0018278E /* ContentView.swift */; };
1EFF149B2A10E76C0018278E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1EFF149A2A10E76C0018278E /* Assets.xcassets */; };
@ -59,6 +60,7 @@
1E92BCEE2A14319D0026C641 /* PodcastListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PodcastListView.swift; sourceTree = "<group>"; };
1E92BCF02A1439000026C641 /* PodcastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PodcastView.swift; sourceTree = "<group>"; };
1E92BCF22A1440B20026C641 /* LibraryMenuItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryMenuItem.swift; sourceTree = "<group>"; };
1EE5D3E62A196A7C00F92680 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
1EFF14932A10E76A0018278E /* PodcastsApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PodcastsApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
1EFF14962A10E76A0018278E /* PodcastsAppApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PodcastsAppApp.swift; sourceTree = "<group>"; };
1EFF14982A10E76A0018278E /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
@ -99,6 +101,14 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
1EE5D3E82A196A8200F92680 /* Utils */ = {
isa = PBXGroup;
children = (
1EE5D3E62A196A7C00F92680 /* Extensions.swift */,
);
path = Utils;
sourceTree = "<group>";
};
1EFF148A2A10E76A0018278E = {
isa = PBXGroup;
children = (
@ -122,6 +132,7 @@
1EFF14952A10E76A0018278E /* PodcastsApp */ = {
isa = PBXGroup;
children = (
1EE5D3E82A196A8200F92680 /* Utils */,
1EFF14C52A1116430018278E /* Model */,
1EFF14C02A10F3AC0018278E /* Views */,
1EFF14962A10E76A0018278E /* PodcastsAppApp.swift */,
@ -327,6 +338,7 @@
1E8272F12A1597C8005837D3 /* MenuItem.swift in Sources */,
1E8272EF2A1584CC005837D3 /* LibraryMenu.swift in Sources */,
1E8272EB2A151FA6005837D3 /* Stub.swift in Sources */,
1EE5D3E72A196A7C00F92680 /* Extensions.swift in Sources */,
1E92BCF12A1439000026C641 /* PodcastView.swift in Sources */,
1EFF14C72A1116D90018278E /* PodcastEpisode.swift in Sources */,
1E92BCEB2A14032D0026C641 /* Podcast.swift in Sources */,

@ -52,7 +52,7 @@ struct ContentView: View {
}
.overlay(VStack {
Spacer()
NowPlayingBar()
NowPlayingBar(podcast: podcastList[0])
.frame(height: 162)
})
}

@ -30,11 +30,21 @@ let podcastList : [Podcast] = [
topic: "Technologies",
lastUpdateDate: Date.now,
episodes: [
Episode(title: "Salut", description: "Ceci est un texte", duration: 34),
Episode(title: "Salut", description: "Ceci est un texte", duration: 34),
Episode(title: "Salut", description: "Ceci est un texte", duration: 34),
Episode(title: "Salut", description: "Ceci est un texte", duration: 34),
Episode(title: "Salut", description: "Ceci est un texte", duration: 34),
Episode(title: "L'histoire de la triche sur CS:GO",
description: "Le jeu CS:GO est connu pour être gangrené par la triche, y compris dans les sphères professionnels et la scène esport. Pourquoi CS:GO est particulièrement touché ? Doù ça vient techniquement, et peut-on y faire quelque-chose ? On remonte lhistoire, qui prend racine en 2014, à quelques semaines de la DreamHack Winter, le plus gros évènement CS:GO de lannée !",
duration: 32),
Episode(title: "L'assistant vocal d'Underscore",
description: "Nos assistants vocaux ne sont pas très efficaces… mis à part peut-être pour lancer un minuteur. Mais est-il possible den créer un de toute pièce, correspondant à nos envies et à ce quon aime ? Avec les nouveaux services dIA sortis ces derniers mois, on a fait le test, et on vous fait une petite démo en direct ! “OK Michel, écoute Underscore_”",
duration: 30,
isPlayed: true),
Episode(title: "Le témoignage de cet étudiant arnaqué par le directeur de son école",
description: "Un ancien étudiant vient témoigner de son expérience à SUPINFO. Derrière des pratiques parfois douteuses se cachaient en réalité une organisation quasi mafieuse et un patron prêt à tout pour détourner de largent ! Aujourdhui, il semble pourtant avoir récidivé…",
duration: 47,
isPlayed: true,
isDownloaded: true),
Episode(title: "La révolution du stockage est en marche",
description: "Une nouvelle technologie de mémoire, la ReRAM, pourrait bien bouleverser le secteur et faire radicalement chuter son prix dans les années à venir. Édouard, qui a étudié le sujet pendant trois ans, revient pour nous sur cette technologie très prometteuse !",
duration: 34),
]),
Podcast(
name: "Popcorn",
@ -43,7 +53,12 @@ let podcastList : [Podcast] = [
nbStars: 4.9,
nbEvaluations: 709,
topic: "Actualité du divertissement",
lastUpdateDate: Date.now),
lastUpdateDate: Date.now,
episodes: [
Episode(title: "Le futur des écrans se déroule devant vous",
description: "PP Garcia nous présente Mardi Turfu, la rubrique tech de Popcorn ! Et pour cette semaine il nous parle des futurs des écrans, mais pas que !",
duration: 21)
]),
Podcast(
name: "Un bon moment avec Kyan KHOJANDI et NAVO",
creator: "Kyan Khojandi & navo",

@ -0,0 +1,25 @@
//
// Extensions.swift
// PodcastsApp
//
// Created by BREUIL Yohann on 20/05/2023.
//
import Foundation
import UIKit
extension UIImage {
var averageColor: UIColor? {
guard let inputImage = CIImage(image: self) else { return nil }
let extentVector = CIVector(x: inputImage.extent.origin.x, y: inputImage.extent.origin.y, z: inputImage.extent.size.width, w: inputImage.extent.size.height)
guard let filter = CIFilter(name: "CIAreaAverage", parameters: [kCIInputImageKey: inputImage, kCIInputExtentKey: extentVector]) else { return nil }
guard let outputImage = filter.outputImage else { return nil }
var bitmap = [UInt8](repeating: 0, count: 4)
let context = CIContext(options: [.workingColorSpace: kCFNull])
context.render(outputImage, toBitmap: &bitmap, rowBytes: 4, bounds: CGRect(x: 0, y: 0, width: 1, height: 1), format: .RGBA8, colorSpace: nil)
return UIColor(red: CGFloat(bitmap[0]) / 255, green: CGFloat(bitmap[1]) / 255, blue: CGFloat(bitmap[2]) / 255, alpha: CGFloat(bitmap[3]) / 255)
}
}

@ -8,44 +8,57 @@
import SwiftUI
struct NowPlayingBar : View {
var podcast : Podcast
var body: some View {
ZStack {
Rectangle()
.foregroundColor(Color.black.opacity(0.2))
.frame(width: UIScreen.main.bounds.size.width, height: 65)
HStack {
Button(action: {}) {
HStack {
Image("Cover")
.resizable()
.frame(width: 45, height: 45)
.shadow(radius: 6, x: 0, y: 3)
.padding(.leading)
Text("Shake It Off").padding(.leading, 10)
Spacer()
HStack {
Button(action: {}) {
HStack {
Image(podcast.coverImage)
.resizable()
.cornerRadius(8)
.frame(width: 50, height: 50)
.shadow(radius: 6, x: 0, y: 3)
VStack(alignment: .leading) {
Text(podcast.episodes[0].title)
.frame(width: 150)
.truncationMode(.tail)
.font(.body)
.bold()
Text("29 Avril 2023")
.font(.caption)
}
}
.buttonStyle(PlainButtonStyle())
Button(action: {}) {
Image(systemName: "play.fill").font(.title3)
Spacer()
}
.buttonStyle(PlainButtonStyle()).padding(.horizontal)
.padding()
}
.buttonStyle(.plain)
Button(action: {}) {
Image(systemName: "forward.fill").font(.title3)
}
.buttonStyle(PlainButtonStyle())
.padding(.trailing, 30)
Button(action: {}) {
Image(systemName: "play.fill").font(.title3)
}
}
.buttonStyle(.plain)
.padding(.horizontal)
Button(action: {}) {
Image(systemName: "goforward.30").font(.title3)
}
.buttonStyle(.plain)
.padding(.trailing, 30)
}
.frame(width: UIScreen.main.bounds.size.width, height: 65)
}
}
struct NowPlayingBar_Previews: PreviewProvider {
static var previews: some View {
NowPlayingBar()
Group {
NowPlayingBar(podcast: podcastList[0])
NowPlayingBar(podcast: podcastList[0]).preferredColorScheme(.dark)
}
}
}

@ -11,42 +11,37 @@ struct PodcastCover: View {
var podcast: Podcast
var body: some View {
ZStack {
Rectangle()
.fill(.cyan)
VStack {
Image(podcast.coverImage)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 300, height: 300)
Text(podcast.name)
Text(podcast.creator)
Button(action: {}) {
Image(systemName: "play.fill")
Text("Reprendre")
}
VStack {
Image(podcast.coverImage)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 200, height: 200)
.cornerRadius(8)
.opacity(20)
.shadow(radius: 20)
Text(podcast.name)
.font(.title2)
.bold()
.frame(width: 200, height: 20, alignment: .center)
.cornerRadius(20)
.padding()
.background(
RoundedRectangle(
cornerRadius: 20,
style: .continuous
)
.fill(.yellow))
.overlay {
RoundedRectangle(
cornerRadius: 20,
style: .continuous
)
.stroke(.pink, lineWidth: 2)
}
}
Text(podcast.creator)
.font(.title3)
Button(action: {}) {
Image(systemName: "play.fill")
Text("Reprendre")
.font(.headline)
}
.bold()
.frame(width: 250, height: 25, alignment: .center)
.padding()
.background(
RoundedRectangle(
cornerRadius: 8,
style: .continuous
)
.fill(.white))
}
.frame(width: UIScreen.main.bounds.width, height: 400)
.background(Color(uiColor: UIImage(imageLiteralResourceName: podcast.coverImage).averageColor ?? .white))
}
}

@ -12,7 +12,8 @@ struct PodcastEpisode: View {
var body: some View {
VStack(alignment: .leading) {
Text("5 Mai")
// Date
Text(episode.datePublication.formatted(date: .abbreviated, time: .omitted))
.font(.caption)
.bold()
.textCase(.uppercase)
@ -20,11 +21,11 @@ struct PodcastEpisode: View {
// Title
if episode.isPlayed {
Text(episode.title)
.font(.title2)
.font(.headline)
.bold()
} else {
Text(episode.title)
.font(.title3)
.font(.headline)
}
// Description
@ -36,7 +37,7 @@ struct PodcastEpisode: View {
Button(action: {}) {
Image(systemName: "play.fill")
}
.frame(width: 33, height: 33)
.buttonStyle(PlainButtonStyle())
.foregroundColor(Color.purple)
.background(Color("#747476"))
.clipShape(Circle())
@ -48,12 +49,13 @@ struct PodcastEpisode: View {
.foregroundColor(Color.accentColor)
.bold()
} else {
Text("\(episode.duration)")
Text("\(episode.duration) min")
.foregroundColor(Color.accentColor)
.bold()
}
Spacer()
if (episode.isDownloaded) {
Image(systemName: "arrow.down.circle.fill")
}
@ -62,43 +64,21 @@ struct PodcastEpisode: View {
}
}
.padding()
.frame(width: UIScreen.main.bounds.width, height: 200)
.frame(width: UIScreen.main.bounds.width, height: 160)
}
}
struct PodcastEpisodeDetail_Previews: PreviewProvider {
static var previews: some View {
let episode1: Episode = Episode(
title: "L'assistant vocal d'Underscore",
description: "Texte qui ne décrit pas grand chose mais c'est intéressant de marquer beaucoup de texte juste pour écrire. C'est long mais bon c'est la vie, la vie c'est l'inverse de la mort. Je peux encore écrire pendant longtemts mais là j'ai une flemme.",
datePublication: Date.now,
duration: 30,
isPlayed: true)
let episode2: Episode = Episode(
title: "L'assistant vocal d'Underscore",
description: "Texte qui ne décrit pas grand chose mais c'est intéressant de marquer beaucoup de texte juste pour écrire. C'est long mais bon c'est la vie, la vie c'est l'inverse de la mort. Je peux encore écrire pendant longtemts mais là j'ai une flemme.",
datePublication: Date.now,
duration: 30,
isPlayed: false)
let episode3: Episode = Episode(
title: "L'assistant vocal d'Underscore",
description: "Texte qui ne décrit pas grand chose mais c'est intéressant de marquer beaucoup de texte juste pour écrire. C'est long mais bon c'est la vie, la vie c'est l'inverse de la mort. Je peux encore écrire pendant longtemts mais là j'ai une flemme.",
datePublication: Date.now,
duration: 30,
isPlayed: true,
isDownloaded: true)
Group {
PodcastEpisode(episode: episode1)
PodcastEpisode(episode: episode1).preferredColorScheme(.dark)
PodcastEpisode(episode: podcastList[0].episodes[0])
PodcastEpisode(episode: podcastList[0].episodes[0]).preferredColorScheme(.dark)
PodcastEpisode(episode: episode2)
PodcastEpisode(episode: episode2).preferredColorScheme(.dark)
PodcastEpisode(episode: podcastList[0].episodes[1])
PodcastEpisode(episode: podcastList[0].episodes[1]).preferredColorScheme(.dark)
PodcastEpisode(episode: episode3)
PodcastEpisode(episode: episode3).preferredColorScheme(.dark)
PodcastEpisode(episode: podcastList[0].episodes[2])
PodcastEpisode(episode: podcastList[0].episodes[2]).preferredColorScheme(.dark)
}
}

@ -14,33 +14,21 @@ struct PodcastListItem: View {
VStack(alignment: .leading) {
Image(podcast.coverImage)
.resizable()
.aspectRatio(contentMode: .fill)
.cornerRadius(8)
VStack(alignment: .leading) {
Text(podcast.name)
.bold()
Text("Mise à jour : Il y a 2j")
}
.aspectRatio(contentMode: .fit)
.scaledToFill()
.cornerRadius(6)
Text(podcast.name)
.bold()
Text("Mise à jour : Il y a 2j")
}
.frame(width: 175, height: 175)
.frame(width: 150, height: 150)
}
}
struct PodcastListDetail_Previews: PreviewProvider {
static var previews: some View {
let podcast: Podcast = Podcast(
name: "Underscore_",
creator: "Micode",
coverImage: "underscore_podcast",
nbStars: 4.7,
nbEvaluations: 963,
topic: "Technologies",
lastUpdateDate: Date.now)
Group {
PodcastListItem(podcast: podcast)
PodcastListItem(podcast: podcast).preferredColorScheme(.dark)
PodcastListItem(podcast: podcastList[0])
PodcastListItem(podcast: podcastList[0]).preferredColorScheme(.dark)
}
}
}

@ -18,30 +18,27 @@ struct PodcastView: View {
VStack {
PodcastCover(podcast: podcast)
LazyVGrid(columns: columns, spacing: 10, pinnedViews: [.sectionHeaders]) {
Section {
HStack {
Text("Épisodes")
}
}
LazyVStack {
ForEach (podcast.episodes) { episode in
PodcastEpisode(episode: episode)
Divider()
}
}
}
}
.toolbar {
HStack {
ToolbarItemGroup {
Button(action: {}) {
Image(systemName: "checkmark")
}
.frame(width: 30, height: 30)
.clipShape(Circle())
.buttonStyle(.bordered)
Button(action: {}) {
Image(systemName: "ellipsis")
}
.frame(width: 30, height: 30)
.clipShape(Circle())
.buttonStyle(.bordered)
}

Loading…
Cancel
Save