Skip to content

Commit 517fc39

Browse files
committed
Merge remote-tracking branch 'origin/trunk' into feature/18440-prompt-card-avatar-train-color
2 parents 447411d + 5ef12d7 commit 517fc39

64 files changed

Lines changed: 2197 additions & 181 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

RELEASE-NOTES.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
-----
33
* [**] Self hosted sites are not restricted by video length during media uploads [https://github.com/wordpress-mobile/WordPress-iOS/pull/18414]
44
* [*] [internal] My Site Dashboard: Made some changes to the code architecture of the dashboard. The majority of the changes are related to the posts cards. It should have no visible changes but could cause regressions. Please test it by creating/trashing drafts and scheduled posts and testing that they appear correctly on the dashboard. [#18405]
5+
* [*] Quick Start: Updated the Stats tour. The tour can now be accessed from either the dashboard or the menu tab. [#18413]
6+
* [*] Quick Start: Updated the Reader tour. The tour now highlights the Discover tab and guides users to follow topics via the Settings screen. [#18450]
57
* [*] [internal] Quick Start: Refactored some code related to the tasks displayed in the Quick Start Card and the Quick Start modal. It should have no visible changes but could cause regressions. [#18395]
8+
* [**] We'll now ask users logging in which area of the app they'd like to focus on to build towards a more personalized experience. [#18385]
69

710
19.7
811
-----
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env ruby
2+
3+
require 'xcodeproj'
4+
5+
REPO_ROOT = Pathname.new(__dir__) + '../..'
6+
7+
def lint(file_path:, target_name:)
8+
violations_count = 0
9+
File.foreach(file_path, mode: 'rb:BOM|UTF-8').with_index do |line, line_no|
10+
next if line.match? %r(^\s*//) # Skip commented lines
11+
12+
col_no = line.index('NSLocalizedString')
13+
next if col_no.nil?
14+
15+
puts "#{file_path}:#{line_no+1}:#{col_no+1}: error: Use `AppLocalizedString` instead of `NSLocalizedString` in source files that are used in the `#{target_name}` extension target. See paNNhX-nP-p2 for more info."
16+
violations_count += 1
17+
end
18+
violations_count
19+
end
20+
21+
## Main ##
22+
23+
project = Xcodeproj::Project.open(REPO_ROOT + 'WordPress/WordPress.xcodeproj')
24+
targets_to_analyze = if ARGV.count.positive?
25+
project.targets.select { |t| t.name == ARGV.first }
26+
else
27+
project.targets.select { |t| t.is_a?(Xcodeproj::Project::Object::PBXNativeTarget) && t.extension_target_type? }
28+
end
29+
30+
violations_count = 0
31+
targets_to_analyze.each do |target|
32+
build_phase = target.build_phases.find { |p| p.is_a?(Xcodeproj::Project::Object::PBXSourcesBuildPhase) }
33+
next if build_phase.nil?
34+
35+
puts "Linting extension target #{target.name} for improper NSLocalizedString usage..."
36+
source_files = build_phase.files_references.map(&:real_path).select { |f| ['.m', '.swift'].any? { |ext| f.extname == ext } }
37+
source_files.each { |f| violations_count += lint(file_path: f, target_name: target.name) }
38+
puts "Done."
39+
end
40+
41+
exit 1 if violations_count > 0

Scripts/BuildPhases/runRubyScript

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/bin/bash -eu
2+
3+
# Use this to run a Ruby script from a "Script Build Phase" from Xcode.
4+
#
5+
# Since shell scripts ran by Xcode do not source the user shell profile, typical user setups like the configurations of `rbenv` or `rvm` would not be set up properly.
6+
# This script check if either `rbenv` or `rvm` is installed on the Mac and runs the setup steps as appropriate, before running the ruby script via `bundle exec`
7+
#
8+
# Usage:
9+
# `runRubyScript <script_name.rb> <optional_args>`
10+
#
11+
# Where <script_name.rb` can be either an absolute path, or a path relative to this runRubyScript wrapper script.
12+
#
13+
# Inspiration: https://mgrebenets.github.io/xcode/2019/04/04/xcode-build-phases-and-environment
14+
#
15+
16+
# Add `rbenv` and `rvm` binaries to PATH, so that we support both
17+
export PATH="$HOME/.rbenv/shims:$HOME/.rvm/bin:$PATH"
18+
RUBY_VERSION="$(cat "${PROJECT_DIR}/../.ruby-version")"
19+
if command -v rvm; then
20+
source "$(rvm "${RUBY_VERSION}" do rvm env --path | tail -n1)"
21+
fi
22+
23+
# Run the script with bundle exec
24+
echo "Running the script using 'bundle exec' ..."
25+
cd "$(dirname "${BASH_SOURCE[0]}")"
26+
bundle exec ruby "$@"
27+
cd -

WordPress/Classes/Extensions/UIScrollView+Helpers.swift

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import UIKit
22

33
extension UIScrollView {
44

5-
// Scroll to a specific view so that it's top is at the top our scrollview
6-
@objc func scrollToView(_ view: UIView, animated: Bool) {
5+
// MARK: - Vertical scrollview
6+
7+
// Scroll to a specific view in a vertical scrollview so that it's top is at the top our scrollview
8+
@objc func scrollVerticallyToView(_ view: UIView, animated: Bool) {
79
if let origin = view.superview {
810

911
// Get the Y position of your child view
@@ -16,39 +18,82 @@ extension UIScrollView {
1618
//
1719
if childStartPoint.y + safeAreaLayoutGuide.layoutFrame.height < contentSize.height {
1820
let targetRect = CGRect(x: 0,
19-
y: childStartPoint.y - Constants.yOffset,
20-
width: Constants.targetRectWidth,
21+
y: childStartPoint.y - Constants.targetRectPadding,
22+
width: Constants.targetRectDimension,
2123
height: safeAreaLayoutGuide.layoutFrame.height)
2224
scrollRectToVisible(targetRect, animated: animated)
25+
26+
// This ensures scrolling to the correct position, especially when there are layout changes
27+
//
28+
// See: https://stackoverflow.com/a/35437399
29+
//
30+
layoutIfNeeded()
2331
} else {
2432
scrollToBottom(animated: true)
2533
}
26-
27-
// This ensures scrolling to the correct position, especially when there are layout changes
28-
//
29-
// See: https://stackoverflow.com/a/35437399
30-
//
31-
layoutIfNeeded()
3234
}
3335
}
3436

3537
@objc func scrollToTop(animated: Bool) {
3638
let topOffset = CGPoint(x: 0, y: -adjustedContentInset.top)
3739
setContentOffset(topOffset, animated: animated)
40+
layoutIfNeeded()
3841
}
3942

4043
@objc func scrollToBottom(animated: Bool) {
4144
let bottomOffset = CGPoint(x: 0, y: contentSize.height - bounds.size.height + adjustedContentInset.bottom)
4245
if bottomOffset.y > 0 {
4346
setContentOffset(bottomOffset, animated: animated)
47+
layoutIfNeeded()
48+
}
49+
}
50+
51+
// MARK: - Horizontal scrollview
52+
53+
// Scroll to a specific view in a horizontal scrollview so that it's leading edge is at the leading edge of our scrollview
54+
@objc func scrollHorizontallyToView(_ view: UIView, animated: Bool) {
55+
if let origin = view.superview {
56+
57+
// Get the X position of your child view
58+
let childStartPoint = origin.convert(view.frame.origin, to: self)
59+
60+
// Scroll to a rectangle starting at the X of your subview, with a width of the scrollview safe area
61+
// if the end of the rectangle is within the content size width.
62+
//
63+
// Otherwise, scroll all the way to the end.
64+
//
65+
if childStartPoint.x + safeAreaLayoutGuide.layoutFrame.width < contentSize.width {
66+
let targetRect = CGRect(x: childStartPoint.x - Constants.targetRectPadding,
67+
y: 0,
68+
width: safeAreaLayoutGuide.layoutFrame.width,
69+
height: Constants.targetRectDimension)
70+
scrollRectToVisible(targetRect, animated: animated)
71+
72+
// This ensures scrolling to the correct position, especially when there are layout changes
73+
//
74+
// See: https://stackoverflow.com/a/35437399
75+
//
76+
layoutIfNeeded()
77+
} else {
78+
scrollToEnd(animated: true)
79+
}
80+
81+
}
82+
}
83+
84+
func scrollToEnd(animated: Bool) {
85+
let endOffset = CGPoint(x: contentSize.width - bounds.size.width, y: 0)
86+
if endOffset.x > 0 {
87+
setContentOffset(endOffset, animated: animated)
88+
layoutIfNeeded()
4489
}
4590
}
4691

4792
private enum Constants {
4893
/// An arbitrary placeholder value for the target rect -- must be some value larger than 0
49-
static let targetRectWidth: CGFloat = 1
94+
static let targetRectDimension: CGFloat = 1
5095

51-
/// Vertical padding for the target rect
52-
static let yOffset: CGFloat = 24
96+
/// Padding for the target rect
97+
static let targetRectPadding: CGFloat = 20
5398
}
5499
}

WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,16 @@ import Foundation
338338
// Quick Start
339339
case quickStartStarted
340340

341+
// Onboarding Question Prompt
342+
case onboardingQuestionsDisplayed
343+
case onboardingQuestionsItemSelected
344+
case onboardingQuestionsSkipped
345+
346+
// Onboarding Enable Notifications Prompt
347+
case onboardingEnableNotificationsDisplayed
348+
case onboardingEnableNotificationsSkipped
349+
case onboardingEnableNotificationsEnableTapped
350+
341351
/// A String that represents the event
342352
var value: String {
343353
switch self {
@@ -895,6 +905,21 @@ import Foundation
895905
case .enhancedSiteCreationIntentQuestionExperiment:
896906
return "enhanced_site_creation_intent_question_experiment"
897907

908+
// Onboarding Question Prompt
909+
case .onboardingQuestionsDisplayed:
910+
return "onboarding_questions_displayed"
911+
case .onboardingQuestionsItemSelected:
912+
return "onboarding_questions_item_selected"
913+
case .onboardingQuestionsSkipped:
914+
return "onboarding_questions_skipped"
915+
916+
// Onboarding Enable Notifications Prompt
917+
case .onboardingEnableNotificationsDisplayed:
918+
return "onboarding_enable_notifications_displayed"
919+
case .onboardingEnableNotificationsSkipped:
920+
return "onboarding_enable_notifications_skipped"
921+
case .onboardingEnableNotificationsEnableTapped:
922+
return "onboarding_enable_notifications_enable_tapped"
898923
// Site Name
899924
case .enhancedSiteCreationSiteNameCanceled:
900925
return "enhanced_site_creation_site_name_canceled"

WordPress/Classes/Utility/FormattableContent/Actions/FormattableContentAction.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ public enum NotificationDeletionKind {
1212
public var legendText: String {
1313
switch self {
1414
case .deletion:
15-
return NSLocalizedString("Comment has been deleted", comment: "Displayed when a Comment is deleted")
15+
return AppLocalizedString("Comment has been deleted", comment: "Displayed when a Comment is deleted")
1616
case .spamming:
17-
return NSLocalizedString("Comment has been marked as Spam", comment: "Displayed when a Comment is spammed")
17+
return AppLocalizedString("Comment has been marked as Spam", comment: "Displayed when a Comment is spammed")
1818
}
1919
}
2020
}

WordPress/Classes/ViewRelated/Blog/Blog Dashboard/BlogDashboardViewController.swift

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ final class BlogDashboardViewController: UIViewController {
3333
return refreshControl
3434
}()
3535

36+
/// The "My Site" parent view controller
37+
var mySiteViewController: MySiteViewController? {
38+
return parent as? MySiteViewController
39+
}
40+
3641
/// The "My Site" main scroll view
3742
var mySiteScrollView: UIScrollView? {
3843
return view.superview?.superview as? UIScrollView
@@ -69,7 +74,7 @@ final class BlogDashboardViewController: UIViewController {
6974
super.viewDidAppear(animated)
7075

7176
viewModel.loadCards()
72-
QuickStartTourGuide.shared.currentTourOrigin = .blogDashboard
77+
QuickStartTourGuide.shared.currentEntryPoint = .blogDashboard
7378
startAlertTimer()
7479

7580
WPAnalytics.track(.mySiteDashboardShown)
@@ -147,7 +152,30 @@ final class BlogDashboardViewController: UIViewController {
147152
}
148153

149154
private func addQuickStartObserver() {
150-
NotificationCenter.default.addObserver(self, selector: #selector(loadCardsFromCache), name: .QuickStartTourElementChangedNotification, object: nil)
155+
NotificationCenter.default.addObserver(forName: .QuickStartTourElementChangedNotification, object: nil, queue: nil) { [weak self] notification in
156+
157+
guard let self = self else {
158+
return
159+
}
160+
161+
if let info = notification.userInfo,
162+
let element = info[QuickStartTourGuide.notificationElementKey] as? QuickStartTourElement {
163+
164+
switch element {
165+
case .setupQuickStart, .removeQuickStart:
166+
self.loadCardsFromCache()
167+
case .stats:
168+
if self.embeddedInScrollView {
169+
self.mySiteScrollView?.scrollToTop(animated: true)
170+
} else {
171+
self.collectionView.scrollToTop(animated: true)
172+
}
173+
self.mySiteViewController?.additionalSafeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: Constants.bottomPaddingForQuickStartNotices, right: 0)
174+
default:
175+
break
176+
}
177+
}
178+
}
151179
}
152180

153181
@objc private func updateCollectionViewHeight(notification: Notification) {
@@ -266,6 +294,7 @@ extension BlogDashboardViewController {
266294
static let horizontalSectionInset: CGFloat = 20
267295
static let verticalSectionInset: CGFloat = 20
268296
static let cellSpacing: CGFloat = 20
297+
static let bottomPaddingForQuickStartNotices: CGFloat = 80
269298
}
270299
}
271300

WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/DashboardEmptyPostsCardCell.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import UIKit
2+
import WordPressShared
23

34
/// Card cell prompting the user to create their first post
45
final class DashboardFirstPostCardCell: DashboardEmptyPostsCardCell, BlogDashboardCardConfigurable {
@@ -48,7 +49,7 @@ class DashboardEmptyPostsCardCell: UICollectionViewCell, Reusable {
4849
private lazy var titleLabel: UILabel = {
4950
let titleLabel = UILabel()
5051
titleLabel.text = "Create your first post"
51-
titleLabel.font = WPStyleGuide.notoBoldFontForTextStyle(.title3)
52+
titleLabel.font = WPStyleGuide.serifFontForTextStyle(.title3, fontWeight: .semibold)
5253
titleLabel.adjustsFontForContentSizeCategory = true
5354
titleLabel.adjustsFontSizeToFitWidth = true
5455
titleLabel.minimumScaleFactor = 0.5

0 commit comments

Comments
 (0)