This test-only change should have no user impact.
I wrote these tests last year (in
c5bdf6c094). They test every single
string, which proves annoying to update and offers little value. This
updates the tests in an effort to make them more useful.
We plan to support PayPal and credit/debit cards for gift badges. This
change, invisible to external users, is a step towards that.
Before this change, Apple Pay was always shown as the only payment
method. Now, all supported payment methods are shown.
PayPal and card don't do anything right now—they show an error UI if
tapped.
This change should have no user impact.
`DONATION_PAYMENT_ERROR_*` is now `APPLE_PAY_DONATION_ERROR_*`, and
Apple Pay is now mentioned in the string comments. None of the
user-visible strings actually change.
We plan to show different errors for cards and PayPal and this will help
us get there, but I think this is a useful change on its own.
This formats the text users enter on the card donation screen. For
example, "4242424242424242" becomes "4242 4242 4242 4242".
It uses [the `textField(_:shouldChangeCharactersIn:replacementString:)`
method of `UITextFieldDelegate`][0] to accomplish this, and implements a
helper that can handle all the cases (inserting, deleting, replacing,
pasting, and so on).
Tested this in an iPhone 14 simulator and on a physical iOS 12 device.
[0]: https://developer.apple.com/documentation/uikit/uitextfielddelegate/1619599-textfield
This is the keystone commit of turning MediaTileView asynchronous.
Because updates to the collection view's datasource now happen asynchronously and out-of-order, the batch update must be computed on the main queue based on what has changed.
MediaGalleryCollectionViewUpdater combines a log of operations from JournalingOrderedDictionary with the previous state of the collection view to compute insertions/deletions/reloads of items and sections.
This adds very basic support for donations via credit/debit card. It's
missing important features which is why it's behind an internal-only
feature flag.
At a high level, this adds a new screen with a card form. This card data
is submitted to Stripe and then uses the same "rails" as our existing
Apple Pay donations.
This change is missing a few important features, intended to be added
soon:
- [3D Secure][3DS] support
- Validation error messages
- Input formatting (e.g., "1234" becomes "12/34")
- Gift badge support (currently only supports Apple Pay)
- Various smaller UI changes
[3DS]: https://stripe.com/docs/payments/3d-secure
We shouldn't ask for Apple Pay when users update their subscriptions.
The update should just happen, unless there was previously a charge
failure.
This also fixes two other bugs:
- Some race conditions around observing subscription jobs
- One-time donations used the wrong progress spinner
This makes an upcoming change easier but is also useful on its own.
This change also moves mutation to the ordered
dictionary into a separate queue. There is no
change to behavior yet because the queue is only
dispatched to synchronously so far. Doing this
forces changes to how database transactions are
acquired since they must be used on the same queue
where they orignated.
This is a wrappar around OrderedDictionary that
maintains a change log to facilitate
UICollectionView batch updates in a system with
concurrent updates to the dictionary.
_I recommend reviewing this with whitespace changes disabled._
The server's `global.donations.apayDisabledRegions` is a list of regions
(phone number prefixes) where Apple Pay is disallowed. This respects
that.
The badge expiration sheet sometimes shows "Okay" and sometimes shows
"Ok". This makes it consistent.
I think this is a useful change on its own but it'll make an upcoming
change a little smaller.
Previously, one-time donations were on one screen and monthly donations
were on another. Now, they're on a single screen with a picker.
Most of the interesting changes are in `DonateViewController`.
Other things of note:
- There are some new TODOs here for existing bugs I didn't fix. For
example, one-time donations don't do so well if there are any problems
at all.
- Even though we only support Apple Pay, there's code that alludes to
additional payment methods. For example,
`DonateChoosePaymentMethodSheet`. We'll expand on this in the future.
- Users should only be able to select currencies that the server
supports. For example, you shouldn't be able to select EUR if the
server doesn't support euros. This wasn't working correctly before,
but is fixed here.
We already fixed one part, where users could change to an unsupported
currency (see dab02f30ae). However, if
your _default_ currency is unsupported and you didn't change it,
that's no good. This is unlikely for most users but could happen.
I fixed this by changing it from (effectively)
`Locale.current.currencyCode ?? "USD"`, which might not be supported,
to a preference list, choosing the first one the server likes.
- I skip animations if the Reduce Motion setting is enabled.
- On the donation screen, the logic for the preview badge has changed
slightly. If you already have a badge, we'll always use that.
In order to get the most out of struct method
mutability annotations, move the code that
modifies MediaGallerySections.State into State.
The remaining methods in MediaGallerySections are
wafer-thin wrappers. Eventually
MediaGallerySections will justify its existence by
managing two instances of state.
* Encapsulate mutable state of MediaGallerySections.
This is the first baby step toward imbuing
MediaGallerySections with multi-version
concurrency.
* Store rowid for each item in MediaGallerySections
This is necessary for forthcoming asynchronicity
as well as to correct existing problems where an
IndexPath is used as an identifier for an item.
IndexPath is a bad identifier because a database
change can invalidate it at any time. This will be
needed, for example, by an async ensureItemLoaded
method.
This change should have no user impact.
We commonly pair a currency, like USD, and an amount, like 1.23. This
adds the `FiatMoney` struct. It's a simple struct with two fields.
After adding it, I tried to use it everywhere. (It's possible I missed a
spot.)
I think this is a useful change on its own, but it'll be nice for an
upcoming change, too.
See also: [Android's equivalent class][0].
[0]: cb65347bb3/core-util/src/main/java/org/signal/core/util/money/FiatMoney.java (L1)
Change license to AGPL
This commit:
- Updates the `LICENSE` file
- Start every file with something like:
// Copyright YEAR_FIRST_PUBLISHED Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
---
First, I removed existing license headers with this Ruby 3.1.2 script:
require 'set'
EXTENSIONS_TO_CHECK = Set['.h', '.hpp', '.cpp', '.m', '.mm', '.pch', '.swift']
same = 0
different = 0
all_files = `git ls-files`.lines.map { |line| line.strip }
all_files.each do |relative_path|
if relative_path == 'Pods'
next
end
unless EXTENSIONS_TO_CHECK.include? File.extname(relative_path)
next
end
path = File.expand_path(relative_path)
contents = File.read(path)
new_contents = contents.sub(/\/\/\n\/\/ Copyright .*\n\/\/\n\n/, '')
if contents == new_contents
same += 1
else
different += 1
end
File.write(path, new_contents)
end
puts "updated #{different} file(s), left #{same} untouched"
I'm sure this script could be improved, but it worked well enough.
Then, I created `Scripts/lint/lint-license-headers` and ran it to auto-
fix a lot of files. This changed the mode of some files, but I think
that's actually desirable. For example,
`SignalServiceKit/src/Util/AppContext.m` previously had a mode of
`0755/-rwxr-xr-x`, and it's now `0644/-rw-r--r--`.
Then I fixed some stragglers and updated the precommit script.
See [a similar change in the Desktop app][0].
[0]: 8bfaf598af
- Revert "More flexible selection styling in CVTextLabel"
(commit e1317d814c)
- Revert "Show the MemberActionSheet for tapped names in group system messages"
(commit 48bc3c07d0)
The Boost case used `String(format:...)` even though there aren’t any
string replacements in the body text. We should avoid formatting strings
that don’t have format specifiers.
There was also a typo in the localized string key.
This also separates the monthly donation call to action string so that
it can be reused for gift badges.
In c5bdf6c094, we started to show errors
when a subscription failed to renew because of a charge failure.
Now, we show additional text depending on what the charge failure was.
For example, if you had an invalid card number, we show a special string
for that.
This adds the first screen for badge gifting. It lets you see the gift
badge, pick the currency, and advance to the next screen.
It also adds a skeleton for the next screen, so there's somewhere to
advance to, but that screen is unfinished.
All of this is behind disabled flags, so this should have no user
impact.
Currently, when your subscription expires due a charge failure, we
incorrectly tell you that it's due to inactivity. This fixes that, by
telling you about the charge failure.
This is a bit difficult to test on its own, so I:
- Faked out the smallest pieces I could in an effort to test states
manually
- Created `BadgeErrorSheetState` which is pretty thoroughly tested
MediaGallery models a list of GalleryDate-based sections (in practice, months), each of which has a certain number of items. Sections are loaded on demand (that is, there may be newer and older sections that are not in the model), and always know their number of items. Items are also loaded on demand, potentially non-contiguously. This model is designed around the needs of UICollectionView (a thread's All Media view), but it also supports flat views of media (swiping between items in the media detail view, which can cross album boundaries).
This model is a result of refactoring I did last year to improve the performance and UX of the All Media view, but the implementation in MediaGallery.swift is entangled with the actual attachments and messages in the database, making it hard to test. This commit pulls the state management part out into its own struct, MediaGallerySections, which wraps the OrderedDictionary of items-by-section. Our MediaGalleryItem model references TSAttachmentStream directly and our queries go straight to the database, so to avoid having to set up real attachments in testing, MediaGallerySections is generic over a loader (delegate? data source?) of items with "gallery dates" and unique IDs. Now all the basic section- and item-loading APIs can be unit-tested.
This is implemented by seeing if a data-detected item is at the very
end of a truncated string, in which case it isn't trusted to be
complete. This applies not only to URLs, but to other data-detected
items as well like emails and addresses. It's also specific to
truncated text since a user could very well type an ellipsis in their
actual message, and *that* shouldn't prevent linkification.
It's possible that an item at the very end of a truncated string *is*
complete (i.e. the truncation point was just *after* the URL), but we
can't be sure without comparing to the full text or storing additional
information, and that's trickier for a number of reasons. The user can
still expand the message and get the linkification in this case.