Group snapshots fetched from the service do not store the
`didJoinFromInviteLink` field on their members, and when we parse a
snapshot into a group model we hardcode this value to `false` for all
members. However, we store that field locally on a `GroupMembership`'s
`MemberStateMap` when processing an "add members" change action, as the
field is provided in the `AddMember` change action proto.
This becomes an issue, since when we refresh the group's state from the
service (which we do periodically, e.g. when opening a group for the
first time after launch) the `GroupMembership` from the group's snapshot
on the service will not match the `GroupMembership` we have locally,
even though they are from the same revision, due to mismatched
`didJoinFromInviteLink` values (hardcoded in the snapshot).
Consequently, we believed we were "updating the group model in a user-
facing way", but the only change therein was clobbering a
`didJoinFromInviteLink: true` to `...: false`, which was 1) wrong and
2) did not have a description to show.
This commit changes `GroupMembership` to ignore values for
`didJoinFromInviteLink` when comparing equality. This means that when we
parse a snapshot into a `TSGroupModel` with all those values hardcoded
to false, but otherwise identical to our local, we will no longer see it
as different from our local (and subsequently clobber our local and
generate an empty update).
Previously, `String#formatDurationLossless` rolled a custom formatter.
Now, it uses `DateComponentsFormatter`.
See also: the tests in `Signal/test/util/StringAdditionsTest.swift`,
which were untouched as part of this change.
I think this is a useful refactor anyway, but it should also fix rare
RTL bugs where duration components would be backwards. (I don't think
this ever happened under normal conditions, but it could happen if a
disappearing messages timer was set to something unusual like "1 day, 3
hours".)
I also plan to build off of this for an upcoming change, which is why
I did this now.
This is a trivial change that should have no user impact.
`String.formatDurationLossless` calls `NSString.formatDurationLossless`,
so this is a no-op. I think it's slightly better to call a `String`
method from Swift than an `NSString` one.
I did this because it makes an upcoming change easier, but I think it's
useful on its own.
The block-based API returns a token that needs to be explicitly
unregistered, *and* the block should not capture 'self' strongly.
The fixes in this PR come in three flavors:
1. Switch to the selector-based API, sometimes taking advantage of
the fact that extra arguments to an Objective-C method can be
safely discarded (because they are passed at +0).
2. Save the observer token and unregister in deinit.
3. Comment why it's safe to leave the observer registered forever
in this particular case.
Refactoring around media sharing flow classes.
• extract camera controls classes into a separate .swift file.
• extract a few SendMediaNavDelegate methods into SendMediaNavDataSource.
• use block-based method for handling UIDevice.orientationDidChangeNotification.
• prepare PhotoCaptureViewController to add support for text story composer.• remove unnecessary `public` declarations.
• other minor stylistic changes.
This change should have no direct user impact.
This is just a file move.
I think this is a useful change on its own, but it may be useful in
upcoming changes too (e.g., making SignalServiceKit not a pod).
This change should have no direct user impact.
This tests `TypingIndicatorMessage`'s `isOnline` getter.
I plan to add additional tests to this file in a future commit, but I
think this is a useful change on its own.
_I recommend reviewing this with whitespace changes disabled._
If your device can't send emails (e.g., because you uninstalled
Mail.app), we shouldn't show the "Email Support" option, as it will show
an error.
If we detect database corruption, we should log the [SQLite extended
result code][0], as it may offer insights.
This change also funnels the error handling through a single code path.
[0]: https://www.sqlite.org/rescode.html#extended_result_code_list