-
Notifications
You must be signed in to change notification settings - Fork 59
feat: add dev mode for previewing local paywalls #511
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
chroxify
wants to merge
34
commits into
develop
Choose a base branch
from
christo/sw-framework-support
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
6519c3c
feat: add dev mode for previewing local paywalls
chroxify 4f1779f
Merge remote-tracking branch 'origin/develop' into christo/sw-framewo…
yusuftor 48b6b35
chore: fold dev mode changelog entry into staged 4.16.4 section
yusuftor 5d8c076
chore: restage 4.16.4 release as 4.17.0
yusuftor 154f0a2
review: gate dev links out of production and unfreeze the dev-mode cache
yusuftor 75da4e8
review: pin dev-server mount URLs to the manifest's origin
yusuftor 4a032b8
review: log when a dev server surface is rejected as off-origin
yusuftor d1f5e0d
chore(examples): scope Advanced app ATS to web content and local netw…
yusuftor 254d6de
chore: split DevServerManifest.swift into one file per type
yusuftor 3482bf2
style: invert the paywall picker's open guard into a positive early r…
yusuftor 0d7ce5e
style: split the paywall picker gate into a three-branch predicate
yusuftor 362950d
style: state the picker gate positively with guard
yusuftor 11cd922
style: group the ATS warning flag with the locator's other state
yusuftor 6fed06c
style: split the ATS warning gate into single-condition checks
yusuftor c22e098
style: split the dev link parse into single-condition guards
yusuftor cf2020c
docs: drop the superwall.lock binding detail from the dev mode change…
yusuftor e751849
review: drop the debugger's product-variables timeout
yusuftor 6240aa2
style: positive-if and multiline-guard formatting in dev mode gates
yusuftor b61b66e
feat!: replace devMode and devServerURL with SuperwallOptions.devServer
yusuftor ae9e819
chore: retrigger CI after a stuck Pullfrog run
yusuftor d6f8f63
fix(debugger): make Preview work for unpushed dev-server surfaces
yusuftor ee963aa
feat(dev): serve matching local surfaces wholesale instead of patchin…
yusuftor 75c29ba
feat(dev): mark locally served paywalls and honour their presentation…
yusuftor 79e8ed2
Merge remote-tracking branch 'origin/develop' into christo/sw-framewo…
yusuftor 7689d10
refactor(debugger): hold published paywalls as PaywallSummary
yusuftor eedda06
review: keep gating real, contain manifest decode failures, share the…
yusuftor 5181d83
review: inherit dashboard-owned behaviour, keep the manifest identifi…
yusuftor 8dee668
fix(dev): let the local paywall keep owning its notifications
yusuftor 0027657
fix(dev): inherit what the manifest can't carry, honour multi-paywall…
yusuftor bff8c79
refactor(dev): read paywall settings from the published paywall only
yusuftor 694331b
fix(dev): take identity from the paywall a surface stands in for
yusuftor a280567
docs(dev): stop promising config.ts presentation reaches dev mode
yusuftor e518f87
docs(dev): name local notifications as the exception to inheritance
yusuftor 1af8f0a
docs(dev): make the on-device cache exception explicit
yusuftor File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
172 changes: 172 additions & 0 deletions
172
Sources/SuperwallKit/Debug/DebugPaywallPickerViewController.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,172 @@ | ||
| // | ||
| // DebugPaywallPickerViewController.swift | ||
| // SuperwallKit | ||
| // | ||
| // The debugger's paywall list: a searchable, sectioned table of the local | ||
| // surfaces a `superwall dev` server serves and the app's published paywalls. | ||
| // | ||
|
|
||
| import UIKit | ||
|
|
||
| @MainActor | ||
| final class DebugPaywallPickerViewController: UIViewController { | ||
| private let localSurfaceIds: [String] | ||
| private let publishedNames: [String] | ||
| private let selectedLocalId: String? | ||
| private let selectedPublishedIndex: Int? | ||
| private let onSelect: (DebugPickerLogic.Kind) -> Void | ||
|
|
||
| private var sections: [DebugPickerLogic.Section] = [] | ||
|
|
||
| private lazy var tableView: UITableView = { | ||
| let table = UITableView(frame: .zero, style: .insetGrouped) | ||
| table.backgroundColor = darkBackgroundColor | ||
| table.separatorColor = UIColor.white.withAlphaComponent(0.1) | ||
| table.dataSource = self | ||
| table.delegate = self | ||
| table.keyboardDismissMode = .onDrag | ||
| table.translatesAutoresizingMaskIntoConstraints = false | ||
| return table | ||
| }() | ||
|
|
||
| private lazy var searchController: UISearchController = { | ||
| let controller = UISearchController(searchResultsController: nil) | ||
| controller.searchResultsUpdater = self | ||
| controller.obscuresBackgroundDuringPresentation = false | ||
| controller.searchBar.placeholder = "Search paywalls" | ||
| controller.searchBar.tintColor = primaryColor | ||
| controller.searchBar.searchTextField.textColor = .white | ||
| return controller | ||
| }() | ||
|
|
||
| init( | ||
| localSurfaceIds: [String], | ||
| publishedNames: [String], | ||
| selectedLocalId: String?, | ||
| selectedPublishedIndex: Int?, | ||
| onSelect: @escaping (DebugPickerLogic.Kind) -> Void | ||
| ) { | ||
| self.localSurfaceIds = localSurfaceIds | ||
| self.publishedNames = publishedNames | ||
| self.selectedLocalId = selectedLocalId | ||
| self.selectedPublishedIndex = selectedPublishedIndex | ||
| self.onSelect = onSelect | ||
| super.init(nibName: nil, bundle: nil) | ||
| } | ||
|
|
||
| @available(*, unavailable) | ||
| required init?(coder: NSCoder) { | ||
| fatalError("init(coder:) has not been implemented") | ||
| } | ||
|
|
||
| override func viewDidLoad() { | ||
| super.viewDidLoad() | ||
| view.backgroundColor = darkBackgroundColor | ||
| title = "Paywalls" | ||
|
|
||
| navigationItem.searchController = searchController | ||
| navigationItem.hidesSearchBarWhenScrolling = false | ||
| navigationItem.rightBarButtonItem = UIBarButtonItem( | ||
| barButtonSystemItem: .close, | ||
| target: self, | ||
| action: #selector(pressedClose) | ||
| ) | ||
| navigationItem.rightBarButtonItem?.tintColor = primaryColor | ||
|
|
||
| view.addSubview(tableView) | ||
| NSLayoutConstraint.activate([ | ||
| tableView.topAnchor.constraint(equalTo: view.topAnchor), | ||
| tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), | ||
| tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), | ||
| tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor) | ||
| ]) | ||
|
|
||
| reload(query: "") | ||
| } | ||
|
|
||
| private func reload(query: String) { | ||
| sections = DebugPickerLogic.sections( | ||
| localSurfaceIds: localSurfaceIds, | ||
| publishedNames: publishedNames, | ||
| selectedLocalId: selectedLocalId, | ||
| selectedPublishedIndex: selectedPublishedIndex, | ||
| query: query | ||
| ) | ||
| tableView.reloadData() | ||
| } | ||
|
|
||
| @objc private func pressedClose() { | ||
| dismiss(animated: true) | ||
| } | ||
| } | ||
|
|
||
| // MARK: - Table | ||
|
|
||
| extension DebugPaywallPickerViewController: UITableViewDataSource, UITableViewDelegate { | ||
| func numberOfSections(in tableView: UITableView) -> Int { | ||
| return sections.count | ||
| } | ||
|
|
||
| func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { | ||
| return sections[section].rows.count | ||
| } | ||
|
|
||
| func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { | ||
| return sections[section].title | ||
| } | ||
|
|
||
| func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { | ||
| let row = sections[indexPath.section].rows[indexPath.row] | ||
| let cell = UITableViewCell(style: .default, reuseIdentifier: nil) | ||
| cell.backgroundColor = lightBackgroundColor | ||
| cell.textLabel?.text = row.title | ||
| cell.textLabel?.textColor = .white | ||
| cell.textLabel?.font = .systemFont(ofSize: 16, weight: row.isSelected ? .semibold : .regular) | ||
| cell.accessoryType = row.isSelected ? .checkmark : .none | ||
| cell.tintColor = primaryColor | ||
| let selected = UIView() | ||
| selected.backgroundColor = UIColor.white.withAlphaComponent(0.08) | ||
| cell.selectedBackgroundView = selected | ||
| return cell | ||
| } | ||
|
|
||
| func tableView( | ||
| _ tableView: UITableView, | ||
| willDisplayHeaderView view: UIView, | ||
| forSection section: Int | ||
| ) { | ||
| guard let header = view as? UITableViewHeaderFooterView else { | ||
| return | ||
| } | ||
| // A grouped header renders through its content configuration on iOS 14+, | ||
| // which ignores `textLabel` — the default grey is unreadable on the | ||
| // debugger's near-black sheet. | ||
| if #available(iOS 14.0, *) { | ||
| var configuration = header.defaultContentConfiguration() | ||
| configuration.text = sections[section].title | ||
| configuration.textProperties.color = UIColor.white.withAlphaComponent(0.5) | ||
| configuration.textProperties.font = .systemFont(ofSize: 13, weight: .semibold) | ||
| header.contentConfiguration = configuration | ||
| } else { | ||
| header.textLabel?.textColor = UIColor.white.withAlphaComponent(0.5) | ||
| header.textLabel?.font = .systemFont(ofSize: 13, weight: .semibold) | ||
| } | ||
| } | ||
|
|
||
| func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { | ||
| tableView.deselectRow(at: indexPath, animated: true) | ||
| let row = sections[indexPath.section].rows[indexPath.row] | ||
| let onSelect = self.onSelect | ||
| dismiss(animated: true) { | ||
| onSelect(row.kind) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // MARK: - Search | ||
|
|
||
| extension DebugPaywallPickerViewController: UISearchResultsUpdating { | ||
| func updateSearchResults(for searchController: UISearchController) { | ||
| reload(query: searchController.searchBar.text ?? "") | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.