Skip to content

Commit fa4a331

Browse files
wpmobilebotcrazytonylikean
authored
Merge release/26.8 into trunk (#25461)
* Show more detailed application password login errors (#25454) * Fix colors in post inline comment section (#25456) * Revert a localizable string change (#25460) Introduced in #25454, and caused trouble in the release process: > Inconsistencies found between 'en' and 'zh-Hant': > `addSite.selfHosted.loadingSiteInfoFailure` expected placeholders for [String] but found [] instead. * Update strings for localization * Update app translations – `Localizable.strings` * Update WordPress metadata translations * Update Jetpack metadata translations * Bump version number --------- Co-authored-by: Tony Li <tony.li@automattic.com> Co-authored-by: Alex Grebenyuk <alex.grebenyuk@automattic.com>
1 parent 9ecc000 commit fa4a331

52 files changed

Lines changed: 872 additions & 66 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.

Modules/Sources/WordPressReader/Comments/Views/CommentContentRenderer.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import UIKit
55
public protocol CommentContentRenderer: AnyObject {
66
var delegate: CommentContentRendererDelegate? { get set }
77

8+
var displaySettings: ReaderDisplaySettings { get set }
9+
810
/// A view for rendering the comments.
911
var view: UIView { get }
1012

Modules/Sources/WordPressReader/Comments/Views/CommentWebView.swift

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ final class CommentWebView: UIView, CommentContentRendererDelegate {
66
let renderer = WebCommentContentRenderer()
77
lazy var heightConstraint = renderer.view.heightAnchor.constraint(equalToConstant: 20)
88

9-
init(comment: String) {
9+
init(comment: String, displaySettings: ReaderDisplaySettings = .standard) {
1010
super.init(frame: .zero)
1111

1212
addSubview(renderer.view)
1313
renderer.view.pinEdges()
1414

1515
heightConstraint.isActive = true
1616

17+
renderer.displaySettings = displaySettings
1718
renderer.delegate = self
1819
renderer.render(comment: comment)
1920
}
@@ -43,19 +44,27 @@ final class CommentWebView: UIView, CommentContentRendererDelegate {
4344
""")
4445
}
4546

47+
#Preview("Sepia") {
48+
makeView(
49+
comment: "<p>Thank you so much! You should <a href=\"https:://wordpress.com/\">see it now</a> &#8211; people are losing their minds!</p>\n",
50+
displaySettings: ReaderDisplaySettings(color: .sepia, font: .sans, size: .normal)
51+
)
52+
}
53+
4654
#Preview("Media") {
4755
makeView(comment: """
4856
<p>Test image in the middle.</p>\n<figure class=\"wp-block-image size-medium\"><img src=\"https://fastly.picsum.photos/id/31/3264/4912.jpg?hmac=lfmmWE3h_aXmRwDDZ7pZb6p0Foq6u86k_PpaFMnq0r8\" alt=\"\" /></figure>\n<p>Text below.</p>\n
4957
""")
5058
}
5159

5260
@MainActor
53-
private func makeView(comment: String) -> UIView {
54-
let webView = CommentWebView(comment: comment)
61+
private func makeView(comment: String, displaySettings: ReaderDisplaySettings = .standard) -> UIView {
62+
let webView = CommentWebView(comment: comment, displaySettings: displaySettings)
5563
webView.layer.borderColor = UIColor.opaqueSeparator.withAlphaComponent(0.66).cgColor
5664
webView.layer.borderWidth = 0.5
5765

5866
let container = UIView()
67+
container.backgroundColor = displaySettings.color.background
5968
container.addSubview(webView)
6069
webView.pinEdges(insets: UIEdgeInsets(.all, 16))
6170

Modules/Sources/WordPressReader/Comments/Views/WebCommentContentRenderer.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public final class WebCommentContentRenderer: NSObject, CommentContentRenderer {
2020

2121
/// It can't be changed at the moment, but this capability was included from the
2222
/// start, and this implementation continues supporting it.
23-
private var displaySetting = ReaderDisplaySettings.standard
23+
public var displaySettings = ReaderDisplaySettings.standard
2424

2525
/// - warning: This has to be configured _before_ you render.
2626
public var tintColor: UIColor {
@@ -109,7 +109,7 @@ extension WebCommentContentRenderer: WKNavigationDelegate {
109109
/// The display setting's custom size is applied through the HTML's initial-scale property
110110
/// in the meta tag. The `scrollHeight` value seems to return the height as if it's at 1.0 scale,
111111
/// so we'll need to add the custom scale into account.
112-
let actualHeight = round(height * self.displaySetting.size.scale)
112+
let actualHeight = round(height * self.displaySettings.size.scale)
113113
self.delegate?.renderer(self, asyncRenderCompletedWithHeight: actualHeight, comment: comment)
114114
}
115115
}
@@ -175,8 +175,8 @@ private extension WebCommentContentRenderer {
175175
}
176176

177177
private func actuallyMakeHead() -> String {
178-
let meta = "width=device-width,initial-scale=\(displaySetting.size.scale),maximum-scale=\(displaySetting.size.scale),user-scalable=no,shrink-to-fit=no"
179-
let styles = displaySetting.makeStyles(tintColor: webView.tintColor)
178+
let meta = "width=device-width,initial-scale=\(displaySettings.size.scale),maximum-scale=\(displaySettings.size.scale),user-scalable=no,shrink-to-fit=no"
179+
let styles = displaySettings.makeStyles(tintColor: webView.tintColor)
180180
return String(format: Self.headTemplate, meta, styles)
181181
}
182182

Modules/Sources/WordPressReader/Settings/ReaderDisplaySettings+WebKit.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ extension ReaderDisplaySettings {
2626
:root {
2727
--text-font: \(font.cssString);
2828
--link-font-weight: \(color == .system ? "inherit" : "600");
29-
--link-text-decoration: \(color == .system ? "inherit" : "underline");
29+
--link-text-decoration: underline;
3030
}
3131
3232
@media(prefers-color-scheme: light) {
@@ -44,6 +44,7 @@ extension ReaderDisplaySettings {
4444
/// - parameter interfaceStyle: The current `UIUserInterfaceStyle` value.
4545
private func makeColors(interfaceStyle: UIUserInterfaceStyle, tintColor: UIColor) -> String {
4646
let trait = UITraitCollection(userInterfaceStyle: interfaceStyle)
47+
let tintColor = color == .system ? tintColor : color.foreground
4748
return """
4849
:root {
4950
--text-color: \(color.foreground.color(for: trait).cssHex);

Modules/Sources/WordPressReader/Settings/ReaderDisplaySettings.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,9 @@ public struct ReaderDisplaySettings: Codable, Equatable, Hashable, Sendable {
166166
case .system:
167167
return .tertiaryLabel
168168
case .evening, .oled, .hacker:
169-
return foreground.withAlphaComponent(0.8) // slightly higher contrast for dark themes.
169+
return foreground.withAlphaComponent(0.45) // slightly higher contrast for dark themes.
170170
default:
171-
return foreground.withAlphaComponent(0.6)
171+
return foreground.withAlphaComponent(0.33)
172172
}
173173
}
174174

WordPress/Classes/Login/SelfHostedSiteAuthenticator.swift

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ struct SelfHostedSiteAuthenticator {
6565
enum SignInError: Error, LocalizedError {
6666
case authentication(Error)
6767
case xmlrpcDisabled(Error)
68-
case loadingSiteInfoFailure
68+
case xmlrpcEndpointNotFound
69+
case loadingSiteInfoFailure(Error)
6970
case savingSiteFailure
7071
case mismatchedUser(expectedUsername: String)
7172
case cancelled
@@ -74,6 +75,8 @@ struct SelfHostedSiteAuthenticator {
7475
switch self {
7576
case .authentication(let error):
7677
return error.localizedDescription
78+
case .xmlrpcEndpointNotFound:
79+
return NSLocalizedString("addSite.selfHosted.xmlrpcEndpointNotFound", value: "Could not determine the site's XML-RPC endpoint", comment: "Error message when the app cannot find the XML-RPC endpoint of a self-hosted WordPress site")
7780
case .loadingSiteInfoFailure:
7881
return NSLocalizedString("addSite.selfHosted.loadingSiteInfoFailure", value: "Cannot load the WordPress site details", comment: "Error message shown when failing to load details from a self-hosted WordPress site")
7982
case .savingSiteFailure:
@@ -264,7 +267,7 @@ struct SelfHostedSiteAuthenticator {
264267
let xmlrpc = (try? await discoverXMLRPCEndpoint(site: credentials.siteUrl))
265268
?? URL(string: credentials.siteUrl)?.appending(component: "xmlrpc.php")
266269
guard let xmlrpc else {
267-
throw .loadingSiteInfoFailure
270+
throw .xmlrpcEndpointNotFound
268271
}
269272

270273
let api = WordPressAPI(
@@ -273,13 +276,15 @@ struct SelfHostedSiteAuthenticator {
273276
authentication: WpAuthentication(username: credentials.userLogin, password: credentials.password)
274277
)
275278

276-
let siteSettings: SiteSettingsWithViewContext
279+
let siteSettings: SiteSettingsWithViewContext?
277280
let isAdmin: Bool
278281
let jetpackSite: RemoteBlog?
279282
let jetpackConnection: JetpackConnectionData?
280283
let xmlrpcOptions: [AnyHashable: Any]?
281284
do {
282-
async let siteSettings_ = api.siteSettings.retrieveWithViewContext().data
285+
// site settings is only available to admin users. Ignore errors for now,
286+
// since we need to allow other users to sign in to the app too.
287+
async let siteSettings_ = try? api.siteSettings.retrieveWithViewContext().data
283288
async let isAdmin_ = api.users.retrieveMeWithEditContext().data.roles.contains(.administrator)
284289
async let jetpackSite_ = fetchJetpackSite(apiRootURL: apiRootURL, credentials: credentials)
285290
async let jetpackConnection_ = fetchJetpackConnectionData(apiRootURL: apiRootURL, credentials: credentials)
@@ -288,7 +293,7 @@ struct SelfHostedSiteAuthenticator {
288293
(siteSettings, isAdmin, jetpackSite, jetpackConnection, xmlrpcOptions) =
289294
try await (siteSettings_, isAdmin_, jetpackSite_, jetpackConnection_, xmlrpcOptions_)
290295
} catch {
291-
throw .loadingSiteInfoFailure
296+
throw .loadingSiteInfoFailure(error)
292297
}
293298

294299
let blog: TaggedManagedObjectID<Blog>
@@ -306,7 +311,7 @@ struct SelfHostedSiteAuthenticator {
306311

307312
blog.isAdmin = isAdmin
308313
blog.addSettingsIfNecessary()
309-
blog.settings?.name = siteSettings.title
314+
blog.settings?.name = siteSettings?.title
310315

311316
blog.options = (xmlrpcOptions ?? [:])
312317
.merging(
@@ -327,12 +332,12 @@ struct SelfHostedSiteAuthenticator {
327332
}
328333
}
329334

330-
if blog.getOptionString(name: "blog_title") == nil {
331-
blog.setValue(siteSettings.title, forOption: "blog_title")
335+
if blog.getOptionString(name: "blog_title") == nil, let title = siteSettings?.title {
336+
blog.setValue(title, forOption: "blog_title")
332337
}
333338

334-
if blog.getOptionString(name: "timezone") == nil {
335-
blog.setValue(siteSettings.timezone, forOption: "timezone")
339+
if blog.getOptionString(name: "timezone") == nil, let timezone = siteSettings?.timezone {
340+
blog.setValue(timezone, forOption: "timezone")
336341
}
337342

338343
if blog.getOptionString(name: "gmt_offset") == nil, let offset = apiDetails.gmtOffset() {

WordPress/Classes/ViewRelated/Comments/Views/Detail/CommentContentTableViewCell.swift

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ final class CommentContentTableViewCell: UITableViewCell, NibReusable {
113113
/// can be scoped by using the "legacy" style when the passed parameter is nil.
114114
private var style: CellStyle = .init(displaySetting: nil)
115115

116-
var displaySetting: ReaderDisplaySettings? = nil {
116+
var displaySetting: ReaderDisplaySettings = .standard {
117117
didSet {
118118
style = CellStyle(displaySetting: displaySetting)
119119
applyStyles()
@@ -377,20 +377,17 @@ private extension CommentContentTableViewCell {
377377
dateLabel?.font = style.dateFont
378378
dateLabel?.textColor = style.dateTextColor
379379

380-
accessoryButton?.tintColor = .secondaryLabel
381380
accessoryButton?.setImage(accessoryButtonImage, for: .normal)
382381
accessoryButton?.addTarget(self, action: #selector(accessoryButtonTapped), for: .touchUpInside)
383382

384383
replyButton.configuration = makeReactionButtonConfiguration(image: UIImage(named: "icon-reader-comment-reply"))
385384
replyButton.configuration?.contentInsets.leading = 0
386-
replyButton.tintColor = .secondaryLabel
387385
replyButton.setTitle(.reply, for: .normal)
388386
replyButton.addTarget(self, action: #selector(replyButtonTapped), for: .touchUpInside)
389387
replyButton.maximumContentSizeCategory = .accessibilityMedium
390388
replyButton.accessibilityIdentifier = .replyButtonAccessibilityId
391389

392390
likeButton.configuration = makeReactionButtonConfiguration(image: WPStyleGuide.ReaderDetail.likeToolbarIcon)
393-
likeButton.tintColor = .secondaryLabel
394391

395392
likeButton.addTarget(self, action: #selector(likeButtonTapped), for: .touchUpInside)
396393
likeButton.maximumContentSizeCategory = .accessibilityMedium
@@ -422,6 +419,11 @@ private extension CommentContentTableViewCell {
422419

423420
dateLabel?.font = style.dateFont
424421
dateLabel?.textColor = style.dateTextColor
422+
423+
replyButton?.tintColor = displaySetting.color.secondaryForeground
424+
likeButton?.tintColor = displaySetting.color.secondaryForeground
425+
426+
accessoryButton?.tintColor = displaySetting.color.secondaryForeground
425427
}
426428

427429
private func getShowMoreOverlay() -> UIView {
@@ -461,7 +463,7 @@ private extension CommentContentTableViewCell {
461463
}
462464

463465
func updateLikeButton(isLiked: Bool, likeCount: Int) {
464-
likeButton.tintColor = isLiked ? UIAppColor.primary : .secondaryLabel
466+
likeButton.tintColor = isLiked ? UIAppColor.primary : displaySetting.color.secondaryForeground
465467
if var configuration = likeButton.configuration {
466468
configuration.image = isLiked ? WPStyleGuide.ReaderDetail.likeSelectedToolbarIcon : WPStyleGuide.ReaderDetail.likeToolbarIcon
467469
configuration.title = likeCount > 0 ? "\(likeCount)" : String.noLikes
@@ -489,6 +491,8 @@ private extension CommentContentTableViewCell {
489491
return renderer
490492
}()
491493

494+
renderer.displaySettings = displaySetting
495+
492496
configureContentView(contentHeight: helper.getCachedContentHeight(for: content))
493497

494498
let contentView = renderer.view

WordPress/Classes/ViewRelated/Reader/Detail/Views/ReaderDetailCommentsTableViewDelegate.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ private extension ReaderDetailCommentsTableViewDelegate {
167167
}
168168

169169
cell.displaySetting = displaySetting
170+
170171
cell.configureForPostDetails(with: comment, helper: helper) { _ in
171172
do {
172173
try WPException.objcTry {
@@ -215,12 +216,13 @@ private extension ReaderDetailCommentsTableViewDelegate {
215216
configuration.title = Constants.viewAllButtonTitle.localizedCapitalized + " \(totalComments)"
216217
configuration.image = UIImage(systemName: "chevron.right")
217218
configuration.imagePlacement = .trailing
218-
configuration.titleTextAttributesTransformer = .init {
219+
configuration.titleTextAttributesTransformer = .init { [displaySetting] in
219220
var container = $0
221+
container.foregroundColor = displaySetting.color.foreground
220222
container.font = UIFont.preferredFont(forTextStyle: .headline).withWeight(.medium)
221223
return container
222224
}
223-
configuration.preferredSymbolConfigurationForImage = UIImage.SymbolConfiguration(paletteColors: [.tertiaryLabel])
225+
configuration.preferredSymbolConfigurationForImage = UIImage.SymbolConfiguration(paletteColors: [displaySetting.color.tertiatyForeground])
224226
.applying(UIImage.SymbolConfiguration(font: UIFont.preferredFont(forTextStyle: .caption2).withWeight(.bold)))
225227
configuration.imagePadding = 4
226228
configuration.contentInsets = .init(top: 9, leading: 12, bottom: 9, trailing: 12)

WordPress/Resources/ar.lproj/Localizable.strings

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Translation-Revision-Date: 2026-03-24 13:58:13+0000 */
1+
/* Translation-Revision-Date: 2026-03-25 19:54:39+0000 */
22
/* Plural-Forms: nplurals=6; plural=(n == 0) ? 0 : ((n == 1) ? 1 : ((n == 2) ? 2 : ((n % 100 >= 3 && n % 100 <= 10) ? 3 : ((n % 100 >= 11 && n % 100 <= 99) ? 4 : 5)))); */
33
/* Generator: GlotPress/4.0.3 */
44
/* Language: ar */
@@ -10154,6 +10154,42 @@ Example: Reply to Pamela Nguyen */
1015410154
/* Menu title for the visit site option */
1015510155
"mySite.siteActions.visitSite" = "زيارة الموقع";
1015610156

10157+
/* Button to confirm to switch to the New Stats announcement screen */
10158+
"newStats.announcement.continueButton" = "ابدأ الآن";
10159+
10160+
/* Disclosure at the bottom of the New Stats announcement screen, informing users they can opt out */
10161+
"newStats.announcement.disclosure" = "لست مستعدًا للتبديل؟ يمكنك إيقاف تشغيل الإحصائيات الجديدة من قائمة \"المزيد\" في تبويب الإحصائيات.";
10162+
10163+
/* Feature description: navigation moved to the bottom for thumb-friendly access */
10164+
"newStats.announcement.feature.bottomNav.description" = "أصبح التنقل وأداة اختيار التاريخ الآن في أسفل الشاشة - تمامًا حيث يوجد إبهامك.";
10165+
10166+
/* Feature title: navigation moved to the bottom */
10167+
"newStats.announcement.feature.bottomNav.title" = "وصول أسهل";
10168+
10169+
/* Feature description: flexible date picker with presets, custom ranges, and comparisons */
10170+
"newStats.announcement.feature.datePicker.description" = "اختر من الإعدادات المسبقة الشائعة أو حدد نطاقًا زمنيًا مخصصًا مع فترة مقارنة - كل ذلك بنقرة واحدة.";
10171+
10172+
/* Feature title: flexible date picker */
10173+
"newStats.announcement.feature.datePicker.title" = "أي فترة، أي نطاق";
10174+
10175+
/* Feature description: feature parity with the web version of Stats */
10176+
"newStats.announcement.feature.parity.description" = "الأجهزة، وUTM، والمواقع، وWordAds - نفس البيانات التي تحصل عليها في WordPress.com.";
10177+
10178+
/* Feature title: feature parity with the web version of Stats */
10179+
"newStats.announcement.feature.parity.title" = "مماثلة لنسخة الويب";
10180+
10181+
/* Feature description: trends shown for all metrics with comparison to previous period */
10182+
"newStats.announcement.feature.trends.description" = "يوضح كل مقياس اتجاهه مقارنة بالفترة السابقة، لتعرف دائمًا ما إذا كنت تحقق نموًا.";
10183+
10184+
/* Feature title: trends visible for all metrics */
10185+
"newStats.announcement.feature.trends.title" = "لمحة عن الاتجاهات";
10186+
10187+
/* Subtitle for the New Stats announcement screen */
10188+
"newStats.announcement.subtitle" = "طريقة أفضل لفهم أداء موقعك الإلكتروني - مفعلة الآن افتراضيًا.";
10189+
10190+
/* Title for the New Stats announcement screen */
10191+
"newStats.announcement.title" = "إحصاءات جديدة";
10192+
1015710193
/* A no results message displayed on the atomic logs screen. */
1015810194
"noLogs.empty" = "لا توجد إدخالات سجل في هذا النطاق الزمني";
1015910195

WordPress/Resources/cs.lproj/Localizable.strings

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Translation-Revision-Date: 2026-03-24 10:13:49+0000 */
1+
/* Translation-Revision-Date: 2026-03-24 22:05:34+0000 */
22
/* Plural-Forms: nplurals=3; plural=(n == 1) ? 0 : ((n >= 2 && n <= 4) ? 1 : 2); */
33
/* Generator: GlotPress/4.0.3 */
44
/* Language: cs_CZ */
@@ -7976,6 +7976,9 @@ Example: Reply to Pamela Nguyen */
79767976
/* Tab title for trashed posts */
79777977
"customPostTab.trash" = "Koš";
79787978

7979+
/* Badge label indicating that custom post type support is a beta feature. Displayed next to the navigation title. */
7980+
"customPostType.navigation.betaBadge" = "BETA";
7981+
79797982
/* Empty state message when there are no custom post types to display */
79807983
"customPostTypes.emptyState.message" = "Žádné vlastní typy příspěvků";
79817984

0 commit comments

Comments
 (0)