Skip to content

Commit

Permalink
Deep link to story (#878)
Browse files Browse the repository at this point in the history
* Parse story-template deep link

* Add StoryTemplatesNetworkService

* Route to story with id

* Update analytics

* Handle remote notification
  • Loading branch information
ivan-magda authored Jan 26, 2021
1 parent eb194fa commit dcaa8e5
Show file tree
Hide file tree
Showing 20 changed files with 317 additions and 60 deletions.
8 changes: 8 additions & 0 deletions Stepic.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,8 @@
2C3ABA9123D229C200E90439 /* Bundle+Version.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C3ABA9023D229C200E90439 /* Bundle+Version.swift */; };
2C3DAB8D233D71B100453B1C /* StepFontSizeStorageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C3DAB8C233D71B100453B1C /* StepFontSizeStorageManager.swift */; };
2C3DAB91233D735E00453B1C /* StepFontSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C3DAB90233D735D00453B1C /* StepFontSize.swift */; };
2C41F0EC25BAE6F200DA634A /* StoryTemplatesNetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C41F0EB25BAE6F200DA634A /* StoryTemplatesNetworkService.swift */; };
2C41F0F625BB007C00DA634A /* StoryOpenSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C41F0F525BB007C00DA634A /* StoryOpenSource.swift */; };
2C42EFB62476F28B00423695 /* MagicLinksAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C42EFB52476F28B00423695 /* MagicLinksAPI.swift */; };
2C42EFBA2476FADB00423695 /* MagicLinksNetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C42EFB92476FADB00423695 /* MagicLinksNetworkService.swift */; };
2C434D2C25B6F0C400854D6F /* StepikNetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C434D2B25B6F0C400854D6F /* StepikNetworkService.swift */; };
Expand Down Expand Up @@ -2095,6 +2097,8 @@
2C3D00C124C8080F00441053 /* Info-Release.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-Release.plist"; sourceTree = "<group>"; };
2C3DAB8C233D71B100453B1C /* StepFontSizeStorageManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepFontSizeStorageManager.swift; sourceTree = "<group>"; };
2C3DAB90233D735D00453B1C /* StepFontSize.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StepFontSize.swift; sourceTree = "<group>"; };
2C41F0EB25BAE6F200DA634A /* StoryTemplatesNetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoryTemplatesNetworkService.swift; sourceTree = "<group>"; };
2C41F0F525BB007C00DA634A /* StoryOpenSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoryOpenSource.swift; sourceTree = "<group>"; };
2C42EFB52476F28B00423695 /* MagicLinksAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MagicLinksAPI.swift; sourceTree = "<group>"; };
2C42EFB92476FADB00423695 /* MagicLinksNetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MagicLinksNetworkService.swift; sourceTree = "<group>"; };
2C434D2B25B6F0C400854D6F /* StepikNetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepikNetworkService.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -4932,6 +4936,7 @@
08484EE6211AF42E0006266F /* SegmentedProgressView.swift */,
08484EED211AF4300006266F /* Story.swift */,
08D2F72C2122E4B5009BA052 /* StoryNavigationDelegate.swift */,
2C41F0F525BB007C00DA634A /* StoryOpenSource.swift */,
080E1ACB212571D9006B58A9 /* StoryPartViewFactory.swift */,
2CA4CF99242A1825008BC4E8 /* OpenedStories */,
2CA4CF9A242A1831008BC4E8 /* Stories */,
Expand Down Expand Up @@ -6850,6 +6855,7 @@
2C5418CB24A2903700B2DCE2 /* StepikMetricsNetworkService.swift */,
62E987944A98FB989B36D72C /* StepsNetworkService.swift */,
2CF10C8A238426B300F8CC95 /* StepSourcesNetworkService.swift */,
2C41F0EB25BAE6F200DA634A /* StoryTemplatesNetworkService.swift */,
2C6BBBBE22B26DB100889A45 /* SubmissionsNetworkService.swift */,
62E98E41865820B1B8F7357D /* UnitsNetworkService.swift */,
2C16495822C10DD300DF18CA /* UserActivitiesNetworkService.swift */,
Expand Down Expand Up @@ -9436,6 +9442,7 @@
62E983B402214CA82BF050E8 /* LessonsNetworkService.swift in Sources */,
2CA93080253C6B03007B717A /* DiscussionThreadPlainObject.swift in Sources */,
2CE9BF44248D07D0004F6659 /* CodeTemplatesPersistenceService.swift in Sources */,
2C41F0EC25BAE6F200DA634A /* StoryTemplatesNetworkService.swift in Sources */,
2C8F3AE123CCBD26004D113A /* DownloadVideoQuality.swift in Sources */,
2CDB95892412C08100F676A7 /* SpotlightContinueUserActivityService.swift in Sources */,
62E98F5FB06328B5D7212700 /* HighlightFakeButton.swift in Sources */,
Expand Down Expand Up @@ -9988,6 +9995,7 @@
62E987084C26B24E039EA0A0 /* NotificationsPersistenceService.swift in Sources */,
62E98778B1320381E97A0E1F /* LastStepPersistenceService.swift in Sources */,
62E98672DA4B29B46167B0A4 /* LastCodeLanguagePersistenceService.swift in Sources */,
2C41F0F625BB007C00DA634A /* StoryOpenSource.swift in Sources */,
46115BB4590732AAB387046D /* NewProfileUserActivityAssembly.swift in Sources */,
8A248387CF216CCCFFC39E76 /* NewProfileUserActivityDataFlow.swift in Sources */,
9FAD76150240B4F8C13ADFA2 /* NewProfileUserActivityInteractor.swift in Sources */,
Expand Down
20 changes: 13 additions & 7 deletions Stepic/Legacy/Analytics/Events/AmplitudeAnalyticsEvents.swift
Original file line number Diff line number Diff line change
Expand Up @@ -665,13 +665,17 @@ extension AnalyticsEvent {

// MARK: - Stories -

static func storyOpened(id: Int) -> AmplitudeAnalyticsEvent {
AmplitudeAnalyticsEvent(
name: "Story opened",
parameters: [
"id": id
]
)
static func storyOpened(id: Int, source: StoryOpenSource) -> AmplitudeAnalyticsEvent {
var parameters: [String: Any] = [
"id": id,
"source": source.name
]

if case .deeplink(let path) = source {
parameters["deeplink_url"] = path
}

return AmplitudeAnalyticsEvent(name: "Story opened", parameters: parameters)
}

static func storyPartOpened(id: Int, position: Int) -> AmplitudeAnalyticsEvent {
Expand Down Expand Up @@ -786,6 +790,8 @@ extension AnalyticsEvent {
return "coursePromo"
case .certificates:
return "certificates"
case .story:
return "story-template"
}
}()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,17 @@ final class OpenedStoriesAssembly: Assembly {

private let stories: [Story]
private let startPosition: Int
private let storyOpenSource: StoryOpenSource

init(stories: [Story], startPosition: Int, moduleOutput: OpenedStoriesOutputProtocol?) {
init(
stories: [Story],
startPosition: Int,
storyOpenSource: StoryOpenSource,
moduleOutput: OpenedStoriesOutputProtocol? = nil
) {
self.stories = stories
self.startPosition = startPosition
self.storyOpenSource = storyOpenSource
self.moduleOutput = moduleOutput
}

Expand All @@ -28,7 +35,9 @@ final class OpenedStoriesAssembly: Assembly {
)
let presenter = OpenedStoriesPresenter(
view: viewController,
stories: self.stories, startPosition: self.startPosition,
stories: self.stories,
startPosition: self.startPosition,
storyOpenSource: self.storyOpenSource,
analytics: StepikAnalytics.shared
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,20 @@ class OpenedStoriesPresenter: OpenedStoriesPresenterProtocol {

var currentPosition: Int

private let storyOpenSource: StoryOpenSource
private let analytics: Analytics

init(view: OpenedStoriesViewProtocol, stories: [Story], startPosition: Int, analytics: Analytics) {
init(
view: OpenedStoriesViewProtocol,
stories: [Story],
startPosition: Int,
storyOpenSource: StoryOpenSource,
analytics: Analytics
) {
self.view = view
self.stories = stories
self.currentPosition = startPosition
self.storyOpenSource = storyOpenSource
self.analytics = analytics

NotificationCenter.default.addObserver(
Expand Down Expand Up @@ -98,7 +106,11 @@ class OpenedStoriesPresenter: OpenedStoriesPresenterProtocol {
}

private func makeModule(for story: Story) -> UIViewController {
StoryAssembly(story: story, navigationDelegate: self).makeModule()
StoryAssembly(
story: story,
storyOpenSource: self.storyOpenSource,
navigationDelegate: self
).makeModule()
}

@objc
Expand Down
11 changes: 1 addition & 10 deletions Stepic/Legacy/Controllers/Stories/Stories/StoriesPresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,6 @@ final class StoriesPresenter: StoriesPresenterProtocol {
self.view?.updateStory(index: index)
}

private func isSupported(story: Story) -> Bool {
for part in story.parts {
if part.type == nil {
return false
}
}
return story.parts.count > 0
}

func refresh() {
self.view?.set(state: .loading)

Expand All @@ -90,7 +81,7 @@ final class StoriesPresenter: StoriesPresenterProtocol {
}

strongSelf.stories = stories.filter {
strongSelf.isSupported(story: $0)
$0.isSupported
}.sorted(by: {
$0.position >= $1.position
}).sorted(by: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ final class StoriesViewController: UIViewController, ControllerWithStepikPlaceho
let moduleToPresent = OpenedStoriesAssembly(
stories: self.stories,
startPosition: index,
storyOpenSource: .catalog,
moduleOutput: self.presenter as? OpenedStoriesOutputProtocol
).makeModule()
if DeviceInfo.current.isPad {
Expand Down
9 changes: 9 additions & 0 deletions Stepic/Legacy/Controllers/Stories/Story.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ final class Story: JSONSerializable {
var parts: [StoryPart]
var position: Int

var isSupported: Bool {
for part in self.parts {
if part.type == nil {
return false
}
}
return self.parts.count > 0
}

required init(json: JSON) {
let id = json["id"].intValue
self.id = json["id"].intValue
Expand Down
9 changes: 8 additions & 1 deletion Stepic/Legacy/Controllers/Stories/Story/StoryAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@ import UIKit

final class StoryAssembly: Assembly {
private let story: Story
private let storyOpenSource: StoryOpenSource
private weak var navigationDelegate: StoryNavigationDelegate?

init(story: Story, navigationDelegate: StoryNavigationDelegate) {
init(
story: Story,
storyOpenSource: StoryOpenSource,
navigationDelegate: StoryNavigationDelegate
) {
self.story = story
self.storyOpenSource = storyOpenSource
self.navigationDelegate = navigationDelegate
}

Expand All @@ -32,6 +38,7 @@ final class StoryAssembly: Assembly {
urlNavigator: urlNavigator,
navigationDelegate: self.navigationDelegate,
storyPartsReactionsPersistenceService: StoryPartsReactionsPersistenceService(),
storyOpenSource: self.storyOpenSource,
analytics: StepikAnalytics.shared
)

Expand Down
6 changes: 5 additions & 1 deletion Stepic/Legacy/Controllers/Stories/Story/StoryPresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ final class StoryPresenter: StoryPresenterProtocol {
private var urlNavigator: URLNavigator
private var story: Story

private let storyOpenSource: StoryOpenSource

private let storyPartsReactionsPersistenceService: StoryPartsReactionsPersistenceServiceProtocol
private let analytics: Analytics

Expand All @@ -67,6 +69,7 @@ final class StoryPresenter: StoryPresenterProtocol {
urlNavigator: URLNavigator,
navigationDelegate: StoryNavigationDelegate?,
storyPartsReactionsPersistenceService: StoryPartsReactionsPersistenceServiceProtocol,
storyOpenSource: StoryOpenSource,
analytics: Analytics
) {
self.view = view
Expand All @@ -75,6 +78,7 @@ final class StoryPresenter: StoryPresenterProtocol {
self.navigationDelegate = navigationDelegate
self.urlNavigator = urlNavigator
self.storyPartsReactionsPersistenceService = storyPartsReactionsPersistenceService
self.storyOpenSource = storyOpenSource
self.analytics = analytics
}

Expand Down Expand Up @@ -138,7 +142,7 @@ final class StoryPresenter: StoryPresenterProtocol {
}

func didAppear() {
self.analytics.send(.storyOpened(id: self.storyID))
self.analytics.send(.storyOpened(id: self.storyID, source: self.storyOpenSource))
NotificationCenter.default.post(name: .storyDidAppear, object: nil, userInfo: ["id": self.storyID])

if self.shouldRestartSegment {
Expand Down
18 changes: 18 additions & 0 deletions Stepic/Legacy/Controllers/Stories/StoryOpenSource.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Foundation

enum StoryOpenSource {
case home
case catalog
case deeplink(path: String)

var name: String {
switch self {
case .home:
return "home"
case .catalog:
return "catalog"
case .deeplink:
return "deeplink"
}
}
}
18 changes: 10 additions & 8 deletions Stepic/Legacy/Model/Network/Endpoints/StoryTemplatesAPI.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
//
// StoryTemplatesAPI.swift
// Stepic
//
// Created by Ostrenkiy on 16.08.2018.
// Copyright © 2018 Alex Karpov. All rights reserved.
//

import Alamofire
import Foundation
import PromiseKit
Expand Down Expand Up @@ -41,4 +33,14 @@ final class StoryTemplatesAPI: APIEndpoint {
}
}
}

func retrieve(ids: [Int]) -> Promise<[Story]> {
self.retrieve.request(
requestEndpoint: self.name,
paramName: self.name,
ids: ids,
updating: [],
withManager: self.manager
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,11 @@ final class RetrieveRequestMaker {
updating: [T],
withManager manager: Alamofire.Session
) -> Promise<[T]> {
Promise { seal in
if ids.isEmpty {
return .value([])
}

return Promise { seal in
self.request(
requestEndpoint: requestEndpoint,
paramName: paramName,
Expand Down
Loading

0 comments on commit dcaa8e5

Please sign in to comment.