This commit:
- Converts `AppVersion` to Swift
- Creates `AppVersionForObjC` as a bridge
- Stops storing many properties; instead, pulls them off `UserDefaults`
as needed
This change should have no user impact.
`appVersion` used to be a property of `Dependencies` and `NSObject`. It
just deferred to `AppVersion.shared()`.
This commit removes those properties and relies on `AppVersion.shared`
instead. Also, `AppVersion.shared` is now a getter, not a function.
Sometimes, `UIActivityViewController` will dismiss the parent view
controller on completion. We have a hack to get around that: present an
invisible VC behind the share sheet. When the share sheet is done, we
dismiss the invisible VC.
However, if you share to an app that crashes (which is out of our
control), we won't always dismiss the invisible VC. I don't know why
this is, but double-dismissing VC works.
* add deserialization test for MessageBodyRanges
* Add style ranges to MessageBodyText
* add deserialization tests and fix small other test
* add basic mention hydration tests
* Add RTL support for @mention hydration
* Add a test with accents for unicode shenanigans
* unique-ify TODOs
* Add emoji test and fix implementation to account for multi-point unicode that is captured in NSString.length but not String.count
* Add more TODOs for text formatting
* Collapse style ranges on init
* Handle mention overlaps on MessageBodyRanges init
* add tests, update existing tests, fix bugs
* Update v2 deserialization test; the meaning of Style raw values has changed
* comment nit
This should cause no change in behavior.
We had logic like this pseudocode:
```
unreadCount = db.countUnreadMessages()
messagesWithUnreadReactionsCount = db.countMessagesWithUnreadReactions()
if unreadCount == 0 && messagesWithUnreadReactionsCount == 0 {
// Avoid unnecessary writes.
return
}
db.markMessagesRead()
```
This optimization works but has two problems:
1. We don't actually need the count. We just need to know whether
anything exists.
2. If there are unread messages, we should do the cleanup regardless,
and we don't need to do the second check query.
Now the pseudocode looks like this:
```
if db.hasUnreadMessages() || db.hasMessagesToMarkRead() {
// Avoid unnecessary writes.
return
}
db.markMessagesRead()
```