Compare commits

..

172 Commits

Author SHA1 Message Date
Shadowfacts 01cf597b5d Account for bidi text in combined display/username label 2024-10-22 17:51:58 -04:00
Shadowfacts 12bab71b17 Remove UITabBarController workaround on iOS 18.1 2024-10-14 18:24:47 -04:00
Shadowfacts f4b51c06c1 Raise min deployment target to iOS 16 2024-09-12 10:30:58 -04:00
Shadowfacts c99c397cf6 Bump build number and update changelog 2024-09-11 18:26:20 -04:00
Shadowfacts 814f64b3e2 Simplify add saved hashtag toolbar buttons
Closes #522
2024-09-10 10:20:27 -04:00
Shadowfacts 3a3af77907 Fix swipe action completion handler not being called 2024-09-10 10:18:08 -04:00
Shadowfacts 93e72e1cb6 Fix add saved hashtag search results selection not being cleared 2024-09-09 23:53:37 -04:00
Shadowfacts 522e7830e5 Fix scroll-to-top not working in in-app Safari
Closes #538
2024-09-09 19:42:55 -04:00
Shadowfacts 263210ac3c Fix gallery controls insets on iPhone 16
And change the default to the dynamic island metrics, so I hopefully
don't have to touch this every year
2024-09-09 19:39:30 -04:00
Shadowfacts 506d2ad8a9 Actually fix multi-column nav scrolling animations this time (hopefully)
Closes #539
2024-09-09 19:35:15 -04:00
Shadowfacts f9c0506590 Add tab-switching shortcuts to new tab bar
Closes #541
2024-09-09 19:18:12 -04:00
Shadowfacts 3f4917931b Poll own_votes is a nullable array of nullable ints, at least on pleroma
I do not understand why

Closes #540
2024-09-09 19:13:57 -04:00
Shadowfacts b7166771cf Include SVGs in repo 2024-08-31 11:42:48 -04:00
Shadowfacts 40230c5478 Add dark mode app icons, optimize pngs 2024-08-31 11:37:39 -04:00
Shadowfacts 68bd9e0bed Tweak mute button symbol animation 2024-08-31 11:20:09 -04:00
Shadowfacts 3e28c012d7 Shhh 2024-08-31 11:10:59 -04:00
Shadowfacts 57c023c973 Fix profile tab switching animation ending in bad state
Caused by fda0c18794, old/new.view is no
longer the same as .collectionView, so the transform wasn't being
properly reset.

Closes #536
2024-08-31 11:09:17 -04:00
Shadowfacts cc696e58fc Change how profile header collection view cell is sized
Fixes crash due to collection view layout loop in some circumstances

Closes #537
2024-08-31 10:49:21 -04:00
Shadowfacts 59af29ff64 Fix incorrect background color on feature flag prefs section 2024-08-27 20:42:51 -04:00
Shadowfacts 59fb69525b Custom emoji in push notifications, behind a feature flag 2024-08-27 20:41:39 -04:00
Shadowfacts 1bd4d144a3 Fix crash on launch if there are somehow duplicate saved hashtags 2024-08-27 12:42:41 -04:00
Shadowfacts b54d34ebfc Fix video controls overlay being positioned incorrectly on macOS with Reduce Motion enabled
Closes #535
2024-08-26 19:16:35 -04:00
Shadowfacts d1ffab3e42 Only hide gallery controls automatically while playing 2024-08-26 19:08:44 -04:00
Shadowfacts d873b157ee Fix video gallery controls not auto hiding
#535
2024-08-26 10:25:28 -04:00
Shadowfacts d7be2048af Whoops
Closes #533
Closes #534
2024-08-23 01:19:29 -04:00
Shadowfacts 3d1f506684 Actually show the error message when video loading fails
See #531
2024-08-22 14:54:16 -04:00
Shadowfacts cd8f0e7926 Use navigation sequencing for user activity handling 2024-08-22 14:49:27 -04:00
Shadowfacts 960ba84683 New way of sequencing navigation operations
Better fix for #484
2024-08-22 14:34:05 -04:00
Shadowfacts 2eead1f9de Revert "Fix crash when opening push notification while VC modally presented"
This reverts commit 0f2a85b108.

This fixes state restoration happening asynchronously and causing the
new tab bar animation to run.
2024-08-22 14:17:04 -04:00
Shadowfacts b663335c6d Use the image description from imported image when possible
Closes #523
2024-08-22 13:54:03 -04:00
Shadowfacts 9ce6bd566f Show errors when video loading fails
Closes #532
2024-08-22 13:33:02 -04:00
Shadowfacts 9547bd2913 Fix incorrect split nav layout when closing split with new sidebar 2024-08-22 12:08:43 -04:00
Shadowfacts 9b2e6140a3 Fix reselecting current sidebar item not popping to root on Catalyst and new sidebar
Closes #525
2024-08-22 11:39:39 -04:00
Shadowfacts 6de255681c Fix assorted warnings when building with Xcode 16 2024-08-22 11:08:27 -04:00
Shadowfacts 805e5eddd0 Bump build number and update changelog 2024-08-21 19:30:54 -04:00
Shadowfacts 4945a234e7 Fix new tab bar VC getting stuck in bad state after presenting Compose 2024-08-21 19:28:12 -04:00
Shadowfacts 230696f456 Bump build number and update changelog 2024-08-21 18:52:36 -04:00
Shadowfacts c113903980 Fix SplitNavigationController layout with new sidebar 2024-08-21 18:37:20 -04:00
Shadowfacts 0e95cd0adf Update AdaptableNavigationController when interface preference changes 2024-08-21 18:34:49 -04:00
Shadowfacts 494708a362 Fix compiling on visionOS 2024-08-21 18:27:30 -04:00
Shadowfacts 3a21983b98 Merge branch 'tabbarnav' into develop 2024-08-21 17:53:08 -04:00
Shadowfacts 1817247077 Add saved instances to new sidebar 2024-08-21 17:10:01 -04:00
Shadowfacts 0d9eed73dd Add saved/followed hashtags to new sidebar 2024-08-21 16:58:16 -04:00
Shadowfacts 59d43fd3f6 Open in New Window context menu actions for new sidebar 2024-08-21 16:50:30 -04:00
Shadowfacts d321c31776 Implement more protocols for AdaptableNavigationController 2024-08-21 16:36:13 -04:00
Shadowfacts ce10c7d6e2 Implement adding list using new sidebar 2024-08-21 16:19:51 -04:00
Shadowfacts 37b9673b12 Fix list timeline no content view being added repetedly on refresh 2024-08-21 16:17:57 -04:00
Shadowfacts 7c7af945e4 Show avatar in tab/side bar when using new API 2024-08-21 16:12:05 -04:00
Shadowfacts cb32c66a59 Support fast account switching with new sidebar 2024-08-21 14:48:47 -04:00
Shadowfacts 4249ab30ca Fix crash when hashtag search results include duplicate 2024-08-21 14:10:59 -04:00
Shadowfacts 67e9c1245e Size class switching fixes for new tab/side bar 2024-08-21 12:17:26 -04:00
Shadowfacts 3d9a1086b6 Remove dead code 2024-08-20 12:31:29 -04:00
Shadowfacts fda0c18794 Fix insets with new sidebar 2024-08-20 12:31:06 -04:00
Shadowfacts dffa5d8f75 Lists in new sidebar 2024-08-20 11:55:19 -04:00
Shadowfacts 9891b601a8 Initial tab bar/sidebar implementation 2024-08-19 19:10:31 -04:00
Shadowfacts a8f6aa6ed7 Use new UITabBarController API on iOS 18 2024-08-19 13:29:48 -04:00
Shadowfacts 348dcc558c Fix profile page switching on iOS 18 2024-08-19 11:34:17 -04:00
Shadowfacts 703f6f695b Update Sentry and swift-url 2024-08-19 11:33:07 -04:00
Shadowfacts fdbfe49a7c Improve tab switching animation in non-pure-black dark mode on iOS 18 2024-08-19 11:32:29 -04:00
Shadowfacts 3f0dd599b3 Fix compiling with Xcode 16 2024-08-19 11:31:10 -04:00
Shadowfacts 07b6bf33cb Bump build number and update changelog 2024-08-09 18:46:38 -07:00
Shadowfacts d0758dc73c Add more info for subscription to Tip Jar 2024-08-09 18:36:42 -07:00
Shadowfacts b85c0eb95d Bump build number and update changelog 2024-08-08 21:06:00 -07:00
Shadowfacts eea0ef258c Add pointless ToS nag before logging in
Thanks, App Review
2024-08-08 20:39:55 -07:00
Shadowfacts 18f6445a7c Bump build number and update changelog 2024-07-30 22:28:44 -07:00
Shadowfacts c5f42719a0 Fix Cmd+3 not properly selecting Explore tab
Having MainSidebarViewController.Item.explore and .tab(.explore) was a
mistake and made it easy to accidentally use the wrong one for the key
command, so use .tab(.explore) for everything.

Closes #519
2024-07-30 22:03:36 -07:00
Shadowfacts eb89aec00f Bump build number and update changelog 2024-07-24 21:09:42 -07:00
Shadowfacts 61576bce58 Fix Drafts button never turning into Post on Mac Catalyst
Closes #504
2024-07-24 20:57:23 -07:00
Shadowfacts f7d4737782 Add more details to notification loading crash 2024-07-24 20:48:01 -07:00
Shadowfacts 3dd0f3a154 Report DraftsPersistentContainer initializer errors to Sentry 2024-07-24 20:42:35 -07:00
Shadowfacts 145ffbfcf0 Fix crash when selection changes to nil in custom alert
Closes #517
2024-07-24 20:33:17 -07:00
Shadowfacts bcf2a2f026 Improve compose reply view avatar scrolling animation 2024-07-24 20:26:33 -07:00
Shadowfacts 1358152dec Fix discrepancy between SearchResultsViewController.Item == and hash 2024-07-22 22:19:31 -07:00
Shadowfacts 2e2279ba8c Bump build number and update changelog 2024-07-22 21:56:44 -07:00
Shadowfacts 60dadf599c Fix status meta indicators overlapping thread links
This isn't great, but there's nowhere else for either to go and the
difference between the large/default scales wasn't doing much before.

Closes #449
2024-07-22 21:48:43 -07:00
Shadowfacts 90537f9d12 Fix not being able to resolve remote Mastodon posts
Closes #515
2024-07-22 21:40:19 -07:00
Shadowfacts 8b0c2f80b6 Fix preserving conversation expand all not working for ancestors
Closes #516
2024-07-22 21:28:42 -07:00
Shadowfacts 42423f36db Fix Dynamic Type not applying to status content 2024-07-21 19:46:17 -07:00
Shadowfacts 176eb7c011 Undo overzealous Xcode rename 2024-07-21 18:41:03 -07:00
Shadowfacts da9ca78a8b Update card view less often
Speculative fix for #314
2024-07-21 18:40:58 -07:00
Shadowfacts b470ee6401 Fix status/mention push notifications not showing CW and fix sensitive attachments being included in push notifications
Closes #512
2024-07-21 18:13:48 -07:00
Shadowfacts fccd4e427c Fix profile moved header not being VO accessible
Closes #479
2024-07-21 14:03:18 -07:00
Shadowfacts f25031afd4 Fix profile moved view appearing behind avatar/header images 2024-07-21 13:46:07 -07:00
Shadowfacts ca65f84137 Lift pinned timelines modifiers up to CustomizeTimelinesList
.sheet on a Section with a header does not work, and produces warnings
about trying to present on a VC that already has a presentation. It
seems like the .sheet modifier is being applied to both the Section
content and header?

Fixes #514
2024-07-21 12:02:14 -07:00
Shadowfacts d4057adf4d Avoid updating AccountDisplayNameLabel when emojis pref hasn't changed
Oops
2024-07-21 10:36:24 -07:00
Shadowfacts 007937d2d7 Consolidate display/username labels on timeline statuses
Closes #513
2024-07-20 23:35:31 -07:00
Shadowfacts 5f040ed390 Workaround text view not being baseline-aligned with label
Closes #509
2024-07-20 11:08:59 -07:00
Shadowfacts 870d0c8404 Replay video from start when play is pressed at end
Closes #510
2024-07-20 10:33:08 -07:00
Shadowfacts 47b9ac890a Fix gallery controls visibility not transferring between pages
Closes #511
2024-07-20 10:27:49 -07:00
Shadowfacts 50b84350d9 Don't reload relationship every time profile page switched 2024-07-11 22:32:02 -07:00
Shadowfacts cdc64f1b2c Bump build number and update changelog 2024-07-10 20:49:50 -07:00
Shadowfacts 2913098e74 Fix badges not appearing on gifv attachments
Closes #507
2024-07-10 20:25:09 -07:00
Shadowfacts ce99352e90 Don't let let audio session tokens be double consumed 2024-07-09 23:27:18 -07:00
Shadowfacts 8322d3a36c Fix gifv playback not continuing when returning from background
Closes #506
2024-07-08 22:05:27 -07:00
Shadowfacts a818457f8c Fix gifv playing pausing audio from other apps
Closes #505
2024-07-08 22:05:27 -07:00
Shadowfacts 1f6644b703 Bump HTMLStreamer
Fixes crash when whitespace occurs at the end of <pre> content
2024-07-08 21:14:29 -07:00
Shadowfacts 412c5ee91d Fix multi column navigation not animating when scrolling back while replacing multiple columns 2024-07-07 10:01:33 -07:00
Shadowfacts dcc5f7f716 visionOS: Workaround for gallery not working at all 2024-07-06 17:36:45 -07:00
Shadowfacts 9fefc9e8f8 Precise video scrubbing for pointer/pencil 2024-07-06 17:26:33 -07:00
Shadowfacts d1af911241 Custom alert: show menu when long press moves onto menu button 2024-07-06 17:19:30 -07:00
Shadowfacts 5abd265195 Support haptic feedback on new Magic Keyboard 2024-07-06 17:10:29 -07:00
Shadowfacts 3cb0f46533 Add hover effects to poll view
Closes #503
2024-07-06 14:05:16 -07:00
Shadowfacts c367a2e9f1 Fix selecting poll option playing too much haptic feedback 2024-07-06 10:19:09 -07:00
Shadowfacts 3eceffbb6b Add visionOS app icon 2024-06-16 18:51:17 -07:00
Shadowfacts 7c3a00a40d Fix compiling for visionOS 2024-06-16 17:49:25 -07:00
Shadowfacts 45a90fb4a2 Fix compiling for Catalyst 2024-06-16 17:40:23 -07:00
Shadowfacts 8557e110a8 Bump build number and update changelog 2024-06-08 13:55:32 -07:00
Shadowfacts c2232a5e14 Don't fail decoding when one status fails to decode
Also remove old workaround for bad dates from #477

Closes #478
2024-06-08 13:29:56 -07:00
Shadowfacts e6d9a33dbf Actually don't purge old persistent history 2024-06-08 13:18:23 -07:00
Shadowfacts d8fccc8f1b Purge old persistent history after processing
Closes #480
2024-06-08 12:23:12 -07:00
Shadowfacts 6528070f1c Save persistent history tokens across launches
See #480
2024-06-08 12:18:22 -07:00
Shadowfacts 09c6a87e19 Fix switching sidebar sections with keyboard shortcuts not saving old section's navigation stack 2024-06-08 11:30:16 -07:00
Shadowfacts cd0d8fffcb Fix conversation thread links appearing above avatar when lifted by pointer 2024-06-08 11:28:19 -07:00
Shadowfacts 1b6f0c07fd Add pointer effect to search token suggestions 2024-06-08 11:26:10 -07:00
Shadowfacts 2f31b50a5b Fix search results always pushing new column in multi-column nav
Closes #498
2024-06-08 11:21:05 -07:00
Shadowfacts cee4e15b06 Fix not being able to select text by double clicking with cursor on iPad
Also fix not being able to single-tap data detector value to see menu

Closes #499
2024-06-08 11:01:07 -07:00
Shadowfacts 888f44366c Fix multi-column nav not animating scroll position when replacing subsequent columns
Closes #500
2024-06-08 10:32:32 -07:00
Shadowfacts c88076eec0 Use text view for profile field value view
Fixes #501
2024-06-08 10:23:24 -07:00
Shadowfacts afe47437e4 Disallow blocking your own domain 2024-06-02 11:41:50 -07:00
Shadowfacts 4dc484c3c2 Fix follow button never activating on Pixelfed
Caused by not being able to decode Relationship due to missing fields.
Also disable actions that are unsupported on Pixelfed.

Closes #481
2024-06-02 11:40:42 -07:00
Shadowfacts 0f2a85b108 Fix crash when opening push notification while VC modally presented
The dismissal of the modally presented VC turns the route change into an
asynchronous operation, even when not animated.

Closes #484
2024-06-02 11:25:49 -07:00
Shadowfacts 5e55ce75c2 Fix previous sidebar selection losing navigation stack in some circumstances 2024-06-02 10:33:25 -07:00
Shadowfacts eec2adbfd9 Set target content identifiers on scenes/activities 2024-06-02 10:10:16 -07:00
Shadowfacts a848f6e425 Fix error on Pixelfed/Firefish due to missing followers/following counts
Closes #483
2024-06-02 09:44:20 -07:00
Shadowfacts 44896d305e Add pointer interaction to profile followers/following buttons
Closes #497
2024-06-02 09:42:54 -07:00
Shadowfacts 6c70ed4b4e Fix crash in MultiColumnNavController due to closing already-removed VC
Not sure how this is possible, but there was a report of it

Closes #485
2024-06-02 09:41:22 -07:00
Shadowfacts e3c480131a Fix gallery dismiss transition from sheet-presented VC
Closes #490
2024-06-01 11:22:19 -07:00
Shadowfacts 575166f5b4 Fix Cmd+1/etc. resetting navigation stacks
Closes #491
2024-06-01 10:56:55 -07:00
Shadowfacts c60aa3e3f3 Fix close buttons unnecessarily being added to navigation column 2024-06-01 10:56:31 -07:00
Shadowfacts 75f0d12c82 Fix incorrect pointer actions on conversation main status
Closes #493
2024-06-01 10:47:56 -07:00
Shadowfacts 5cf2bc4fbf Fix profile header images being blurry
Due to the old method using ImageCache.avatars for the headers 🤦

Closes #494
2024-06-01 10:44:49 -07:00
Shadowfacts 908b499f8f Fix Remove Suggestion action missing from Suggested Accounts screen
Closes #495
2024-06-01 10:40:30 -07:00
Shadowfacts 67c7905acf Fix missing VC callbacks in removeViewAndController 2024-06-01 10:29:33 -07:00
Shadowfacts eacafe87b3 Fix logout from current resulting in black screen after switching to reused VC
Closes #489
2024-06-01 10:28:46 -07:00
Shadowfacts 2a53b24487 Merge branch 'public-beta' into develop 2024-05-29 22:42:43 -07:00
Shadowfacts 9df3c33c6c Bump build number and update changelog 2024-05-29 22:37:53 -07:00
Shadowfacts d4e82d6e7a Fix AVPlayer periodic time observers not being removed 2024-05-29 22:35:45 -07:00
Shadowfacts 06ba758309 Merge branch 'public-beta' into develop 2024-05-29 22:30:48 -07:00
Shadowfacts 2c56902389 Remove old account UI state when logging out 2024-05-29 22:23:09 -07:00
Shadowfacts cb3fd43dbd Fix video thubmnail being flipped in Compose
Closes #487
2024-05-29 22:03:53 -07:00
Shadowfacts 3d15759fb9 Don't constantly commit CA transactions when scrubbing video
Closes #488
2024-05-29 21:56:18 -07:00
Shadowfacts 5620b6ab78 Merge branch 'public-beta' into develop 2024-05-27 22:29:23 -07:00
Shadowfacts 09999175f7 Fix editing attachment descriptions not working on Pleroma 2024-05-27 22:29:11 -07:00
Shadowfacts f2a9f890ff Use development URLSession in more places 2024-05-27 22:14:28 -07:00
Shadowfacts 093994b474 More push subscription logging 2024-05-27 13:33:00 -07:00
Shadowfacts 3d0de5af04 Persist more state when switching accounts
Closes #486
2024-05-24 14:03:51 -04:00
Shadowfacts 966a906436 Fix AVPlayer periodic time observers not being removed 2024-05-23 14:29:56 -04:00
Shadowfacts 844d4056e3 Bump version and update changelog 2024-05-23 14:25:39 -04:00
Shadowfacts 00ef131bb6 Update HTMLStreamer 2024-05-23 14:12:35 -04:00
Shadowfacts d6be6f14dc Hide subscription section from tip jar when there are no products 2024-05-23 14:11:54 -04:00
Shadowfacts 2ccf028bc2 Bump build number and update changelog 2024-05-20 14:28:25 -04:00
Shadowfacts 3eeffada1f Add tip jar link to push notifications settings 2024-05-20 12:49:26 -04:00
Shadowfacts 0499255be7 Add tip jar subscription 2024-05-20 12:49:20 -04:00
Shadowfacts f909c1da10 Fix selecting follow request push notification
Closes #474
2024-05-19 15:14:03 -04:00
Shadowfacts 81543965ae Fix notification extension not building on visionOS 2024-05-19 15:00:47 -04:00
Shadowfacts 96d42756d5 Fix caption not displaying in gallery while image loading
Closes #476
2024-05-19 15:00:25 -04:00
Shadowfacts f6e57d664f Handle invalid date in Status created_at
Closes #477
2024-05-19 14:48:57 -04:00
Shadowfacts c33be1cbf3 Bump build number 2024-05-17 11:26:57 -04:00
Shadowfacts 6d99156bd9 Include badly formatted date in error message 2024-05-10 16:33:03 -04:00
Shadowfacts ca764811ed Bump build number and update changelog 2024-04-23 13:19:52 -04:00
Shadowfacts a589bb2863 Support emoji reaction push notifications on pleroma/akkoma 2024-04-18 13:17:55 -04:00
Shadowfacts 6f35fd2676 Show pleroma/akkoma emoji notifications
Closes #159
2024-04-18 12:59:44 -04:00
Shadowfacts e83cef1c8c Fix overzealously attempting to migrate local data to cloud store
Fix error when actually migrating due to not opening the store with
NSPersistentHistoryTrackingKey set to true.
2024-04-18 11:45:32 -04:00
Shadowfacts b89df3f27b Add instance announcements
Closes #356
2024-04-18 00:00:00 -04:00
Shadowfacts 4ecc16a93b Move FuzzyMatcher to TuskerComponents 2024-04-17 22:34:31 -04:00
Shadowfacts 8960873ff3 Remove redundant toastableViewController property 2024-04-17 22:34:31 -04:00
Shadowfacts 043a708515 Add more logging to onboarding VC 2024-04-17 17:04:32 -04:00
Shadowfacts c6b230414e Fix error decoding InstanceV2 response on certain instances 2024-04-17 10:18:01 -04:00
Shadowfacts f5e9f66f76 Fix app background colors not updating when preference changed
This only fully fixes it on iOS 17, but it seems to be the best we can do
2024-04-16 12:03:52 -04:00
Shadowfacts ee5f9a62ff Fix push subscription settings GroupBox background in dark mode
Closes #470
2024-04-16 11:37:36 -04:00
Shadowfacts a92cf8c812 Fix potential crash when hit testing StatusCollapseButton 2024-04-15 22:50:31 -04:00
Shadowfacts 756874949a Actually add notification extension privacy manifest to target 2024-04-15 22:42:18 -04:00
251 changed files with 6640 additions and 2382 deletions

View File

@ -0,0 +1,157 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
sodipodi:docname="Tusker.svg"
inkscape:version="1.0beta2 (2b71d25, 2019-12-03)"
inkscape:export-ydpi="11.52"
inkscape:export-xdpi="11.52"
inkscape:export-filename="/Users/shadowfacts/Desktop/60x60@2x.png"
id="svg8"
version="1.1"
viewBox="0 0 264.58333 264.58333"
height="1000"
width="1000">
<defs
id="defs2">
<inkscape:path-effect
bendpath1-nodetypes="cc"
bendpath4="M 27.271345,85.808468 V 178.94843"
bendpath3="M 27.271345,178.94843 H 242.39013"
bendpath2="M 242.39013,85.808468 V 178.94843"
bendpath1="M 26.897168,85.995557 242.39013,85.808468"
xx="true"
yy="true"
lpeversion="1"
is_visible="true"
id="path-effect1345"
effect="envelope" />
<inkscape:path-effect
allow_transforms="true"
css_properties=""
attributes=""
method="d"
linkeditem=""
lpeversion="1"
is_visible="true"
id="path-effect38"
effect="clone_original" />
<inkscape:path-effect
scale_y_rel="false"
prop_scale="1"
strokepath="M0,0 L1,0"
endpoint_spacing_variation="0;1"
endpoint_edge_variation="0;1"
startpoint_spacing_variation="0;1"
startpoint_edge_variation="0;1"
count="5"
lpeversion="1"
is_visible="true"
id="path-effect32"
effect="curvestitching" />
<filter
height="1.3500000000000001"
width="1.2"
id="filter1277"
inkscape:label="Drop Shadow"
style="color-interpolation-filters:sRGB;">
<feFlood
id="feFlood1267"
result="flood"
flood-color="rgb(0,0,0)"
flood-opacity="0.321569" />
<feComposite
id="feComposite1269"
result="composite1"
operator="in"
in2="SourceGraphic"
in="flood" />
<feGaussianBlur
id="feGaussianBlur1271"
result="blur"
stdDeviation="5"
in="composite1" />
<feOffset
id="feOffset1273"
result="offset"
dy="5"
dx="-2.5" />
<feComposite
id="feComposite1275"
result="composite2"
operator="over"
in2="offset"
in="SourceGraphic" />
</filter>
</defs>
<sodipodi:namedview
inkscape:window-maximized="0"
inkscape:window-y="23"
inkscape:window-x="1920"
inkscape:window-height="1395"
inkscape:window-width="1902"
units="px"
showgrid="false"
inkscape:document-rotation="0"
inkscape:current-layer="layer2"
inkscape:document-units="px"
inkscape:cy="496.39379"
inkscape:cx="442.66632"
inkscape:zoom="1.4142136"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 2"
id="layer2"
inkscape:groupmode="layer">
<rect
y="-0.14500916"
x="-0.14500916"
height="264.87335"
width="264.87335"
id="rect865"
style="fill:#75e04e;fill-opacity:1;stroke:#75e04e;stroke-width:0.239149;stroke-opacity:1" />
</g>
<g
style="display:none"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<path
inkscape:connector-curvature="0"
d="m 63.595661,96.781172 c 2.610557,8.549728 11.109144,14.261728 18.221441,19.677268 14.285995,10.87784 30.777538,19.16253 47.836068,24.76819 12.08516,3.97134 24.9714,5.89737 37.69211,5.9756 11.75058,0.0723 23.533,-2.04773 34.88282,-5.09124 8.49997,-2.27931 17.13306,-4.99674 24.52676,-9.76937 5.59427,-3.6111 11.35542,-7.93448 14.37737,-13.86775 0.73693,-1.44688 2.00968,-3.90176 0.67356,-4.82442 -4.90929,-3.39011 -10.18592,6.31619 -15.70026,8.59349 -8.68681,3.58745 -17.81526,6.26681 -27.07782,7.85916 -11.94219,2.05301 -24.25018,3.46797 -36.29097,2.10779 -12.7013,-1.4348 -25.14557,-5.50493 -36.82103,-10.70737 -8.48127,-3.77914 -16.22058,-9.14294 -23.66896,-14.68689 C 96.49438,102.53405 91.950513,96.75601 86.13513,92.560411 82.533585,89.96202 79.028923,86.323649 74.610572,85.8754 c -3.438589,-0.34885 -7.602338,0.653715 -9.831133,3.295317 -1.655568,1.962204 -1.933509,5.155042 -1.183778,7.610455 z m -36.276154,1.911751 c 1.000129,9.935377 9.068818,18.042637 15.683118,25.523487 13.285704,15.02628 29.55205,27.69127 47.022482,37.54435 12.376983,6.98044 26.073563,11.90937 39.996973,14.7475 13.12015,2.67439 26.76072,2.8433 40.12178,1.96426 10.02366,-0.65947 20.39718,-1.4876 29.64741,-5.40445 6.55654,-2.77625 13.10939,-6.72368 17.37506,-12.42454 1.08663,-1.45223 3.06381,-3.85048 1.78759,-5.13927 -4.73249,-4.77911 -12.53753,5.06785 -19.12154,6.4416 -10.27704,2.1443 -20.88256,2.99026 -31.37744,2.71972 -13.53101,-0.3488 -27.32398,-1.47627 -40.22043,-5.58617 -13.6039,-4.33535 -26.35283,-11.50217 -38.013078,-19.74231 -8.470214,-5.98579 -15.782756,-13.54635 -22.737346,-21.24101 -5.371021,-5.94258 -9.092383,-13.26181 -14.551151,-19.123884 -3.38068,-3.630455 -6.428954,-8.379273 -11.172348,-9.831658 -3.691559,-1.130322 -8.47165,-0.937751 -11.488322,1.47159 -2.240814,1.789682 -3.239987,5.227417 -2.952758,8.080785 z"
style="fill:#f9f7f3;fill-opacity:1;stroke:#d0c1a2;stroke-width:0.565786px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter1277)"
id="path28" />
</g>
<g
inkscape:label="Layer 1 copy"
inkscape:groupmode="layer"
id="g1343">
<path
id="path1341"
style="fill:#f9f7f3;fill-opacity:1;stroke:#d0c1a2;stroke-width:0.56578600000000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 63.595661,96.781172 c 2.610557,8.549728 11.109144,14.261728 18.221441,19.677268 14.285995,10.87784 30.777538,19.16253 47.836068,24.76819 12.08516,3.97134 24.9714,5.89737 37.69211,5.9756 11.75058,0.0723 23.533,-2.04773 34.88282,-5.09124 8.49997,-2.27931 17.13306,-4.99674 24.52676,-9.76937 5.59427,-3.6111 11.35542,-7.93448 14.37737,-13.86775 0.73693,-1.44688 2.00968,-3.90176 0.67356,-4.82442 -4.90929,-3.39011 -10.18592,6.31619 -15.70026,8.59349 -8.68681,3.58745 -17.81526,6.26681 -27.07782,7.85916 -11.94219,2.05301 -24.25018,3.46797 -36.29097,2.10779 -12.7013,-1.4348 -25.14557,-5.50493 -36.82103,-10.70737 -8.48127,-3.77914 -16.22058,-9.14294 -23.66896,-14.68689 C 96.49438,102.53405 91.950513,96.75601 86.13513,92.560411 82.533585,89.96202 79.028923,86.323649 74.610572,85.8754 c -3.438589,-0.34885 -7.602338,0.653715 -9.831133,3.295317 -1.655568,1.962204 -1.933509,5.155042 -1.183778,7.610455 z m -36.276154,1.911751 c 1.000129,9.935377 9.068818,18.042637 15.683118,25.523487 13.285704,15.02628 29.55205,27.69127 47.022482,37.54435 12.376983,6.98044 26.073563,11.90937 39.996973,14.7475 13.12015,2.67439 26.76072,2.8433 40.12178,1.96426 10.02366,-0.65947 20.39718,-1.4876 29.64741,-5.40445 6.55654,-2.77625 13.10939,-6.72368 17.37506,-12.42454 1.08663,-1.45223 3.06381,-3.85048 1.78759,-5.13927 -4.73249,-4.77911 -12.53753,5.06785 -19.12154,6.4416 -10.27704,2.1443 -20.88256,2.99026 -31.37744,2.71972 -13.53101,-0.3488 -27.32398,-1.47627 -40.22043,-5.58617 -13.6039,-4.33535 -26.35283,-11.50217 -38.013078,-19.74231 -8.470214,-5.98579 -15.782756,-13.54635 -22.737346,-21.24101 -5.371021,-5.94258 -9.092383,-13.26181 -14.551151,-19.123884 -3.38068,-3.630455 -6.428954,-8.379273 -11.172348,-9.831658 -3.691559,-1.130322 -8.47165,-0.937751 -11.488322,1.47159 -2.240814,1.789682 -3.239987,5.227417 -2.952758,8.080785 z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.1 KiB

View File

@ -0,0 +1,153 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
sodipodi:docname="Tusker transparent.svg"
inkscape:version="1.3.2 (091e20e, 2023-11-25)"
inkscape:export-ydpi="98.304001"
inkscape:export-xdpi="98.304001"
inkscape:export-filename="../Desktop/1024x1024-dark@1x.png"
id="svg8"
version="1.1"
viewBox="0 0 264.58333 264.58333"
height="1000"
width="1000"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2">
<inkscape:path-effect
bendpath1-nodetypes="cc"
bendpath4="M 27.271345,85.808468 V 178.94843"
bendpath3="M 27.271345,178.94843 H 242.39013"
bendpath2="M 242.39013,85.808468 V 178.94843"
bendpath1="M 26.897168,85.995557 242.39013,85.808468"
xx="true"
yy="true"
lpeversion="1"
is_visible="true"
id="path-effect1345"
effect="envelope" />
<inkscape:path-effect
allow_transforms="true"
css_properties=""
attributes=""
method="d"
linkeditem=""
lpeversion="1"
is_visible="true"
id="path-effect38"
effect="clone_original" />
<inkscape:path-effect
scale_y_rel="false"
prop_scale="1"
strokepath="M0,0 L1,0"
endpoint_spacing_variation="0;1"
endpoint_edge_variation="0;1"
startpoint_spacing_variation="0;1"
startpoint_edge_variation="0;1"
count="5"
lpeversion="1"
is_visible="true"
id="path-effect32"
effect="curvestitching" />
<filter
height="1.317445"
width="1.1258237"
id="filter1277"
inkscape:label="Drop Shadow"
style="color-interpolation-filters:sRGB;"
x="-0.068723437"
y="-0.1318855">
<feFlood
id="feFlood1267"
result="flood"
flood-color="rgb(0,0,0)"
flood-opacity="0.321569" />
<feComposite
id="feComposite1269"
result="composite1"
operator="in"
in2="SourceGraphic"
in="flood" />
<feGaussianBlur
id="feGaussianBlur1271"
result="blur"
stdDeviation="5"
in="composite1" />
<feOffset
id="feOffset1273"
result="offset"
dy="5"
dx="-2.5" />
<feComposite
id="feComposite1275"
result="composite2"
operator="over"
in2="offset"
in="SourceGraphic" />
</filter>
</defs>
<sodipodi:namedview
inkscape:window-maximized="0"
inkscape:window-y="25"
inkscape:window-x="1280"
inkscape:window-height="1387"
inkscape:window-width="1280"
units="px"
showgrid="false"
inkscape:document-rotation="0"
inkscape:current-layer="layer2"
inkscape:document-units="px"
inkscape:cy="404.46507"
inkscape:cx="442.29528"
inkscape:zoom="1.4142136"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 2"
id="layer2"
inkscape:groupmode="layer" />
<g
style="display:none"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<path
inkscape:connector-curvature="0"
d="m 63.595661,96.781172 c 2.610557,8.549728 11.109144,14.261728 18.221441,19.677268 14.285995,10.87784 30.777538,19.16253 47.836068,24.76819 12.08516,3.97134 24.9714,5.89737 37.69211,5.9756 11.75058,0.0723 23.533,-2.04773 34.88282,-5.09124 8.49997,-2.27931 17.13306,-4.99674 24.52676,-9.76937 5.59427,-3.6111 11.35542,-7.93448 14.37737,-13.86775 0.73693,-1.44688 2.00968,-3.90176 0.67356,-4.82442 -4.90929,-3.39011 -10.18592,6.31619 -15.70026,8.59349 -8.68681,3.58745 -17.81526,6.26681 -27.07782,7.85916 -11.94219,2.05301 -24.25018,3.46797 -36.29097,2.10779 -12.7013,-1.4348 -25.14557,-5.50493 -36.82103,-10.70737 -8.48127,-3.77914 -16.22058,-9.14294 -23.66896,-14.68689 C 96.49438,102.53405 91.950513,96.75601 86.13513,92.560411 82.533585,89.96202 79.028923,86.323649 74.610572,85.8754 c -3.438589,-0.34885 -7.602338,0.653715 -9.831133,3.295317 -1.655568,1.962204 -1.933509,5.155042 -1.183778,7.610455 z m -36.276154,1.911751 c 1.000129,9.935377 9.068818,18.042637 15.683118,25.523487 13.285704,15.02628 29.55205,27.69127 47.022482,37.54435 12.376983,6.98044 26.073563,11.90937 39.996973,14.7475 13.12015,2.67439 26.76072,2.8433 40.12178,1.96426 10.02366,-0.65947 20.39718,-1.4876 29.64741,-5.40445 6.55654,-2.77625 13.10939,-6.72368 17.37506,-12.42454 1.08663,-1.45223 3.06381,-3.85048 1.78759,-5.13927 -4.73249,-4.77911 -12.53753,5.06785 -19.12154,6.4416 -10.27704,2.1443 -20.88256,2.99026 -31.37744,2.71972 -13.53101,-0.3488 -27.32398,-1.47627 -40.22043,-5.58617 -13.6039,-4.33535 -26.35283,-11.50217 -38.013078,-19.74231 -8.470214,-5.98579 -15.782756,-13.54635 -22.737346,-21.24101 -5.371021,-5.94258 -9.092383,-13.26181 -14.551151,-19.123884 -3.38068,-3.630455 -6.428954,-8.379273 -11.172348,-9.831658 -3.691559,-1.130322 -8.47165,-0.937751 -11.488322,1.47159 -2.240814,1.789682 -3.239987,5.227417 -2.952758,8.080785 z"
style="fill:#f9f7f3;fill-opacity:1;stroke:#d0c1a2;stroke-width:0.565786px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter1277)"
id="path28" />
</g>
<g
inkscape:label="Layer 1 copy"
inkscape:groupmode="layer"
id="g1343">
<path
id="path1341"
style="fill:#75e04e;fill-opacity:1;stroke:#74e04d;stroke-width:0.565786px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 63.595661,96.781172 c 2.610557,8.549728 11.109144,14.261728 18.221441,19.677268 14.285995,10.87784 30.777538,19.16253 47.836068,24.76819 12.08516,3.97134 24.9714,5.89737 37.69211,5.9756 11.75058,0.0723 23.533,-2.04773 34.88282,-5.09124 8.49997,-2.27931 17.13306,-4.99674 24.52676,-9.76937 5.59427,-3.6111 11.35542,-7.93448 14.37737,-13.86775 0.73693,-1.44688 2.00968,-3.90176 0.67356,-4.82442 -4.90929,-3.39011 -10.18592,6.31619 -15.70026,8.59349 -8.68681,3.58745 -17.81526,6.26681 -27.07782,7.85916 -11.94219,2.05301 -24.25018,3.46797 -36.29097,2.10779 -12.7013,-1.4348 -25.14557,-5.50493 -36.82103,-10.70737 -8.48127,-3.77914 -16.22058,-9.14294 -23.66896,-14.68689 C 96.49438,102.53405 91.950513,96.75601 86.13513,92.560411 82.533585,89.96202 79.028923,86.323649 74.610572,85.8754 c -3.438589,-0.34885 -7.602338,0.653715 -9.831133,3.295317 -1.655568,1.962204 -1.933509,5.155042 -1.183778,7.610455 z m -36.276154,1.911751 c 1.000129,9.935377 9.068818,18.042637 15.683118,25.523487 13.285704,15.02628 29.55205,27.69127 47.022482,37.54435 12.376983,6.98044 26.073563,11.90937 39.996973,14.7475 13.12015,2.67439 26.76072,2.8433 40.12178,1.96426 10.02366,-0.65947 20.39718,-1.4876 29.64741,-5.40445 6.55654,-2.77625 13.10939,-6.72368 17.37506,-12.42454 1.08663,-1.45223 3.06381,-3.85048 1.78759,-5.13927 -4.73249,-4.77911 -12.53753,5.06785 -19.12154,6.4416 -10.27704,2.1443 -20.88256,2.99026 -31.37744,2.71972 -13.53101,-0.3488 -27.32398,-1.47627 -40.22043,-5.58617 -13.6039,-4.33535 -26.35283,-11.50217 -38.013078,-19.74231 -8.470214,-5.98579 -15.782756,-13.54635 -22.737346,-21.24101 -5.371021,-5.94258 -9.092383,-13.26181 -14.551151,-19.123884 -3.38068,-3.630455 -6.428954,-8.379273 -11.172348,-9.831658 -3.691559,-1.130322 -8.47165,-0.937751 -11.488322,1.47159 -2.240814,1.789682 -3.239987,5.227417 -2.952758,8.080785 z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.9 KiB

162
Artwork/Tusker.svg Normal file
View File

@ -0,0 +1,162 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
sodipodi:docname="Tusker.svg"
inkscape:version="1.3.2 (091e20e, 2023-11-25)"
inkscape:export-ydpi="98.304001"
inkscape:export-xdpi="98.304001"
inkscape:export-filename="../Desktop/1024x1024@1x.png"
id="svg8"
version="1.1"
viewBox="0 0 264.58333 264.58333"
height="1000"
width="1000"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2">
<inkscape:path-effect
bendpath1-nodetypes="cc"
bendpath4="M 27.271345,85.808468 V 178.94843"
bendpath3="M 27.271345,178.94843 H 242.39013"
bendpath2="M 242.39013,85.808468 V 178.94843"
bendpath1="M 26.897168,85.995557 242.39013,85.808468"
xx="true"
yy="true"
lpeversion="1"
is_visible="true"
id="path-effect1345"
effect="envelope" />
<inkscape:path-effect
allow_transforms="true"
css_properties=""
attributes=""
method="d"
linkeditem=""
lpeversion="1"
is_visible="true"
id="path-effect38"
effect="clone_original" />
<inkscape:path-effect
scale_y_rel="false"
prop_scale="1"
strokepath="M0,0 L1,0"
endpoint_spacing_variation="0;1"
endpoint_edge_variation="0;1"
startpoint_spacing_variation="0;1"
startpoint_edge_variation="0;1"
count="5"
lpeversion="1"
is_visible="true"
id="path-effect32"
effect="curvestitching" />
<filter
height="1.317445"
width="1.1258237"
id="filter1277"
inkscape:label="Drop Shadow"
style="color-interpolation-filters:sRGB;"
x="-0.068723437"
y="-0.1318855">
<feFlood
id="feFlood1267"
result="flood"
flood-color="rgb(0,0,0)"
flood-opacity="0.321569" />
<feComposite
id="feComposite1269"
result="composite1"
operator="in"
in2="SourceGraphic"
in="flood" />
<feGaussianBlur
id="feGaussianBlur1271"
result="blur"
stdDeviation="5"
in="composite1" />
<feOffset
id="feOffset1273"
result="offset"
dy="5"
dx="-2.5" />
<feComposite
id="feComposite1275"
result="composite2"
operator="over"
in2="offset"
in="SourceGraphic" />
</filter>
</defs>
<sodipodi:namedview
inkscape:window-maximized="0"
inkscape:window-y="25"
inkscape:window-x="1280"
inkscape:window-height="1387"
inkscape:window-width="1280"
units="px"
showgrid="false"
inkscape:document-rotation="0"
inkscape:current-layer="layer2"
inkscape:document-units="px"
inkscape:cy="496.38895"
inkscape:cx="442.29528"
inkscape:zoom="1.4142136"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 2"
id="layer2"
inkscape:groupmode="layer">
<rect
y="-0.14500916"
x="-0.14500916"
height="264.87335"
width="264.87335"
id="rect865"
style="fill:#75e04e;fill-opacity:1;stroke:#75e04e;stroke-width:0.239149;stroke-opacity:1" />
</g>
<g
style="display:none"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<path
inkscape:connector-curvature="0"
d="m 63.595661,96.781172 c 2.610557,8.549728 11.109144,14.261728 18.221441,19.677268 14.285995,10.87784 30.777538,19.16253 47.836068,24.76819 12.08516,3.97134 24.9714,5.89737 37.69211,5.9756 11.75058,0.0723 23.533,-2.04773 34.88282,-5.09124 8.49997,-2.27931 17.13306,-4.99674 24.52676,-9.76937 5.59427,-3.6111 11.35542,-7.93448 14.37737,-13.86775 0.73693,-1.44688 2.00968,-3.90176 0.67356,-4.82442 -4.90929,-3.39011 -10.18592,6.31619 -15.70026,8.59349 -8.68681,3.58745 -17.81526,6.26681 -27.07782,7.85916 -11.94219,2.05301 -24.25018,3.46797 -36.29097,2.10779 -12.7013,-1.4348 -25.14557,-5.50493 -36.82103,-10.70737 -8.48127,-3.77914 -16.22058,-9.14294 -23.66896,-14.68689 C 96.49438,102.53405 91.950513,96.75601 86.13513,92.560411 82.533585,89.96202 79.028923,86.323649 74.610572,85.8754 c -3.438589,-0.34885 -7.602338,0.653715 -9.831133,3.295317 -1.655568,1.962204 -1.933509,5.155042 -1.183778,7.610455 z m -36.276154,1.911751 c 1.000129,9.935377 9.068818,18.042637 15.683118,25.523487 13.285704,15.02628 29.55205,27.69127 47.022482,37.54435 12.376983,6.98044 26.073563,11.90937 39.996973,14.7475 13.12015,2.67439 26.76072,2.8433 40.12178,1.96426 10.02366,-0.65947 20.39718,-1.4876 29.64741,-5.40445 6.55654,-2.77625 13.10939,-6.72368 17.37506,-12.42454 1.08663,-1.45223 3.06381,-3.85048 1.78759,-5.13927 -4.73249,-4.77911 -12.53753,5.06785 -19.12154,6.4416 -10.27704,2.1443 -20.88256,2.99026 -31.37744,2.71972 -13.53101,-0.3488 -27.32398,-1.47627 -40.22043,-5.58617 -13.6039,-4.33535 -26.35283,-11.50217 -38.013078,-19.74231 -8.470214,-5.98579 -15.782756,-13.54635 -22.737346,-21.24101 -5.371021,-5.94258 -9.092383,-13.26181 -14.551151,-19.123884 -3.38068,-3.630455 -6.428954,-8.379273 -11.172348,-9.831658 -3.691559,-1.130322 -8.47165,-0.937751 -11.488322,1.47159 -2.240814,1.789682 -3.239987,5.227417 -2.952758,8.080785 z"
style="fill:#f9f7f3;fill-opacity:1;stroke:#d0c1a2;stroke-width:0.565786px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter1277)"
id="path28" />
</g>
<g
inkscape:label="Layer 1 copy"
inkscape:groupmode="layer"
id="g1343">
<path
id="path1341"
style="fill:#f9f7f3;fill-opacity:1;stroke:#d0c1a2;stroke-width:0.56578600000000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter1277)"
d="m 63.595661,96.781172 c 2.610557,8.549728 11.109144,14.261728 18.221441,19.677268 14.285995,10.87784 30.777538,19.16253 47.836068,24.76819 12.08516,3.97134 24.9714,5.89737 37.69211,5.9756 11.75058,0.0723 23.533,-2.04773 34.88282,-5.09124 8.49997,-2.27931 17.13306,-4.99674 24.52676,-9.76937 5.59427,-3.6111 11.35542,-7.93448 14.37737,-13.86775 0.73693,-1.44688 2.00968,-3.90176 0.67356,-4.82442 -4.90929,-3.39011 -10.18592,6.31619 -15.70026,8.59349 -8.68681,3.58745 -17.81526,6.26681 -27.07782,7.85916 -11.94219,2.05301 -24.25018,3.46797 -36.29097,2.10779 -12.7013,-1.4348 -25.14557,-5.50493 -36.82103,-10.70737 -8.48127,-3.77914 -16.22058,-9.14294 -23.66896,-14.68689 C 96.49438,102.53405 91.950513,96.75601 86.13513,92.560411 82.533585,89.96202 79.028923,86.323649 74.610572,85.8754 c -3.438589,-0.34885 -7.602338,0.653715 -9.831133,3.295317 -1.655568,1.962204 -1.933509,5.155042 -1.183778,7.610455 z m -36.276154,1.911751 c 1.000129,9.935377 9.068818,18.042637 15.683118,25.523487 13.285704,15.02628 29.55205,27.69127 47.022482,37.54435 12.376983,6.98044 26.073563,11.90937 39.996973,14.7475 13.12015,2.67439 26.76072,2.8433 40.12178,1.96426 10.02366,-0.65947 20.39718,-1.4876 29.64741,-5.40445 6.55654,-2.77625 13.10939,-6.72368 17.37506,-12.42454 1.08663,-1.45223 3.06381,-3.85048 1.78759,-5.13927 -4.73249,-4.77911 -12.53753,5.06785 -19.12154,6.4416 -10.27704,2.1443 -20.88256,2.99026 -31.37744,2.71972 -13.53101,-0.3488 -27.32398,-1.47627 -40.22043,-5.58617 -13.6039,-4.33535 -26.35283,-11.50217 -38.013078,-19.74231 -8.470214,-5.98579 -15.782756,-13.54635 -22.737346,-21.24101 -5.371021,-5.94258 -9.092383,-13.26181 -14.551151,-19.123884 -3.38068,-3.630455 -6.428954,-8.379273 -11.172348,-9.831658 -3.691559,-1.130322 -8.47165,-0.937751 -11.488322,1.47159 -2.240814,1.789682 -3.239987,5.227417 -2.952758,8.080785 z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@ -1,3 +1,66 @@
## 2024.4
This release introduces support for iOS 18, including a new sidebar/tab bar on iPad, as well as bugfixes and improvements.
Features/Improvements:
- Import image description when adding attachments from Photos if possible
- iPadOS 18: New floating sidebar/tab bar
Bugfixes:
- Fix crash when viewing profiles in certain circumstances
- Fix video controls in attachment gallery not auto-hiding
- Fix crash if hashtag search results includes duplicates
- Fix "no content" text not being removed from list timeline after refreshing
- macOS: Fix video controls overlay being positioned incorrectly when Reduce Motion is on
- macOS: Fix reselecting current item not navigating back
## 2024.3
This update includes a number of bugfixes and performance improvements. See below for a list of fixes.
Bugfixes:
- Fix an issue displaying rich text in certain cases
- Fix crash when video attachment finishes playing
- Fix video attachment thumbnails being flipped on Compose screen
- Fix profile header images being blurry
- Fix crash when opening push notifications in certain circumstances
- Fix certain links in profile fields not being tappable
- Fix gifv playback pausing audio from other apps
- Fix gifv playback being paused when returning from background
- Fix badges on gifv attachments not appearing
- Fix excessive network traffic when opening profile pages
- Fix controls visibility not matching across attachment gallery pages
- Fix add hashtag/instance pinned timeline sheet in Customize Timelines dismissing instantly
- Fix Dynamic Type not applying to status content
- Fix mention/status push notifications not showing CW
- Fix sensitive attachment thumbnails being shown in push notifications
- Fix profile moved overlay visual and VoiceOver issues
- Fix opening Mastodon remote status links
- Fix reply author avatar on Compose screen not being pinned to top when scrolling while typing
- Pleroma/Akkoma: Fix editing attachment descriptions not working
- Pixelfed/Firefish: Fix error loading certain accounts
- Pixelfed: Fix error loading relationships and follow/block/etc. actions
- iPadOS: Fix pointer interactions throughout the app
- iPadOS: Fix multiple close buttons being added in multi-column interface
- iPadOS: Fix Cmd+1/etc. removing columns when returning to previous tab
- iPadOS: Fix multi-column interface not animating for some actions
- iPadOS: Fix selecting search results always adding new column
## 2024.2
This release introduces push notifications as well as an enhanced multi-column interface on iPadOS!
Features/Improvements:
- Push notifications
- Add post preview to Appearance preferences
- Show instance announcements in Notifications tab
- Add subscription option to Tip Jar
- iPadOS: Multi-column navigation
- Pleroma/Akkoma: Emoji reaction notifications
Bugfixes:
- Fix fetching server info on some instances
- Fix attachment captions not displaying while loading in gallery
- macOS: Remove in-app Safari preferences
- Pleroma: Handle posts with missing creation date
## 2024.1 ## 2024.1
This update includes a significant improvements for the attachment gallery and displaying rich text posts. See below for a full list of improvements and fixes. This update includes a significant improvements for the attachment gallery and displaying rich text posts. See below for a full list of improvements and fixes.

View File

@ -1,5 +1,127 @@
# Changelog # Changelog
## 2024.4 (136)
Features/Improvements:
- Import image description when adding attachments from Photos if possible
- Reorganize toolbar buttons when adding saved hashtag
- Show errors when loading video in attachment gallery fails
Bugfixes:
- Fix crash when viewing profiles in certain circumstances
- Fix profile tab switching animation getting stuck
- Fix video controls in attachment gallery not auto-hiding
- Pleroma: Fix error when loading polls in some circumstances
- iPadOS 18: Fix incorrect two-column layout when closing sidebar
- macOS: Fix video controls overlay being positioned incorrectly when Reduce Motion is on
- macOS: Fix reselecting current item not navigating back
## 2024.4 (135)
Features/Improvements:
- iOS 18: New floating sidebar/tab bar
Bugfixes:
- Fix crash when hashtag search results include duplicates
- Fix "no content" text not being removed from list timeline after refreshing
## 2024.3 (133)
- Add additional info to Tip Jar
## 2024.3 (132)
- Add ToS nag before signing in
## 2024.3 (131)
Bugfixes:
- Fix Cmd+3 not correctly switching to Explore tab
## 2024.3 (130)
Bugfixes:
- Fix reply author avatar on Compose screen not being pinned to top when scrolling while typing
- Fix crash when dragging between buttons in reblog confirmation alert
- Fix potential crash when displaying search results
- Mac: Fix Post button not displaying on Compose screen
## 2024.3 (129)
Bugfixes:
- Fix excessive network traffic on profile pages
- Fix attachment gallery controls visibility not being synced between pages
- Fix video attachments not restarting when play pressed while at ends
- Fix profile field text being misaligned
- Fix at sign in timeline statuses usernames sometimes clipping
- Fix add hashtag/instance to Pinned Timelines sheets dismissing immediately when opened
- Fix for display name being replaced with incorrect user in certain circumstances
- Fix profile moved overlay view appearing behind avatar/header
- Fix profile moved view accessibility with VoiceOver
- Fix mention/status push notifications not showing content warning
- Fix sensitive attachment thumbnails being shown in push notifications
- Fix Dynamic Type not applying to status content
- Fix expand all option in Conversation not transferring when opening ancestors
- Fix not being able to resolve remote Mastodon status links in Conversation screen
- Fix status indicator icons overlapping thread links when Dynamic Type is enabled
## 2024.3 (128)
Bugfixes:
- Fix selecting poll option playing too much haptic feedback
- Fix crash when displaying HTML in certain posts
- Fix gifv playback pausing audio from other apps
- Fix gifv playback not resuming after returning from background
- Fix attachment badges not appearing on gifvs
- iPadOS: Fix poll options not having pointer hover effects
- iPadOS: Fix haptic feedback not working on new Magic Keyboard
- iPadOS: Fix scrubbing video with pointer not letting you click to select position
- iPadOS: Fix multi-column navigation not animating when replacing multiple columns
## 2024.3 (127)
Bugfixes:
- Fix Remove Suggestion context menu action missing from Suggested Accounts screen
- Fix profile header images being blurry
- Fix dismissing gallery when presented from sheet
- Fix potential crash in multi-column interface
- Fix crash when opening push notification while sheet presented
- Fix being able to block your own domain
- Fix links in profile fields with other text not being interactable
- Fix excessive CPU use immediately after app launch
- Fix timeline failing to load when one status is malformed
- iPadOS: Fix pointer interactions on conversation main status action buttons
- iPadOS: Fix multiple close buttons being added in multi-column interface
- iPadOS: Fix Cmd+1/etc. resetting navigation state when returning to previous column
- iPadOS: Fix previous sidebar selection losing navigation state in some circumstances
- iPadOS: Fix profile followers/following buttons not having pointer effect
- iPadOS: Fix search token suggestions not having pointer effect
- iPadOS: Fix conversation thread links appearing above avatar during pointer effect
- iPadOS: Fix multi-column interface not animating scroll when replacing subsequent columns
- iPadOS: Fix not being able to select text on conversation main status by double-clicking with cursor
- iPadOS: Fix selecting search result always pushing new column rather than replacing
- Pixelfed/Firefish: Fix error loading accounts in some circumstances
- Pixelfed: Fix loading relationships and follow/block/etc. actions not working
## 2024.3 (126)
Bugfixes:
- Fix an issue displaying post HTML in certain edge cases
- Fix crash when video attachment playback ends
- Fix excessive CPU usage when scrubbing video attachment
- Fix video attachment thubmnails being flipped on Compose screen
- Pleroma: Fix editing attachment descriptions not working
## 2024.2 (124)
Features/Improvements:
- Add subscription option to Tip Jar
Bugfixes:
- Fix attachment captions not displaying while loading in gallery
- Fix tapping follow request push notification not working
- Pleroma: Handle posts with missing creation dates
## 2024.2 (122)
Features/Improvements:
- Show instance announcements in Notifications
- Pleroma/Akkoma: Display emoji reactions in Notifications
- Pleroma/Akkoma: Add push notifications for emoji reactions
Bugfixes:
- Fix issue fetching server info on some instances
- Fix Preferences background color not updating after changing Pure Black Dark Mode
- Fix push subscription settings background using incorrect color with Pure Black Dark Mode off
## 2024.2 (121) ## 2024.2 (121)
This build introduces a new multi-column navigation mode on iPad. You can revert to the old mode under Preferences -> Appearance. This build introduces a new multi-column navigation mode on iPad. You can revert to the old mode under Preferences -> Appearance.

View File

@ -15,9 +15,13 @@ import Pachyderm
import Intents import Intents
import HTMLStreamer import HTMLStreamer
import WebURL import WebURL
import UIKit
import TuskerPreferences
private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "NotificationService") private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "NotificationService")
private let emojiRegex = try! NSRegularExpression(pattern: ":(\\w+):", options: [])
class NotificationService: UNNotificationServiceExtension { class NotificationService: UNNotificationServiceExtension {
private static let textConverter = TextConverter(configuration: .init(insertNewlines: false), callbacks: HTMLCallbacks.self) private static let textConverter = TextConverter(configuration: .init(insertNewlines: false), callbacks: HTMLCallbacks.self)
@ -63,6 +67,7 @@ class NotificationService: UNNotificationServiceExtension {
mutableContent.body = notification.body mutableContent.body = notification.body
mutableContent.userInfo["notificationID"] = notification.notificationID mutableContent.userInfo["notificationID"] = notification.notificationID
mutableContent.userInfo["accountID"] = accountID mutableContent.userInfo["accountID"] = accountID
mutableContent.targetContentIdentifier = accountID
let task = Task { let task = Task {
await updateNotificationContent(mutableContent, account: account, push: notification) await updateNotificationContent(mutableContent, account: account, push: notification)
@ -109,13 +114,24 @@ class NotificationService: UNNotificationServiceExtension {
kindStr = "📊 Poll finished" kindStr = "📊 Poll finished"
case .update: case .update:
kindStr = "✏️ Edited" kindStr = "✏️ Edited"
case .emojiReaction:
if let emoji = notification.emoji {
kindStr = "\(emoji) Reacted"
} else {
kindStr = nil
}
default: default:
kindStr = nil kindStr = nil
} }
let notificationContent: String? let notificationContent: String?
if let status = notification.status { if let status = notification.status {
notificationContent = NotificationService.textConverter.convert(html: status.content) if notification.kind == .mention || notification.kind == .status,
!status.spoilerText.isEmpty {
notificationContent = "⚠️ \(status.spoilerText)"
} else {
notificationContent = NotificationService.textConverter.convert(html: status.content)
}
} else if notification.kind == .follow || notification.kind == .followRequest { } else if notification.kind == .follow || notification.kind == .followRequest {
notificationContent = nil notificationContent = nil
} else { } else {
@ -128,7 +144,9 @@ class NotificationService: UNNotificationServiceExtension {
// We deliberately don't include attachments for other types of notifications that have statuses (favs, etc.) // We deliberately don't include attachments for other types of notifications that have statuses (favs, etc.)
// because we risk just fetching the same thing a bunch of times for many senders. // because we risk just fetching the same thing a bunch of times for many senders.
if notification.kind == .mention || notification.kind == .status || notification.kind == .update, if notification.kind == .mention || notification.kind == .status || notification.kind == .update,
let attachment = notification.status?.attachments.first { let status = notification.status,
!status.sensitive,
let attachment = status.attachments.first {
let url = attachment.previewURL ?? attachment.url let url = attachment.previewURL ?? attachment.url
attachmentDataTask = Task { attachmentDataTask = Task {
do { do {
@ -211,8 +229,33 @@ class NotificationService: UNNotificationServiceExtension {
} }
let updatedContent: UNMutableNotificationContent let updatedContent: UNMutableNotificationContent
let contentProviding: any UNNotificationContentProviding
if #available(iOS 18.0, visionOS 2.0, *),
await Preferences.shared.hasFeatureFlag(.pushNotifCustomEmoji) {
let attributedString = NSMutableAttributedString(string: content.body)
for match in emojiRegex.matches(in: content.body, range: NSRange(location: 0, length: content.body.utf16.count)).reversed() {
let emojiName = (content.body as NSString).substring(with: match.range(at: 1))
guard let emoji = notification.status?.emojis.first(where: { $0.shortcode == emojiName }),
let url = URL(emoji.url),
let (data, _) = try? await URLSession.shared.data(from: url),
let image = UIImage(data: data) else {
continue
}
let attachment = NSTextAttachment(image: image)
let attachmentStr = NSAttributedString(attachment: attachment)
attributedString.replaceCharacters(in: match.range, with: attachmentStr)
}
let attributedCtx = UNNotificationAttributedMessageContext(sendMessageIntent: intent, attributedContent: attributedString)
contentProviding = attributedCtx
} else {
contentProviding = intent
}
do { do {
let newContent = try content.updating(from: intent) let newContent = try content.updating(from: contentProviding)
if let newMutableContent = newContent.mutableCopy() as? UNMutableNotificationContent { if let newMutableContent = newContent.mutableCopy() as? UNMutableNotificationContent {
pendingRequest?.0 = newMutableContent pendingRequest?.0 = newMutableContent
updatedContent = newMutableContent updatedContent = newMutableContent
@ -328,14 +371,13 @@ private struct HTMLCallbacks: HTMLConversionCallbacks {
// Converting WebURL to URL is a small but non-trivial expense (since it works by // Converting WebURL to URL is a small but non-trivial expense (since it works by
// serializing the WebURL as a string and then having Foundation parse it again), // serializing the WebURL as a string and then having Foundation parse it again),
// so, if available, use the system parser which doesn't require another round trip. // so, if available, use the system parser which doesn't require another round trip.
if #available(iOS 16.0, macOS 13.0, *), if let url = try? URL.ParseStrategy().parse(string) {
let url = try? URL.ParseStrategy().parse(string) {
url url
} else if let web = WebURL(string), } else if let web = WebURL(string),
let url = URL(web) { let url = URL(web) {
url url
} else { } else {
URL(string: string) nil
} }
} }

View File

@ -24,6 +24,8 @@
<dict> <dict>
<key>NSExtensionAttributes</key> <key>NSExtensionAttributes</key>
<dict> <dict>
<key>NSExtensionServiceRoleType</key>
<string>NSExtensionServiceRoleTypeViewer</string>
<key>NSExtensionActivationRule</key> <key>NSExtensionActivationRule</key>
<dict> <dict>
<key>NSExtensionActivationSupportsAttachmentsWithMinCount</key> <key>NSExtensionActivationSupportsAttachmentsWithMinCount</key>

View File

@ -1,4 +1,4 @@
// swift-tools-version: 5.7 // swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package. // The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription import PackageDescription
@ -6,7 +6,7 @@ import PackageDescription
let package = Package( let package = Package(
name: "ComposeUI", name: "ComposeUI",
platforms: [ platforms: [
.iOS(.v15), .iOS(.v16),
], ],
products: [ products: [
// Products define the executables and libraries a package produces, and make them visible to other packages. // Products define the executables and libraries a package produces, and make them visible to other packages.
@ -26,9 +26,15 @@ let package = Package(
// Targets can depend on other targets in this package, and on products in packages this package depends on. // Targets can depend on other targets in this package, and on products in packages this package depends on.
.target( .target(
name: "ComposeUI", name: "ComposeUI",
dependencies: ["Pachyderm", "InstanceFeatures", "TuskerComponents", "MatchedGeometryPresentation"]), dependencies: ["Pachyderm", "InstanceFeatures", "TuskerComponents", "MatchedGeometryPresentation"],
swiftSettings: [
.swiftLanguageMode(.v5)
]),
.testTarget( .testTarget(
name: "ComposeUITests", name: "ComposeUITests",
dependencies: ["ComposeUI"]), dependencies: ["ComposeUI"],
swiftSettings: [
.swiftLanguageMode(.v5)
]),
] ]
) )

View File

@ -156,7 +156,7 @@ class AttachmentRowController: ViewController {
Button(role: .destructive, action: controller.removeAttachment) { Button(role: .destructive, action: controller.removeAttachment) {
Label("Delete", systemImage: "trash") Label("Delete", systemImage: "trash")
} }
} previewIfAvailable: { } preview: {
ControllerView(controller: { controller.thumbnailController }) ControllerView(controller: { controller.thumbnailController })
} }
@ -221,16 +221,3 @@ extension AttachmentRowController {
case allowEntry, recognizingText case allowEntry, recognizingText
} }
} }
private extension View {
@available(iOS, obsoleted: 16.0)
@available(visionOS 1.0, *)
@ViewBuilder
func contextMenu<M: View, P: View>(@ViewBuilder menuItems: () -> M, @ViewBuilder previewIfAvailable preview: () -> P) -> some View {
if #available(iOS 16.0, *) {
self.contextMenu(menuItems: menuItems, preview: preview)
} else {
self.contextMenu(menuItems: menuItems)
}
}
}

View File

@ -40,6 +40,7 @@ class AttachmentThumbnailController: ViewController {
case .video, .gifv: case .video, .gifv:
let asset = AVURLAsset(url: url) let asset = AVURLAsset(url: url)
let imageGenerator = AVAssetImageGenerator(asset: asset) let imageGenerator = AVAssetImageGenerator(asset: asset)
imageGenerator.appliesPreferredTrackTransform = true
#if os(visionOS) #if os(visionOS)
#warning("Use async AVAssetImageGenerator.image(at:)") #warning("Use async AVAssetImageGenerator.image(at:)")
#else #else
@ -91,6 +92,7 @@ class AttachmentThumbnailController: ViewController {
if type.conforms(to: .movie) { if type.conforms(to: .movie) {
let asset = AVURLAsset(url: url) let asset = AVURLAsset(url: url)
let imageGenerator = AVAssetImageGenerator(asset: asset) let imageGenerator = AVAssetImageGenerator(asset: asset)
imageGenerator.appliesPreferredTrackTransform = true
#if os(visionOS) #if os(visionOS)
#warning("Use async AVAssetImageGenerator.image(at:)") #warning("Use async AVAssetImageGenerator.image(at:)")
#else #else

View File

@ -214,44 +214,6 @@ fileprivate extension View {
self self
} }
} }
@available(iOS, obsoleted: 16.0)
@ViewBuilder
func sheetOrPopover(isPresented: Binding<Bool>, @ViewBuilder content: @escaping () -> some View) -> some View {
if #available(iOS 16.0, *) {
self.modifier(SheetOrPopover(isPresented: isPresented, view: content))
} else {
self.popover(isPresented: isPresented, content: content)
}
}
@available(iOS, obsoleted: 16.0)
@ViewBuilder
func withSheetDetentsIfAvailable() -> some View {
if #available(iOS 16.0, *) {
self
.presentationDetents([.medium, .large])
.presentationDragIndicator(.visible)
} else {
self
}
}
}
@available(iOS 16.0, *)
fileprivate struct SheetOrPopover<V: View>: ViewModifier {
@Binding var isPresented: Bool
@ViewBuilder let view: () -> V
@Environment(\.horizontalSizeClass) var sizeClass
func body(content: Content) -> some View {
if sizeClass == .compact {
content.sheet(isPresented: $isPresented, content: view)
} else {
content.popover(isPresented: $isPresented, content: view)
}
}
} }
@available(visionOS 1.0, *) @available(visionOS 1.0, *)

View File

@ -8,6 +8,7 @@
import SwiftUI import SwiftUI
import Pachyderm import Pachyderm
import Combine import Combine
import TuskerComponents
class AutocompleteEmojisController: ViewController { class AutocompleteEmojisController: ViewController {
unowned let composeController: ComposeController unowned let composeController: ComposeController

View File

@ -8,6 +8,7 @@
import SwiftUI import SwiftUI
import Combine import Combine
import Pachyderm import Pachyderm
import TuskerComponents
class AutocompleteHashtagsController: ViewController { class AutocompleteHashtagsController: ViewController {
unowned let composeController: ComposeController unowned let composeController: ComposeController

View File

@ -125,9 +125,7 @@ public final class ComposeController: ViewController {
self.toolbarController = ToolbarController(parent: self) self.toolbarController = ToolbarController(parent: self)
self.attachmentsListController = AttachmentsListController(parent: self) self.attachmentsListController = AttachmentsListController(parent: self)
if #available(iOS 16.0, *) { NotificationCenter.default.addObserver(self, selector: #selector(currentInputModeChanged), name: UITextInputMode.currentInputModeDidChangeNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(currentInputModeChanged), name: UITextInputMode.currentInputModeDidChangeNotification, object: nil)
}
NotificationCenter.default.addObserver(self, selector: #selector(managedObjectsDidChange), name: .NSManagedObjectContextObjectsDidChange, object: DraftsPersistentContainer.shared.viewContext) NotificationCenter.default.addObserver(self, selector: #selector(managedObjectsDidChange), name: .NSManagedObjectContextObjectsDidChange, object: DraftsPersistentContainer.shared.viewContext)
} }
@ -324,16 +322,17 @@ public final class ComposeController: ViewController {
ControllerView(controller: { controller.toolbarController }) ControllerView(controller: { controller.toolbarController })
#endif #endif
} }
#if !os(visionOS)
// on iPadOS15, the toolbar ends up below the keyboard's toolbar without this
.padding(.bottom, keyboardInset)
#endif
.transition(.move(edge: .bottom)) .transition(.move(edge: .bottom))
} }
} }
.toolbar { .toolbar {
ToolbarItem(placement: .cancellationAction) { cancelButton } ToolbarItem(placement: .cancellationAction) { cancelButton }
#if targetEnvironment(macCatalyst)
ToolbarItem(placement: .topBarTrailing) { draftsButton }
ToolbarItem(placement: .confirmationAction) { postButton } ToolbarItem(placement: .confirmationAction) { postButton }
#else
ToolbarItem(placement: .confirmationAction) { postOrDraftsButton }
#endif
#if os(visionOS) #if os(visionOS)
ToolbarItem(placement: .bottomOrnament) { ToolbarItem(placement: .bottomOrnament) {
ControllerView(controller: { controller.toolbarController }) ControllerView(controller: { controller.toolbarController })
@ -431,7 +430,7 @@ public final class ComposeController: ViewController {
} }
.listStyle(.plain) .listStyle(.plain)
#if !os(visionOS) #if !os(visionOS)
.scrollDismissesKeyboardInteractivelyIfAvailable() .scrollDismissesKeyboard(.interactively)
#endif #endif
.disabled(controller.isPosting) .disabled(controller.isPosting)
} }
@ -461,43 +460,26 @@ public final class ComposeController: ViewController {
} }
@ViewBuilder @ViewBuilder
private var postButton: some View { private var postOrDraftsButton: some View {
if draft.hasContent || draft.editedStatusID != nil || !controller.config.allowSwitchingDrafts { if draft.hasContent || draft.editedStatusID != nil || !controller.config.allowSwitchingDrafts {
Button(action: controller.postStatus) { postButton
Text(draft.editedStatusID == nil ? "Post" : "Edit")
}
.keyboardShortcut(.return, modifiers: .command)
.disabled(!controller.postButtonEnabled)
} else { } else {
Button(action: controller.showDrafts) { draftsButton
Text("Drafts")
}
} }
} }
#if !os(visionOS) private var draftsButton: some View {
@available(iOS, obsoleted: 16.0) Button(action: controller.showDrafts) {
private var keyboardInset: CGFloat { Text("Drafts")
if #unavailable(iOS 16.0),
UIDevice.current.userInterfaceIdiom == .pad,
keyboardReader.isVisible {
return ToolbarController.height
} else {
return 0
} }
} }
#endif
} private var postButton: some View {
} Button(action: controller.postStatus) {
Text(draft.editedStatusID == nil ? "Post" : "Edit")
private extension View { }
@available(iOS, obsoleted: 16.0) .keyboardShortcut(.return, modifiers: .command)
@ViewBuilder .disabled(!controller.postButtonEnabled)
func scrollDismissesKeyboardInteractivelyIfAvailable() -> some View {
if #available(iOS 16.0, *) {
self.scrollDismissesKeyboard(.interactively)
} else {
self
} }
} }
} }

View File

@ -51,14 +51,11 @@ class FocusedAttachmentController: ViewController {
.onAppear { .onAppear {
player.play() player.play()
} }
} else if #available(iOS 16.0, *) { } else {
ZoomableScrollView { ZoomableScrollView {
attachmentView attachmentView
.matchedGeometryDestination(id: attachment.id) .matchedGeometryDestination(id: attachment.id)
} }
} else {
attachmentView
.matchedGeometryDestination(id: attachment.id)
} }
Spacer(minLength: 0) Spacer(minLength: 0)

View File

@ -96,7 +96,7 @@ class PollController: ViewController {
.onMove(perform: controller.moveOptions) .onMove(perform: controller.moveOptions)
} }
.listStyle(.plain) .listStyle(.plain)
.scrollDisabledIfAvailable(true) .scrollDisabled(true)
.frame(height: 44 * CGFloat(poll.options.count)) .frame(height: 44 * CGFloat(poll.options.count))
Button(action: controller.addOption) { Button(action: controller.addOption) {

View File

@ -66,7 +66,7 @@ class ToolbarController: ViewController {
} }
}) })
} }
.scrollDisabledIfAvailable(realWidth ?? 0 <= minWidth ?? 0) .scrollDisabled(realWidth ?? 0 <= minWidth ?? 0)
.frame(height: ToolbarController.height) .frame(height: ToolbarController.height)
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.background(.regularMaterial, ignoresSafeAreaEdges: [.bottom, .leading, .trailing]) .background(.regularMaterial, ignoresSafeAreaEdges: [.bottom, .leading, .trailing])
@ -122,8 +122,7 @@ class ToolbarController: ViewController {
Spacer() Spacer()
if #available(iOS 16.0, *), if composeController.mastodonController.instanceFeatures.createStatusWithLanguage {
composeController.mastodonController.instanceFeatures.createStatusWithLanguage {
LanguagePicker(draftLanguage: $draft.language, hasChangedSelection: $composeController.hasChangedLanguageSelection) LanguagePicker(draftLanguage: $draft.language, hasChangedSelection: $composeController.hasChangedLanguageSelection)
} }
} }

View File

@ -167,11 +167,23 @@ extension DraftAttachment: NSItemProviderReading {
type = .png type = .png
} }
// Read the caption from the image itself, if there is one.
let caption: String
if let source = CGImageSourceCreateWithData(data as CFData, [kCGImageSourceTypeIdentifierHint: typeIdentifier as CFString] as CFDictionary),
let properties = CGImageSourceCopyPropertiesAtIndex(source, 0, nil) as? [String: Any],
// This is the dictionary for TIFF properties, but it's present for other image types too
let tiffProperties = properties[kCGImagePropertyTIFFDictionary as String] as? [String: Any],
let imageDescription = tiffProperties[kCGImagePropertyTIFFImageDescription as String] as? String {
caption = imageDescription
} else {
caption = ""
}
let attachment = DraftAttachment(entity: DraftsPersistentContainer.shared.persistentStoreCoordinator.managedObjectModel.entitiesByName["DraftAttachment"]!, insertInto: nil) let attachment = DraftAttachment(entity: DraftsPersistentContainer.shared.persistentStoreCoordinator.managedObjectModel.entitiesByName["DraftAttachment"]!, insertInto: nil)
attachment.id = UUID() attachment.id = UUID()
attachment.fileURL = try writeDataToFile(data, id: attachment.id, type: type) attachment.fileURL = try writeDataToFile(data, id: attachment.id, type: type)
attachment.fileType = type.identifier attachment.fileType = type.identifier
attachment.attachmentDescription = "" attachment.attachmentDescription = caption
return attachment return attachment
} }

View File

@ -16,6 +16,8 @@ public class DraftsPersistentContainer: NSPersistentContainer {
public static let shared = DraftsPersistentContainer() public static let shared = DraftsPersistentContainer()
public static var captureError: ((any Error) -> Void)?
private static let managedObjectModel: NSManagedObjectModel = { private static let managedObjectModel: NSManagedObjectModel = {
let url = Bundle.module.url(forResource: "Drafts", withExtension: "momd")! let url = Bundle.module.url(forResource: "Drafts", withExtension: "momd")!
return NSManagedObjectModel(contentsOf: url)! return NSManagedObjectModel(contentsOf: url)!
@ -39,6 +41,7 @@ public class DraftsPersistentContainer: NSPersistentContainer {
loadPersistentStores { _, error in loadPersistentStores { _, error in
if let error { if let error {
DraftsPersistentContainer.captureError?(error)
fatalError("Loading persistent store: \(error)") fatalError("Loading persistent store: \(error)")
} }
} }

View File

@ -10,7 +10,6 @@
import UIKit import UIKit
import Combine import Combine
@available(iOS, obsoleted: 16.0)
class KeyboardReader: ObservableObject { class KeyboardReader: ObservableObject {
// @Published var isVisible = false // @Published var isVisible = false
@Published var keyboardHeight: CGFloat = 0 @Published var keyboardHeight: CGFloat = 0

View File

@ -39,6 +39,7 @@ extension TextViewCaretScrolling {
let animator = UIViewPropertyAnimator(duration: 0.2, curve: .easeInOut) { let animator = UIViewPropertyAnimator(duration: 0.2, curve: .easeInOut) {
scrollView.scrollRectToVisible(rectToMakeVisible, animated: false) scrollView.scrollRectToVisible(rectToMakeVisible, animated: false)
scrollView.layoutIfNeeded()
} }
self.caretScrollPositionAnimator = animator self.caretScrollPositionAnimator = animator
animator.startAnimation() animator.startAnimation()

View File

@ -1,26 +0,0 @@
//
// View+ForwardsCompat.swift
// ComposeUI
//
// Created by Shadowfacts on 3/25/23.
//
import SwiftUI
extension View {
#if os(visionOS)
func scrollDisabledIfAvailable(_ disabled: Bool) -> some View {
self.scrollDisabled(disabled)
}
#else
@available(iOS, obsoleted: 16.0)
@ViewBuilder
func scrollDisabledIfAvailable(_ disabled: Bool) -> some View {
if #available(iOS 16.0, *) {
self.scrollDisabled(disabled)
} else {
self
}
}
#endif
}

View File

@ -76,13 +76,15 @@ struct ReplyStatusView: View {
// once you scroll past the in-reply-to-content, the bottom of the avatar should be pinned to the bottom of the content // once you scroll past the in-reply-to-content, the bottom of the avatar should be pinned to the bottom of the content
offset = min(offset, maxOffset) offset = min(offset, maxOffset)
return AvatarImageView( return AvatarContainerRepresentable(offset: offset) {
url: status.account.avatar, AvatarImageView(
size: 50, url: status.account.avatar,
style: controller.config.avatarStyle, size: 50,
fetchAvatar: controller.fetchAvatar style: controller.config.avatarStyle,
) fetchAvatar: controller.fetchAvatar
.offset(x: 0, y: offset) )
}
.frame(width: 50, height: 50)
.accessibilityHidden(true) .accessibilityHidden(true)
} }
@ -94,3 +96,39 @@ private struct DisplayNameHeightPrefKey: PreferenceKey {
value = nextValue() value = nextValue()
} }
} }
// This whole dance is necessary so that the offset can be animatable from
// UIKit animations, like TextViewCaretScrolling.
private struct AvatarContainerRepresentable<Content: View>: UIViewControllerRepresentable {
let offset: CGFloat
@ViewBuilder let content: Content
func makeUIViewController(context: Context) -> Controller {
Controller(host: UIHostingController(rootView: content))
}
func updateUIViewController(_ uiViewController: Controller, context: Context) {
uiViewController.host.rootView = content
uiViewController.host.view.transform = CGAffineTransform(translationX: 0, y: offset)
}
// This extra layer is necessary because applying a transform to the
// representable's VC's view doesn't seem to have an effect.
class Controller: UIViewController {
let host: UIHostingController<Content>
init(host: UIHostingController<Content>) {
self.host = host
super.init(nibName: nil, bundle: nil)
addChild(host)
host.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(host.view)
host.view.frame = view.bounds
host.didMove(toParent: self)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
}

View File

@ -1,4 +1,4 @@
// swift-tools-version: 5.7 // swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package. // The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription import PackageDescription
@ -6,7 +6,7 @@ import PackageDescription
let package = Package( let package = Package(
name: "Duckable", name: "Duckable",
platforms: [ platforms: [
.iOS(.v15), .iOS(.v16),
], ],
products: [ products: [
// Products define the executables and libraries a package produces, and make them visible to other packages. // Products define the executables and libraries a package produces, and make them visible to other packages.
@ -23,7 +23,10 @@ let package = Package(
// Targets can depend on other targets in this package, and on products in packages this package depends on. // Targets can depend on other targets in this package, and on products in packages this package depends on.
.target( .target(
name: "Duckable", name: "Duckable",
dependencies: []), dependencies: [],
swiftSettings: [
.swiftLanguageMode(.v5)
]),
// .testTarget( // .testTarget(
// name: "DuckableTests", // name: "DuckableTests",
// dependencies: ["Duckable"]), // dependencies: ["Duckable"]),

View File

@ -33,11 +33,11 @@ public enum DuckAttemptAction {
extension UIViewController { extension UIViewController {
@available(iOS 16.0, *) @available(iOS 16.0, *)
public func presentDuckable(_ viewController: DuckableViewController, animated: Bool, isDucked: Bool = false) -> Bool { public func presentDuckable(_ viewController: DuckableViewController, animated: Bool, isDucked: Bool = false, completion: (() -> Void)? = nil) -> Bool {
var cur: UIViewController? = self var cur: UIViewController? = self
while let vc = cur { while let vc = cur {
if let container = vc as? DuckableContainerViewController { if let container = vc as? DuckableContainerViewController {
container.presentDuckable(viewController, animated: animated, isDucked: isDucked, completion: nil) container._presentDuckable(viewController, animated: animated, isDucked: isDucked, completion: completion)
return true return true
} else { } else {
cur = vc.parent cur = vc.parent

View File

@ -58,7 +58,7 @@ public class DuckableContainerViewController: UIViewController {
]) ])
} }
func presentDuckable(_ viewController: DuckableViewController, animated: Bool, isDucked: Bool, completion: (() -> Void)?) { func _presentDuckable(_ viewController: DuckableViewController, animated: Bool, isDucked: Bool, completion: (() -> Void)?) {
guard case .idle = state else { guard case .idle = state else {
if animated, if animated,
case .ducked(_, placeholder: let placeholder) = state { case .ducked(_, placeholder: let placeholder) = state {

View File

@ -1,4 +1,4 @@
// swift-tools-version: 5.10 // swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package. // The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription import PackageDescription
@ -6,7 +6,7 @@ import PackageDescription
let package = Package( let package = Package(
name: "GalleryVC", name: "GalleryVC",
platforms: [ platforms: [
.iOS(.v15), .iOS(.v16),
], ],
products: [ products: [
// Products define the executables and libraries a package produces, making them visible to other packages. // Products define the executables and libraries a package produces, making them visible to other packages.
@ -18,9 +18,15 @@ let package = Package(
// Targets are the basic building blocks of a package, defining a module or a test suite. // Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies. // Targets can depend on other targets in this package and products from dependencies.
.target( .target(
name: "GalleryVC"), name: "GalleryVC",
swiftSettings: [
.swiftLanguageMode(.v5)
]),
.testTarget( .testTarget(
name: "GalleryVCTests", name: "GalleryVCTests",
dependencies: ["GalleryVC"]), dependencies: ["GalleryVC"],
swiftSettings: [
.swiftLanguageMode(.v5)
]),
] ]
) )

View File

@ -17,7 +17,7 @@ public protocol GalleryContentViewController: UIViewController {
var bottomControlsAccessoryViewController: UIViewController? { get } var bottomControlsAccessoryViewController: UIViewController? { get }
var canAnimateFromSourceView: Bool { get } var canAnimateFromSourceView: Bool { get }
func setControlsVisible(_ visible: Bool, animated: Bool) func setControlsVisible(_ visible: Bool, animated: Bool, dueToUserInteraction: Bool)
func galleryContentDidAppear() func galleryContentDidAppear()
func galleryContentWillDisappear() func galleryContentWillDisappear()
} }
@ -35,7 +35,7 @@ public extension GalleryContentViewController {
true true
} }
func setControlsVisible(_ visible: Bool, animated: Bool) { func setControlsVisible(_ visible: Bool, animated: Bool, dueToUserInteraction: Bool) {
} }
func galleryContentDidAppear() { func galleryContentDidAppear() {

View File

@ -52,15 +52,22 @@ class GalleryDismissAnimationController: NSObject, UIViewControllerAnimatedTrans
appliedSourceToDestTransform = false appliedSourceToDestTransform = false
} }
to.view.frame = container.bounds // Moving `to.view` to the container is necessary when the presenting VC (i.e., `to`)
// is in the window's root presentation.
// But it breaks when the gallery is presented from a sheet-presented VC--in which case
// `to.view` is already in the view hierarchy at this point; and adding it to the
// container causees it to be removed when the transition completes.
if to.view.superview == nil {
to.view.frame = container.bounds
container.addSubview(to.view)
}
from.view.frame = container.bounds from.view.frame = container.bounds
container.addSubview(from.view)
let content = itemViewController.takeContent() let content = itemViewController.takeContent()
content.view.translatesAutoresizingMaskIntoConstraints = true content.view.translatesAutoresizingMaskIntoConstraints = true
content.view.layer.masksToBounds = true content.view.layer.masksToBounds = true
container.addSubview(to.view)
container.addSubview(from.view)
container.addSubview(content.view) container.addSubview(content.view)
content.view.frame = destFrameInContainer content.view.frame = destFrameInContainer
@ -99,7 +106,7 @@ class GalleryDismissAnimationController: NSObject, UIViewControllerAnimatedTrans
content.view.frame = sourceFrameInContainer content.view.frame = sourceFrameInContainer
content.view.layer.opacity = 0 content.view.layer.opacity = 0
itemViewController.setControlsVisible(false, animated: false) itemViewController.setControlsVisible(false, animated: false, dueToUserInteraction: false)
} }
animator.addCompletion { _ in animator.addCompletion { _ in

View File

@ -42,7 +42,7 @@ class GalleryDismissInteraction: NSObject {
origControlsVisible = viewController.currentItemViewController.controlsVisible origControlsVisible = viewController.currentItemViewController.controlsVisible
if origControlsVisible! { if origControlsVisible! {
viewController.currentItemViewController.setControlsVisible(false, animated: true) viewController.currentItemViewController.setControlsVisible(false, animated: true, dueToUserInteraction: false)
} }
case .changed: case .changed:

View File

@ -44,6 +44,7 @@ class GalleryItemViewController: UIViewController {
private(set) var scrollAndZoomEnabled = true private(set) var scrollAndZoomEnabled = true
private var scrollViewSizeForLastZoomScaleUpdate: CGSize? private var scrollViewSizeForLastZoomScaleUpdate: CGSize?
override var prefersHomeIndicatorAutoHidden: Bool { override var prefersHomeIndicatorAutoHidden: Bool {
return !controlsVisible return !controlsVisible
} }
@ -80,10 +81,10 @@ class GalleryItemViewController: UIViewController {
overlayVC.view.translatesAutoresizingMaskIntoConstraints = false overlayVC.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(overlayVC.view) view.addSubview(overlayVC.view)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
overlayVC.view.leadingAnchor.constraint(equalTo: content.view.leadingAnchor), overlayVC.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
overlayVC.view.trailingAnchor.constraint(equalTo: content.view.trailingAnchor), overlayVC.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
overlayVC.view.topAnchor.constraint(equalTo: content.view.topAnchor), overlayVC.view.topAnchor.constraint(equalTo: view.topAnchor),
overlayVC.view.bottomAnchor.constraint(equalTo: content.view.bottomAnchor), overlayVC.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
]) ])
} }
@ -212,7 +213,7 @@ class GalleryItemViewController: UIViewController {
updateZoomScale(resetZoom: false) updateZoomScale(resetZoom: false)
// Ensure the transform is correct if the controls are hidden // Ensure the transform is correct if the controls are hidden
setControlsVisible(controlsVisible, animated: false) setControlsVisible(controlsVisible, animated: false, dueToUserInteraction: false)
updateTopControlsInsets() updateTopControlsInsets()
} }
@ -227,6 +228,8 @@ class GalleryItemViewController: UIViewController {
updateZoomScale(resetZoom: true) updateZoomScale(resetZoom: true)
} }
centerContent() centerContent()
// Ensure the transform is correct if the controls are hidden and their size changed.
setControlsVisible(controlsVisible, animated: false, dueToUserInteraction: false)
} }
override func viewDidAppear(_ animated: Bool) { override func viewDidAppear(_ animated: Bool) {
@ -247,7 +250,7 @@ class GalleryItemViewController: UIViewController {
func addContent() { func addContent() {
content.loadViewIfNeeded() content.loadViewIfNeeded()
content.setControlsVisible(controlsVisible, animated: false) content.setControlsVisible(controlsVisible, animated: false, dueToUserInteraction: false)
content.view.translatesAutoresizingMaskIntoConstraints = false content.view.translatesAutoresizingMaskIntoConstraints = false
if content.parent != self { if content.parent != self {
@ -287,16 +290,18 @@ class GalleryItemViewController: UIViewController {
content.view.layoutIfNeeded() content.view.layoutIfNeeded()
} }
func setControlsVisible(_ visible: Bool, animated: Bool) { func setControlsVisible(_ visible: Bool, animated: Bool, dueToUserInteraction: Bool) {
controlsVisible = visible controlsVisible = visible
guard let topControlsView, guard let topControlsView,
let bottomControlsView else { let bottomControlsView else {
return return
} }
func updateControlsViews() { func updateControlsViews() {
topControlsView.transform = CGAffineTransform(translationX: 0, y: visible ? 0 : -topControlsView.bounds.height) topControlsView.transform = CGAffineTransform(translationX: 0, y: visible ? 0 : -topControlsView.bounds.height)
bottomControlsView.transform = CGAffineTransform(translationX: 0, y: visible ? 0 : bottomControlsView.bounds.height) bottomControlsView.transform = CGAffineTransform(translationX: 0, y: visible ? 0 : bottomControlsView.bounds.height)
content.setControlsVisible(visible, animated: animated) content.setControlsVisible(visible, animated: animated, dueToUserInteraction: dueToUserInteraction)
} }
if animated { if animated {
let animator = UIViewPropertyAnimator(duration: 0.2, timingParameters: UISpringTimingParameters()) let animator = UIViewPropertyAnimator(duration: 0.2, timingParameters: UISpringTimingParameters())
@ -373,9 +378,6 @@ class GalleryItemViewController: UIViewController {
47, // iPhone 12, 12 Pro, 12 Pro Max, 13, 13 Pro, 13 Pro Max, 14, 14 Plus 47, // iPhone 12, 12 Pro, 12 Pro Max, 13, 13 Pro, 13 Pro Max, 14, 14 Plus
50, // iPhone 12 mini, 13 mini 50, // iPhone 12 mini, 13 mini
] ]
let islandDeviceTopInsets: [CGFloat] = [
59, // iPhone 14 Pro, 14 Pro Max, 15 Pro, 15 Pro Max
]
if notchedDeviceTopInsets.contains(view.safeAreaInsets.top) { if notchedDeviceTopInsets.contains(view.safeAreaInsets.top) {
// the notch width is not the same for the iPhones 13, // the notch width is not the same for the iPhones 13,
// but what we actually want is the same offset from the edges // but what we actually want is the same offset from the edges
@ -385,16 +387,18 @@ class GalleryItemViewController: UIViewController {
let offset = (earWidth - (shareButton.imageView?.bounds.width ?? 0)) / 2 let offset = (earWidth - (shareButton.imageView?.bounds.width ?? 0)) / 2
shareButtonLeadingConstraint.constant = offset shareButtonLeadingConstraint.constant = offset
closeButtonTrailingConstraint.constant = offset closeButtonTrailingConstraint.constant = offset
} else if islandDeviceTopInsets.contains(view.safeAreaInsets.top) { } else if view.safeAreaInsets.top == 0 {
shareButtonLeadingConstraint.constant = 24 // square corner devices
shareButtonTopConstraint.constant = 24
closeButtonTrailingConstraint.constant = 24
closeButtonTopConstraint.constant = 24
} else {
shareButtonLeadingConstraint.constant = 8 shareButtonLeadingConstraint.constant = 8
shareButtonTopConstraint.constant = 8 shareButtonTopConstraint.constant = 8
closeButtonTrailingConstraint.constant = 8 closeButtonTrailingConstraint.constant = 8
closeButtonTopConstraint.constant = 8 closeButtonTopConstraint.constant = 8
} else {
// dynamic island devices
shareButtonLeadingConstraint.constant = 24
shareButtonTopConstraint.constant = 24
closeButtonTrailingConstraint.constant = 24
closeButtonTopConstraint.constant = 24
} }
} }
@ -424,7 +428,7 @@ class GalleryItemViewController: UIViewController {
scrollView.zoomScale > scrollView.minimumZoomScale { scrollView.zoomScale > scrollView.minimumZoomScale {
animateZoomOut() animateZoomOut()
} else { } else {
setControlsVisible(!controlsVisible, animated: true) setControlsVisible(!controlsVisible, animated: true, dueToUserInteraction: true)
} }
} }
@ -526,7 +530,7 @@ extension GalleryItemViewController: GalleryContentViewControllerContainer {
} }
func setGalleryControlsVisible(_ visible: Bool, animated: Bool) { func setGalleryControlsVisible(_ visible: Bool, animated: Bool) {
setControlsVisible(visible, animated: animated) setControlsVisible(visible, animated: animated, dueToUserInteraction: false)
} }
} }
@ -541,9 +545,9 @@ extension GalleryItemViewController: UIScrollViewDelegate {
func scrollViewDidZoom(_ scrollView: UIScrollView) { func scrollViewDidZoom(_ scrollView: UIScrollView) {
if scrollView.zoomScale <= scrollView.minimumZoomScale { if scrollView.zoomScale <= scrollView.minimumZoomScale {
setControlsVisible(true, animated: true) setControlsVisible(true, animated: true, dueToUserInteraction: true)
} else { } else {
setControlsVisible(false, animated: true) setControlsVisible(false, animated: true, dueToUserInteraction: true)
} }
centerContent() centerContent()

View File

@ -75,7 +75,7 @@ class GalleryPresentationAnimationController: NSObject, UIViewControllerAnimated
container.layoutIfNeeded() container.layoutIfNeeded()
// This needs to take place after the layout, so that the transform is correct. // This needs to take place after the layout, so that the transform is correct.
itemViewController.setControlsVisible(false, animated: false) itemViewController.setControlsVisible(false, animated: false, dueToUserInteraction: false)
let duration = self.transitionDuration(using: transitionContext) let duration = self.transitionDuration(using: transitionContext)
// rougly equivalent to duration: 0.35, bounce: 0.3 // rougly equivalent to duration: 0.35, bounce: 0.3
@ -90,7 +90,7 @@ class GalleryPresentationAnimationController: NSObject, UIViewControllerAnimated
content.view.frame = destFrameInContainer content.view.frame = destFrameInContainer
content.view.layer.opacity = 1 content.view.layer.opacity = 1
itemViewController.setControlsVisible(true, animated: false) itemViewController.setControlsVisible(true, animated: false, dueToUserInteraction: false)
if let sourceToDestTransform { if let sourceToDestTransform {
self.sourceView.transform = sourceToDestTransform self.sourceView.transform = sourceToDestTransform

View File

@ -125,6 +125,8 @@ extension GalleryViewController: UIPageViewControllerDataSource {
extension GalleryViewController: UIPageViewControllerDelegate { extension GalleryViewController: UIPageViewControllerDelegate {
public func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) { public func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
currentItemViewController.content.galleryContentWillDisappear() currentItemViewController.content.galleryContentWillDisappear()
let new = pendingViewControllers[0] as! GalleryItemViewController
new.setControlsVisible(currentItemViewController.controlsVisible, animated: false, dueToUserInteraction: false)
} }
public func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { public func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
@ -152,14 +154,21 @@ extension GalleryViewController: GalleryItemViewControllerDelegate {
extension GalleryViewController: UIViewControllerTransitioningDelegate { extension GalleryViewController: UIViewControllerTransitioningDelegate {
public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
#if os(visionOS)
return nil
#else
if let sourceView = galleryDataSource.galleryContentTransitionSourceView(forItemAt: initialItemIndex) { if let sourceView = galleryDataSource.galleryContentTransitionSourceView(forItemAt: initialItemIndex) {
return GalleryPresentationAnimationController(sourceView: sourceView) return GalleryPresentationAnimationController(sourceView: sourceView)
} else { } else {
return nil return nil
} }
#endif
} }
public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
#if os(visionOS)
return nil
#else
if let sourceView = galleryDataSource.galleryContentTransitionSourceView(forItemAt: currentItemViewController.itemIndex) { if let sourceView = galleryDataSource.galleryContentTransitionSourceView(forItemAt: currentItemViewController.itemIndex) {
let translation: CGPoint? let translation: CGPoint?
let velocity: CGPoint? let velocity: CGPoint?
@ -175,5 +184,6 @@ extension GalleryViewController: UIViewControllerTransitioningDelegate {
} else { } else {
return nil return nil
} }
#endif
} }
} }

View File

@ -1,4 +1,4 @@
// swift-tools-version: 5.7 // swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package. // The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription import PackageDescription
@ -6,7 +6,7 @@ import PackageDescription
let package = Package( let package = Package(
name: "InstanceFeatures", name: "InstanceFeatures",
platforms: [ platforms: [
.iOS(.v15), .iOS(.v16),
], ],
products: [ products: [
// Products define the executables and libraries a package produces, and make them visible to other packages. // Products define the executables and libraries a package produces, and make them visible to other packages.
@ -23,9 +23,15 @@ let package = Package(
// Targets can depend on other targets in this package, and on products in packages this package depends on. // Targets can depend on other targets in this package, and on products in packages this package depends on.
.target( .target(
name: "InstanceFeatures", name: "InstanceFeatures",
dependencies: ["Pachyderm"]), dependencies: ["Pachyderm"],
swiftSettings: [
.swiftLanguageMode(.v5)
]),
.testTarget( .testTarget(
name: "InstanceFeaturesTests", name: "InstanceFeaturesTests",
dependencies: ["InstanceFeatures"]), dependencies: ["InstanceFeatures"],
swiftSettings: [
.swiftLanguageMode(.v5)
]),
] ]
) )

View File

@ -157,7 +157,7 @@ public final class InstanceFeatures: ObservableObject {
} }
public var needsEditAttachmentsInSeparateRequest: Bool { public var needsEditAttachmentsInSeparateRequest: Bool {
instanceType.isPleroma(.akkoma(nil)) instanceType.isPleroma
} }
public var composeDirectStatuses: Bool { public var composeDirectStatuses: Bool {
@ -209,6 +209,26 @@ public final class InstanceFeatures: ObservableObject {
} }
} }
public var instanceAnnouncements: Bool {
hasMastodonVersion(3, 1, 0)
}
public var emojiReactionNotifications: Bool {
instanceType.isPleroma
}
public var muteNotifications: Bool {
!instanceType.isPixelfed
}
public var blockDomains: Bool {
!instanceType.isPixelfed
}
public var hideReblogs: Bool {
!instanceType.isPixelfed
}
public init() { public init() {
} }
@ -330,6 +350,14 @@ extension InstanceFeatures {
return false return false
} }
} }
var isPixelfed: Bool {
if case .pixelfed = self {
return true
} else {
return false
}
}
} }
@_spi(InstanceType) public enum MastodonType { @_spi(InstanceType) public enum MastodonType {

View File

@ -1,4 +1,4 @@
// swift-tools-version: 5.8 // swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package. // The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription import PackageDescription
@ -6,7 +6,7 @@ import PackageDescription
let package = Package( let package = Package(
name: "MatchedGeometryPresentation", name: "MatchedGeometryPresentation",
platforms: [ platforms: [
.iOS(.v15), .iOS(.v16),
], ],
products: [ products: [
// Products define the executables and libraries a package produces, making them visible to other packages. // Products define the executables and libraries a package produces, making them visible to other packages.
@ -18,7 +18,10 @@ let package = Package(
// Targets are the basic building blocks of a package, defining a module or a test suite. // Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies. // Targets can depend on other targets in this package and products from dependencies.
.target( .target(
name: "MatchedGeometryPresentation"), name: "MatchedGeometryPresentation",
swiftSettings: [
.swiftLanguageMode(.v5)
]),
// .testTarget( // .testTarget(
// name: "MatchedGeometryPresentationTests", // name: "MatchedGeometryPresentationTests",
// dependencies: ["MatchedGeometryPresentation"]), // dependencies: ["MatchedGeometryPresentation"]),

View File

@ -1,4 +1,4 @@
// swift-tools-version: 5.6 // swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package. // The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription import PackageDescription
@ -6,7 +6,7 @@ import PackageDescription
let package = Package( let package = Package(
name: "Pachyderm", name: "Pachyderm",
platforms: [ platforms: [
.iOS(.v15), .iOS(.v16),
], ],
products: [ products: [
// Products define the executables and libraries a package produces, and make them visible to other packages. // Products define the executables and libraries a package produces, and make them visible to other packages.
@ -16,7 +16,7 @@ let package = Package(
], ],
dependencies: [ dependencies: [
// Dependencies declare other packages that this package depends on. // Dependencies declare other packages that this package depends on.
.package(url: "https://github.com/karwa/swift-url.git", branch: "main"), .package(url: "https://github.com/karwa/swift-url.git", exact: "0.4.2"),
], ],
targets: [ targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets are the basic building blocks of a package. A target can define a module or a test suite.
@ -26,9 +26,15 @@ let package = Package(
dependencies: [ dependencies: [
.product(name: "WebURL", package: "swift-url"), .product(name: "WebURL", package: "swift-url"),
.product(name: "WebURLFoundationExtras", package: "swift-url"), .product(name: "WebURLFoundationExtras", package: "swift-url"),
],
swiftSettings: [
.swiftLanguageMode(.v5)
]), ]),
.testTarget( .testTarget(
name: "PachydermTests", name: "PachydermTests",
dependencies: ["Pachyderm"]), dependencies: ["Pachyderm"],
swiftSettings: [
.swiftLanguageMode(.v5)
]),
] ]
) )

View File

@ -42,7 +42,7 @@ public struct Client: Sendable {
} else if let date = iso8601.date(from: str) { } else if let date = iso8601.date(from: str) {
return date return date
} else { } else {
throw DecodingError.typeMismatch(Date.self, .init(codingPath: container.codingPath, debugDescription: "unexpected date format")) throw DecodingError.typeMismatch(Date.self, .init(codingPath: container.codingPath, debugDescription: "unexpected date format: \(str)"))
} }
}) })
@ -204,8 +204,8 @@ public struct Client: Sendable {
return Request<Account>(method: .get, path: "/api/v1/accounts/verify_credentials") return Request<Account>(method: .get, path: "/api/v1/accounts/verify_credentials")
} }
public static func getFavourites(range: RequestRange = .default) -> Request<[Status]> { public static func getFavourites(range: RequestRange = .default) -> Request<[TryDecode<Status>]> {
var request = Request<[Status]>(method: .get, path: "/api/v1/favourites") var request = Request<[TryDecode<Status>]>(method: .get, path: "/api/v1/favourites")
request.range = range request.range = range
return request return request
} }
@ -456,14 +456,13 @@ public struct Client: Sendable {
} }
// MARK: - Timelines // MARK: - Timelines
public static func getStatuses(timeline: Timeline, range: RequestRange = .default) -> Request<[Status]> { public static func getStatuses(timeline: Timeline, range: RequestRange = .default) -> Request<[TryDecode<Status>]> {
return timeline.request(range: range) return timeline.request(range: range)
} }
// MARK: - Bookmarks // MARK: - Bookmarks
public static func getBookmarks(range: RequestRange = .default) -> Request<[Status]> { public static func getBookmarks(range: RequestRange = .default) -> Request<[TryDecode<Status>]> {
var request = Request<[Status]>(method: .get, path: "/api/v1/bookmarks") var request = Request<[TryDecode<Status>]>(method: .get, path: "/api/v1/bookmarks")
request.range = range request.range = range
return request return request
} }
@ -491,7 +490,7 @@ public struct Client: Sendable {
return Request<[Hashtag]>(method: .get, path: "/api/v1/trends/tags", queryParameters: parameters) return Request<[Hashtag]>(method: .get, path: "/api/v1/trends/tags", queryParameters: parameters)
} }
public static func getTrendingStatuses(limit: Int? = nil, offset: Int? = nil) -> Request<[Status]> { public static func getTrendingStatuses(limit: Int? = nil, offset: Int? = nil) -> Request<[TryDecode<Status>]> {
var parameters: [Parameter] = [] var parameters: [Parameter] = []
if let limit { if let limit {
parameters.append("limit" => limit) parameters.append("limit" => limit)

View File

@ -40,8 +40,9 @@ public final class Account: AccountProtocol, Decodable, Sendable {
self.displayName = try container.decode(String.self, forKey: .displayName) self.displayName = try container.decode(String.self, forKey: .displayName)
self.locked = try container.decode(Bool.self, forKey: .locked) self.locked = try container.decode(Bool.self, forKey: .locked)
self.createdAt = try container.decode(Date.self, forKey: .createdAt) self.createdAt = try container.decode(Date.self, forKey: .createdAt)
self.followersCount = try container.decode(Int.self, forKey: .followersCount) // some instance types (pixelfed, firefish) seem to sometimes send null for these fields, so just fallback to 0
self.followingCount = try container.decode(Int.self, forKey: .followingCount) self.followersCount = try container.decodeIfPresent(Int.self, forKey: .followersCount) ?? 0
self.followingCount = try container.decodeIfPresent(Int.self, forKey: .followingCount) ?? 0
self.statusesCount = try container.decode(Int.self, forKey: .statusesCount) self.statusesCount = try container.decode(Int.self, forKey: .statusesCount)
self.note = try container.decode(String.self, forKey: .note) self.note = try container.decode(String.self, forKey: .note)
self.url = try container.decode(URL.self, forKey: .url) self.url = try container.decode(URL.self, forKey: .url)
@ -94,8 +95,8 @@ public final class Account: AccountProtocol, Decodable, Sendable {
return request return request
} }
public static func getStatuses(_ accountID: String, range: RequestRange = .default, onlyMedia: Bool? = nil, pinned: Bool? = nil, excludeReplies: Bool? = nil, excludeReblogs: Bool? = nil) -> Request<[Status]> { public static func getStatuses(_ accountID: String, range: RequestRange = .default, onlyMedia: Bool? = nil, pinned: Bool? = nil, excludeReplies: Bool? = nil, excludeReblogs: Bool? = nil) -> Request<[TryDecode<Status>]> {
var request = Request<[Status]>(method: .get, path: "/api/v1/accounts/\(accountID)/statuses", queryParameters: [ var request = Request<[TryDecode<Status>]>(method: .get, path: "/api/v1/accounts/\(accountID)/statuses", queryParameters: [
"only_media" => onlyMedia, "only_media" => onlyMedia,
"pinned" => pinned, "pinned" => pinned,
"exclude_replies" => excludeReplies, "exclude_replies" => excludeReplies,

View File

@ -0,0 +1,99 @@
//
// Announcement.swift
// Pachyderm
//
// Created by Shadowfacts on 4/16/24.
//
import Foundation
import WebURL
public struct Announcement: Decodable, Sendable, Hashable, Identifiable {
public let id: String
public let content: String
public let startsAt: Date?
public let endsAt: Date?
public let allDay: Bool
public let publishedAt: Date
public let updatedAt: Date
public let read: Bool?
public let mentions: [Account]
public let statuses: [Status]
public let tags: [Hashtag]
public let emojis: [Emoji]
public var reactions: [Reaction]
public static func all() -> Request<[Announcement]> {
return Request(method: .get, path: "/api/v1/announcements")
}
public static func dismiss(id: String) -> Request<Empty> {
return Request(method: .post, path: "/api/v1/announcements/\(id)/dismiss")
}
public static func react(id: String, name: String) -> Request<Empty> {
return Request(method: .put, path: "/api/v1/announcements/\(id)/reactions/\(name)")
}
public static func unreact(id: String, name: String) -> Request<Empty> {
return Request(method: .delete, path: "/api/v1/announcements/\(id)/reactions/\(name)")
}
enum CodingKeys: String, CodingKey {
case id
case content
case startsAt = "starts_at"
case endsAt = "ends_at"
case allDay = "all_day"
case publishedAt = "published_at"
case updatedAt = "updated_at"
case read
case mentions
case statuses
case tags
case emojis
case reactions
}
}
extension Announcement {
public struct Account: Decodable, Sendable, Hashable {
public let id: String
public let username: String
public let url: WebURL
public let acct: String
}
}
extension Announcement {
public struct Status: Decodable, Sendable, Hashable {
public let id: String
public let url: WebURL
}
}
extension Announcement {
public struct Reaction: Decodable, Sendable, Hashable {
public let name: String
public var count: Int
public var me: Bool?
public let url: URL?
public let staticURL: URL?
public init(name: String, count: Int, me: Bool?, url: URL?, staticURL: URL?) {
self.name = name
self.count = count
self.me = me
self.url = url
self.staticURL = staticURL
}
enum CodingKeys: String, CodingKey {
case name
case count
case me
case url
case staticURL = "static_url"
}
}
}

View File

@ -43,8 +43,13 @@ extension Emoji: CustomDebugStringConvertible {
} }
} }
extension Emoji: Equatable { extension Emoji: Equatable, Hashable {
public static func ==(lhs: Emoji, rhs: Emoji) -> Bool { public static func ==(lhs: Emoji, rhs: Emoji) -> Bool {
return lhs.shortcode == rhs.shortcode && lhs.url == rhs.url return lhs.shortcode == rhs.shortcode && lhs.url == rhs.url
} }
public func hash(into hasher: inout Hasher) {
hasher.combine(shortcode)
hasher.combine(url)
}
} }

View File

@ -53,7 +53,7 @@ extension InstanceV2 {
public struct Thumbnail: Decodable, Sendable { public struct Thumbnail: Decodable, Sendable {
public let url: String public let url: String
public let blurhash: String? public let blurhash: String?
public let versions: ThumbnailVersions public let versions: ThumbnailVersions?
} }
public struct ThumbnailVersions: Decodable, Sendable { public struct ThumbnailVersions: Decodable, Sendable {
@ -120,6 +120,6 @@ extension InstanceV2 {
extension InstanceV2 { extension InstanceV2 {
public struct Contact: Decodable, Sendable { public struct Contact: Decodable, Sendable {
public let email: String public let email: String
public let account: Account public let account: Account?
} }
} }

View File

@ -7,6 +7,7 @@
// //
import Foundation import Foundation
import WebURL
public struct Notification: Decodable, Sendable { public struct Notification: Decodable, Sendable {
public let id: String public let id: String
@ -14,6 +15,10 @@ public struct Notification: Decodable, Sendable {
public let createdAt: Date public let createdAt: Date
public let account: Account public let account: Account
public let status: Status? public let status: Status?
// Only present for pleroma emoji reactions
// Either an emoji or :shortcode: (for akkoma custom emoji reactions)
public let emoji: String?
public let emojiURL: WebURL?
public init(from decoder: Decoder) throws { public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self) let container = try decoder.container(keyedBy: CodingKeys.self)
@ -27,6 +32,8 @@ public struct Notification: Decodable, Sendable {
self.createdAt = try container.decode(Date.self, forKey: .createdAt) self.createdAt = try container.decode(Date.self, forKey: .createdAt)
self.account = try container.decode(Account.self, forKey: .account) self.account = try container.decode(Account.self, forKey: .account)
self.status = try container.decodeIfPresent(Status.self, forKey: .status) self.status = try container.decodeIfPresent(Status.self, forKey: .status)
self.emoji = try container.decodeIfPresent(String.self, forKey: .emoji)
self.emojiURL = try container.decodeIfPresent(WebURL.self, forKey: .emojiURL)
} }
public static func dismiss(id notificationID: String) -> Request<Empty> { public static func dismiss(id notificationID: String) -> Request<Empty> {
@ -39,6 +46,8 @@ public struct Notification: Decodable, Sendable {
case createdAt = "created_at" case createdAt = "created_at"
case account case account
case status case status
case emoji
case emojiURL = "emoji_url"
} }
} }
@ -52,6 +61,7 @@ extension Notification {
case poll case poll
case update case update
case status case status
case emojiReaction = "pleroma:emoji_reaction"
case unknown case unknown
} }
} }

View File

@ -16,7 +16,7 @@ public struct Poll: Codable, Sendable {
public let votesCount: Int public let votesCount: Int
public let votersCount: Int? public let votersCount: Int?
public let voted: Bool? public let voted: Bool?
public let ownVotes: [Int]? public let ownVotes: [Int?]?
public let options: [Option] public let options: [Option]
public let emojis: [Emoji] public let emojis: [Emoji]
@ -33,7 +33,7 @@ public struct Poll: Codable, Sendable {
self.votesCount = try container.decode(Int.self, forKey: .votesCount) self.votesCount = try container.decode(Int.self, forKey: .votesCount)
self.votersCount = try container.decodeIfPresent(Int.self, forKey: .votersCount) self.votersCount = try container.decodeIfPresent(Int.self, forKey: .votersCount)
self.voted = try container.decodeIfPresent(Bool.self, forKey: .voted) self.voted = try container.decodeIfPresent(Bool.self, forKey: .voted)
self.ownVotes = try container.decodeIfPresent([Int].self, forKey: .ownVotes) self.ownVotes = try container.decodeIfPresent([Int?].self, forKey: .ownVotes)
self.options = try container.decode([Poll.Option].self, forKey: .options) self.options = try container.decode([Poll.Option].self, forKey: .options)
self.emojis = try container.decodeIfPresent([Emoji].self, forKey: .emojis) ?? [] self.emojis = try container.decodeIfPresent([Emoji].self, forKey: .emojis) ?? []
} }

View File

@ -44,6 +44,7 @@ public struct PushSubscription: Decodable, Sendable {
"data[alerts][favourite]" => alerts.favourite, "data[alerts][favourite]" => alerts.favourite,
"data[alerts][poll]" => alerts.poll, "data[alerts][poll]" => alerts.poll,
"data[alerts][update]" => alerts.update, "data[alerts][update]" => alerts.update,
"data[alerts][pleroma:emoji_reaction]" => alerts.emojiReaction,
"data[policy]" => policy.rawValue, "data[policy]" => policy.rawValue,
])) ]))
} }
@ -58,6 +59,7 @@ public struct PushSubscription: Decodable, Sendable {
"data[alerts][favourite]" => alerts.favourite, "data[alerts][favourite]" => alerts.favourite,
"data[alerts][poll]" => alerts.poll, "data[alerts][poll]" => alerts.poll,
"data[alerts][update]" => alerts.update, "data[alerts][update]" => alerts.update,
"data[alerts][pleroma:emoji_reaction]" => alerts.emojiReaction,
"data[policy]" => policy.rawValue, "data[policy]" => policy.rawValue,
])) ]))
} }
@ -85,8 +87,19 @@ extension PushSubscription {
public let favourite: Bool public let favourite: Bool
public let poll: Bool public let poll: Bool
public let update: Bool public let update: Bool
public let emojiReaction: Bool
public init(mention: Bool, status: Bool, reblog: Bool, follow: Bool, followRequest: Bool, favourite: Bool, poll: Bool, update: Bool) {
public init(
mention: Bool,
status: Bool,
reblog: Bool,
follow: Bool,
followRequest: Bool,
favourite: Bool,
poll: Bool,
update: Bool,
emojiReaction: Bool
) {
self.mention = mention self.mention = mention
self.status = status self.status = status
self.reblog = reblog self.reblog = reblog
@ -95,6 +108,7 @@ extension PushSubscription {
self.favourite = favourite self.favourite = favourite
self.poll = poll self.poll = poll
self.update = update self.update = update
self.emojiReaction = emojiReaction
} }
public init(from decoder: any Decoder) throws { public init(from decoder: any Decoder) throws {
@ -110,6 +124,8 @@ extension PushSubscription {
self.poll = try container.decode(Bool.self, forKey: PushSubscription.Alerts.CodingKeys.poll) self.poll = try container.decode(Bool.self, forKey: PushSubscription.Alerts.CodingKeys.poll)
// update added in mastodon 3.5.0 // update added in mastodon 3.5.0
self.update = try container.decodeIfPresent(Bool.self, forKey: PushSubscription.Alerts.CodingKeys.update) ?? false self.update = try container.decodeIfPresent(Bool.self, forKey: PushSubscription.Alerts.CodingKeys.update) ?? false
// pleroma/akkoma only
self.emojiReaction = try container.decodeIfPresent(Bool.self, forKey: .emojiReaction) ?? false
} }
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
@ -121,6 +137,7 @@ extension PushSubscription {
case favourite case favourite
case poll case poll
case update case update
case emojiReaction = "pleroma:emoji_reaction"
} }
} }
} }

View File

@ -27,10 +27,13 @@ public struct Relationship: RelationshipProtocol, Decodable, Sendable {
self.followedBy = try container.decode(Bool.self, forKey: .followedBy) self.followedBy = try container.decode(Bool.self, forKey: .followedBy)
self.blocking = try container.decode(Bool.self, forKey: .blocking) self.blocking = try container.decode(Bool.self, forKey: .blocking)
self.muting = try container.decode(Bool.self, forKey: .muting) self.muting = try container.decode(Bool.self, forKey: .muting)
self.mutingNotifications = try container.decode(Bool.self, forKey: .mutingNotifications) // not supported on pixelfed
self.mutingNotifications = try container.decodeIfPresent(Bool.self, forKey: .mutingNotifications) ?? false
self.followRequested = try container.decode(Bool.self, forKey: .followRequested) self.followRequested = try container.decode(Bool.self, forKey: .followRequested)
self.domainBlocking = try container.decode(Bool.self, forKey: .domainBlocking) // not supported on pixelfed
self.showingReblogs = try container.decode(Bool.self, forKey: .showingReblogs) self.domainBlocking = try container.decodeIfPresent(Bool.self, forKey: .domainBlocking) ?? false
// not supported on pixelfed
self.showingReblogs = try container.decodeIfPresent(Bool.self, forKey: .showingReblogs) ?? true
self.endorsed = try container.decodeIfPresent(Bool.self, forKey: .endorsed) ?? false self.endorsed = try container.decodeIfPresent(Bool.self, forKey: .endorsed) ?? false
} }

View File

@ -10,7 +10,7 @@ import Foundation
public struct SearchResults: Decodable, Sendable { public struct SearchResults: Decodable, Sendable {
public let accounts: [Account] public let accounts: [Account]
public let statuses: [Status] public let statuses: [TryDecode<Status>]
public let hashtags: [Hashtag] public let hashtags: [Hashtag]
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {

View File

@ -124,6 +124,12 @@ public final class Status: StatusProtocol, Decodable, Sendable {
return request return request
} }
public static func getReactions(_ statusID: String, emoji: String, range: RequestRange = .default) -> Request<[Account]> {
var request = Request<[Account]>(method: .get, path: "/api/v1/statuses/\(statusID)/reactions/\(emoji)")
request.range = range
return request
}
public static func delete(_ statusID: String) -> Request<Empty> { public static func delete(_ statusID: String) -> Request<Empty> {
return Request<Empty>(method: .delete, path: "/api/v1/statuses/\(statusID)") return Request<Empty>(method: .delete, path: "/api/v1/statuses/\(statusID)")
} }

View File

@ -32,8 +32,8 @@ extension Timeline {
} }
} }
func request(range: RequestRange) -> Request<[Status]> { func request(range: RequestRange) -> Request<[TryDecode<Status>]> {
var request: Request<[Status]> = Request<[Status]>(method: .get, path: endpoint) var request = Request<[TryDecode<Status>]>(method: .get, path: endpoint)
if case .public(true) = self { if case .public(true) = self {
request.queryParameters.append("local" => true) request.queryParameters.append("local" => true)
} }

View File

@ -7,17 +7,18 @@
// //
import Foundation import Foundation
import WebURL
public struct NotificationGroup: Identifiable, Hashable, Sendable { public struct NotificationGroup: Identifiable, Hashable, Sendable {
public private(set) var notifications: [Notification] public private(set) var notifications: [Notification]
public let id: String public let id: String
public let kind: Notification.Kind public let kind: Kind
public init?(notifications: [Notification]) { public init?(notifications: [Notification], kind: Kind) {
guard !notifications.isEmpty else { return nil } guard !notifications.isEmpty else { return nil }
self.notifications = notifications self.notifications = notifications
self.id = notifications.first!.id self.id = notifications.first!.id
self.kind = notifications.first!.kind self.kind = kind
} }
public static func ==(lhs: NotificationGroup, rhs: NotificationGroup) -> Bool { public static func ==(lhs: NotificationGroup, rhs: NotificationGroup) -> Bool {
@ -43,31 +44,62 @@ public struct NotificationGroup: Identifiable, Hashable, Sendable {
private mutating func append(group: NotificationGroup) { private mutating func append(group: NotificationGroup) {
notifications.append(contentsOf: group.notifications) notifications.append(contentsOf: group.notifications)
} }
private static func groupKind(for notification: Notification) -> Kind {
switch notification.kind {
case .mention:
return .mention
case .reblog:
return .reblog
case .favourite:
return .favourite
case .follow:
return .follow
case .followRequest:
return .followRequest
case .poll:
return .poll
case .update:
return .update
case .status:
return .status
case .emojiReaction:
if let emoji = notification.emoji {
return .emojiReaction(emoji, notification.emojiURL)
} else {
return .unknown
}
case .unknown:
return .unknown
}
}
@MainActor @MainActor
public static func createGroups(notifications: [Notification], only allowedTypes: [Notification.Kind]) -> [NotificationGroup] { public static func createGroups(notifications: [Notification], only allowedTypes: [Notification.Kind]) -> [NotificationGroup] {
var groups = [NotificationGroup]() var groups = [NotificationGroup]()
for notification in notifications { for notification in notifications {
let groupKind = groupKind(for: notification)
if allowedTypes.contains(notification.kind) { if allowedTypes.contains(notification.kind) {
if let lastGroup = groups.last, canMerge(notification: notification, into: lastGroup) { if let lastGroup = groups.last, canMerge(notification: notification, kind: groupKind, into: lastGroup) {
groups[groups.count - 1].append(notification) groups[groups.count - 1].append(notification)
continue continue
} else if groups.count >= 2 { } else if groups.count >= 2 {
let secondToLastGroup = groups[groups.count - 2] let secondToLastGroup = groups[groups.count - 2]
if allowedTypes.contains(groups[groups.count - 1].kind), canMerge(notification: notification, into: secondToLastGroup) { if allowedTypes.contains(notification.kind), canMerge(notification: notification, kind: groupKind, into: secondToLastGroup) {
groups[groups.count - 2].append(notification) groups[groups.count - 2].append(notification)
continue continue
} }
} }
} }
groups.append(NotificationGroup(notifications: [notification])!) groups.append(NotificationGroup(notifications: [notification], kind: groupKind)!)
} }
return groups return groups
} }
private static func canMerge(notification: Notification, into group: NotificationGroup) -> Bool { private static func canMerge(notification: Notification, kind: Kind, into group: NotificationGroup) -> Bool {
return notification.kind == group.kind && notification.status?.id == group.notifications.first!.status?.id return kind == group.kind && notification.status?.id == group.notifications.first!.status?.id
} }
public static func mergeGroups(first: [NotificationGroup], second: [NotificationGroup], only allowedTypes: [Notification.Kind]) -> [NotificationGroup] { public static func mergeGroups(first: [NotificationGroup], second: [NotificationGroup], only allowedTypes: [Notification.Kind]) -> [NotificationGroup] {
@ -82,21 +114,21 @@ public struct NotificationGroup: Identifiable, Hashable, Sendable {
var second = second var second = second
merged.reserveCapacity(second.count) merged.reserveCapacity(second.count)
while let firstGroupFromSecond = second.first, while let firstGroupFromSecond = second.first,
allowedTypes.contains(firstGroupFromSecond.kind) { allowedTypes.contains(firstGroupFromSecond.kind.notificationKind) {
second.removeFirst() second.removeFirst()
guard let lastGroup = merged.last, guard let lastGroup = merged.last,
allowedTypes.contains(lastGroup.kind) else { allowedTypes.contains(lastGroup.kind.notificationKind) else {
merged.append(firstGroupFromSecond) merged.append(firstGroupFromSecond)
break break
} }
if canMerge(notification: firstGroupFromSecond.notifications.first!, into: lastGroup) { if canMerge(notification: firstGroupFromSecond.notifications.first!, kind: firstGroupFromSecond.kind, into: lastGroup) {
merged[merged.count - 1].append(group: firstGroupFromSecond) merged[merged.count - 1].append(group: firstGroupFromSecond)
} else if merged.count >= 2 { } else if merged.count >= 2 {
let secondToLastGroup = merged[merged.count - 2] let secondToLastGroup = merged[merged.count - 2]
if allowedTypes.contains(secondToLastGroup.kind), canMerge(notification: firstGroupFromSecond.notifications.first!, into: secondToLastGroup) { if allowedTypes.contains(secondToLastGroup.kind.notificationKind), canMerge(notification: firstGroupFromSecond.notifications.first!, kind: firstGroupFromSecond.kind, into: secondToLastGroup) {
merged[merged.count - 2].append(group: firstGroupFromSecond) merged[merged.count - 2].append(group: firstGroupFromSecond)
} else { } else {
merged.append(firstGroupFromSecond) merged.append(firstGroupFromSecond)
@ -109,4 +141,42 @@ public struct NotificationGroup: Identifiable, Hashable, Sendable {
return merged return merged
} }
public enum Kind: Sendable, Equatable {
case mention
case reblog
case favourite
case follow
case followRequest
case poll
case update
case status
case emojiReaction(String, WebURL?)
case unknown
var notificationKind: Notification.Kind {
switch self {
case .mention:
.mention
case .reblog:
.reblog
case .favourite:
.favourite
case .follow:
.follow
case .followRequest:
.followRequest
case .poll:
.poll
case .update:
.update
case .status:
.status
case .emojiReaction(_, _):
.emojiReaction
case .unknown:
.unknown
}
}
}
} }

View File

@ -0,0 +1,32 @@
//
// TryDecode.swift
// Pachyderm
//
// Created by Shadowfacts on 6/8/24.
//
import Foundation
public enum TryDecode<T: Decodable>: Decodable {
case error(String)
case value(T)
public init(from decoder: any Decoder) throws {
do {
self = .value(try T(from: decoder))
} catch {
self = .error(error.localizedDescription)
}
}
public var value: T? {
if case .value(let value) = self {
value
} else {
nil
}
}
}
extension TryDecode: Sendable where T: Sendable {
}

View File

@ -1,4 +1,4 @@
// swift-tools-version: 5.10 // swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package. // The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription import PackageDescription
@ -6,7 +6,7 @@ import PackageDescription
let package = Package( let package = Package(
name: "PushNotifications", name: "PushNotifications",
platforms: [ platforms: [
.iOS(.v15), .iOS(.v16),
], ],
products: [ products: [
// Products define the executables and libraries a package produces, making them visible to other packages. // Products define the executables and libraries a package produces, making them visible to other packages.
@ -23,10 +23,17 @@ let package = Package(
// Targets can depend on other targets in this package and products from dependencies. // Targets can depend on other targets in this package and products from dependencies.
.target( .target(
name: "PushNotifications", name: "PushNotifications",
dependencies: ["UserAccounts", "Pachyderm"] dependencies: ["UserAccounts", "Pachyderm"],
swiftSettings: [
.swiftLanguageMode(.v5)
]
), ),
.testTarget( .testTarget(
name: "PushNotificationsTests", name: "PushNotificationsTests",
dependencies: ["PushNotifications"]), dependencies: ["PushNotifications"],
swiftSettings: [
.swiftLanguageMode(.v5)
]
),
] ]
) )

View File

@ -104,6 +104,7 @@ class PushManagerImpl: _PushManager {
self.subscriptions = await AsyncSequenceAdaptor(wrapping: subscriptions).map { self.subscriptions = await AsyncSequenceAdaptor(wrapping: subscriptions).map {
let newEndpoint = await self.endpointURL(deviceToken: token, accountID: $0.accountID) let newEndpoint = await self.endpointURL(deviceToken: token, accountID: $0.accountID)
guard newEndpoint != $0.endpoint else { guard newEndpoint != $0.endpoint else {
PushManager.logger.debug("Skipping update of push subscription with endpoint \($0.endpoint, privacy: .public)")
return $0 return $0
} }
var copy = $0 var copy = $0

View File

@ -70,6 +70,7 @@ public struct PushSubscription {
public static let favorite = Alerts(rawValue: 1 << 5) public static let favorite = Alerts(rawValue: 1 << 5)
public static let poll = Alerts(rawValue: 1 << 6) public static let poll = Alerts(rawValue: 1 << 6)
public static let update = Alerts(rawValue: 1 << 7) public static let update = Alerts(rawValue: 1 << 7)
public static let emojiReaction = Alerts(rawValue: 1 << 8)
public let rawValue: Int public let rawValue: Int

View File

@ -1,4 +1,4 @@
// swift-tools-version: 5.7 // swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package. // The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription import PackageDescription
@ -6,7 +6,7 @@ import PackageDescription
let package = Package( let package = Package(
name: "TTTKit", name: "TTTKit",
platforms: [ platforms: [
.iOS(.v15), .iOS(.v16),
], ],
products: [ products: [
// Products define the executables and libraries a package produces, and make them visible to other packages. // Products define the executables and libraries a package produces, and make them visible to other packages.
@ -23,9 +23,15 @@ let package = Package(
// Targets can depend on other targets in this package, and on products in packages this package depends on. // Targets can depend on other targets in this package, and on products in packages this package depends on.
.target( .target(
name: "TTTKit", name: "TTTKit",
dependencies: []), dependencies: [],
swiftSettings: [
.swiftLanguageMode(.v5)
]),
.testTarget( .testTarget(
name: "TTTKitTests", name: "TTTKitTests",
dependencies: ["TTTKit"]), dependencies: ["TTTKit"],
swiftSettings: [
.swiftLanguageMode(.v5)
]),
] ]
) )

View File

@ -1,4 +1,4 @@
// swift-tools-version: 5.7 // swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package. // The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription import PackageDescription
@ -6,7 +6,7 @@ import PackageDescription
let package = Package( let package = Package(
name: "TuskerComponents", name: "TuskerComponents",
platforms: [ platforms: [
.iOS(.v15), .iOS(.v16),
], ],
products: [ products: [
// Products define the executables and libraries a package produces, and make them visible to other packages. // Products define the executables and libraries a package produces, and make them visible to other packages.
@ -23,7 +23,10 @@ let package = Package(
// Targets can depend on other targets in this package, and on products in packages this package depends on. // Targets can depend on other targets in this package, and on products in packages this package depends on.
.target( .target(
name: "TuskerComponents", name: "TuskerComponents",
dependencies: []), dependencies: [],
swiftSettings: [
.swiftLanguageMode(.v5)
]),
// .testTarget( // .testTarget(
// name: "TuskerComponentsTests", // name: "TuskerComponentsTests",
// dependencies: ["TuskerComponents"]), // dependencies: ["TuskerComponents"]),

View File

@ -9,21 +9,14 @@ import SwiftUI
public struct AsyncPicker<V: Hashable, Content: View>: View { public struct AsyncPicker<V: Hashable, Content: View>: View {
let titleKey: LocalizedStringKey let titleKey: LocalizedStringKey
#if !os(visionOS)
@available(iOS, obsoleted: 16.0, message: "Switch to LabeledContent")
let labelHidden: Bool
#endif
let alignment: Alignment let alignment: Alignment
@Binding var value: V @Binding var value: V
let onChange: (V) async -> Bool let onChange: (V) async -> Bool
let content: Content let content: Content
@State private var isLoading = false @State private var isLoading = false
public init(_ titleKey: LocalizedStringKey, labelHidden: Bool = false, alignment: Alignment = .center, value: Binding<V>, onChange: @escaping (V) async -> Bool, @ViewBuilder content: () -> Content) { public init(_ titleKey: LocalizedStringKey, alignment: Alignment = .center, value: Binding<V>, onChange: @escaping (V) async -> Bool, @ViewBuilder content: () -> Content) {
self.titleKey = titleKey self.titleKey = titleKey
#if !os(visionOS)
self.labelHidden = labelHidden
#endif
self.alignment = alignment self.alignment = alignment
self._value = value self._value = value
self.onChange = onChange self.onChange = onChange
@ -31,25 +24,9 @@ public struct AsyncPicker<V: Hashable, Content: View>: View {
} }
public var body: some View { public var body: some View {
#if os(visionOS)
LabeledContent(titleKey) { LabeledContent(titleKey) {
picker picker
} }
#else
if #available(iOS 16.0, *) {
LabeledContent(titleKey) {
picker
}
} else if labelHidden {
picker
} else {
HStack {
Text(titleKey)
Spacer()
picker
}
}
#endif
} }
private var picker: some View { private var picker: some View {

View File

@ -10,42 +10,19 @@ import SwiftUI
public struct AsyncToggle: View { public struct AsyncToggle: View {
let titleKey: LocalizedStringKey let titleKey: LocalizedStringKey
#if !os(visionOS)
@available(iOS, obsoleted: 16.0, message: "Switch to LabeledContent")
let labelHidden: Bool
#endif
@Binding var mode: Mode @Binding var mode: Mode
let onChange: (Bool) async -> Bool let onChange: (Bool) async -> Bool
public init(_ titleKey: LocalizedStringKey, labelHidden: Bool = false, mode: Binding<Mode>, onChange: @escaping (Bool) async -> Bool) { public init(_ titleKey: LocalizedStringKey, mode: Binding<Mode>, onChange: @escaping (Bool) async -> Bool) {
self.titleKey = titleKey self.titleKey = titleKey
#if !os(visionOS)
self.labelHidden = labelHidden
#endif
self._mode = mode self._mode = mode
self.onChange = onChange self.onChange = onChange
} }
public var body: some View { public var body: some View {
#if os(visionOS)
LabeledContent(titleKey) { LabeledContent(titleKey) {
toggleOrSpinner toggleOrSpinner
} }
#else
if #available(iOS 16.0, *) {
LabeledContent(titleKey) {
toggleOrSpinner
}
} else if labelHidden {
toggleOrSpinner
} else {
HStack {
Text(titleKey)
Spacer()
toggleOrSpinner
}
}
#endif
} }
@ViewBuilder @ViewBuilder

View File

@ -1,6 +1,6 @@
// //
// FuzzyMatcher.swift // FuzzyMatcher.swift
// ComposeUI // TuskerComponents
// //
// Created by Shadowfacts on 10/10/20. // Created by Shadowfacts on 10/10/20.
// Copyright © 2020 Shadowfacts. All rights reserved. // Copyright © 2020 Shadowfacts. All rights reserved.
@ -8,7 +8,7 @@
import Foundation import Foundation
struct FuzzyMatcher { public struct FuzzyMatcher {
private init() {} private init() {}
@ -21,7 +21,7 @@ struct FuzzyMatcher {
/// +2 points for every char in `pattern` that occurs in `str` sequentially /// +2 points for every char in `pattern` that occurs in `str` sequentially
/// -2 points for every char in `pattern` that does not occur in `str` sequentially /// -2 points for every char in `pattern` that does not occur in `str` sequentially
/// -1 point for every char in `str` skipped between matching chars from the `pattern` /// -1 point for every char in `str` skipped between matching chars from the `pattern`
static func match(pattern: String, str: String) -> (matched: Bool, score: Int) { public static func match(pattern: String, str: String) -> (matched: Bool, score: Int) {
let pattern = pattern.lowercased() let pattern = pattern.lowercased()
let str = str.lowercased() let str = str.lowercased()

View File

@ -47,9 +47,7 @@ public struct MenuPicker<Value: Hashable>: UIViewRepresentable {
private func makeConfiguration() -> UIButton.Configuration { private func makeConfiguration() -> UIButton.Configuration {
var config = UIButton.Configuration.borderless() var config = UIButton.Configuration.borderless()
if #available(iOS 16.0, *) { config.indicator = .popup
config.indicator = .popup
}
if buttonStyle.hasIcon { if buttonStyle.hasIcon {
config.image = selectedOption.image config.image = selectedOption.image
} }

View File

@ -1,4 +1,4 @@
// swift-tools-version: 5.8 // swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package. // The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription import PackageDescription
@ -6,7 +6,7 @@ import PackageDescription
let package = Package( let package = Package(
name: "TuskerPreferences", name: "TuskerPreferences",
platforms: [ platforms: [
.iOS(.v15), .iOS(.v16),
], ],
products: [ products: [
// Products define the executables and libraries a package produces, making them visible to other packages. // Products define the executables and libraries a package produces, making them visible to other packages.
@ -22,11 +22,17 @@ let package = Package(
// Targets can depend on other targets in this package and products from dependencies. // Targets can depend on other targets in this package and products from dependencies.
.target( .target(
name: "TuskerPreferences", name: "TuskerPreferences",
dependencies: ["Pachyderm"] dependencies: ["Pachyderm"],
swiftSettings: [
.swiftLanguageMode(.v5)
]
), ),
.testTarget( .testTarget(
name: "TuskerPreferencesTests", name: "TuskerPreferencesTests",
dependencies: ["TuskerPreferences"] dependencies: ["TuskerPreferences"],
swiftSettings: [
.swiftLanguageMode(.v5)
]
) )
] ]
) )

View File

@ -74,4 +74,9 @@ extension PreferenceStore {
public func hasFeatureFlag(_ flag: FeatureFlag) -> Bool { public func hasFeatureFlag(_ flag: FeatureFlag) -> Bool {
enabledFeatureFlags.contains(flag) enabledFeatureFlags.contains(flag)
} }
public func getValue<Key: PreferenceKey>(preferenceKeyPath: KeyPath<PreferenceStore, PreferencePublisher<Key>>) -> Key.Value {
self[keyPath: preferenceKeyPath].preference.wrappedValue
}
} }

View File

@ -9,4 +9,5 @@ import Foundation
public enum FeatureFlag: String, Codable { public enum FeatureFlag: String, Codable {
case iPadBrowserNavigation = "ipad-browser-navigation" case iPadBrowserNavigation = "ipad-browser-navigation"
case pushNotifCustomEmoji = "push-notif-custom-emoji"
} }

View File

@ -1,4 +1,4 @@
// swift-tools-version: 5.7 // swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package. // The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription import PackageDescription
@ -6,7 +6,7 @@ import PackageDescription
let package = Package( let package = Package(
name: "UserAccounts", name: "UserAccounts",
platforms: [ platforms: [
.iOS(.v15), .iOS(.v16),
], ],
products: [ products: [
// Products define the executables and libraries a package produces, and make them visible to other packages. // Products define the executables and libraries a package produces, and make them visible to other packages.
@ -23,7 +23,10 @@ let package = Package(
// Targets can depend on other targets in this package, and on products in packages this package depends on. // Targets can depend on other targets in this package, and on products in packages this package depends on.
.target( .target(
name: "UserAccounts", name: "UserAccounts",
dependencies: ["Pachyderm"]), dependencies: ["Pachyderm"],
swiftSettings: [
.swiftLanguageMode(.v5)
]),
// .testTarget( // .testTarget(
// name: "UserAccountsTests", // name: "UserAccountsTests",
// dependencies: ["UserAccounts"]), // dependencies: ["UserAccounts"]),

View File

@ -36,6 +36,7 @@
D60E2F2E244248BF005F8713 /* MastodonCachePersistentStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = D60E2F2D244248BF005F8713 /* MastodonCachePersistentStore.swift */; }; D60E2F2E244248BF005F8713 /* MastodonCachePersistentStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = D60E2F2D244248BF005F8713 /* MastodonCachePersistentStore.swift */; };
D6114E0D27F7FEB30080E273 /* TrendingStatusesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6114E0C27F7FEB30080E273 /* TrendingStatusesViewController.swift */; }; D6114E0D27F7FEB30080E273 /* TrendingStatusesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6114E0C27F7FEB30080E273 /* TrendingStatusesViewController.swift */; };
D6114E1127F899B30080E273 /* TrendingLinksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6114E1027F899B30080E273 /* TrendingLinksViewController.swift */; }; D6114E1127F899B30080E273 /* TrendingLinksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6114E1027F899B30080E273 /* TrendingLinksViewController.swift */; };
D6187BED2BFA840B00B3A281 /* FollowRequestNotificationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6187BEC2BFA840B00B3A281 /* FollowRequestNotificationViewController.swift */; };
D61A45E628DC0F2F002BE511 /* ConfirmLoadMoreCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D61A45E528DC0F2F002BE511 /* ConfirmLoadMoreCollectionViewCell.swift */; }; D61A45E628DC0F2F002BE511 /* ConfirmLoadMoreCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D61A45E528DC0F2F002BE511 /* ConfirmLoadMoreCollectionViewCell.swift */; };
D61A45E828DF477D002BE511 /* LoadingCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D61A45E728DF477D002BE511 /* LoadingCollectionViewCell.swift */; }; D61A45E828DF477D002BE511 /* LoadingCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D61A45E728DF477D002BE511 /* LoadingCollectionViewCell.swift */; };
D61A45EA28DF51EE002BE511 /* TimelineLikeCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D61A45E928DF51EE002BE511 /* TimelineLikeCollectionViewController.swift */; }; D61A45EA28DF51EE002BE511 /* TimelineLikeCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D61A45E928DF51EE002BE511 /* TimelineLikeCollectionViewController.swift */; };
@ -74,7 +75,9 @@
D620483423D3801D008A63EF /* LinkTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D620483323D3801D008A63EF /* LinkTextView.swift */; }; D620483423D3801D008A63EF /* LinkTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D620483323D3801D008A63EF /* LinkTextView.swift */; };
D620483623D38075008A63EF /* ContentTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D620483523D38075008A63EF /* ContentTextView.swift */; }; D620483623D38075008A63EF /* ContentTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D620483523D38075008A63EF /* ContentTextView.swift */; };
D620483823D38190008A63EF /* StatusContentTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D620483723D38190008A63EF /* StatusContentTextView.swift */; }; D620483823D38190008A63EF /* StatusContentTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D620483723D38190008A63EF /* StatusContentTextView.swift */; };
D6210D762C0B924F009BB569 /* RemoveProfileSuggestionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6210D752C0B924F009BB569 /* RemoveProfileSuggestionService.swift */; };
D621733328F1D5ED004C7DB1 /* ReblogService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D621733228F1D5ED004C7DB1 /* ReblogService.swift */; }; D621733328F1D5ED004C7DB1 /* ReblogService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D621733228F1D5ED004C7DB1 /* ReblogService.swift */; };
D62220472C7EA8DF003E43B7 /* TuskerPreferences in Frameworks */ = {isa = PBXBuildFile; productRef = D62220462C7EA8DF003E43B7 /* TuskerPreferences */; };
D62275A824F1CA2800B82A16 /* ComposeReplyContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62275A724F1CA2800B82A16 /* ComposeReplyContentView.swift */; }; D62275A824F1CA2800B82A16 /* ComposeReplyContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62275A724F1CA2800B82A16 /* ComposeReplyContentView.swift */; };
D623A53D2635F5590095BD04 /* StatusPollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D623A53C2635F5590095BD04 /* StatusPollView.swift */; }; D623A53D2635F5590095BD04 /* StatusPollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D623A53C2635F5590095BD04 /* StatusPollView.swift */; };
D623A5412635FB3C0095BD04 /* PollOptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D623A5402635FB3C0095BD04 /* PollOptionView.swift */; }; D623A5412635FB3C0095BD04 /* PollOptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D623A5402635FB3C0095BD04 /* PollOptionView.swift */; };
@ -95,7 +98,7 @@
D630C3CA2BC59FF500208903 /* MastodonController+Push.swift in Sources */ = {isa = PBXBuildFile; fileRef = D630C3C92BC59FF500208903 /* MastodonController+Push.swift */; }; D630C3CA2BC59FF500208903 /* MastodonController+Push.swift in Sources */ = {isa = PBXBuildFile; fileRef = D630C3C92BC59FF500208903 /* MastodonController+Push.swift */; };
D630C3CC2BC5FD4600208903 /* GetAuthorizationTokenService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D630C3CB2BC5FD4600208903 /* GetAuthorizationTokenService.swift */; }; D630C3CC2BC5FD4600208903 /* GetAuthorizationTokenService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D630C3CB2BC5FD4600208903 /* GetAuthorizationTokenService.swift */; };
D630C3D42BC61B6100208903 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D630C3D32BC61B6100208903 /* NotificationService.swift */; }; D630C3D42BC61B6100208903 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D630C3D32BC61B6100208903 /* NotificationService.swift */; };
D630C3D82BC61B6100208903 /* NotificationExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D630C3D12BC61B6000208903 /* NotificationExtension.appex */; platformFilters = (ios, maccatalyst, ); settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; D630C3D82BC61B6100208903 /* NotificationExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D630C3D12BC61B6000208903 /* NotificationExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
D630C3DF2BC61C4900208903 /* PushNotifications in Frameworks */ = {isa = PBXBuildFile; productRef = D630C3DE2BC61C4900208903 /* PushNotifications */; }; D630C3DF2BC61C4900208903 /* PushNotifications in Frameworks */ = {isa = PBXBuildFile; productRef = D630C3DE2BC61C4900208903 /* PushNotifications */; };
D630C3E12BC61C6700208903 /* UserAccounts in Frameworks */ = {isa = PBXBuildFile; productRef = D630C3E02BC61C6700208903 /* UserAccounts */; }; D630C3E12BC61C6700208903 /* UserAccounts in Frameworks */ = {isa = PBXBuildFile; productRef = D630C3E02BC61C6700208903 /* UserAccounts */; };
D630C3E52BC6313400208903 /* Pachyderm in Frameworks */ = {isa = PBXBuildFile; productRef = D630C3E42BC6313400208903 /* Pachyderm */; }; D630C3E52BC6313400208903 /* Pachyderm in Frameworks */ = {isa = PBXBuildFile; productRef = D630C3E42BC6313400208903 /* Pachyderm */; };
@ -127,6 +130,10 @@
D646DCD82A07F3500059ECEB /* FollowRequestNotificationCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D646DCD72A07F3500059ECEB /* FollowRequestNotificationCollectionViewCell.swift */; }; D646DCD82A07F3500059ECEB /* FollowRequestNotificationCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D646DCD72A07F3500059ECEB /* FollowRequestNotificationCollectionViewCell.swift */; };
D646DCDA2A081A2C0059ECEB /* PollFinishedNotificationCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D646DCD92A081A2C0059ECEB /* PollFinishedNotificationCollectionViewCell.swift */; }; D646DCDA2A081A2C0059ECEB /* PollFinishedNotificationCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D646DCD92A081A2C0059ECEB /* PollFinishedNotificationCollectionViewCell.swift */; };
D646DCDC2A081CF10059ECEB /* StatusUpdatedNotificationCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D646DCDB2A081CF10059ECEB /* StatusUpdatedNotificationCollectionViewCell.swift */; }; D646DCDC2A081CF10059ECEB /* StatusUpdatedNotificationCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D646DCDB2A081CF10059ECEB /* StatusUpdatedNotificationCollectionViewCell.swift */; };
D64A50462C739DC0009D7193 /* NewMainTabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64A50452C739DC0009D7193 /* NewMainTabBarViewController.swift */; };
D64A50482C739DEA009D7193 /* BaseMainTabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64A50472C739DEA009D7193 /* BaseMainTabBarViewController.swift */; };
D64A50BC2C74F8F4009D7193 /* FindInstanceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64A50BB2C74F8F4009D7193 /* FindInstanceViewController.swift */; };
D64A50BE2C752247009D7193 /* AdaptableNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64A50BD2C752247009D7193 /* AdaptableNavigationController.swift */; };
D64AAE9126C80DC600FC57FB /* ToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64AAE9026C80DC600FC57FB /* ToastView.swift */; }; D64AAE9126C80DC600FC57FB /* ToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64AAE9026C80DC600FC57FB /* ToastView.swift */; };
D64AAE9526C88C5000FC57FB /* ToastableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64AAE9426C88C5000FC57FB /* ToastableViewController.swift */; }; D64AAE9526C88C5000FC57FB /* ToastableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64AAE9426C88C5000FC57FB /* ToastableViewController.swift */; };
D64AAE9726C88DC400FC57FB /* ToastConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64AAE9626C88DC400FC57FB /* ToastConfiguration.swift */; }; D64AAE9726C88DC400FC57FB /* ToastConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64AAE9626C88DC400FC57FB /* ToastConfiguration.swift */; };
@ -134,7 +141,6 @@
D64B96812BC3279D002C8990 /* PrefsAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64B96802BC3279D002C8990 /* PrefsAccountView.swift */; }; D64B96812BC3279D002C8990 /* PrefsAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64B96802BC3279D002C8990 /* PrefsAccountView.swift */; };
D64B96842BC3893C002C8990 /* PushSubscriptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64B96832BC3893C002C8990 /* PushSubscriptionView.swift */; }; D64B96842BC3893C002C8990 /* PushSubscriptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64B96832BC3893C002C8990 /* PushSubscriptionView.swift */; };
D64D0AB12128D9AE005A6F37 /* OnboardingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64D0AB02128D9AE005A6F37 /* OnboardingViewController.swift */; }; D64D0AB12128D9AE005A6F37 /* OnboardingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64D0AB02128D9AE005A6F37 /* OnboardingViewController.swift */; };
D64D8CA92463B494006B0BAA /* MultiThreadDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64D8CA82463B494006B0BAA /* MultiThreadDictionary.swift */; };
D651C5B42915B00400236EF6 /* ProfileFieldsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D651C5B32915B00400236EF6 /* ProfileFieldsView.swift */; }; D651C5B42915B00400236EF6 /* ProfileFieldsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D651C5B32915B00400236EF6 /* ProfileFieldsView.swift */; };
D6531DEE246B81C9000F9538 /* GifvPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6531DED246B81C9000F9538 /* GifvPlayerView.swift */; }; D6531DEE246B81C9000F9538 /* GifvPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6531DED246B81C9000F9538 /* GifvPlayerView.swift */; };
D6538945214D6D7500E3CEFC /* TableViewSwipeActionProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6538944214D6D7500E3CEFC /* TableViewSwipeActionProvider.swift */; }; D6538945214D6D7500E3CEFC /* TableViewSwipeActionProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6538944214D6D7500E3CEFC /* TableViewSwipeActionProvider.swift */; };
@ -159,7 +165,6 @@
D663626C21361C6700C9CBA2 /* Account+Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = D663626B21361C6700C9CBA2 /* Account+Preferences.swift */; }; D663626C21361C6700C9CBA2 /* Account+Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = D663626B21361C6700C9CBA2 /* Account+Preferences.swift */; };
D6674AEA23341F7600E8DF94 /* AppShortcutItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6674AE923341F7600E8DF94 /* AppShortcutItems.swift */; }; D6674AEA23341F7600E8DF94 /* AppShortcutItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6674AE923341F7600E8DF94 /* AppShortcutItems.swift */; };
D6676CA527A8D0020052936B /* WebURLFoundationExtras in Frameworks */ = {isa = PBXBuildFile; productRef = D6676CA427A8D0020052936B /* WebURLFoundationExtras */; }; D6676CA527A8D0020052936B /* WebURLFoundationExtras in Frameworks */ = {isa = PBXBuildFile; productRef = D6676CA427A8D0020052936B /* WebURLFoundationExtras */; };
D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D667E5F72135C3040057A976 /* Mastodon+Equatable.swift */; };
D66A77BB233838DC0058F1EC /* UIFont+Traits.swift in Sources */ = {isa = PBXBuildFile; fileRef = D66A77BA233838DC0058F1EC /* UIFont+Traits.swift */; }; D66A77BB233838DC0058F1EC /* UIFont+Traits.swift in Sources */ = {isa = PBXBuildFile; fileRef = D66A77BA233838DC0058F1EC /* UIFont+Traits.swift */; };
D66C900B28DAB7FD00217BF2 /* TimelineViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D66C900A28DAB7FD00217BF2 /* TimelineViewController.swift */; }; D66C900B28DAB7FD00217BF2 /* TimelineViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D66C900A28DAB7FD00217BF2 /* TimelineViewController.swift */; };
D674A50927F9128D00BA03AC /* Pachyderm in Frameworks */ = {isa = PBXBuildFile; productRef = D674A50827F9128D00BA03AC /* Pachyderm */; }; D674A50927F9128D00BA03AC /* Pachyderm in Frameworks */ = {isa = PBXBuildFile; productRef = D674A50827F9128D00BA03AC /* Pachyderm */; };
@ -213,20 +218,24 @@
D6934F402BAA19EC002B1C8D /* VideoActivityItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6934F3F2BAA19EC002B1C8D /* VideoActivityItemSource.swift */; }; D6934F402BAA19EC002B1C8D /* VideoActivityItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6934F3F2BAA19EC002B1C8D /* VideoActivityItemSource.swift */; };
D6934F422BAC7D6E002B1C8D /* VideoControlsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6934F412BAC7D6E002B1C8D /* VideoControlsViewController.swift */; }; D6934F422BAC7D6E002B1C8D /* VideoControlsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6934F412BAC7D6E002B1C8D /* VideoControlsViewController.swift */; };
D693A72825CF282E003A14E2 /* TrendingHashtagsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D693A72725CF282E003A14E2 /* TrendingHashtagsViewController.swift */; }; D693A72825CF282E003A14E2 /* TrendingHashtagsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D693A72725CF282E003A14E2 /* TrendingHashtagsViewController.swift */; };
D693A72F25CF91C6003A14E2 /* FeaturedProfileCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D693A72D25CF91C6003A14E2 /* FeaturedProfileCollectionViewCell.swift */; };
D693A73025CF91C6003A14E2 /* FeaturedProfileCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D693A72E25CF91C6003A14E2 /* FeaturedProfileCollectionViewCell.xib */; };
D693DE5723FE1A6A0061E07D /* EnhancedNavigationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D693DE5623FE1A6A0061E07D /* EnhancedNavigationViewController.swift */; }; D693DE5723FE1A6A0061E07D /* EnhancedNavigationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D693DE5623FE1A6A0061E07D /* EnhancedNavigationViewController.swift */; };
D693DE5923FE24310061E07D /* InteractivePushTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = D693DE5823FE24300061E07D /* InteractivePushTransition.swift */; }; D693DE5923FE24310061E07D /* InteractivePushTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = D693DE5823FE24300061E07D /* InteractivePushTransition.swift */; };
D6945C2F23AC47C3005C403C /* SavedDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6945C2E23AC47C3005C403C /* SavedDataManager.swift */; }; D6945C2F23AC47C3005C403C /* SavedDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6945C2E23AC47C3005C403C /* SavedDataManager.swift */; };
D6945C3223AC4D36005C403C /* HashtagTimelineViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6945C3123AC4D36005C403C /* HashtagTimelineViewController.swift */; }; D6945C3223AC4D36005C403C /* HashtagTimelineViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6945C3123AC4D36005C403C /* HashtagTimelineViewController.swift */; };
D6945C3423AC6431005C403C /* AddSavedHashtagViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6945C3323AC6431005C403C /* AddSavedHashtagViewController.swift */; }; D6945C3423AC6431005C403C /* AddSavedHashtagViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6945C3323AC6431005C403C /* AddSavedHashtagViewController.swift */; };
D6945C3823AC739F005C403C /* InstanceTimelineViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6945C3723AC739F005C403C /* InstanceTimelineViewController.swift */; }; D6945C3823AC739F005C403C /* InstanceTimelineViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6945C3723AC739F005C403C /* InstanceTimelineViewController.swift */; };
D6945C3A23AC75E2005C403C /* FindInstanceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6945C3923AC75E2005C403C /* FindInstanceViewController.swift */; };
D6958F3D2AA383D90062FE52 /* WidescreenNavigationPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6958F3C2AA383D90062FE52 /* WidescreenNavigationPrefsView.swift */; }; D6958F3D2AA383D90062FE52 /* WidescreenNavigationPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6958F3C2AA383D90062FE52 /* WidescreenNavigationPrefsView.swift */; };
D69693F42585941A00F4E116 /* UIWindowSceneDelegate+Close.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69693F32585941A00F4E116 /* UIWindowSceneDelegate+Close.swift */; }; D69693F42585941A00F4E116 /* UIWindowSceneDelegate+Close.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69693F32585941A00F4E116 /* UIWindowSceneDelegate+Close.swift */; };
D69693FA25859A8000F4E116 /* ComposeSceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69693F925859A8000F4E116 /* ComposeSceneDelegate.swift */; }; D69693FA25859A8000F4E116 /* ComposeSceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69693F925859A8000F4E116 /* ComposeSceneDelegate.swift */; };
D6969E9E240C81B9002843CE /* NSTextAttachment+Emoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6969E9D240C81B9002843CE /* NSTextAttachment+Emoji.swift */; }; D6969E9E240C81B9002843CE /* NSTextAttachment+Emoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6969E9D240C81B9002843CE /* NSTextAttachment+Emoji.swift */; };
D6969EA0240C8384002843CE /* EmojiLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6969E9F240C8384002843CE /* EmojiLabel.swift */; }; D6969EA0240C8384002843CE /* EmojiLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6969E9F240C8384002843CE /* EmojiLabel.swift */; };
D698F4672BD079800054DB14 /* AnnouncementsHostingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D698F4662BD079800054DB14 /* AnnouncementsHostingController.swift */; };
D698F4692BD0799F0054DB14 /* AnnouncementsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D698F4682BD0799F0054DB14 /* AnnouncementsView.swift */; };
D698F46B2BD079F00054DB14 /* AnnouncementListRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D698F46A2BD079F00054DB14 /* AnnouncementListRow.swift */; };
D698F46D2BD0B8310054DB14 /* AnnouncementsCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D698F46C2BD0B8310054DB14 /* AnnouncementsCollection.swift */; };
D698F46F2BD0B8DF0054DB14 /* AddReactionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D698F46E2BD0B8DF0054DB14 /* AddReactionView.swift */; };
D698F4712BD0CBAA0054DB14 /* AnnouncementContentTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D698F4702BD0CBAA0054DB14 /* AnnouncementContentTextView.swift */; };
D69F26342C4CDFD300FAF761 /* AccountDisplayAndUserNameLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69F26332C4CDFD300FAF761 /* AccountDisplayAndUserNameLabel.swift */; };
D6A00B1D26379FC900316AD4 /* PollOptionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A00B1C26379FC900316AD4 /* PollOptionsView.swift */; }; D6A00B1D26379FC900316AD4 /* PollOptionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A00B1C26379FC900316AD4 /* PollOptionsView.swift */; };
D6A3A380295515550036B6EF /* ProfileHeaderButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3A37F295515550036B6EF /* ProfileHeaderButton.swift */; }; D6A3A380295515550036B6EF /* ProfileHeaderButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3A37F295515550036B6EF /* ProfileHeaderButton.swift */; };
D6A3A3822956123A0036B6EF /* TimelinePosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3A3812956123A0036B6EF /* TimelinePosition.swift */; }; D6A3A3822956123A0036B6EF /* TimelinePosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3A3812956123A0036B6EF /* TimelinePosition.swift */; };
@ -251,6 +260,7 @@
D6A6C10F25B62D2400298D0F /* DiskCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6C10E25B62D2400298D0F /* DiskCache.swift */; }; D6A6C10F25B62D2400298D0F /* DiskCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6C10E25B62D2400298D0F /* DiskCache.swift */; };
D6A6C11525B62E9700298D0F /* CacheExpiry.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6C11425B62E9700298D0F /* CacheExpiry.swift */; }; D6A6C11525B62E9700298D0F /* CacheExpiry.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6C11425B62E9700298D0F /* CacheExpiry.swift */; };
D6A6C11B25B63CEE00298D0F /* MemoryCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6C11A25B63CEE00298D0F /* MemoryCache.swift */; }; D6A6C11B25B63CEE00298D0F /* MemoryCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A6C11A25B63CEE00298D0F /* MemoryCache.swift */; };
D6A8D7A52C14DB280007B285 /* PersistentHistoryTokenStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A8D7A42C14DB280007B285 /* PersistentHistoryTokenStore.swift */; };
D6AC956723C4347E008C9946 /* MainSceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6AC956623C4347E008C9946 /* MainSceneDelegate.swift */; }; D6AC956723C4347E008C9946 /* MainSceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6AC956623C4347E008C9946 /* MainSceneDelegate.swift */; };
D6ADB6E828E8C878009924AB /* PublicTimelineDescriptionCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6ADB6E728E8C878009924AB /* PublicTimelineDescriptionCollectionViewCell.swift */; }; D6ADB6E828E8C878009924AB /* PublicTimelineDescriptionCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6ADB6E728E8C878009924AB /* PublicTimelineDescriptionCollectionViewCell.swift */; };
D6ADB6EA28E91C30009924AB /* TimelineStatusCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6ADB6E928E91C30009924AB /* TimelineStatusCollectionViewCell.swift */; }; D6ADB6EA28E91C30009924AB /* TimelineStatusCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6ADB6E928E91C30009924AB /* TimelineStatusCollectionViewCell.swift */; };
@ -291,6 +301,7 @@
D6C3F5192991F5D60009FCFF /* TimelineJumpButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C3F5182991F5D60009FCFF /* TimelineJumpButton.swift */; }; D6C3F5192991F5D60009FCFF /* TimelineJumpButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C3F5182991F5D60009FCFF /* TimelineJumpButton.swift */; };
D6C4532D2BCB86AC00E26A0E /* AppearancePrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C4532C2BCB86AC00E26A0E /* AppearancePrefsView.swift */; }; D6C4532D2BCB86AC00E26A0E /* AppearancePrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C4532C2BCB86AC00E26A0E /* AppearancePrefsView.swift */; };
D6C4532F2BCB873400E26A0E /* MockStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C4532E2BCB873400E26A0E /* MockStatusView.swift */; }; D6C4532F2BCB873400E26A0E /* MockStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C4532E2BCB873400E26A0E /* MockStatusView.swift */; };
D6C453372BCE1CEF00E26A0E /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = D6C4532A2BCAD7F900E26A0E /* PrivacyInfo.xcprivacy */; };
D6C693EF216192C2007D6A6D /* TuskerNavigationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C693EE216192C2007D6A6D /* TuskerNavigationDelegate.swift */; }; D6C693EF216192C2007D6A6D /* TuskerNavigationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C693EE216192C2007D6A6D /* TuskerNavigationDelegate.swift */; };
D6C693FC2162FE6F007D6A6D /* LoadingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C693FB2162FE6F007D6A6D /* LoadingViewController.swift */; }; D6C693FC2162FE6F007D6A6D /* LoadingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C693FB2162FE6F007D6A6D /* LoadingViewController.swift */; };
D6C693FE2162FEEA007D6A6D /* UIViewController+Children.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C693FD2162FEEA007D6A6D /* UIViewController+Children.swift */; }; D6C693FE2162FEEA007D6A6D /* UIViewController+Children.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C693FD2162FEEA007D6A6D /* UIViewController+Children.swift */; };
@ -325,7 +336,7 @@
D6D79F592A13293200AB2315 /* BackgroundManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D79F582A13293200AB2315 /* BackgroundManager.swift */; }; D6D79F592A13293200AB2315 /* BackgroundManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D79F582A13293200AB2315 /* BackgroundManager.swift */; };
D6D94955298963A900C59229 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D94954298963A900C59229 /* Colors.swift */; }; D6D94955298963A900C59229 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D94954298963A900C59229 /* Colors.swift */; };
D6D9498D298CBB4000C59229 /* TrendingStatusCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D9498C298CBB4000C59229 /* TrendingStatusCollectionViewCell.swift */; }; D6D9498D298CBB4000C59229 /* TrendingStatusCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D9498C298CBB4000C59229 /* TrendingStatusCollectionViewCell.swift */; };
D6D9498F298EB79400C59229 /* CopyableLable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D9498E298EB79400C59229 /* CopyableLable.swift */; }; D6D9498F298EB79400C59229 /* CopyableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D9498E298EB79400C59229 /* CopyableLabel.swift */; };
D6DD8FFD298495A8002AD3FD /* LogoutService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD8FFC298495A8002AD3FD /* LogoutService.swift */; }; D6DD8FFD298495A8002AD3FD /* LogoutService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD8FFC298495A8002AD3FD /* LogoutService.swift */; };
D6DD8FFF2984D327002AD3FD /* BookmarksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD8FFE2984D327002AD3FD /* BookmarksViewController.swift */; }; D6DD8FFF2984D327002AD3FD /* BookmarksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD8FFE2984D327002AD3FD /* BookmarksViewController.swift */; };
D6DD996B2998611A0015C962 /* SuggestedProfilesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD996A2998611A0015C962 /* SuggestedProfilesViewController.swift */; }; D6DD996B2998611A0015C962 /* SuggestedProfilesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD996A2998611A0015C962 /* SuggestedProfilesViewController.swift */; };
@ -351,6 +362,7 @@
D6EBF01523C55C0900AE061B /* UIApplication+Scenes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6EBF01423C55C0900AE061B /* UIApplication+Scenes.swift */; }; D6EBF01523C55C0900AE061B /* UIApplication+Scenes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6EBF01423C55C0900AE061B /* UIApplication+Scenes.swift */; };
D6EBF01723C55E0D00AE061B /* UISceneSession+MastodonController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6EBF01623C55E0D00AE061B /* UISceneSession+MastodonController.swift */; }; D6EBF01723C55E0D00AE061B /* UISceneSession+MastodonController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6EBF01623C55E0D00AE061B /* UISceneSession+MastodonController.swift */; };
D6EE63FB2551F7F60065485C /* StatusCollapseButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6EE63FA2551F7F60065485C /* StatusCollapseButton.swift */; }; D6EE63FB2551F7F60065485C /* StatusCollapseButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6EE63FA2551F7F60065485C /* StatusCollapseButton.swift */; };
D6EEDE932C3CF21800E10E51 /* AudioSessionCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6EEDE922C3CF21800E10E51 /* AudioSessionCoordinator.swift */; };
D6F0B12B24A3071C001E48C3 /* MainSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F0B12A24A3071C001E48C3 /* MainSplitViewController.swift */; }; D6F0B12B24A3071C001E48C3 /* MainSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F0B12A24A3071C001E48C3 /* MainSplitViewController.swift */; };
D6F0B17524A3A1AA001E48C3 /* MainSidebarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F0B17424A3A1AA001E48C3 /* MainSidebarViewController.swift */; }; D6F0B17524A3A1AA001E48C3 /* MainSidebarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F0B17424A3A1AA001E48C3 /* MainSidebarViewController.swift */; };
D6F253CF2AC9F86300806D83 /* SearchTokenSuggestionCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F253CE2AC9F86300806D83 /* SearchTokenSuggestionCollectionViewCell.swift */; }; D6F253CF2AC9F86300806D83 /* SearchTokenSuggestionCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F253CE2AC9F86300806D83 /* SearchTokenSuggestionCollectionViewCell.swift */; };
@ -460,6 +472,7 @@
D60E2F2D244248BF005F8713 /* MastodonCachePersistentStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonCachePersistentStore.swift; sourceTree = "<group>"; }; D60E2F2D244248BF005F8713 /* MastodonCachePersistentStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonCachePersistentStore.swift; sourceTree = "<group>"; };
D6114E0C27F7FEB30080E273 /* TrendingStatusesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingStatusesViewController.swift; sourceTree = "<group>"; }; D6114E0C27F7FEB30080E273 /* TrendingStatusesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingStatusesViewController.swift; sourceTree = "<group>"; };
D6114E1027F899B30080E273 /* TrendingLinksViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingLinksViewController.swift; sourceTree = "<group>"; }; D6114E1027F899B30080E273 /* TrendingLinksViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingLinksViewController.swift; sourceTree = "<group>"; };
D6187BEC2BFA840B00B3A281 /* FollowRequestNotificationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowRequestNotificationViewController.swift; sourceTree = "<group>"; };
D61A45E528DC0F2F002BE511 /* ConfirmLoadMoreCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmLoadMoreCollectionViewCell.swift; sourceTree = "<group>"; }; D61A45E528DC0F2F002BE511 /* ConfirmLoadMoreCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmLoadMoreCollectionViewCell.swift; sourceTree = "<group>"; };
D61A45E728DF477D002BE511 /* LoadingCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingCollectionViewCell.swift; sourceTree = "<group>"; }; D61A45E728DF477D002BE511 /* LoadingCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingCollectionViewCell.swift; sourceTree = "<group>"; };
D61A45E928DF51EE002BE511 /* TimelineLikeCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineLikeCollectionViewController.swift; sourceTree = "<group>"; }; D61A45E928DF51EE002BE511 /* TimelineLikeCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineLikeCollectionViewController.swift; sourceTree = "<group>"; };
@ -497,6 +510,7 @@
D620483323D3801D008A63EF /* LinkTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkTextView.swift; sourceTree = "<group>"; }; D620483323D3801D008A63EF /* LinkTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkTextView.swift; sourceTree = "<group>"; };
D620483523D38075008A63EF /* ContentTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentTextView.swift; sourceTree = "<group>"; }; D620483523D38075008A63EF /* ContentTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentTextView.swift; sourceTree = "<group>"; };
D620483723D38190008A63EF /* StatusContentTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusContentTextView.swift; sourceTree = "<group>"; }; D620483723D38190008A63EF /* StatusContentTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusContentTextView.swift; sourceTree = "<group>"; };
D6210D752C0B924F009BB569 /* RemoveProfileSuggestionService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveProfileSuggestionService.swift; sourceTree = "<group>"; };
D621733228F1D5ED004C7DB1 /* ReblogService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReblogService.swift; sourceTree = "<group>"; }; D621733228F1D5ED004C7DB1 /* ReblogService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReblogService.swift; sourceTree = "<group>"; };
D62275A724F1CA2800B82A16 /* ComposeReplyContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeReplyContentView.swift; sourceTree = "<group>"; }; D62275A724F1CA2800B82A16 /* ComposeReplyContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeReplyContentView.swift; sourceTree = "<group>"; };
D623A53C2635F5590095BD04 /* StatusPollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusPollView.swift; sourceTree = "<group>"; }; D623A53C2635F5590095BD04 /* StatusPollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusPollView.swift; sourceTree = "<group>"; };
@ -546,6 +560,10 @@
D646DCD72A07F3500059ECEB /* FollowRequestNotificationCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowRequestNotificationCollectionViewCell.swift; sourceTree = "<group>"; }; D646DCD72A07F3500059ECEB /* FollowRequestNotificationCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowRequestNotificationCollectionViewCell.swift; sourceTree = "<group>"; };
D646DCD92A081A2C0059ECEB /* PollFinishedNotificationCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFinishedNotificationCollectionViewCell.swift; sourceTree = "<group>"; }; D646DCD92A081A2C0059ECEB /* PollFinishedNotificationCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFinishedNotificationCollectionViewCell.swift; sourceTree = "<group>"; };
D646DCDB2A081CF10059ECEB /* StatusUpdatedNotificationCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusUpdatedNotificationCollectionViewCell.swift; sourceTree = "<group>"; }; D646DCDB2A081CF10059ECEB /* StatusUpdatedNotificationCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusUpdatedNotificationCollectionViewCell.swift; sourceTree = "<group>"; };
D64A50452C739DC0009D7193 /* NewMainTabBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewMainTabBarViewController.swift; sourceTree = "<group>"; };
D64A50472C739DEA009D7193 /* BaseMainTabBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseMainTabBarViewController.swift; sourceTree = "<group>"; };
D64A50BB2C74F8F4009D7193 /* FindInstanceViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FindInstanceViewController.swift; sourceTree = "<group>"; };
D64A50BD2C752247009D7193 /* AdaptableNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdaptableNavigationController.swift; sourceTree = "<group>"; };
D64AAE9026C80DC600FC57FB /* ToastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastView.swift; sourceTree = "<group>"; }; D64AAE9026C80DC600FC57FB /* ToastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastView.swift; sourceTree = "<group>"; };
D64AAE9426C88C5000FC57FB /* ToastableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastableViewController.swift; sourceTree = "<group>"; }; D64AAE9426C88C5000FC57FB /* ToastableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastableViewController.swift; sourceTree = "<group>"; };
D64AAE9626C88DC400FC57FB /* ToastConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastConfiguration.swift; sourceTree = "<group>"; }; D64AAE9626C88DC400FC57FB /* ToastConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastConfiguration.swift; sourceTree = "<group>"; };
@ -553,7 +571,6 @@
D64B96802BC3279D002C8990 /* PrefsAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefsAccountView.swift; sourceTree = "<group>"; }; D64B96802BC3279D002C8990 /* PrefsAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefsAccountView.swift; sourceTree = "<group>"; };
D64B96832BC3893C002C8990 /* PushSubscriptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushSubscriptionView.swift; sourceTree = "<group>"; }; D64B96832BC3893C002C8990 /* PushSubscriptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushSubscriptionView.swift; sourceTree = "<group>"; };
D64D0AB02128D9AE005A6F37 /* OnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewController.swift; sourceTree = "<group>"; }; D64D0AB02128D9AE005A6F37 /* OnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewController.swift; sourceTree = "<group>"; };
D64D8CA82463B494006B0BAA /* MultiThreadDictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiThreadDictionary.swift; sourceTree = "<group>"; };
D651C5B32915B00400236EF6 /* ProfileFieldsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileFieldsView.swift; sourceTree = "<group>"; }; D651C5B32915B00400236EF6 /* ProfileFieldsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileFieldsView.swift; sourceTree = "<group>"; };
D6531DED246B81C9000F9538 /* GifvPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GifvPlayerView.swift; sourceTree = "<group>"; }; D6531DED246B81C9000F9538 /* GifvPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GifvPlayerView.swift; sourceTree = "<group>"; };
D6538944214D6D7500E3CEFC /* TableViewSwipeActionProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewSwipeActionProvider.swift; sourceTree = "<group>"; }; D6538944214D6D7500E3CEFC /* TableViewSwipeActionProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewSwipeActionProvider.swift; sourceTree = "<group>"; };
@ -580,7 +597,6 @@
D6620ACD2511A0ED00312CA0 /* StatusStateResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusStateResolver.swift; sourceTree = "<group>"; }; D6620ACD2511A0ED00312CA0 /* StatusStateResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusStateResolver.swift; sourceTree = "<group>"; };
D663626B21361C6700C9CBA2 /* Account+Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Account+Preferences.swift"; sourceTree = "<group>"; }; D663626B21361C6700C9CBA2 /* Account+Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Account+Preferences.swift"; sourceTree = "<group>"; };
D6674AE923341F7600E8DF94 /* AppShortcutItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppShortcutItems.swift; sourceTree = "<group>"; }; D6674AE923341F7600E8DF94 /* AppShortcutItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppShortcutItems.swift; sourceTree = "<group>"; };
D667E5F72135C3040057A976 /* Mastodon+Equatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Mastodon+Equatable.swift"; sourceTree = "<group>"; };
D66A77BA233838DC0058F1EC /* UIFont+Traits.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont+Traits.swift"; sourceTree = "<group>"; }; D66A77BA233838DC0058F1EC /* UIFont+Traits.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont+Traits.swift"; sourceTree = "<group>"; };
D66C900A28DAB7FD00217BF2 /* TimelineViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineViewController.swift; sourceTree = "<group>"; }; D66C900A28DAB7FD00217BF2 /* TimelineViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineViewController.swift; sourceTree = "<group>"; };
D671A6BE299DA96100A81FEA /* Tusker-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Tusker-Bridging-Header.h"; sourceTree = "<group>"; }; D671A6BE299DA96100A81FEA /* Tusker-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Tusker-Bridging-Header.h"; sourceTree = "<group>"; };
@ -635,20 +651,24 @@
D6934F3F2BAA19EC002B1C8D /* VideoActivityItemSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoActivityItemSource.swift; sourceTree = "<group>"; }; D6934F3F2BAA19EC002B1C8D /* VideoActivityItemSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoActivityItemSource.swift; sourceTree = "<group>"; };
D6934F412BAC7D6E002B1C8D /* VideoControlsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoControlsViewController.swift; sourceTree = "<group>"; }; D6934F412BAC7D6E002B1C8D /* VideoControlsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoControlsViewController.swift; sourceTree = "<group>"; };
D693A72725CF282E003A14E2 /* TrendingHashtagsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingHashtagsViewController.swift; sourceTree = "<group>"; }; D693A72725CF282E003A14E2 /* TrendingHashtagsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingHashtagsViewController.swift; sourceTree = "<group>"; };
D693A72D25CF91C6003A14E2 /* FeaturedProfileCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeaturedProfileCollectionViewCell.swift; sourceTree = "<group>"; };
D693A72E25CF91C6003A14E2 /* FeaturedProfileCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FeaturedProfileCollectionViewCell.xib; sourceTree = "<group>"; };
D693DE5623FE1A6A0061E07D /* EnhancedNavigationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnhancedNavigationViewController.swift; sourceTree = "<group>"; }; D693DE5623FE1A6A0061E07D /* EnhancedNavigationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnhancedNavigationViewController.swift; sourceTree = "<group>"; };
D693DE5823FE24300061E07D /* InteractivePushTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractivePushTransition.swift; sourceTree = "<group>"; }; D693DE5823FE24300061E07D /* InteractivePushTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractivePushTransition.swift; sourceTree = "<group>"; };
D6945C2E23AC47C3005C403C /* SavedDataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavedDataManager.swift; sourceTree = "<group>"; }; D6945C2E23AC47C3005C403C /* SavedDataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavedDataManager.swift; sourceTree = "<group>"; };
D6945C3123AC4D36005C403C /* HashtagTimelineViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashtagTimelineViewController.swift; sourceTree = "<group>"; }; D6945C3123AC4D36005C403C /* HashtagTimelineViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashtagTimelineViewController.swift; sourceTree = "<group>"; };
D6945C3323AC6431005C403C /* AddSavedHashtagViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddSavedHashtagViewController.swift; sourceTree = "<group>"; }; D6945C3323AC6431005C403C /* AddSavedHashtagViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddSavedHashtagViewController.swift; sourceTree = "<group>"; };
D6945C3723AC739F005C403C /* InstanceTimelineViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceTimelineViewController.swift; sourceTree = "<group>"; }; D6945C3723AC739F005C403C /* InstanceTimelineViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceTimelineViewController.swift; sourceTree = "<group>"; };
D6945C3923AC75E2005C403C /* FindInstanceViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = FindInstanceViewController.swift; path = Tusker/Screens/FindInstanceViewController.swift; sourceTree = SOURCE_ROOT; };
D6958F3C2AA383D90062FE52 /* WidescreenNavigationPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidescreenNavigationPrefsView.swift; sourceTree = "<group>"; }; D6958F3C2AA383D90062FE52 /* WidescreenNavigationPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidescreenNavigationPrefsView.swift; sourceTree = "<group>"; };
D69693F32585941A00F4E116 /* UIWindowSceneDelegate+Close.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIWindowSceneDelegate+Close.swift"; sourceTree = "<group>"; }; D69693F32585941A00F4E116 /* UIWindowSceneDelegate+Close.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIWindowSceneDelegate+Close.swift"; sourceTree = "<group>"; };
D69693F925859A8000F4E116 /* ComposeSceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeSceneDelegate.swift; sourceTree = "<group>"; }; D69693F925859A8000F4E116 /* ComposeSceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeSceneDelegate.swift; sourceTree = "<group>"; };
D6969E9D240C81B9002843CE /* NSTextAttachment+Emoji.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSTextAttachment+Emoji.swift"; sourceTree = "<group>"; }; D6969E9D240C81B9002843CE /* NSTextAttachment+Emoji.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSTextAttachment+Emoji.swift"; sourceTree = "<group>"; };
D6969E9F240C8384002843CE /* EmojiLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiLabel.swift; sourceTree = "<group>"; }; D6969E9F240C8384002843CE /* EmojiLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiLabel.swift; sourceTree = "<group>"; };
D698F4662BD079800054DB14 /* AnnouncementsHostingController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnnouncementsHostingController.swift; sourceTree = "<group>"; };
D698F4682BD0799F0054DB14 /* AnnouncementsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnnouncementsView.swift; sourceTree = "<group>"; };
D698F46A2BD079F00054DB14 /* AnnouncementListRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnnouncementListRow.swift; sourceTree = "<group>"; };
D698F46C2BD0B8310054DB14 /* AnnouncementsCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnnouncementsCollection.swift; sourceTree = "<group>"; };
D698F46E2BD0B8DF0054DB14 /* AddReactionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddReactionView.swift; sourceTree = "<group>"; };
D698F4702BD0CBAA0054DB14 /* AnnouncementContentTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnnouncementContentTextView.swift; sourceTree = "<group>"; };
D69F26332C4CDFD300FAF761 /* AccountDisplayAndUserNameLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountDisplayAndUserNameLabel.swift; sourceTree = "<group>"; };
D6A00B1C26379FC900316AD4 /* PollOptionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollOptionsView.swift; sourceTree = "<group>"; }; D6A00B1C26379FC900316AD4 /* PollOptionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollOptionsView.swift; sourceTree = "<group>"; };
D6A3A37F295515550036B6EF /* ProfileHeaderButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileHeaderButton.swift; sourceTree = "<group>"; }; D6A3A37F295515550036B6EF /* ProfileHeaderButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileHeaderButton.swift; sourceTree = "<group>"; };
D6A3A3812956123A0036B6EF /* TimelinePosition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinePosition.swift; sourceTree = "<group>"; }; D6A3A3812956123A0036B6EF /* TimelinePosition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinePosition.swift; sourceTree = "<group>"; };
@ -670,6 +690,7 @@
D6A6C10E25B62D2400298D0F /* DiskCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiskCache.swift; sourceTree = "<group>"; }; D6A6C10E25B62D2400298D0F /* DiskCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiskCache.swift; sourceTree = "<group>"; };
D6A6C11425B62E9700298D0F /* CacheExpiry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheExpiry.swift; sourceTree = "<group>"; }; D6A6C11425B62E9700298D0F /* CacheExpiry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheExpiry.swift; sourceTree = "<group>"; };
D6A6C11A25B63CEE00298D0F /* MemoryCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryCache.swift; sourceTree = "<group>"; }; D6A6C11A25B63CEE00298D0F /* MemoryCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryCache.swift; sourceTree = "<group>"; };
D6A8D7A42C14DB280007B285 /* PersistentHistoryTokenStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistentHistoryTokenStore.swift; sourceTree = "<group>"; };
D6A9E04F29F8917500BEDC7E /* MatchedGeometryPresentation */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = MatchedGeometryPresentation; sourceTree = "<group>"; }; D6A9E04F29F8917500BEDC7E /* MatchedGeometryPresentation */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = MatchedGeometryPresentation; sourceTree = "<group>"; };
D6AC956623C4347E008C9946 /* MainSceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainSceneDelegate.swift; sourceTree = "<group>"; }; D6AC956623C4347E008C9946 /* MainSceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainSceneDelegate.swift; sourceTree = "<group>"; };
D6ADB6E728E8C878009924AB /* PublicTimelineDescriptionCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicTimelineDescriptionCollectionViewCell.swift; sourceTree = "<group>"; }; D6ADB6E728E8C878009924AB /* PublicTimelineDescriptionCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicTimelineDescriptionCollectionViewCell.swift; sourceTree = "<group>"; };
@ -755,7 +776,7 @@
D6D79F582A13293200AB2315 /* BackgroundManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundManager.swift; sourceTree = "<group>"; }; D6D79F582A13293200AB2315 /* BackgroundManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundManager.swift; sourceTree = "<group>"; };
D6D94954298963A900C59229 /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; }; D6D94954298963A900C59229 /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; };
D6D9498C298CBB4000C59229 /* TrendingStatusCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingStatusCollectionViewCell.swift; sourceTree = "<group>"; }; D6D9498C298CBB4000C59229 /* TrendingStatusCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingStatusCollectionViewCell.swift; sourceTree = "<group>"; };
D6D9498E298EB79400C59229 /* CopyableLable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyableLable.swift; sourceTree = "<group>"; }; D6D9498E298EB79400C59229 /* CopyableLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyableLabel.swift; sourceTree = "<group>"; };
D6DD8FFC298495A8002AD3FD /* LogoutService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoutService.swift; sourceTree = "<group>"; }; D6DD8FFC298495A8002AD3FD /* LogoutService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoutService.swift; sourceTree = "<group>"; };
D6DD8FFE2984D327002AD3FD /* BookmarksViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksViewController.swift; sourceTree = "<group>"; }; D6DD8FFE2984D327002AD3FD /* BookmarksViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksViewController.swift; sourceTree = "<group>"; };
D6DD996A2998611A0015C962 /* SuggestedProfilesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestedProfilesViewController.swift; sourceTree = "<group>"; }; D6DD996A2998611A0015C962 /* SuggestedProfilesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestedProfilesViewController.swift; sourceTree = "<group>"; };
@ -784,6 +805,7 @@
D6EBF01423C55C0900AE061B /* UIApplication+Scenes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+Scenes.swift"; sourceTree = "<group>"; }; D6EBF01423C55C0900AE061B /* UIApplication+Scenes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+Scenes.swift"; sourceTree = "<group>"; };
D6EBF01623C55E0D00AE061B /* UISceneSession+MastodonController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UISceneSession+MastodonController.swift"; sourceTree = "<group>"; }; D6EBF01623C55E0D00AE061B /* UISceneSession+MastodonController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UISceneSession+MastodonController.swift"; sourceTree = "<group>"; };
D6EE63FA2551F7F60065485C /* StatusCollapseButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusCollapseButton.swift; sourceTree = "<group>"; }; D6EE63FA2551F7F60065485C /* StatusCollapseButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusCollapseButton.swift; sourceTree = "<group>"; };
D6EEDE922C3CF21800E10E51 /* AudioSessionCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioSessionCoordinator.swift; sourceTree = "<group>"; };
D6F0B12A24A3071C001E48C3 /* MainSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainSplitViewController.swift; sourceTree = "<group>"; }; D6F0B12A24A3071C001E48C3 /* MainSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainSplitViewController.swift; sourceTree = "<group>"; };
D6F0B17424A3A1AA001E48C3 /* MainSidebarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainSidebarViewController.swift; sourceTree = "<group>"; }; D6F0B17424A3A1AA001E48C3 /* MainSidebarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainSidebarViewController.swift; sourceTree = "<group>"; };
D6F253CE2AC9F86300806D83 /* SearchTokenSuggestionCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchTokenSuggestionCollectionViewCell.swift; sourceTree = "<group>"; }; D6F253CE2AC9F86300806D83 /* SearchTokenSuggestionCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchTokenSuggestionCollectionViewCell.swift; sourceTree = "<group>"; };
@ -805,6 +827,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
D630C4252BC7845800208903 /* WebURL in Frameworks */, D630C4252BC7845800208903 /* WebURL in Frameworks */,
D62220472C7EA8DF003E43B7 /* TuskerPreferences in Frameworks */,
D630C4232BC7842C00208903 /* HTMLStreamer in Frameworks */, D630C4232BC7842C00208903 /* HTMLStreamer in Frameworks */,
D630C3E52BC6313400208903 /* Pachyderm in Frameworks */, D630C3E52BC6313400208903 /* Pachyderm in Frameworks */,
D630C3DF2BC61C4900208903 /* PushNotifications in Frameworks */, D630C3DF2BC61C4900208903 /* PushNotifications in Frameworks */,
@ -954,7 +977,7 @@
D68E525C24A3E8F00054355A /* InlineTrendsViewController.swift */, D68E525C24A3E8F00054355A /* InlineTrendsViewController.swift */,
D6945C3323AC6431005C403C /* AddSavedHashtagViewController.swift */, D6945C3323AC6431005C403C /* AddSavedHashtagViewController.swift */,
D6093F9A25BDD4B9004811E6 /* HashtagSearchResultsViewController.swift */, D6093F9A25BDD4B9004811E6 /* HashtagSearchResultsViewController.swift */,
D6945C3923AC75E2005C403C /* FindInstanceViewController.swift */, D64A50BB2C74F8F4009D7193 /* FindInstanceViewController.swift */,
D6114E0C27F7FEB30080E273 /* TrendingStatusesViewController.swift */, D6114E0C27F7FEB30080E273 /* TrendingStatusesViewController.swift */,
D693A72725CF282E003A14E2 /* TrendingHashtagsViewController.swift */, D693A72725CF282E003A14E2 /* TrendingHashtagsViewController.swift */,
D6114E1027F899B30080E273 /* TrendingLinksViewController.swift */, D6114E1027F899B30080E273 /* TrendingLinksViewController.swift */,
@ -964,8 +987,6 @@
D601FA81297EEC3F00A8E8B5 /* SuggestedProfileCardCollectionViewCell.swift */, D601FA81297EEC3F00A8E8B5 /* SuggestedProfileCardCollectionViewCell.swift */,
D601FA82297EEC3F00A8E8B5 /* SuggestedProfileCardCollectionViewCell.xib */, D601FA82297EEC3F00A8E8B5 /* SuggestedProfileCardCollectionViewCell.xib */,
D6BC74852AFC4772000DD603 /* SuggestedProfileCardView.swift */, D6BC74852AFC4772000DD603 /* SuggestedProfileCardView.swift */,
D693A72D25CF91C6003A14E2 /* FeaturedProfileCollectionViewCell.swift */,
D693A72E25CF91C6003A14E2 /* FeaturedProfileCollectionViewCell.xib */,
D6C3F4FA299035650009FCFF /* TrendsViewController.swift */, D6C3F4FA299035650009FCFF /* TrendsViewController.swift */,
D68329EE299540050026EB24 /* MoreTrendsFooterCollectionViewCell.swift */, D68329EE299540050026EB24 /* MoreTrendsFooterCollectionViewCell.swift */,
D6DD996A2998611A0015C962 /* SuggestedProfilesViewController.swift */, D6DD996A2998611A0015C962 /* SuggestedProfilesViewController.swift */,
@ -1034,6 +1055,7 @@
D608470E2A245D1F00C17380 /* ActiveInstance.swift */, D608470E2A245D1F00C17380 /* ActiveInstance.swift */,
D60E2F2D244248BF005F8713 /* MastodonCachePersistentStore.swift */, D60E2F2D244248BF005F8713 /* MastodonCachePersistentStore.swift */,
D6B936702829F72900237D0E /* NSManagedObjectContext+Helpers.swift */, D6B936702829F72900237D0E /* NSManagedObjectContext+Helpers.swift */,
D6A8D7A42C14DB280007B285 /* PersistentHistoryTokenStore.swift */,
); );
path = CoreData; path = CoreData;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1054,6 +1076,7 @@
children = ( children = (
D65B4B89297879DE00DABDFB /* Account Follows */, D65B4B89297879DE00DABDFB /* Account Follows */,
D6A3BC822321F69400FD64D5 /* Account List */, D6A3BC822321F69400FD64D5 /* Account List */,
D698F4472BCEE2320054DB14 /* Announcements */,
D641C787213DD862004B4513 /* Compose */, D641C787213DD862004B4513 /* Compose */,
D641C785213DD83B004B4513 /* Conversation */, D641C785213DD83B004B4513 /* Conversation */,
D6F2E960249E772F005846BB /* Crash Reporter */, D6F2E960249E772F005846BB /* Crash Reporter */,
@ -1099,7 +1122,9 @@
D6FF985F255C717400845181 /* AccountSwitchingContainerViewController.swift */, D6FF985F255C717400845181 /* AccountSwitchingContainerViewController.swift */,
D6BEA246291A0F2D002F4D01 /* Duckable+Root.swift */, D6BEA246291A0F2D002F4D01 /* Duckable+Root.swift */,
D6F0B12A24A3071C001E48C3 /* MainSplitViewController.swift */, D6F0B12A24A3071C001E48C3 /* MainSplitViewController.swift */,
D64A50472C739DEA009D7193 /* BaseMainTabBarViewController.swift */,
04DACE8B212CB14B009840C4 /* MainTabBarViewController.swift */, 04DACE8B212CB14B009840C4 /* MainTabBarViewController.swift */,
D64A50452C739DC0009D7193 /* NewMainTabBarViewController.swift */,
D6F0B17424A3A1AA001E48C3 /* MainSidebarViewController.swift */, D6F0B17424A3A1AA001E48C3 /* MainSidebarViewController.swift */,
D6B93666281D937300237D0E /* MainSidebarMyProfileCollectionViewCell.swift */, D6B93666281D937300237D0E /* MainSidebarMyProfileCollectionViewCell.swift */,
D68E525A24A3D77E0054355A /* TuskerRootViewController.swift */, D68E525A24A3D77E0054355A /* TuskerRootViewController.swift */,
@ -1150,6 +1175,7 @@
D646DCD92A081A2C0059ECEB /* PollFinishedNotificationCollectionViewCell.swift */, D646DCD92A081A2C0059ECEB /* PollFinishedNotificationCollectionViewCell.swift */,
D646DCDB2A081CF10059ECEB /* StatusUpdatedNotificationCollectionViewCell.swift */, D646DCDB2A081CF10059ECEB /* StatusUpdatedNotificationCollectionViewCell.swift */,
D68245112BCA1F4000AFB38B /* NotificationLoadingViewController.swift */, D68245112BCA1F4000AFB38B /* NotificationLoadingViewController.swift */,
D6187BEC2BFA840B00B3A281 /* FollowRequestNotificationViewController.swift */,
); );
path = Notifications; path = Notifications;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1296,7 +1322,6 @@
D667E5F62135C2ED0057A976 /* Extensions */ = { D667E5F62135C2ED0057A976 /* Extensions */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D667E5F72135C3040057A976 /* Mastodon+Equatable.swift */,
D663626B21361C6700C9CBA2 /* Account+Preferences.swift */, D663626B21361C6700C9CBA2 /* Account+Preferences.swift */,
D6F4D79329ECB0AF00351B87 /* UIBackgroundConfiguration+AppColors.swift */, D6F4D79329ECB0AF00351B87 /* UIBackgroundConfiguration+AppColors.swift */,
D6333B362137838300CE884A /* AttributedString+Helpers.swift */, D6333B362137838300CE884A /* AttributedString+Helpers.swift */,
@ -1349,6 +1374,19 @@
path = About; path = About;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
D698F4472BCEE2320054DB14 /* Announcements */ = {
isa = PBXGroup;
children = (
D698F4662BD079800054DB14 /* AnnouncementsHostingController.swift */,
D698F46C2BD0B8310054DB14 /* AnnouncementsCollection.swift */,
D698F4682BD0799F0054DB14 /* AnnouncementsView.swift */,
D698F46A2BD079F00054DB14 /* AnnouncementListRow.swift */,
D698F4702BD0CBAA0054DB14 /* AnnouncementContentTextView.swift */,
D698F46E2BD0B8DF0054DB14 /* AddReactionView.swift */,
);
path = Announcements;
sourceTree = "<group>";
};
D6A3BC822321F69400FD64D5 /* Account List */ = { D6A3BC822321F69400FD64D5 /* Account List */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -1443,12 +1481,14 @@
D6BED1722126661300F02DA0 /* Views */ = { D6BED1722126661300F02DA0 /* Views */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D6D79F562A1160B800AB2315 /* AccountDisplayNameLabel.swift */,
D6B4A4FE2506B81A000C81C1 /* AccountDisplayNameView.swift */, D6B4A4FE2506B81A000C81C1 /* AccountDisplayNameView.swift */,
D69F26332C4CDFD300FAF761 /* AccountDisplayAndUserNameLabel.swift */,
D68E6F5E253C9B2D001A1B4C /* BaseEmojiLabel.swift */, D68E6F5E253C9B2D001A1B4C /* BaseEmojiLabel.swift */,
D6ADB6EF28ED1F25009924AB /* CachedImageView.swift */, D6ADB6EF28ED1F25009924AB /* CachedImageView.swift */,
D6895DC328D65342006341DA /* ConfirmReblogStatusPreviewView.swift */, D6895DC328D65342006341DA /* ConfirmReblogStatusPreviewView.swift */,
D620483523D38075008A63EF /* ContentTextView.swift */, D620483523D38075008A63EF /* ContentTextView.swift */,
D6D9498E298EB79400C59229 /* CopyableLable.swift */, D6D9498E298EB79400C59229 /* CopyableLabel.swift */,
D6E426B225337C7000C02E1C /* CustomEmojiImageView.swift */, D6E426B225337C7000C02E1C /* CustomEmojiImageView.swift */,
D6969E9F240C8384002843CE /* EmojiLabel.swift */, D6969E9F240C8384002843CE /* EmojiLabel.swift */,
D61F75B8293C15A000C0B37F /* ZeroHeightCollectionViewCell.swift */, D61F75B8293C15A000C0B37F /* ZeroHeightCollectionViewCell.swift */,
@ -1477,7 +1517,6 @@
D641C78B213DD92F004B4513 /* Profile Header */, D641C78B213DD92F004B4513 /* Profile Header */,
D641C78A213DD926004B4513 /* Status */, D641C78A213DD926004B4513 /* Status */,
D64AAE8F26C80DB600FC57FB /* Toast */, D64AAE8F26C80DB600FC57FB /* Toast */,
D6D79F562A1160B800AB2315 /* AccountDisplayNameLabel.swift */,
); );
path = Views; path = Views;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1516,6 +1555,7 @@
D6B8DB332182A59300424AF7 /* UIAlertController+Visibility.swift */, D6B8DB332182A59300424AF7 /* UIAlertController+Visibility.swift */,
D6C693FD2162FEEA007D6A6D /* UIViewController+Children.swift */, D6C693FD2162FEEA007D6A6D /* UIViewController+Children.swift */,
D61F759129365C6C00C0B37F /* CollectionViewController.swift */, D61F759129365C6C00C0B37F /* CollectionViewController.swift */,
D64A50BD2C752247009D7193 /* AdaptableNavigationController.swift */,
); );
path = Utilities; path = Utilities;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1572,6 +1612,7 @@
D691296D2BA75ACF005C58ED /* PrivacyInfo.xcprivacy */, D691296D2BA75ACF005C58ED /* PrivacyInfo.xcprivacy */,
D671A6BE299DA96100A81FEA /* Tusker-Bridging-Header.h */, D671A6BE299DA96100A81FEA /* Tusker-Bridging-Header.h */,
D6D4DDCF212518A000E1C4BB /* AppDelegate.swift */, D6D4DDCF212518A000E1C4BB /* AppDelegate.swift */,
D6EEDE922C3CF21800E10E51 /* AudioSessionCoordinator.swift */,
D6D79F582A13293200AB2315 /* BackgroundManager.swift */, D6D79F582A13293200AB2315 /* BackgroundManager.swift */,
D69261262BB3BA610023152C /* Box.swift */, D69261262BB3BA610023152C /* Box.swift */,
D61F75B6293C119700C0B37F /* Filterer.swift */, D61F75B6293C119700C0B37F /* Filterer.swift */,
@ -1584,7 +1625,6 @@
D6DEBA8C2B6579830008629A /* MainThreadBox.swift */, D6DEBA8C2B6579830008629A /* MainThreadBox.swift */,
D6B81F432560390300F6E31D /* MenuController.swift */, D6B81F432560390300F6E31D /* MenuController.swift */,
D6CF5B842AC7C56F00F15D83 /* MultiColumnCollectionViewLayout.swift */, D6CF5B842AC7C56F00F15D83 /* MultiColumnCollectionViewLayout.swift */,
D64D8CA82463B494006B0BAA /* MultiThreadDictionary.swift */,
D6945C2E23AC47C3005C403C /* SavedDataManager.swift */, D6945C2E23AC47C3005C403C /* SavedDataManager.swift */,
D61F759E29385AD800C0B37F /* SemiCaseSensitiveComparator.swift */, D61F759E29385AD800C0B37F /* SemiCaseSensitiveComparator.swift */,
D6895DE828D962C2006341DA /* TimelineLikeController.swift */, D6895DE828D962C2006341DA /* TimelineLikeController.swift */,
@ -1727,6 +1767,7 @@
D6DD8FFC298495A8002AD3FD /* LogoutService.swift */, D6DD8FFC298495A8002AD3FD /* LogoutService.swift */,
D6D79F252A0C8D2700AB2315 /* FetchStatusSourceService.swift */, D6D79F252A0C8D2700AB2315 /* FetchStatusSourceService.swift */,
D630C3CB2BC5FD4600208903 /* GetAuthorizationTokenService.swift */, D630C3CB2BC5FD4600208903 /* GetAuthorizationTokenService.swift */,
D6210D752C0B924F009BB569 /* RemoveProfileSuggestionService.swift */,
); );
path = API; path = API;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1753,6 +1794,7 @@
D630C3E42BC6313400208903 /* Pachyderm */, D630C3E42BC6313400208903 /* Pachyderm */,
D630C4222BC7842C00208903 /* HTMLStreamer */, D630C4222BC7842C00208903 /* HTMLStreamer */,
D630C4242BC7845800208903 /* WebURL */, D630C4242BC7845800208903 /* WebURL */,
D62220462C7EA8DF003E43B7 /* TuskerPreferences */,
); );
productName = NotificationExtension; productName = NotificationExtension;
productReference = D630C3D12BC61B6000208903 /* NotificationExtension.appex */; productReference = D630C3D12BC61B6000208903 /* NotificationExtension.appex */;
@ -1954,6 +1996,7 @@
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
D6C453372BCE1CEF00E26A0E /* PrivacyInfo.xcprivacy in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -1971,7 +2014,6 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
D6E77D0D286E6B7300D8B732 /* TrendingLinkCardCollectionViewCell.xib in Resources */, D6E77D0D286E6B7300D8B732 /* TrendingLinkCardCollectionViewCell.xib in Resources */,
D693A73025CF91C6003A14E2 /* FeaturedProfileCollectionViewCell.xib in Resources */,
D61AC1D9232EA42D00C54D2D /* InstanceTableViewCell.xib in Resources */, D61AC1D9232EA42D00C54D2D /* InstanceTableViewCell.xib in Resources */,
D691296E2BA75ADF005C58ED /* PrivacyInfo.xcprivacy in Resources */, D691296E2BA75ADF005C58ED /* PrivacyInfo.xcprivacy in Resources */,
D6412B0B24B0D4C600F5412E /* ProfileHeaderView.xib in Resources */, D6412B0B24B0D4C600F5412E /* ProfileHeaderView.xib in Resources */,
@ -2098,6 +2140,7 @@
D61F75A5293ABD6F00C0B37F /* EditFilterView.swift in Sources */, D61F75A5293ABD6F00C0B37F /* EditFilterView.swift in Sources */,
D6BC9DB1232C61BC002CA326 /* NotificationsPageViewController.swift in Sources */, D6BC9DB1232C61BC002CA326 /* NotificationsPageViewController.swift in Sources */,
D6ADB6EC28EA73CB009924AB /* StatusContentContainer.swift in Sources */, D6ADB6EC28EA73CB009924AB /* StatusContentContainer.swift in Sources */,
D64A50462C739DC0009D7193 /* NewMainTabBarViewController.swift in Sources */,
D6969E9E240C81B9002843CE /* NSTextAttachment+Emoji.swift in Sources */, D6969E9E240C81B9002843CE /* NSTextAttachment+Emoji.swift in Sources */,
D6D79F532A0FFE3200AB2315 /* ToggleableButton.swift in Sources */, D6D79F532A0FFE3200AB2315 /* ToggleableButton.swift in Sources */,
D6BC9DB3232D4C07002CA326 /* WellnessPrefsView.swift in Sources */, D6BC9DB3232D4C07002CA326 /* WellnessPrefsView.swift in Sources */,
@ -2110,6 +2153,7 @@
D61F759B29384F9C00C0B37F /* FilterMO.swift in Sources */, D61F759B29384F9C00C0B37F /* FilterMO.swift in Sources */,
D68FEC4F232C5BC300C84F23 /* SegmentedPageViewController.swift in Sources */, D68FEC4F232C5BC300C84F23 /* SegmentedPageViewController.swift in Sources */,
D6934F342BA8D65A002B1C8D /* ImageGalleryDataSource.swift in Sources */, D6934F342BA8D65A002B1C8D /* ImageGalleryDataSource.swift in Sources */,
D6EEDE932C3CF21800E10E51 /* AudioSessionCoordinator.swift in Sources */,
D6C4532D2BCB86AC00E26A0E /* AppearancePrefsView.swift in Sources */, D6C4532D2BCB86AC00E26A0E /* AppearancePrefsView.swift in Sources */,
D64AAE9126C80DC600FC57FB /* ToastView.swift in Sources */, D64AAE9126C80DC600FC57FB /* ToastView.swift in Sources */,
D6BC74862AFC4772000DD603 /* SuggestedProfileCardView.swift in Sources */, D6BC74862AFC4772000DD603 /* SuggestedProfileCardView.swift in Sources */,
@ -2129,6 +2173,7 @@
D6934F3C2BAA0F80002B1C8D /* VideoGalleryContentViewController.swift in Sources */, D6934F3C2BAA0F80002B1C8D /* VideoGalleryContentViewController.swift in Sources */,
D6F6A552291F098700F496A8 /* RenameListService.swift in Sources */, D6F6A552291F098700F496A8 /* RenameListService.swift in Sources */,
D62D2426217ABF63005076CC /* UserActivityType.swift in Sources */, D62D2426217ABF63005076CC /* UserActivityType.swift in Sources */,
D698F46B2BD079F00054DB14 /* AnnouncementListRow.swift in Sources */,
D6AC956723C4347E008C9946 /* MainSceneDelegate.swift in Sources */, D6AC956723C4347E008C9946 /* MainSceneDelegate.swift in Sources */,
D6311C5025B3765B00B27539 /* ImageDataCache.swift in Sources */, D6311C5025B3765B00B27539 /* ImageDataCache.swift in Sources */,
D6934F362BA8E020002B1C8D /* GifvGalleryContentViewController.swift in Sources */, D6934F362BA8E020002B1C8D /* GifvGalleryContentViewController.swift in Sources */,
@ -2148,6 +2193,7 @@
D6934F322BA7E43E002B1C8D /* LoadingGalleryContentViewController.swift in Sources */, D6934F322BA7E43E002B1C8D /* LoadingGalleryContentViewController.swift in Sources */,
D68E525B24A3D77E0054355A /* TuskerRootViewController.swift in Sources */, D68E525B24A3D77E0054355A /* TuskerRootViewController.swift in Sources */,
D62D2422217AA7E1005076CC /* UserActivityManager.swift in Sources */, D62D2422217AA7E1005076CC /* UserActivityManager.swift in Sources */,
D64A50482C739DEA009D7193 /* BaseMainTabBarViewController.swift in Sources */,
D68A76E329524D2A001DA1B3 /* ListMO.swift in Sources */, D68A76E329524D2A001DA1B3 /* ListMO.swift in Sources */,
D63CC70C2910AADB000E19DE /* TuskerSceneDelegate.swift in Sources */, D63CC70C2910AADB000E19DE /* TuskerSceneDelegate.swift in Sources */,
D61F759D2938574B00C0B37F /* FilterRow.swift in Sources */, D61F759D2938574B00C0B37F /* FilterRow.swift in Sources */,
@ -2159,13 +2205,14 @@
D62D2424217ABF3F005076CC /* NSUserActivity+Extensions.swift in Sources */, D62D2424217ABF3F005076CC /* NSUserActivity+Extensions.swift in Sources */,
D6E77D0F286F773900D8B732 /* SplitNavigationController.swift in Sources */, D6E77D0F286F773900D8B732 /* SplitNavigationController.swift in Sources */,
D6B30E09254BAF63009CAEE5 /* ImageGrayscalifier.swift in Sources */, D6B30E09254BAF63009CAEE5 /* ImageGrayscalifier.swift in Sources */,
D698F4692BD0799F0054DB14 /* AnnouncementsView.swift in Sources */,
D6A6C10F25B62D2400298D0F /* DiskCache.swift in Sources */, D6A6C10F25B62D2400298D0F /* DiskCache.swift in Sources */,
D6C3F4F9298EDBF20009FCFF /* ConversationTree.swift in Sources */, D6C3F4F9298EDBF20009FCFF /* ConversationTree.swift in Sources */,
D698F46F2BD0B8DF0054DB14 /* AddReactionView.swift in Sources */,
D6B81F3C2560365300F6E31D /* RefreshableViewController.swift in Sources */, D6B81F3C2560365300F6E31D /* RefreshableViewController.swift in Sources */,
D6674AEA23341F7600E8DF94 /* AppShortcutItems.swift in Sources */, D6674AEA23341F7600E8DF94 /* AppShortcutItems.swift in Sources */,
D6DD8FFF2984D327002AD3FD /* BookmarksViewController.swift in Sources */, D6DD8FFF2984D327002AD3FD /* BookmarksViewController.swift in Sources */,
D646DCD22A06F2510059ECEB /* NotificationsCollectionViewController.swift in Sources */, D646DCD22A06F2510059ECEB /* NotificationsCollectionViewController.swift in Sources */,
D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */,
D6B4A4FF2506B81A000C81C1 /* AccountDisplayNameView.swift in Sources */, D6B4A4FF2506B81A000C81C1 /* AccountDisplayNameView.swift in Sources */,
D63D8DF42850FE7A008D95E1 /* ViewTags.swift in Sources */, D63D8DF42850FE7A008D95E1 /* ViewTags.swift in Sources */,
D630C3CC2BC5FD4600208903 /* GetAuthorizationTokenService.swift in Sources */, D630C3CC2BC5FD4600208903 /* GetAuthorizationTokenService.swift in Sources */,
@ -2186,8 +2233,10 @@
D691772E29AA5D420054D7EF /* UserActivityHandlingContext.swift in Sources */, D691772E29AA5D420054D7EF /* UserActivityHandlingContext.swift in Sources */,
04ED00B121481ED800567C53 /* SteppedProgressView.swift in Sources */, 04ED00B121481ED800567C53 /* SteppedProgressView.swift in Sources */,
D6A6C11B25B63CEE00298D0F /* MemoryCache.swift in Sources */, D6A6C11B25B63CEE00298D0F /* MemoryCache.swift in Sources */,
D64A50BC2C74F8F4009D7193 /* FindInstanceViewController.swift in Sources */,
D6114E0D27F7FEB30080E273 /* TrendingStatusesViewController.swift in Sources */, D6114E0D27F7FEB30080E273 /* TrendingStatusesViewController.swift in Sources */,
D6BC9DDA232D8BE5002CA326 /* SearchResultsViewController.swift in Sources */, D6BC9DDA232D8BE5002CA326 /* SearchResultsViewController.swift in Sources */,
D698F4672BD079800054DB14 /* AnnouncementsHostingController.swift in Sources */,
D61ABEF628EE74D400B29151 /* StatusCollectionViewCell.swift in Sources */, D61ABEF628EE74D400B29151 /* StatusCollectionViewCell.swift in Sources */,
D65B4B6629773AE600DABDFB /* DeleteStatusService.swift in Sources */, D65B4B6629773AE600DABDFB /* DeleteStatusService.swift in Sources */,
D61DC84628F498F200B82C6E /* Logging.swift in Sources */, D61DC84628F498F200B82C6E /* Logging.swift in Sources */,
@ -2202,8 +2251,8 @@
D65A261D2BC39399005EB5D8 /* PushInstanceSettingsView.swift in Sources */, D65A261D2BC39399005EB5D8 /* PushInstanceSettingsView.swift in Sources */,
D65C6BF525478A9C00A6E89C /* BackgroundableViewController.swift in Sources */, D65C6BF525478A9C00A6E89C /* BackgroundableViewController.swift in Sources */,
D61DC84D28F500D200B82C6E /* ProfileViewController.swift in Sources */, D61DC84D28F500D200B82C6E /* ProfileViewController.swift in Sources */,
D6187BED2BFA840B00B3A281 /* FollowRequestNotificationViewController.swift in Sources */,
D600891F29848DE2005B4D00 /* AddInstancePinnedTimelineView.swift in Sources */, D600891F29848DE2005B4D00 /* AddInstancePinnedTimelineView.swift in Sources */,
D693A72F25CF91C6003A14E2 /* FeaturedProfileCollectionViewCell.swift in Sources */,
D627943223A5466600D38C68 /* SelectableTableViewCell.swift in Sources */, D627943223A5466600D38C68 /* SelectableTableViewCell.swift in Sources */,
D64B96812BC3279D002C8990 /* PrefsAccountView.swift in Sources */, D64B96812BC3279D002C8990 /* PrefsAccountView.swift in Sources */,
D6EAE0DB2550CC8A002DB0AC /* FocusableTextField.swift in Sources */, D6EAE0DB2550CC8A002DB0AC /* FocusableTextField.swift in Sources */,
@ -2223,7 +2272,6 @@
D63CC7102911F1E4000E19DE /* UIScrollView+Top.swift in Sources */, D63CC7102911F1E4000E19DE /* UIScrollView+Top.swift in Sources */,
D6F6A557291F4F1600F496A8 /* MuteAccountView.swift in Sources */, D6F6A557291F4F1600F496A8 /* MuteAccountView.swift in Sources */,
D65B4B8B297879E900DABDFB /* AccountFollowsViewController.swift in Sources */, D65B4B8B297879E900DABDFB /* AccountFollowsViewController.swift in Sources */,
D6945C3A23AC75E2005C403C /* FindInstanceViewController.swift in Sources */,
D65B4B6429771EFF00DABDFB /* ConversationViewController.swift in Sources */, D65B4B6429771EFF00DABDFB /* ConversationViewController.swift in Sources */,
D68E6F59253C9969001A1B4C /* MultiSourceEmojiLabel.swift in Sources */, D68E6F59253C9969001A1B4C /* MultiSourceEmojiLabel.swift in Sources */,
D6EBF01523C55C0900AE061B /* UIApplication+Scenes.swift in Sources */, D6EBF01523C55C0900AE061B /* UIApplication+Scenes.swift in Sources */,
@ -2255,7 +2303,7 @@
D61ABEFE28F1C92600B29151 /* FavoriteService.swift in Sources */, D61ABEFE28F1C92600B29151 /* FavoriteService.swift in Sources */,
D61F75AB293AF11400C0B37F /* FilterKeywordMO.swift in Sources */, D61F75AB293AF11400C0B37F /* FilterKeywordMO.swift in Sources */,
D65B4B5A29720AB000DABDFB /* ReportStatusView.swift in Sources */, D65B4B5A29720AB000DABDFB /* ReportStatusView.swift in Sources */,
D6D9498F298EB79400C59229 /* CopyableLable.swift in Sources */, D6D9498F298EB79400C59229 /* CopyableLabel.swift in Sources */,
D6333B792139AEFD00CE884A /* Date+TimeAgo.swift in Sources */, D6333B792139AEFD00CE884A /* Date+TimeAgo.swift in Sources */,
D6D706A029466649000827ED /* ScrollingSegmentedControl.swift in Sources */, D6D706A029466649000827ED /* ScrollingSegmentedControl.swift in Sources */,
D686BBE324FBF8110068E6AA /* WrappedProgressView.swift in Sources */, D686BBE324FBF8110068E6AA /* WrappedProgressView.swift in Sources */,
@ -2292,6 +2340,7 @@
D6C693FE2162FEEA007D6A6D /* UIViewController+Children.swift in Sources */, D6C693FE2162FEEA007D6A6D /* UIViewController+Children.swift in Sources */,
D61A45EA28DF51EE002BE511 /* TimelineLikeCollectionViewController.swift in Sources */, D61A45EA28DF51EE002BE511 /* TimelineLikeCollectionViewController.swift in Sources */,
D64D0AB12128D9AE005A6F37 /* OnboardingViewController.swift in Sources */, D64D0AB12128D9AE005A6F37 /* OnboardingViewController.swift in Sources */,
D64A50BE2C752247009D7193 /* AdaptableNavigationController.swift in Sources */,
D6934F302BA7AF91002B1C8D /* ImageGalleryContentViewController.swift in Sources */, D6934F302BA7AF91002B1C8D /* ImageGalleryContentViewController.swift in Sources */,
D6934F3E2BAA19D5002B1C8D /* ImageActivityItemSource.swift in Sources */, D6934F3E2BAA19D5002B1C8D /* ImageActivityItemSource.swift in Sources */,
D67C1795266D57D10070F250 /* FastAccountSwitcherIndicatorView.swift in Sources */, D67C1795266D57D10070F250 /* FastAccountSwitcherIndicatorView.swift in Sources */,
@ -2311,6 +2360,7 @@
D65B4B542971F71D00DABDFB /* EditedReport.swift in Sources */, D65B4B542971F71D00DABDFB /* EditedReport.swift in Sources */,
D62D67C52A97D8CD00167EE2 /* MultiColumnNavigationController.swift in Sources */, D62D67C52A97D8CD00167EE2 /* MultiColumnNavigationController.swift in Sources */,
D6A6C11525B62E9700298D0F /* CacheExpiry.swift in Sources */, D6A6C11525B62E9700298D0F /* CacheExpiry.swift in Sources */,
D69F26342C4CDFD300FAF761 /* AccountDisplayAndUserNameLabel.swift in Sources */,
D67C57AF21E28EAD00C3118B /* Array+Uniques.swift in Sources */, D67C57AF21E28EAD00C3118B /* Array+Uniques.swift in Sources */,
D68A76F129539116001DA1B3 /* FlipView.swift in Sources */, D68A76F129539116001DA1B3 /* FlipView.swift in Sources */,
D6945C3223AC4D36005C403C /* HashtagTimelineViewController.swift in Sources */, D6945C3223AC4D36005C403C /* HashtagTimelineViewController.swift in Sources */,
@ -2323,8 +2373,10 @@
D693A72825CF282E003A14E2 /* TrendingHashtagsViewController.swift in Sources */, D693A72825CF282E003A14E2 /* TrendingHashtagsViewController.swift in Sources */,
D621733328F1D5ED004C7DB1 /* ReblogService.swift in Sources */, D621733328F1D5ED004C7DB1 /* ReblogService.swift in Sources */,
D62275A824F1CA2800B82A16 /* ComposeReplyContentView.swift in Sources */, D62275A824F1CA2800B82A16 /* ComposeReplyContentView.swift in Sources */,
D698F46D2BD0B8310054DB14 /* AnnouncementsCollection.swift in Sources */,
D61F75AF293AF50C00C0B37F /* EditedFilter.swift in Sources */, D61F75AF293AF50C00C0B37F /* EditedFilter.swift in Sources */,
D691771929A7B8820054D7EF /* ProfileHeaderMovedOverlayView.swift in Sources */, D691771929A7B8820054D7EF /* ProfileHeaderMovedOverlayView.swift in Sources */,
D6210D762C0B924F009BB569 /* RemoveProfileSuggestionService.swift in Sources */,
D61F75B9293C15A000C0B37F /* ZeroHeightCollectionViewCell.swift in Sources */, D61F75B9293C15A000C0B37F /* ZeroHeightCollectionViewCell.swift in Sources */,
D68232F72464F4FD00325FB8 /* ComposeDrawingViewController.swift in Sources */, D68232F72464F4FD00325FB8 /* ComposeDrawingViewController.swift in Sources */,
04586B4122B2FFB10021BD04 /* PreferencesView.swift in Sources */, 04586B4122B2FFB10021BD04 /* PreferencesView.swift in Sources */,
@ -2335,7 +2387,6 @@
D62E9987279D094F00C26176 /* StatusMetaIndicatorsView.swift in Sources */, D62E9987279D094F00C26176 /* StatusMetaIndicatorsView.swift in Sources */,
D6BEA247291A0F2D002F4D01 /* Duckable+Root.swift in Sources */, D6BEA247291A0F2D002F4D01 /* Duckable+Root.swift in Sources */,
D6C1B2082545D1EC00DAAA66 /* StatusCardView.swift in Sources */, D6C1B2082545D1EC00DAAA66 /* StatusCardView.swift in Sources */,
D64D8CA92463B494006B0BAA /* MultiThreadDictionary.swift in Sources */,
D630C3CA2BC59FF500208903 /* MastodonController+Push.swift in Sources */, D630C3CA2BC59FF500208903 /* MastodonController+Push.swift in Sources */,
D6F6A554291F0D9600F496A8 /* DeleteListService.swift in Sources */, D6F6A554291F0D9600F496A8 /* DeleteListService.swift in Sources */,
D68E6F5F253C9B2D001A1B4C /* BaseEmojiLabel.swift in Sources */, D68E6F5F253C9B2D001A1B4C /* BaseEmojiLabel.swift in Sources */,
@ -2367,9 +2418,11 @@
D6934F2E2BA7AEF9002B1C8D /* StatusAttachmentsGalleryDataSource.swift in Sources */, D6934F2E2BA7AEF9002B1C8D /* StatusAttachmentsGalleryDataSource.swift in Sources */,
D623A543263634100095BD04 /* PollOptionCheckboxView.swift in Sources */, D623A543263634100095BD04 /* PollOptionCheckboxView.swift in Sources */,
D6C4532F2BCB873400E26A0E /* MockStatusView.swift in Sources */, D6C4532F2BCB873400E26A0E /* MockStatusView.swift in Sources */,
D698F4712BD0CBAA0054DB14 /* AnnouncementContentTextView.swift in Sources */,
D68A76E829527884001DA1B3 /* PinnedTimelinesView.swift in Sources */, D68A76E829527884001DA1B3 /* PinnedTimelinesView.swift in Sources */,
D690797324A4EF9700023A34 /* UIBezierPath+Helpers.swift in Sources */, D690797324A4EF9700023A34 /* UIBezierPath+Helpers.swift in Sources */,
D6D12B5A292D684600D528E1 /* AccountListViewController.swift in Sources */, D6D12B5A292D684600D528E1 /* AccountListViewController.swift in Sources */,
D6A8D7A52C14DB280007B285 /* PersistentHistoryTokenStore.swift in Sources */,
D693DE5723FE1A6A0061E07D /* EnhancedNavigationViewController.swift in Sources */, D693DE5723FE1A6A0061E07D /* EnhancedNavigationViewController.swift in Sources */,
D646DCDC2A081CF10059ECEB /* StatusUpdatedNotificationCollectionViewCell.swift in Sources */, D646DCDC2A081CF10059ECEB /* StatusUpdatedNotificationCollectionViewCell.swift in Sources */,
); );
@ -2490,6 +2543,7 @@
INFOPLIST_FILE = NotificationExtension/Info.plist; INFOPLIST_FILE = NotificationExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = NotificationExtension; INFOPLIST_KEY_CFBundleDisplayName = NotificationExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Shadowfacts. All rights reserved."; INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Shadowfacts. All rights reserved.";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -2522,6 +2576,7 @@
INFOPLIST_FILE = NotificationExtension/Info.plist; INFOPLIST_FILE = NotificationExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = NotificationExtension; INFOPLIST_KEY_CFBundleDisplayName = NotificationExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Shadowfacts. All rights reserved."; INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Shadowfacts. All rights reserved.";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -2553,6 +2608,7 @@
INFOPLIST_FILE = NotificationExtension/Info.plist; INFOPLIST_FILE = NotificationExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = NotificationExtension; INFOPLIST_KEY_CFBundleDisplayName = NotificationExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Shadowfacts. All rights reserved."; INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Shadowfacts. All rights reserved.";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -2634,7 +2690,8 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; "ASSETCATALOG_COMPILER_APPICON_NAME[sdk=*]" = AppIcon;
"ASSETCATALOG_COMPILER_APPICON_NAME[sdk=xros*]" = "AppIcon-vision";
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements; CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_IDENTITY = "iPhone Developer";
@ -2642,6 +2699,7 @@
CURRENT_PROJECT_VERSION = "$(CURRENT_PROJECT_VERSION)"; CURRENT_PROJECT_VERSION = "$(CURRENT_PROJECT_VERSION)";
INFOPLIST_FILE = Tusker/Info.plist; INFOPLIST_FILE = Tusker/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -2685,7 +2743,7 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
INFOPLIST_FILE = TuskerUITests/Info.plist; INFOPLIST_FILE = TuskerUITests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0; IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -2708,6 +2766,7 @@
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(CURRENT_PROJECT_VERSION)"; CURRENT_PROJECT_VERSION = "$(CURRENT_PROJECT_VERSION)";
INFOPLIST_FILE = OpenInTusker/Info.plist; INFOPLIST_FILE = OpenInTusker/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -2735,6 +2794,7 @@
INFOPLIST_FILE = ShareExtension/Info.plist; INFOPLIST_FILE = ShareExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension; INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Shadowfacts. All rights reserved."; INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Shadowfacts. All rights reserved.";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -2763,6 +2823,7 @@
INFOPLIST_FILE = ShareExtension/Info.plist; INFOPLIST_FILE = ShareExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension; INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Shadowfacts. All rights reserved."; INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Shadowfacts. All rights reserved.";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -2791,6 +2852,7 @@
INFOPLIST_FILE = ShareExtension/Info.plist; INFOPLIST_FILE = ShareExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension; INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Shadowfacts. All rights reserved."; INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Shadowfacts. All rights reserved.";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -2937,7 +2999,8 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; "ASSETCATALOG_COMPILER_APPICON_NAME[sdk=*]" = AppIcon;
"ASSETCATALOG_COMPILER_APPICON_NAME[sdk=xros*]" = "AppIcon-vision";
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements; CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_IDENTITY = "iPhone Developer";
@ -2945,6 +3008,7 @@
CURRENT_PROJECT_VERSION = "$(CURRENT_PROJECT_VERSION)"; CURRENT_PROJECT_VERSION = "$(CURRENT_PROJECT_VERSION)";
INFOPLIST_FILE = Tusker/Info.plist; INFOPLIST_FILE = Tusker/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -2968,7 +3032,8 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; "ASSETCATALOG_COMPILER_APPICON_NAME[sdk=*]" = AppIcon;
"ASSETCATALOG_COMPILER_APPICON_NAME[sdk=xros*]" = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements; CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_IDENTITY = "iPhone Developer";
@ -2976,6 +3041,7 @@
CURRENT_PROJECT_VERSION = "$(CURRENT_PROJECT_VERSION)"; CURRENT_PROJECT_VERSION = "$(CURRENT_PROJECT_VERSION)";
INFOPLIST_FILE = Tusker/Info.plist; INFOPLIST_FILE = Tusker/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -3040,7 +3106,7 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
INFOPLIST_FILE = TuskerUITests/Info.plist; INFOPLIST_FILE = TuskerUITests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0; IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -3060,7 +3126,7 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
INFOPLIST_FILE = TuskerUITests/Info.plist; INFOPLIST_FILE = TuskerUITests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0; IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -3083,6 +3149,7 @@
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(CURRENT_PROJECT_VERSION)"; CURRENT_PROJECT_VERSION = "$(CURRENT_PROJECT_VERSION)";
INFOPLIST_FILE = OpenInTusker/Info.plist; INFOPLIST_FILE = OpenInTusker/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -3107,6 +3174,7 @@
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(CURRENT_PROJECT_VERSION)"; CURRENT_PROJECT_VERSION = "$(CURRENT_PROJECT_VERSION)";
INFOPLIST_FILE = OpenInTusker/Info.plist; INFOPLIST_FILE = OpenInTusker/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -3203,7 +3271,7 @@
repositoryURL = "https://git.shadowfacts.net/shadowfacts/HTMLStreamer.git"; repositoryURL = "https://git.shadowfacts.net/shadowfacts/HTMLStreamer.git";
requirement = { requirement = {
kind = exactVersion; kind = exactVersion;
version = 0.2.3; version = 0.3.0;
}; };
}; };
D63CC700290EC0B8000E19DE /* XCRemoteSwiftPackageReference "sentry-cocoa" */ = { D63CC700290EC0B8000E19DE /* XCRemoteSwiftPackageReference "sentry-cocoa" */ = {
@ -3211,7 +3279,7 @@
repositoryURL = "https://github.com/getsentry/sentry-cocoa.git"; repositoryURL = "https://github.com/getsentry/sentry-cocoa.git";
requirement = { requirement = {
kind = upToNextMinorVersion; kind = upToNextMinorVersion;
minimumVersion = 8.21.0; minimumVersion = 8.33.0;
}; };
}; };
D6552365289870790048A653 /* XCRemoteSwiftPackageReference "ScreenCorners" */ = { D6552365289870790048A653 /* XCRemoteSwiftPackageReference "ScreenCorners" */ = {
@ -3226,8 +3294,8 @@
isa = XCRemoteSwiftPackageReference; isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/karwa/swift-url"; repositoryURL = "https://github.com/karwa/swift-url";
requirement = { requirement = {
branch = main; kind = exactVersion;
kind = branch; version = 0.4.2;
}; };
}; };
/* End XCRemoteSwiftPackageReference section */ /* End XCRemoteSwiftPackageReference section */
@ -3242,6 +3310,10 @@
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
productName = Pachyderm; productName = Pachyderm;
}; };
D62220462C7EA8DF003E43B7 /* TuskerPreferences */ = {
isa = XCSwiftPackageProductDependency;
productName = TuskerPreferences;
};
D630C3C72BC43AFD00208903 /* PushNotifications */ = { D630C3C72BC43AFD00208903 /* PushNotifications */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
productName = PushNotifications; productName = PushNotifications;

View File

@ -58,7 +58,8 @@ private extension Pachyderm.PushSubscription.Alerts {
followRequest: alerts.contains(.followRequest), followRequest: alerts.contains(.followRequest),
favourite: alerts.contains(.favorite), favourite: alerts.contains(.favorite),
poll: alerts.contains(.poll), poll: alerts.contains(.poll),
update: alerts.contains(.update) update: alerts.contains(.update),
emojiReaction: alerts.contains(.emojiReaction)
) )
} }
} }

View File

@ -0,0 +1,39 @@
//
// RemoveProfileSuggestionService.swift
// Tusker
//
// Created by Shadowfacts on 6/1/24.
// Copyright © 2024 Shadowfacts. All rights reserved.
//
import Foundation
import Pachyderm
@MainActor
class RemoveProfileSuggestionService {
private let accountID: String
private let mastodonController: MastodonController
private let presenter: any TuskerNavigationDelegate
private let completionHandler: @MainActor () -> Void
init(accountID: String, mastodonController: MastodonController, presenter: any TuskerNavigationDelegate, completionHandler: @MainActor @escaping () -> Void) {
self.accountID = accountID
self.mastodonController = mastodonController
self.presenter = presenter
self.completionHandler = completionHandler
}
func run() async {
let req = Suggestion.remove(accountID: accountID)
do {
_ = try await mastodonController.run(req)
completionHandler()
} catch {
let config = ToastConfiguration(from: error, with: "Error Removing Suggestion", in: presenter) { toast in
toast.dismissToast(animated: true)
await self.run()
}
self.presenter.showToast(configuration: config, animated: true)
}
}
}

View File

@ -56,6 +56,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// make sure the persistent container is initialized on the main thread // make sure the persistent container is initialized on the main thread
// otherwise initializing it on the background thread can deadlock with accessing it on the main thread elsewhere // otherwise initializing it on the background thread can deadlock with accessing it on the main thread elsewhere
#if canImport(Sentry)
DraftsPersistentContainer.captureError = { SentrySDK.capture(error: $0) }
#endif
_ = DraftsPersistentContainer.shared _ = DraftsPersistentContainer.shared
DispatchQueue.global(qos: .userInitiated).async { DispatchQueue.global(qos: .userInitiated).async {
@ -107,6 +110,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// we don't care about events like battery, keyboard show/hide // we don't care about events like battery, keyboard show/hide
options.enableAutoBreadcrumbTracking = false options.enableAutoBreadcrumbTracking = false
options.enableUserInteractionTracing = false options.enableUserInteractionTracing = false
options.profilesSampleRate = nil
options.tracesSampleRate = nil
options.beforeSend = { event in options.beforeSend = { event in
// just no, why would anyone need this information // just no, why would anyone need this information
@ -185,7 +190,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
let mastodonController = MastodonController.getForAccount(account) let mastodonController = MastodonController.getForAccount(account)
do { do {
let result = try await mastodonController.updatePushSubscription(subscription: $0) let result = try await mastodonController.updatePushSubscription(subscription: $0)
PushManager.logger.debug("Updated push subscription \(result.id) on \(mastodonController.instanceURL)") PushManager.logger.info("Updated push subscription \(result.id, privacy: .public) on \(mastodonController.instanceURL) with endpoint \($0.endpoint, privacy: .public)")
PushManager.logger.debug("New push subscription: \(String(describing: result))")
return true return true
} catch { } catch {
PushManager.logger.error("Error updating push subscription: \(String(describing: error))") PushManager.logger.error("Error updating push subscription: \(String(describing: error))")
@ -286,15 +292,24 @@ extension AppDelegate: UNUserNotificationCenterDelegate {
let rootViewController = delegate.rootViewController { let rootViewController = delegate.rootViewController {
let mastodonController = MastodonController.getForAccount(account) let mastodonController = MastodonController.getForAccount(account)
// if the scene is already active, then we animate the account switching if necessary // if the scene is already active, then we animate things
delegate.activateAccount(account, animated: scene.activationState == .foregroundActive) let animated = scene.activationState == .foregroundActive
rootViewController.select(route: .notifications, animated: false) delegate.activateAccount(account, animated: animated)
let vc = NotificationLoadingViewController(notificationID: notificationID, mastodonController: mastodonController)
rootViewController.getNavigationController().pushViewController(vc, animated: false) rootViewController.runNavigation(animated: animated) { navigation in
navigation.select(route: .notifications)
let vc = NotificationLoadingViewController(notificationID: notificationID, mastodonController: mastodonController)
navigation.push(viewController: vc)
}
} else { } else {
let activity = UserActivityManager.showNotificationActivity(id: notificationID, accountID: accountID) let activity = UserActivityManager.showNotificationActivity(id: notificationID, accountID: accountID)
UIApplication.shared.requestSceneSessionActivation(nil, userActivity: activity, options: nil) if #available(iOS 17.0, *) {
let request = UISceneSessionActivationRequest(userActivity: activity)
UIApplication.shared.activateSceneSession(for: request)
} else {
UIApplication.shared.requestSceneSessionActivation(nil, userActivity: activity, options: nil)
}
} }
completionHandler() completionHandler()
} }

View File

@ -0,0 +1,13 @@
{
"images" : [
{
"filename" : "back.png",
"idiom" : "vision",
"scale" : "2x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,14 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"layers" : [
{
"filename" : "Front.solidimagestacklayer"
},
{
"filename" : "Back.solidimagestacklayer"
}
]
}

View File

@ -0,0 +1,13 @@
{
"images" : [
{
"filename" : "front.png",
"idiom" : "vision",
"scale" : "2x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 723 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 968 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1022 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Some files were not shown because too many files have changed in this diff Show More