From c1d716ea358db7c4d6838f8b9d12a3331face4e6 Mon Sep 17 00:00:00 2001 From: Alexis Drai Date: Sun, 21 May 2023 15:10:23 +0200 Subject: [PATCH] :truck: :lipstick: Move everything and create episode view cell --- PodcastsClone.xcodeproj/project.pbxproj | 36 +++++++- .../accent.colorset/Contents.json | 38 ++++++++ .../background.colorset/Contents.json | 38 ++++++++ .../Contents.json | 38 ++++++++ .../primary.colorset/Contents.json | 38 ++++++++ .../secondary.colorset/Contents.json | 38 ++++++++ PodcastsClone/Model/Episode.swift | 15 ++++ PodcastsClone/View/EpisodeViewCell.swift | 89 +++++++++++++++++++ PodcastsClone/View/Extensions/Color.swift | 21 +++++ .../{Views => View}/LibraryView.swift | 0 PodcastsClone/{Views => View}/MainView.swift | 0 .../{Views => View}/PodcastDetailView.swift | 3 - PodcastsClone/View/Strings/Strings.swift | 12 +++ PodcastsClone/Views/EpisodeViewCell.swift | 28 ------ 14 files changed, 359 insertions(+), 35 deletions(-) create mode 100644 PodcastsClone/Colors.xcassets/accent.colorset/Contents.json create mode 100644 PodcastsClone/Colors.xcassets/background.colorset/Contents.json create mode 100644 PodcastsClone/Colors.xcassets/backgroundSecondary.colorset/Contents.json create mode 100644 PodcastsClone/Colors.xcassets/primary.colorset/Contents.json create mode 100644 PodcastsClone/Colors.xcassets/secondary.colorset/Contents.json create mode 100644 PodcastsClone/Model/Episode.swift create mode 100644 PodcastsClone/View/EpisodeViewCell.swift create mode 100644 PodcastsClone/View/Extensions/Color.swift rename PodcastsClone/{Views => View}/LibraryView.swift (100%) rename PodcastsClone/{Views => View}/MainView.swift (100%) rename PodcastsClone/{Views => View}/PodcastDetailView.swift (97%) create mode 100644 PodcastsClone/View/Strings/Strings.swift delete mode 100644 PodcastsClone/Views/EpisodeViewCell.swift diff --git a/PodcastsClone.xcodeproj/project.pbxproj b/PodcastsClone.xcodeproj/project.pbxproj index d70fb32..785790c 100644 --- a/PodcastsClone.xcodeproj/project.pbxproj +++ b/PodcastsClone.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + EC37FB2A2A1A3231005C78D6 /* Episode.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC37FB292A1A3231005C78D6 /* Episode.swift */; }; + EC37FB2C2A1A3E03005C78D6 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC37FB2B2A1A3E03005C78D6 /* Color.swift */; }; + EC37FB322A1A49EB005C78D6 /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC37FB312A1A49EB005C78D6 /* Strings.swift */; }; EC8CF6202A13A4F200BE6FD5 /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EC8CF61F2A13A4F200BE6FD5 /* Colors.xcassets */; }; EC8CF6232A13A59400BE6FD5 /* LibraryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC8CF6222A13A59400BE6FD5 /* LibraryView.swift */; }; EC8CF6252A13A7F000BE6FD5 /* Podcast.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC8CF6242A13A7F000BE6FD5 /* Podcast.swift */; }; @@ -19,6 +22,9 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + EC37FB292A1A3231005C78D6 /* Episode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Episode.swift; sourceTree = ""; }; + EC37FB2B2A1A3E03005C78D6 /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = ""; }; + EC37FB312A1A49EB005C78D6 /* Strings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = ""; }; EC8CF61F2A13A4F200BE6FD5 /* Colors.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colors.xcassets; sourceTree = ""; }; EC8CF6222A13A59400BE6FD5 /* LibraryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryView.swift; sourceTree = ""; }; EC8CF6242A13A7F000BE6FD5 /* Podcast.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Podcast.swift; sourceTree = ""; }; @@ -42,10 +48,27 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + EC37FB2D2A1A3FA4005C78D6 /* Extensions */ = { + isa = PBXGroup; + children = ( + EC37FB2B2A1A3E03005C78D6 /* Color.swift */, + ); + path = Extensions; + sourceTree = ""; + }; + EC37FB2E2A1A4941005C78D6 /* Strings */ = { + isa = PBXGroup; + children = ( + EC37FB312A1A49EB005C78D6 /* Strings.swift */, + ); + path = Strings; + sourceTree = ""; + }; EC8CF6212A13A57400BE6FD5 /* Model */ = { isa = PBXGroup; children = ( EC8CF6242A13A7F000BE6FD5 /* Podcast.swift */, + EC37FB292A1A3231005C78D6 /* Episode.swift */, ); path = Model; sourceTree = ""; @@ -70,10 +93,10 @@ isa = PBXGroup; children = ( EC8CF6212A13A57400BE6FD5 /* Model */, - EC8CF61F2A13A4F200BE6FD5 /* Colors.xcassets */, - ECB23BA42A0E45CC00A1C62B /* Views */, + ECB23BA42A0E45CC00A1C62B /* View */, ECB23B922A0E33B000A1C62B /* PodcastsCloneApp.swift */, ECB23B962A0E33B200A1C62B /* Assets.xcassets */, + EC8CF61F2A13A4F200BE6FD5 /* Colors.xcassets */, ECB23B982A0E33B200A1C62B /* Preview Content */, ); path = PodcastsClone; @@ -87,15 +110,17 @@ path = "Preview Content"; sourceTree = ""; }; - ECB23BA42A0E45CC00A1C62B /* Views */ = { + ECB23BA42A0E45CC00A1C62B /* View */ = { isa = PBXGroup; children = ( + EC37FB2D2A1A3FA4005C78D6 /* Extensions */, + EC37FB2E2A1A4941005C78D6 /* Strings */, ECB23BA02A0E3FDF00A1C62B /* MainView.swift */, ECB23BA22A0E455300A1C62B /* PodcastDetailView.swift */, ECB23BA52A0E4C0B00A1C62B /* EpisodeViewCell.swift */, EC8CF6222A13A59400BE6FD5 /* LibraryView.swift */, ); - path = Views; + path = View; sourceTree = ""; }; /* End PBXGroup section */ @@ -170,9 +195,12 @@ buildActionMask = 2147483647; files = ( ECB23BA12A0E3FDF00A1C62B /* MainView.swift in Sources */, + EC37FB322A1A49EB005C78D6 /* Strings.swift in Sources */, + EC37FB2A2A1A3231005C78D6 /* Episode.swift in Sources */, ECB23BA62A0E4C0B00A1C62B /* EpisodeViewCell.swift in Sources */, EC8CF6252A13A7F000BE6FD5 /* Podcast.swift in Sources */, ECB23BA32A0E455300A1C62B /* PodcastDetailView.swift in Sources */, + EC37FB2C2A1A3E03005C78D6 /* Color.swift in Sources */, EC8CF6232A13A59400BE6FD5 /* LibraryView.swift in Sources */, ECB23B932A0E33B000A1C62B /* PodcastsCloneApp.swift in Sources */, ); diff --git a/PodcastsClone/Colors.xcassets/accent.colorset/Contents.json b/PodcastsClone/Colors.xcassets/accent.colorset/Contents.json new file mode 100644 index 0000000..0546015 --- /dev/null +++ b/PodcastsClone/Colors.xcassets/accent.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.871", + "green" : "0.314", + "red" : "0.490" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.871", + "green" : "0.314", + "red" : "0.490" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/PodcastsClone/Colors.xcassets/background.colorset/Contents.json b/PodcastsClone/Colors.xcassets/background.colorset/Contents.json new file mode 100644 index 0000000..9cf3e9e --- /dev/null +++ b/PodcastsClone/Colors.xcassets/background.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.980", + "green" : "0.980", + "red" : "0.980" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.020", + "green" : "0.020", + "red" : "0.020" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/PodcastsClone/Colors.xcassets/backgroundSecondary.colorset/Contents.json b/PodcastsClone/Colors.xcassets/backgroundSecondary.colorset/Contents.json new file mode 100644 index 0000000..4734bcd --- /dev/null +++ b/PodcastsClone/Colors.xcassets/backgroundSecondary.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.900", + "green" : "0.900", + "red" : "0.900" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.600", + "green" : "0.600", + "red" : "0.600" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/PodcastsClone/Colors.xcassets/primary.colorset/Contents.json b/PodcastsClone/Colors.xcassets/primary.colorset/Contents.json new file mode 100644 index 0000000..561d0f0 --- /dev/null +++ b/PodcastsClone/Colors.xcassets/primary.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.090", + "green" : "0.090", + "red" : "0.090" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.910", + "green" : "0.910", + "red" : "0.910" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/PodcastsClone/Colors.xcassets/secondary.colorset/Contents.json b/PodcastsClone/Colors.xcassets/secondary.colorset/Contents.json new file mode 100644 index 0000000..1dccaa8 --- /dev/null +++ b/PodcastsClone/Colors.xcassets/secondary.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.666", + "green" : "0.666", + "red" : "0.666" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.833", + "green" : "0.833", + "red" : "0.833" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/PodcastsClone/Model/Episode.swift b/PodcastsClone/Model/Episode.swift new file mode 100644 index 0000000..44f7d08 --- /dev/null +++ b/PodcastsClone/Model/Episode.swift @@ -0,0 +1,15 @@ +// +// PodcastEpisode.swift +// PodcastsClone +// +// Created by etudiant on 2023-05-21. +// + +import Foundation +struct Episode { + var id: UUID + var publicationDate: Date + var title: String + var description: String + var duration: TimeInterval // duration in seconds +} diff --git a/PodcastsClone/View/EpisodeViewCell.swift b/PodcastsClone/View/EpisodeViewCell.swift new file mode 100644 index 0000000..009ef32 --- /dev/null +++ b/PodcastsClone/View/EpisodeViewCell.swift @@ -0,0 +1,89 @@ +// +// PodcastEpisodeViewCell.swift +// PodcastsClone +// +// Created by etudiant on 2023-05-12. +// + +import SwiftUI + + +struct EpisodeViewCell: View { + + let episode: Episode + + private let formatter: DateFormatter = { + // TODO display date smartly + // TODAY + // 1-6D AGO + // 14 MAY (no year if same year as now) + let formatter = DateFormatter() + formatter.dateFormat = "dd/MM/yyyy" + return formatter + }() + + var body: some View { + VStack(alignment: .leading) { + // TODO make divider reach the edge on the right + Divider() + .foregroundColor(Color.theme.backgroundSecondary) + + Text(formatter.string(from: episode.publicationDate)) + .font(.subheadline) + .foregroundColor(Color.theme.secondary) + + (Text(episode.title) + .font(.headline) + .foregroundColor(Color.theme.primary) + + Text("\n\(episode.description)") + .font(.body) + .foregroundColor(Color.theme.secondary)) + .lineLimit(4) + .truncationMode(.tail) + + HStack { + Image(systemName: "play.fill") + .foregroundColor(Color.theme.accent) + .padding() + .background(Color.theme.backgroundSecondary) + .clipShape(Circle()) + Text(timeString(time: episode.duration)) + .foregroundColor(Color.theme.accent) + Spacer() + Text(Strings.threeDots) + .foregroundColor(Color.theme.secondary) + .padding(.horizontal) + } + + } + .padding() + } + + private func timeString(time: TimeInterval) -> String { + let hours = Int(time) / 3600 + let minutes = Int(time) / 60 % 60 + + var timeComponents = [String]() + if hours > 0 { + timeComponents.append("\(hours) hr") + } + if minutes > 0 { + timeComponents.append("\(minutes) min") + } + + return timeComponents.joined(separator: " ") + } +} + +struct EpisodeViewCell_Previews: PreviewProvider { + + static var previews: some View { + EpisodeViewCell(episode: Episode( + id: UUID(), + publicationDate: Date.now, + title: "Episode title and stuff -- what it's about, who's in it, all sorts of things can end up in this title. To us, it's a string", + description: "This is a great episode. The description kinda goes on and on and on and on and on and on and on and on.", + duration: 4000 + )) + } +} diff --git a/PodcastsClone/View/Extensions/Color.swift b/PodcastsClone/View/Extensions/Color.swift new file mode 100644 index 0000000..a023396 --- /dev/null +++ b/PodcastsClone/View/Extensions/Color.swift @@ -0,0 +1,21 @@ +// +// Color.swift +// PodcastsClone +// +// Created by etudiant on 2023-05-21. +// + +import Foundation +import SwiftUI + +extension Color { + static let theme = ColorTheme() +} + +struct ColorTheme { + let primary = Color("primary") + let secondary = Color("secondary") + let background = Color("background") + let backgroundSecondary = Color("backgroundSecondary") + let accent = Color("accent") +} diff --git a/PodcastsClone/Views/LibraryView.swift b/PodcastsClone/View/LibraryView.swift similarity index 100% rename from PodcastsClone/Views/LibraryView.swift rename to PodcastsClone/View/LibraryView.swift diff --git a/PodcastsClone/Views/MainView.swift b/PodcastsClone/View/MainView.swift similarity index 100% rename from PodcastsClone/Views/MainView.swift rename to PodcastsClone/View/MainView.swift diff --git a/PodcastsClone/Views/PodcastDetailView.swift b/PodcastsClone/View/PodcastDetailView.swift similarity index 97% rename from PodcastsClone/Views/PodcastDetailView.swift rename to PodcastsClone/View/PodcastDetailView.swift index b2223e4..7fb9eb7 100644 --- a/PodcastsClone/Views/PodcastDetailView.swift +++ b/PodcastsClone/View/PodcastDetailView.swift @@ -42,9 +42,6 @@ struct PodcastDetailView: View { Text("Episode View Cell goes here") Text("Episode View Cell goes here") } - - - } .padding() } diff --git a/PodcastsClone/View/Strings/Strings.swift b/PodcastsClone/View/Strings/Strings.swift new file mode 100644 index 0000000..583f524 --- /dev/null +++ b/PodcastsClone/View/Strings/Strings.swift @@ -0,0 +1,12 @@ +// +// Strings.swift +// PodcastsClone +// +// Created by etudiant on 2023-05-21. +// + +import Foundation + +struct Strings { + static let threeDots = "ยทยทยท" +} diff --git a/PodcastsClone/Views/EpisodeViewCell.swift b/PodcastsClone/Views/EpisodeViewCell.swift deleted file mode 100644 index d636187..0000000 --- a/PodcastsClone/Views/EpisodeViewCell.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// PodcastEpisodeViewCell.swift -// PodcastsClone -// -// Created by etudiant on 2023-05-12. -// - -import SwiftUI - -struct PodcastEpisodeViewCell: View { - var body: some View { - // TODO add Divider() - - Text("Episode Title goes here") - // TODO add styles to episode title - - // TODO add subtitle info incl duration - podcast title - by: podcast author - episode description - - // TODO add play button and rounded time left (in hours, minutes...) - - } -} - -struct PodcastEpisodeViewCell_Previews: PreviewProvider { - static var previews: some View { - PodcastEpisodeViewCell() - } -}