From ac9265cf8d0fd77ea051fc4ace3f1b08a78387ae Mon Sep 17 00:00:00 2001 From: Nora Trapp Date: Tue, 6 Sep 2022 14:23:54 -0700 Subject: [PATCH] Show sending status on 'My Story' row --- .../HomeView/Stories/MyStoryCell.swift | 48 ++++++++++++++----- .../HomeView/Stories/MyStoryViewModel.swift | 11 ++++- .../Stories/StoriesViewController.swift | 2 +- .../Stories/StoryListDataSource.swift | 6 +-- .../en.lproj/PluralAware.stringsdict | 16 +++++++ 5 files changed, 64 insertions(+), 19 deletions(-) diff --git a/Signal/src/ViewControllers/HomeView/Stories/MyStoryCell.swift b/Signal/src/ViewControllers/HomeView/Stories/MyStoryCell.swift index dacb8a8b73..82389b7e86 100644 --- a/Signal/src/ViewControllers/HomeView/Stories/MyStoryCell.swift +++ b/Signal/src/ViewControllers/HomeView/Stories/MyStoryCell.swift @@ -12,10 +12,12 @@ class MyStoryCell: UITableViewCell { let titleLabel = UILabel() let titleChevron = UIImageView() - let timestampLabel = UILabel() + let subtitleLabel = UILabel() let avatarView = ConversationAvatarView(sizeClass: .fiftySix, localUserDisplayMode: .asUser, useAutolayout: true) let attachmentThumbnail = UIView() + let failedIconView = UIImageView() + let addStoryButton = OWSButton() let contentHStackView = UIStackView() @@ -36,12 +38,21 @@ class MyStoryCell: UITableViewCell { titleChevron.image = chevronImage.withRenderingMode(.alwaysTemplate) - let hStack = UIStackView(arrangedSubviews: [titleLabel, titleChevron]) - hStack.axis = .horizontal - hStack.alignment = .center - hStack.spacing = 6 + let titleStack = UIStackView(arrangedSubviews: [titleLabel, titleChevron]) + titleStack.axis = .horizontal + titleStack.alignment = .center + titleStack.spacing = 6 - let vStack = UIStackView(arrangedSubviews: [hStack, timestampLabel]) + failedIconView.autoSetDimension(.width, toSize: 16) + failedIconView.contentMode = .scaleAspectFit + failedIconView.tintColor = .ows_accentRed + + let subtitleStack = UIStackView(arrangedSubviews: [failedIconView, subtitleLabel]) + subtitleStack.axis = .horizontal + subtitleStack.alignment = .center + subtitleStack.spacing = 6 + + let vStack = UIStackView(arrangedSubviews: [titleStack, subtitleStack]) vStack.axis = .vertical vStack.alignment = .leading @@ -66,7 +77,7 @@ class MyStoryCell: UITableViewCell { } func configure(with model: MyStoryViewModel, addStoryAction: @escaping () -> Void) { - configureTimestamp(with: model) + configureSubtitle(with: model) titleLabel.font = .ows_dynamicTypeHeadline titleLabel.textColor = Theme.primaryTextColor @@ -114,13 +125,24 @@ class MyStoryCell: UITableViewCell { } } - func configureTimestamp(with model: MyStoryViewModel) { - timestampLabel.font = .ows_dynamicTypeSubheadline - timestampLabel.textColor = Theme.secondaryTextAndIconColor - if let latestMessageTimestamp = model.latestMessageTimestamp { - timestampLabel.text = DateUtil.formatTimestampRelatively(latestMessageTimestamp) + func configureSubtitle(with model: MyStoryViewModel) { + subtitleLabel.font = .ows_dynamicTypeSubheadline + subtitleLabel.textColor = Theme.secondaryTextAndIconColor + failedIconView.image = Theme.iconImage(.error16) + + if model.sendingCount > 0 { + let format = NSLocalizedString("STORY_SENDING_%d", tableName: "PluralAware", comment: "Indicates that N stories are currently sending") + subtitleLabel.text = .localizedStringWithFormat(format, model.sendingCount) + failedIconView.isHiddenInStackView = !model.hasFailedSends + } else if model.hasFailedSends { + failedIconView.isHiddenInStackView = false + subtitleLabel.text = NSLocalizedString("STORY_SEND_FAILED", comment: "Text indicating that the story send has failed") + } else if let latestMessageTimestamp = model.latestMessageTimestamp { + subtitleLabel.text = DateUtil.formatTimestampRelatively(latestMessageTimestamp) + failedIconView.isHiddenInStackView = true } else { - timestampLabel.text = nil + subtitleLabel.text = nil + failedIconView.isHiddenInStackView = true } } } diff --git a/Signal/src/ViewControllers/HomeView/Stories/MyStoryViewModel.swift b/Signal/src/ViewControllers/HomeView/Stories/MyStoryViewModel.swift index 0985cacc7c..ae7ba5bb14 100644 --- a/Signal/src/ViewControllers/HomeView/Stories/MyStoryViewModel.swift +++ b/Signal/src/ViewControllers/HomeView/Stories/MyStoryViewModel.swift @@ -10,12 +10,19 @@ struct MyStoryViewModel: Dependencies { let latestMessageAttachment: StoryThumbnailView.Attachment? let latestMessageTimestamp: UInt64? + let sendingCount: UInt64 + let hasFailedSends: Bool let secondLatestMessageAttachment: StoryThumbnailView.Attachment? init(messages: [StoryMessage], transaction: SDSAnyReadTransaction) { - let sortedFilteredMessages = messages.sorted { $0.timestamp < $1.timestamp } - self.messages = sortedFilteredMessages + sendingCount = messages.reduce(0) { + $0 + ([.sending, .pending].contains($1.sendingState) ? 1 : 0) + } + hasFailedSends = messages.contains { $0.sendingState == .failed } + + let sortedFilteredMessages = messages.sorted { $0.timestamp < $1.timestamp }.prefix(2) + self.messages = Array(sortedFilteredMessages) if let latestMessage = sortedFilteredMessages.last { latestMessageAttachment = .from(latestMessage.attachment, transaction: transaction) diff --git a/Signal/src/ViewControllers/HomeView/Stories/StoriesViewController.swift b/Signal/src/ViewControllers/HomeView/Stories/StoriesViewController.swift index bf16d3d46c..1b6b07523b 100644 --- a/Signal/src/ViewControllers/HomeView/Stories/StoriesViewController.swift +++ b/Signal/src/ViewControllers/HomeView/Stories/StoriesViewController.swift @@ -76,7 +76,7 @@ class StoriesViewController: OWSViewController, StoryListDataSourceDelegate { case .myStory: guard let cell = self.tableView.cellForRow(at: indexPath) as? MyStoryCell else { continue } guard let model = self.dataSource.myStory else { continue } - cell.configureTimestamp(with: model) + cell.configureSubtitle(with: model) case .visibleStories, .hiddenStories: guard let cell = self.tableView.cellForRow(at: indexPath) as? StoryCell else { continue } guard let model = self.model(for: indexPath) else { continue } diff --git a/Signal/src/ViewControllers/HomeView/Stories/StoryListDataSource.swift b/Signal/src/ViewControllers/HomeView/Stories/StoryListDataSource.swift index 770b299d59..0ac0d00c9b 100644 --- a/Signal/src/ViewControllers/HomeView/Stories/StoryListDataSource.swift +++ b/Signal/src/ViewControllers/HomeView/Stories/StoryListDataSource.swift @@ -74,7 +74,7 @@ class StoryListDataSource: NSObject, Dependencies { let (listStories, outgoingStories) = Self.databaseStorage.read { ( StoryFinder.storiesForListView(transaction: $0), - StoryFinder.outgoingStories(limit: 2, transaction: $0) + StoryFinder.outgoingStories(transaction: $0) ) } let myStoryModel = Self.databaseStorage.read { MyStoryViewModel(messages: outgoingStories, transaction: $0) } @@ -429,7 +429,7 @@ class StoryListDataSource: NSObject, Dependencies { ) -> MyStoryViewModel? { let oldStoryModel = oldModel.myStory let outgoingStories = Self.databaseStorage.read { - StoryFinder.outgoingStories(limit: 2, transaction: $0) + StoryFinder.outgoingStories(transaction: $0) } let myStoryChanged = changedMessageRowIds.intersection(outgoingStories.map { $0.id! }).count > 0 || Set(oldStoryModel?.messages.map { $0.uniqueId } ?? []) != Set(outgoingStories.map { $0.uniqueId }) @@ -458,7 +458,7 @@ class StoryListDataSource: NSObject, Dependencies { // My story should never go away after being loaded, but for the sake of completeness... tableView.deleteRows(at: [IndexPath(row: 0, section: Section.myStory.rawValue)], with: .automatic) } else if changes.myStoryChanged { - tableView.reloadRows(at: [IndexPath(row: 0, section: Section.myStory.rawValue)], with: .automatic) + tableView.reloadRows(at: [IndexPath(row: 0, section: Section.myStory.rawValue)], with: .none) } // Visible stories section is always visible, directly apply changes. diff --git a/Signal/translations/en.lproj/PluralAware.stringsdict b/Signal/translations/en.lproj/PluralAware.stringsdict index 96f184a77e..d00c3d6eae 100644 --- a/Signal/translations/en.lproj/PluralAware.stringsdict +++ b/Signal/translations/en.lproj/PluralAware.stringsdict @@ -1149,6 +1149,22 @@ %d Excluded + STORY_SENDING_%d + + NSStringLocalizedFormatKey + %#@caption@ + caption + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + d + one + Sending... + other + Sending %d... + + STORY_VIEWS_COUNT_%d NSStringLocalizedFormatKey