Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions podcasts.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -2155,6 +2155,9 @@
FFEE59C12EB37B6400D4B145 /* ListeningTime2025Story.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFEE59C02EB37B5A00D4B145 /* ListeningTime2025Story.swift */; };
FFEE59C32EB37F4300D4B145 /* playback2025_listening_time.json in Resources */ = {isa = PBXBuildFile; fileRef = FFEE59C22EB37F4300D4B145 /* playback2025_listening_time.json */; };
FFEE59C42EB37F4300D4B145 /* playback2025_listening_time.json in Resources */ = {isa = PBXBuildFile; fileRef = FFEE59C22EB37F4300D4B145 /* playback2025_listening_time.json */; };
FFEE59FE2EB5111700D4B145 /* TopSpotStory2025.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFEE59FD2EB5111100D4B145 /* TopSpotStory2025.swift */; };
FFEE5A022EB514C100D4B145 /* playback_2025_top_spot_story.json in Resources */ = {isa = PBXBuildFile; fileRef = FFEE5A012EB514C100D4B145 /* playback_2025_top_spot_story.json */; };
FFEE5A032EB514C100D4B145 /* playback_2025_top_spot_story.json in Resources */ = {isa = PBXBuildFile; fileRef = FFEE5A012EB514C100D4B145 /* playback_2025_top_spot_story.json */; };
FFF024CE2B62AC9400457373 /* IAPHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF024CD2B62AC9400457373 /* IAPHelperTests.swift */; };
FFF024CF2B62B13A00457373 /* Pocket Casts Configuration.storekit in Resources */ = {isa = PBXBuildFile; fileRef = C7547F77286F571900DC1C9E /* Pocket Casts Configuration.storekit */; };
FFF17EC42B97930700E116C8 /* BookmarksProfileListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFF17EC32B97930700E116C8 /* BookmarksProfileListController.swift */; };
Expand Down Expand Up @@ -4292,6 +4295,8 @@
FFEE599B2EB378B300D4B145 /* Humane-SemiBold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Humane-SemiBold.otf"; sourceTree = "<group>"; };
FFEE59C02EB37B5A00D4B145 /* ListeningTime2025Story.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListeningTime2025Story.swift; sourceTree = "<group>"; };
FFEE59C22EB37F4300D4B145 /* playback2025_listening_time.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = playback2025_listening_time.json; sourceTree = "<group>"; };
FFEE59FD2EB5111100D4B145 /* TopSpotStory2025.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopSpotStory2025.swift; sourceTree = "<group>"; };
FFEE5A012EB514C100D4B145 /* playback_2025_top_spot_story.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = playback_2025_top_spot_story.json; sourceTree = "<group>"; };
FFF024CD2B62AC9400457373 /* IAPHelperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IAPHelperTests.swift; sourceTree = "<group>"; };
FFF17EC32B97930700E116C8 /* BookmarksProfileListController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksProfileListController.swift; sourceTree = "<group>"; };
FFF17EC52B979B5500E116C8 /* BookmarksProfileListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksProfileListView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -6797,6 +6802,7 @@
BD7EA4CE1E52C2800014EAC5 /* Animations */ = {
isa = PBXGroup;
children = (
FFEE5A012EB514C100D4B145 /* playback_2025_top_spot_story.json */,
FF9BCB322EA659B400A25F12 /* playback_2025_listened.json */,
FFEE59C22EB37F4300D4B145 /* playback2025_listening_time.json */,
FFB74B0D2E993A8C00F16857 /* end_of_year_2025_intro.json */,
Expand Down Expand Up @@ -8955,6 +8961,7 @@
FFB74B0A2E99363F00F16857 /* 2025 */ = {
isa = PBXGroup;
children = (
FFEE59FD2EB5111100D4B145 /* TopSpotStory2025.swift */,
FFEE59C02EB37B5A00D4B145 /* ListeningTime2025Story.swift */,
FF9BCB302EA64DB000A25F12 /* StoryHeader2025.swift */,
FF9BCB2A2EA2A13500A25F12 /* NumberListened2025.swift */,
Expand Down Expand Up @@ -9964,6 +9971,7 @@
BD1292D122F7CD83004608A6 /* [email protected] in Resources */,
4041FEA2218AA5EC0089D4A1 /* SiriShortcutAddCell.xib in Resources */,
40888F052563792300887D9A /* AppIcon-Round-Pink76x76@2x~ipad.png in Resources */,
FFEE5A032EB514C100D4B145 /* playback_2025_top_spot_story.json in Resources */,
BD12928A22F7CCC9004608A6 /* [email protected] in Resources */,
BD3311A2202171EF00863A15 /* EpisodeListSearchController.xib in Resources */,
BDD3579127BCD33D0000D155 /* FolderViewController.xib in Resources */,
Expand Down Expand Up @@ -10050,6 +10058,7 @@
F5F5097E2CEBFDE6007D6E39 /* skip.json in Resources */,
F5D5F7B82CEBE7CE001F492D /* Preview Assets.xcassets in Resources */,
F5C1FA212D1283F5007CFDF2 /* AppIcon.xcassets in Resources */,
FFEE5A022EB514C100D4B145 /* playback_2025_top_spot_story.json in Resources */,
F5F5097D2CEBFDE2007D6E39 /* skip_button.json in Resources */,
F5F509772CEBF9E3007D6E39 /* Localizable.strings in Resources */,
F55566FF2D14E3D000231367 /* VideoViewController.xib in Resources */,
Expand Down Expand Up @@ -11385,6 +11394,7 @@
8BAD2EB42AEE9620006264B3 /* PaidStoryWallView.swift in Sources */,
40FFCDBD2304E7ED00395CA5 /* ThemeableImageView.swift in Sources */,
BD98C54F1BA8058800E85D3B /* PodcastHeaderListViewController.swift in Sources */,
FFEE59FE2EB5111700D4B145 /* TopSpotStory2025.swift in Sources */,
BDB4E7D4240E3C7A005770E3 /* DefaultPlayer.swift in Sources */,
46CD3C9F2715E38E00F5EB8F /* SupportLogsViewModel.swift in Sources */,
C750EF7F28E3475600E06BA9 /* AnalyticsDescribable+Modules.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class EndOfYear2025StoriesModel: StoryModel {
case .numberOfPodcastsAndEpisodesListened:
return NumberListened2025(listenedNumbers: data.listenedNumbers, podcasts: data.top8Podcasts)
case .topSpot:
return TopSpotStory2024(topPodcast: data.topPodcasts.first!)
return TopSpotStory2025(topPodcast: data.topPodcasts.first!)
case .top5Podcasts:
return Top5Podcasts2024Story(top5Podcasts: data.topPodcasts)
case .ratings:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ struct NumberListened2025: ShareableStory {
})
.playbackMode(.playing(.fromProgress(0, toProgress: 1, loopMode: .autoReverse)))
.scaledToFill()
.scaleEffect(1.5)
.scaleEffect(1.1)
.ignoresSafeArea()
}
}
Expand Down
21 changes: 13 additions & 8 deletions podcasts/End of Year/Stories/2025/StoryHeader2025.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,39 @@ import SwiftUI
import PocketCastsServer

struct StoryHeader2025: View {
let title: String
let title: String?
let description: String?
let subscriptionTier: SubscriptionTier?
let addTopPadding: Bool

init(title: String, description: String? = nil, subscriptionTier: SubscriptionTier? = nil) {
init(title: String? = nil, description: String? = nil, subscriptionTier: SubscriptionTier? = nil, addTopPadding: Bool = true) {
self.title = title
self.description = description
self.subscriptionTier = subscriptionTier
self.addTopPadding = addTopPadding
}

var body: some View {
VStack(alignment: .leading, spacing: 16) {
VStack(alignment: .center, spacing: 16) {
HStack { Spacer() }
if let subscriptionTier {
SubscriptionBadge2024(subscriptionTier: subscriptionTier)
}
Text(title)
.font(size: 25, style: .title, weight: .semibold)
.multilineTextAlignment(.center)
if let title {
Text(title)
.font(size: 25, style: .title, weight: .semibold)
.multilineTextAlignment(.center)
}
if let description {
Text(description)
.font(.system(size: 16, weight: .medium))
.lineSpacing(UIFont.systemFont(ofSize: 16, weight: .medium).lineHeight*1.09)
.multilineTextAlignment(.center)
}
}
.minimumScaleFactor(0.9)
.padding(.horizontal, 24)
.padding(.top, UIScreen.isSmallScreen ? 80 : 110)
.if(addTopPadding) { content in
content.padding(.top, UIScreen.isSmallScreen ? 80 : 110)
}
}
}
83 changes: 83 additions & 0 deletions podcasts/End of Year/Stories/2025/TopSpotStory2025.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import SwiftUI
import PocketCastsDataModel
import PocketCastsUtils
import Lottie

struct TopSpotStory2025: ShareableStory {

@Environment(\.renderForSharing) var renderForSharing: Bool
@Environment(\.animated) var animated: Bool

let topPodcast: TopPodcast

private let foregroundColor = Color.white
private let backgroundColor = Color(hex: "#17423B")
private var scaleFactor: Double = 0.75

let identifier: String = "top_1_show"

init(topPodcast: TopPodcast) {
self.topPodcast = topPodcast
}

var body: some View {
ZStack {
VStack(alignment: .center, spacing: 0) {
StoryHeader2025(title: L10n.playback2025TopSpotTitle, description: L10n.playback2025TopSpotSubtitle)
Spacer()
GeometryReader { proxy in
ZStack {
if renderForSharing {
//TODO: Add correct background image for sharing
Image("playback_2025_listening_time_back")
.resizable()
.scaledToFit()
} else {
LottieView(animation: .named("playback_2025_top_spot_story"))
.animationDidFinish({ completed in
})
.configure({ animationView in
animationView.contentMode = .scaleToFill
})
.playbackMode(.playing(.fromProgress(0, toProgress: 1, loopMode: .autoReverse)))
.scaledToFill()
.ignoresSafeArea()
}
PodcastImage(uuid: topPodcast.podcast.uuid, size: .page, aspectRatio: nil, contentMode: .fill)
.frame(width: proxy.size.width * scaleFactor, height: proxy.size.width * scaleFactor)
.cornerRadius(8)
.shadow(color: .black.opacity(0.15), radius: 4, x: 0, y: 2)
}
.frame(width: proxy.size.width * 1.25, height: proxy.size.width * 1.25)
.offset(x: -proxy.size.width * 0.125, y: 0)
}
VStack {
Spacer()
let timeString = topPodcast.totalPlayedTime.storyTimeDescriptionForSharing
let numberPlayed = topPodcast.numberOfPlayedEpisodes
StoryHeader2025(title: nil, description: L10n.playback2025TopSpotDescription(numberPlayed, timeString), addTopPadding: false)
Spacer()
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.ignoresSafeArea()
.foregroundStyle(foregroundColor)
.background(backgroundColor)
}

func onAppear() {
Analytics.track(.endOfYearStoryShown, story: identifier)
}

func willShare() {
Analytics.track(.endOfYearStoryShare, story: identifier)
}

func sharingAssets() -> [Any] {
[
StoryShareableProvider.new(AnyView(self)),
StoryShareableText(L10n.eoyStoryTopPodcastShareText("%1$@"), podcast: topPodcast.podcast, year: .y2025)
]
}
}
9 changes: 9 additions & 0 deletions podcasts/Strings+Generated.swift

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions podcasts/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -5653,3 +5653,13 @@

/// Text for playback 2025 listening time in minutes
"playback_2025_listening_time" = "minutes listened";

/// Text for playback 2025 top stop title
"playback_2025_top_spot_title" = "Your top podcast of 2025";

/// Text for playback 2025 top stop subtitle
"playback_2025_top_spot_subtitle" = "It doesn’t get more “you” than this";

/// Text for playback 2025 top description. %1$@ is the number of episodes and %1 is the listening time. Ex: 66 episodes, 2 days, and 3 hours. That’s commitment!

"playback_2025_top_spot_description" = "%1$@ episodes, %2$@.\nThat’s commitment!";
1 change: 1 addition & 0 deletions podcasts/playback_2025_top_spot_story.json

Large diffs are not rendered by default.