Compare commits

..

366 commits

Author SHA1 Message Date
Thomas Ricouard
27b3856e05 Various fixes to share as image + copy text 2024-09-27 15:22:34 +02:00
Thomas Ricouard
93beb2fbd9 Only upload on EmergeTools workflow 2024-09-27 09:29:05 +02:00
Thomas Ricouard
04344ba834 fix ci 2024-09-27 08:52:38 +02:00
Thomas Ricouard
f220837309 Fix post script ^2 2024-09-27 08:42:43 +02:00
Thomas Ricouard
97c9a1fcf4 Fix post script 2024-09-27 08:32:47 +02:00
Thomas Ricouard
b4900989fa Upload to emergetools 2024-09-27 08:27:13 +02:00
Pierre-Yves Lapersonne
8b89eb61cc
fix(i18n): add missing french l10n (#2200) (#2201)
Some wording in french are not translated, this commit brings more translations. As a french-native speaker, I validate these wordings

Closes #2200

Signed-off-by: Pierre-Yves Lapersonne <dev@pylapersonne.info>
Co-authored-by: Thomas Ricouard <ricouard77@gmail.com>
2024-09-26 15:45:09 +02:00
Jesús Jiménez Sánchez
90d97885cd
Update ES localization (#2196) 2024-09-26 15:42:07 +02:00
Thomas Ricouard
974d3f1804 Removed unused Telemetry userId 2024-09-26 15:38:22 +02:00
Thomas Ricouard
f0c91784d0 Capsule design for pills 2024-09-25 12:50:05 +02:00
Thomas Ricouard
9fbd0a6a2f Cleanup 2024-09-25 12:49:54 +02:00
Thomas Ricouard
70eb781407 Add a wide layout option 2024-09-22 11:30:47 +02:00
Thomas Ricouard
56f0afb062 Bump version to 1.11.0 2024-09-22 11:13:50 +02:00
Thomas Ricouard
3be69aa4a7 Typo 2024-09-20 14:13:53 +02:00
Thomas Ricouard
6e766a3fa8 Update screenshots 2024-09-20 14:09:15 +02:00
Thomas Ricouard
9af485b2be Correctly updated grouped notifications 2024-09-20 09:23:36 +02:00
Thomas Ricouard
71027e2cc3 Add Picasso screenshots 2024-09-19 13:46:22 +02:00
Thomas Ricouard
4338e0a355 Fix the marker restore 2024-09-19 13:46:13 +02:00
Thomas Ricouard
df19135e19 Typos 2024-09-19 13:46:06 +02:00
Thomas Ricouard
12b6c1af36 Restore tap on status counter 2024-09-19 10:10:25 +02:00
Thomas Ricouard
db7155423a Add back posts streaming behind a setting, default to off 2024-09-19 09:55:56 +02:00
Thomas Ricouard
7eeaf4d902 Add explanations to some settings 2024-09-19 09:30:31 +02:00
Thomas Ricouard
b19a5706e2 Update packages 2024-09-19 09:16:49 +02:00
Thomas Ricouard
a1ce85b188 Bump version to 1.10.59 2024-09-19 09:06:38 +02:00
Thomas Ricouard
009150bc3e Fix MediaUI close button on Catalyst 2024-09-19 08:59:36 +02:00
Thomas Ricouard
23960d6d0f Embed Threads quote 2024-09-18 16:53:54 +02:00
Thomas Ricouard
4dd4968bb2 Fix image preview sheet 2024-09-18 15:53:55 +02:00
Thomas Ricouard
b0846c9a3d Fix issue with various editor sheets 2024-09-18 15:38:42 +02:00
Thomas Ricouard
7cef1c5786 Bump version to 1.10.58 2024-09-18 15:14:38 +02:00
Thomas Ricouard
a167bcdf28 Fix iPad app refresh on background 2024-09-17 20:49:51 +02:00
Thomas Ricouard
d2eca1d646 Fetch timeline 40 per page + 200 per batch 2024-09-17 14:26:57 +02:00
Thomas Ricouard
9ec6a4ef66 Cleanup + use ScrollPoxy 2024-09-17 14:01:32 +02:00
Thomas Ricouard
576b52e8c8 Bump version to 1.10.57 2024-09-17 08:49:00 +02:00
Thomas Ricouard
46f481aabd More fixes 2024-09-17 08:23:53 +02:00
Thomas Ricouard
81d5d4396f More fixes for VideoPlayer 2024-09-16 17:41:55 +02:00
Thomas Ricouard
f610c3f047 Fix timeline next page 2024-09-16 17:32:46 +02:00
Thomas Ricouard
7a35779b29 Fix notifications filter 2024-09-16 17:32:37 +02:00
Thomas Ricouard
e4d1196301 Fix video player 2024-09-16 17:32:31 +02:00
Thomas Ricouard
93421c56d9 Timeline: cleanup datasource near bottom 2024-09-15 13:25:51 +02:00
Thomas Ricouard
0b7c6a799f Bump version to 1.10.56 2024-09-15 08:27:43 +02:00
Thomas Ricouard
8f71f6649a Fixes 2024-09-15 08:06:10 +02:00
Thomas Ricouard
122e57d8ac Restore ScrollToTop on timeline tab 2024-09-14 08:09:51 +02:00
Thomas Ricouard
594fb3ea07 New iOS 18 Icon 2024-09-13 15:21:14 +02:00
Thomas Ricouard
2f1632b950 Bump version to 1.10.55 2024-09-13 14:03:05 +02:00
Thomas Ricouard
c1dfb0a085 Fix tests 2024-09-13 13:22:41 +02:00
Thomas Ricouard
ae1bfbeb45 Lint 2024-09-13 12:06:08 +02:00
Thomas Ricouard
6d289ebd09 Completely remove stream for new statuses 2024-09-13 12:04:55 +02:00
Thomas Ricouard
be2939b13c Fix copy link 2024-09-13 11:27:09 +02:00
Thomas Ricouard
491090e373 New pending statuses behavior 2024-09-13 11:27:01 +02:00
Thomas Ricouard
7c5f2aea81 Bump version to 1.10.54 2024-09-13 11:18:44 +02:00
Thomas Ricouard
24f8982bd4 Fiw boot on macOS 14 2024-09-13 10:08:38 +02:00
Thomas Ricouard
7b67ba0294 Bump version to 1.10.53 2024-09-13 10:02:59 +02:00
Thomas Ricouard
698edc4d58 Catalyst: Fix window size 2024-09-11 21:48:03 +02:00
Thomas Ricouard
9d5d341764 fix macOS window 2024-09-11 11:00:34 +02:00
Thomas Ricouard
896c031ab0 Merge branch 'hotfix-sidebar' 2024-09-11 10:03:32 +02:00
Thomas Ricouard
c0b0a3ee1c Fix sidebar 2024-09-11 09:50:32 +02:00
Thomas Ricouard
30b9a95cac Bump version to 1.10.52 2024-09-11 08:50:02 +02:00
Thomas Ricouard
0a15f7ff1c fix visionOS build 2024-09-10 11:44:14 +02:00
Thomas Ricouard
8f7df06d21 Fix tests 2024-09-10 11:31:16 +02:00
Thomas Ricouard
6297a428a3
Full Xcode 16 supports + iOS 18 support (#2100)
* Compile on iOS 18

* Fix more warnings

* Tweak build settings

* Migrate to Swift Tests

* better tests

* Fix

* Fix tests

* More TabView cleanup

Bump to iOS 18 only + remove custom sidebar

* Revert "More TabView cleanup"

This reverts commit e051437fcb.

* Tabbar fix + bump to iOS 18

* Remove popToRoot

* Cleanup scrollToTop

* Support both TapBar

* Better TabView support

* Better TabView support

* Cleanup

* Disable TabView animations

* Remove id in ForEach

* Remove external init for StatusRowView

* Cleanup

* More Swift 6 concurrency

* Swift 6 mode

* Fixes

* Full Swift 6 packages support

* For now compile env in Swift 5 mode

* Fix archive

* More fix to Archive

* Address `dispatch_assert_queue_fail` (#2161)

See https://twitter.com/dimillian/status/1823089444397724003?s=61&t=SC3rvyJQWn1NQqAgMVrT0Q

* Bump Env to Swift 6

* Fix push notification

* Remove unecessary workaround

* Cleanup

* Move to @Entry

* Fix TabView on Catalyst

* Fix build

* Fix build 2

* fix warning

* Fix icons for iOS 18

---------

Co-authored-by: NachoSoto <NachoSoto@users.noreply.github.com>
2024-09-10 06:53:19 +02:00
Thomas Ricouard
4cce9d6333 Fix build 2024-09-06 11:34:20 +02:00
Thomas Ricouard
435f28dda9 UI tweaks 2024-09-06 11:32:49 +02:00
Thomas Ricouard
904cd3dbd7 Fix Catalyst build 2024-09-06 07:53:01 +02:00
Jesús Jiménez Sánchez
ce3e2d2344
Update ES localization (#2177) 2024-09-05 15:57:23 +02:00
Jerry Zhang
5080a536db
Update Simplified Chinese localization (#2173)
* Update Simplified Chinese localization

* Update term on telemetry for SC localization

* Update SC translation for Telemetry

Co-Authored-By: nixzhu <zhuhongxu@gmail.com>

* Fix TelemetryDeck name

---------

Co-authored-by: nixzhu <zhuhongxu@gmail.com>
2024-09-05 15:57:15 +02:00
Thomas Ricouard
55cbd9ea6f Fix setting background 2024-09-03 16:37:01 +02:00
Thomas Ricouard
24f77a99e1 Fix TelemetryDeck copy 2024-09-03 16:34:10 +02:00
Alessio Mason
45628b5a5f
Updated Italian localization (#2172)
* Latest Italian localizations

* Updated Italian localization
2024-09-03 10:15:27 +02:00
Klaus Dresbach
1b7720c9c4
Prevent a tab item from being set twice (#2166) 2024-09-03 10:15:19 +02:00
Thomas Ricouard
199749b809 Bump version to 1.10.51 2024-08-30 11:48:14 +02:00
Thomas Ricouard
e0eed97bcf Direct subscribe to sub.club 2024-08-21 18:22:38 +02:00
Thomas Ricouard
f80fca91e2 Add TelemetryDeck about 2024-08-20 09:32:33 +02:00
Thomas Ricouard
dc85557d40 Tweak to notifications policy 2024-08-16 07:24:19 +02:00
Thomas Ricouard
412f475d1d Connect to notification filters V2 2024-08-15 22:30:31 +02:00
Thomas Ricouard
dfbbb84e9d Bump version to 1.10.50 2024-08-15 21:37:37 +02:00
Thomas Ricouard
83bf872cca Add timer for sub.club account 2024-08-15 21:25:04 +02:00
Thomas Ricouard
8c6d2bee7f Add Wishlist Kit 2024-08-15 09:23:07 +02:00
Thomas Ricouard
824b2de23f Bump version to 1.10.49 2024-08-14 21:21:06 +02:00
Thomas Ricouard
48febd628f Ignore cancelled error on timeline 2024-08-14 20:27:26 +02:00
Thomas Ricouard
dd1a4585e0 Fix build on visionOS 2024-08-14 20:19:20 +02:00
Thomas Ricouard
1ad4a245f3
Add support for sub.club support (#2162)
* Account tipping

* Tryout full flow

* Add link params

* WIP

* Progress flow

* Fixes

* More progress

* Refresh user profile on notification

* Tweaks

* Fix follow button not refreshing

* Refactor proxy url

* Code cleanup

* Subscribe to a premium account from a standard linked account

* Premium posts tab on linked standard account

* Fix flow

* New domain

* Fix flow

* More fixes to follow flow

* Update so to sub.club

* Add colorScheme in URL

* rollback domain

* Back to sub.club

* Use SubClub API for Subscription info

* Fix

* Merge

* Merge branch 'iOS-18' + fixes
2024-08-14 20:07:43 +02:00
Thomas Ricouard
9d11814e49 Add TelemetryDeck 2024-08-14 17:23:10 +02:00
Thomas Ricouard
56869e3a2f Allow cancel add account sheet even when no account 2024-08-14 17:23:00 +02:00
Thomas Ricouard
a737ac19e5 Add Labels in settings 2024-08-14 17:22:44 +02:00
Thomas Ricouard
456d85eda2 New alternative icon settings 2024-08-14 17:22:27 +02:00
Thomas Ricouard
4158f7c959 Bump version to 1.10.48 2024-08-14 08:47:57 +02:00
Thomas Ricouard
113c4f1c84 Display push notification while in the app 2024-08-14 08:45:20 +02:00
Ahnaf Mahmud
77bec1fae3
Remove space between Settings and ellipsis (#2125) 2024-08-14 08:43:35 +02:00
Thomas Ricouard
6f608efa7f Switch to gpt4 o-mini 2024-08-13 12:41:46 +02:00
Thomas Ricouard
6c9d9161dc Extract function from TimelineViewModel 2024-08-05 13:59:38 +02:00
Thomas Ricouard
a72f290038 Lint 2024-08-01 08:58:54 +02:00
Thomas Ricouard
2a3da72239 Update purchase ios 2024-08-01 08:56:34 +02:00
Thomas Ricouard
9fa19aa132 Add media grid on user profile 2024-07-31 18:44:29 +02:00
Thomas Ricouard
123f05538a Paginate search results fix #2143 2024-07-31 11:19:43 +02:00
Thomas Ricouard
719c023369 Bump version to 1.10.47 2024-07-31 11:02:02 +02:00
Thomas Ricouard
0338d54d81 Fix #2147 2024-07-31 10:47:56 +02:00
Jesús Jiménez Sánchez
6fa4ac6f79
Update ES localization (#2148) 2024-07-30 09:24:16 +02:00
Jerry Zhang
cf494fd07a
Update Simplified Chinese localization (#2140) 2024-07-30 09:24:09 +02:00
Adem Özsayın
6766ed496d
Fix nav bar crash and empty settings screen after logout (#2124) 2024-07-29 07:57:33 +02:00
fwcd
33c2646ea1
Make status rows draggable (#2141) 2024-07-29 07:56:42 +02:00
fwcd
9af98c3921
Add context menu and draggability to attachment image views (#2142)
* Factor out MediaUIShareLink

* Add share link to attachment image view

* Make attachment image views draggable

* Add copy actions to attachment image view
2024-07-29 07:56:22 +02:00
Keita Watanabe
4f9cb2e86a
fix sendable (#2144) 2024-07-29 07:55:44 +02:00
Thomas Ricouard
4c1ba2168d Fix double media in share sheet 2024-07-22 13:35:30 +02:00
Thomas Ricouard
be02b2ea76 Fix toolbar 2024-07-22 08:28:42 +02:00
Klaus Dresbach
a3326c3fc2
AddAccountView: fix error handling (#2137) 2024-07-22 07:17:49 +02:00
Ege Sucu
563213d98f
Changed a Translation Wording (#2136)
"Yükselişteki" is not a 100% translation for "Trend", we also have "Trend" in Turkish & this old longer version breaks UI on the tab because of more characters.
2024-07-22 07:17:42 +02:00
Thomas Ricouard
82338f815a Small Refactor TimelineViewModel 2024-07-21 11:20:36 +02:00
Thomas Ricouard
7a9b6cc0e0 Fix icons credit 2024-07-20 21:36:01 +02:00
Thomas Ricouard
339e2ab1c3 new community icons 2024-07-20 21:32:20 +02:00
Thomas Ricouard
f18f3e0e84 Bump version to 1.10.46 2024-07-20 19:14:31 +02:00
Thomas Ricouard
fc6b2129dd Cleanup 2024-07-18 21:37:18 +02:00
Thomas Ricouard
54768772b5 Remove external init for StatusRowView 2024-07-18 21:37:18 +02:00
Thomas Ricouard
3f2fbeeec4 Remove id in ForEach 2024-07-18 21:37:18 +02:00
Ico Davids
47b5fdf92e
Updated NL translations (#2129)
* Updated NL translations

* Some ellipsis tuning
2024-07-17 17:30:48 +02:00
Klaus Dresbach
d320caaa4f
AddRemoteTimelineView: show error message when instance is invalid (#2105) (#2133) 2024-07-17 17:30:30 +02:00
Thomas Ricouard
fbff1d6dfe Adjust content gradient + settings 2024-07-16 09:00:11 +02:00
Thomas Ricouard
3c5c9adc03 Cache tag + gradient on home timeline 2024-07-10 16:13:41 +02:00
nixzhu
5969e8a166
update Simplified Chinese localization (#2121) 2024-07-09 16:08:46 +02:00
Thomas Ricouard
8a33b6c0d0 better attribution UI 2024-07-05 08:45:40 +02:00
Thomas Ricouard
d7429c078f Timeline subtitle 2024-07-04 08:54:23 +02:00
Thomas Ricouard
6f3f8e9dd0 Fix #2116 2024-07-03 14:17:35 +02:00
Thomas Ricouard
b98a90ced6 Bump version to 1.10.45 2024-07-03 09:22:49 +02:00
Christopher Schindler
fdb213e4bf
AccountDetail: fix wrong space on top of the header view (#2113) 2024-07-03 08:12:29 +02:00
Xabi
4b8d7113f1
Update EU localisation (#2112)
Added delete header and delete avatar
2024-07-03 08:12:16 +02:00
Thomas Ricouard
7b9cfc2863 Enable links in iPad / macOS sidebar 2024-07-02 20:22:09 +02:00
Thomas Ricouard
478a788f87 Redesign News + support links attributions 2024-07-02 19:59:21 +02:00
Pierre-Yves Lapersonne
2d04433783
fix: french localization (#2117) (#2118)
Some wordings were not translated in french, others needed to be improved a bit.
This fix brings evolutions written by myself and tested locally on a real device (french guy with french as mother language)

Signed-off-by: Pierre-Yves Lapersonne <dev@pylapersonne.info>
2024-07-02 15:22:38 +02:00
Thomas Ricouard
59a333cc20 Bump version to 1.10.44 2024-06-26 14:47:35 +02:00
Thomas Ricouard
9bc9961f34 Fix filtered notifications 2024-06-26 13:32:36 +02:00
Thomas Ricouard
0af3732ea9 Fix typo 2024-06-26 11:06:50 +02:00
Thomas Ricouard
5960014da9 Fix warnings 2024-06-26 11:05:35 +02:00
Thomas Ricouard
2ab52d3d3e Optimize some text 2024-06-26 09:43:27 +02:00
Thomas Ricouard
cd60e0ce1a Fixed action view height 2024-06-26 09:26:34 +02:00
Thomas Ricouard
ff1d5733a0 Tryout: Fixed size optimizations 2024-06-26 09:03:00 +02:00
Nam
9887a81ef0
Make toolbar account selector button avatar match shape option. (#2098) 2024-06-25 10:59:43 +02:00
Christopher Schindler
f2ba08e1cc
Add an option to delete the avatar or header (#2109)
* Endpoint: add Profile endpoint

* EditAccount: add an option to delete the avatar or header

* EditAccount: always display avatar view
2024-06-25 10:59:19 +02:00
Thomas Ricouard
2b8bc2ecd3 Pin EmojiText + NukeUI 2024-06-24 16:01:20 +02:00
Thomas Ricouard
513c686b64 Back to main Bodega 2024-06-24 09:01:45 +02:00
Christopher Schindler
aaeb9eaa36
Fix the upload of heavy avatar or header image (#2103)
* Compressor: allows custom parameters for compressing image (maxSize, maxHeight, maxWidth)

* Account: configures the maximum image size for uploading avatar and header
2024-06-24 08:58:06 +02:00
Christopher Schindler
02a8cb12e9
AccountDetailView: fix white spacing on top of the view (#2110) 2024-06-24 08:56:17 +02:00
Jerry Zhang
be54a58ae6
Update Simplified Chinese localization (#2111)
* Update Simplified Chinese localization

* Refine Simplified Chinese localization

Co-Authored-By: nixzhu <zhuhongxu@gmail.com>

* Fix: SC localization

Co-Authored-By: nixzhu <zhuhongxu@gmail.com>

* Fix: Missing SC translations

Co-Authored-By: nixzhu <zhuhongxu@gmail.com>

---------

Co-authored-by: nixzhu <zhuhongxu@gmail.com>
2024-06-24 08:55:54 +02:00
Thomas Ricouard
8e86e6d205 Back to main Introspect 2024-06-18 08:28:19 +02:00
Thomas Ricouard
283e537c44 Bump version to 1.10.43 2024-06-12 21:24:55 +02:00
Thomas Ricouard
551697eb2c Refix Introspect 2024-06-12 20:51:08 +02:00
Thomas Ricouard
ab99ef9a0a Fix 2024-06-12 20:41:19 +02:00
Thomas Ricouard
02d73de113 Fix iOS 18 build + performances 2024-06-12 20:37:43 +02:00
Thomas Ricouard
375ea665b4 Default logout experience to trending timeline + remove cache when logout 2024-06-12 20:02:01 +02:00
Thomas Ricouard
a88b9a7fd9 Merge branch 'main' of https://github.com/Dimillian/IceCubesApp 2024-06-08 18:21:35 +02:00
Thomas Ricouard
520315d50f Update packages 2024-06-08 18:21:33 +02:00
Xabi
1bbbdc8194
Update EU localisation (#2095)
Still unsure whether TimelineFilter and AppAccount need to be translated.
2024-06-08 18:02:31 +02:00
Adem Özsayın
d36930b7af
Updated TR translations (#2088) 2024-06-01 13:55:26 +02:00
David Whetstone
c06e3b59e4
Add "Settings ..." menu and ⌘, hotkey (#2079) 2024-06-01 13:55:06 +02:00
Thomas Ricouard
8cca261e43 Bump version to 1.10.42 2024-06-01 13:54:44 +02:00
Thomas Ricouard
f40aeb9cac Add followers count widget 2024-05-17 14:22:00 +02:00
Thomas Ricouard
1578896b3e Immersive short modal 2024-05-17 13:56:03 +02:00
Thomas Ricouard
ba3d8b1882 Composer: disable predictive type on all platforms 2024-05-17 13:55:55 +02:00
Thomas Ricouard
04af087c4b Bump version to 1.10.41 2024-05-16 07:05:17 +02:00
Thomas Ricouard
a9398c25af fix #2064 2024-05-15 10:52:41 +02:00
Thomas Ricouard
13d721912b Add lists widget 2024-05-15 09:27:35 +02:00
Thomas Ricouard
e3d4e693d2 More improvement to alt edit 2024-05-15 08:30:57 +02:00
Thomas Ricouard
86c053344b Improve media alt edit 2024-05-15 08:28:05 +02:00
Thomas Ricouard
a996aace80 Add translate for image alt 2024-05-14 19:43:52 +02:00
Jesús Jiménez Sánchez
18a1d17230
Update ES localization (#2076) 2024-05-14 19:37:40 +02:00
Thomas Ricouard
69cb9a20f9 Add native translate for media description edit + profile bio 2024-05-14 19:36:25 +02:00
Thomas Ricouard
bab2b4be9c Fix localization 2024-05-14 12:20:25 +02:00
Thomas Ricouard
bb005386df Merge branch 'main' of https://github.com/Dimillian/IceCubesApp 2024-05-13 22:20:45 +02:00
Thomas Ricouard
c77bb992b4 Update OpenAI models to gpt-4o 2024-05-13 22:20:43 +02:00
Paul Schuetz
7caf00d07d
Resolve escaped characters in a status (#2071)
* Resolve escaped characters in a status

Escaped characters are now returned to their original form for
HTMLString.asRawText.

* Unescape the markdown version too

The HTMLString.asMarkdown string is now also unescaped, &amp; and
similar are resolved.

* Fix a internal fallback

If one of the unescape(...) commands fails, the original, unescaped
text is used instead of an empty string.
2024-05-13 21:32:38 +02:00
Thomas Ricouard
6ed760a775 Bump version to 1.10.40 2024-05-13 20:20:24 +02:00
Thomas Ricouard
ecd149b3d2 Fix a crash in quote post editor on macOS 2024-05-13 19:26:48 +02:00
Xabi
9aaf0b2350
Update EU localisation (#2062)
Round 2
2024-05-13 13:28:24 +02:00
Cthulhux
2d6cce6b01
de: translated one more string (#2063) 2024-05-13 13:27:58 +02:00
Paul Schuetz
48faddebea
Implement Apple Translate (#2065)
* Implement a first version of Apple's Translation

The user can now choose between his instance's server, DeepL (with API
key) and Apple's Translation framework. A translation is cleared if
the translation type is changed. The strings aren't yet written, but
the translations settings view's inconsistent background is now fixed.

* Transfer the old "always_use_deepl" setting

The "always_use_deepl"-setting is now deleted, but its content is
transferred to the equivalent value in "preferred_translation_type".

* Show the user if the DeepL-API key is still stored

The user is now shown a prompt if they've switched away from
.useDeepl, but there's still an API key stored. The API key is not
deleted if the user doesn't instruct the app to do so, so this change
makes it more transparent, since a user might not expect the key to
be stored and might not want this to be the case.

* Localize Labels

The labels for the buttons and options are now localized. "DeepL API Key" is written consistently (with uppercase Key)

* Run all the strings through localization

The strings "DeepL" and "Apple Translate" are now also saved in
localizable.strings and addressed through keys. They were taken
directly previously, which was inconsistent.

* Fix storage

The selected value for preferredTranslationType wasn't stored, the
synchronization between UserPreferences and Storage is now in place.

* Hide Apple Translate if not yet on iOS 17.4

The Apple Translate option is hidden if the user hasn't updated their
phone to at least iOS 17.4. If the Apple Translate option is selected
but the user has downgraded to before iOS 17.4, the standard instance
option is selected.

* Consistently show Apple Translate

Apple Translate was previously only shown if the standard translate
button was visible, that is now fixed. It's now attached to the
StatusRowView, which is always present.

* Animate the removal of translations

The reset of a translation when the translation type is changed is now
animated, which is important for iPad users if they've translated a
post in the sidebar.

* Add support for the Mac Catalyst build

The Mac Catalyst Version doesn't allow the import of the api, so
compiler flags now check if the import isn't allowed and then remove
all references to Apple Translate.

* Swift Format

* Revert "Run all the strings through localization"

This reverts commit 86c5099662.

# Conflicts:
#	Packages/Env/Sources/Env/TranslationType.swift

* Remove the DeepL fallback

The DeepL fallback for the instance translation service is removed,
error messages are shown if a translation fails.

* Allow for the use of an User API Key as fallback

The DeepL fallback is reinstated if the user has put in their own API
Key

* Make the localization keys clear strings

* Make Apple and the instance a fallback

Apple Translate is now a fallback for both other translation types,
the instance service is a fallback for DeepL.
2024-05-13 13:27:21 +02:00
Thomas Ricouard
a8039df22d Don't open link on secondary column 2024-05-13 09:27:24 +02:00
Thomas Ricouard
e21ec0bd1f Add expanded sidebar layout 2024-05-08 11:51:28 +02:00
Thomas Ricouard
9c42a3d7cc Add copy button for alt text 2024-05-08 11:03:25 +02:00
Thomas Ricouard
54a16b2c9a Fix unboost icon 2024-05-08 11:00:40 +02:00
Thomas Ricouard
a6f3068728 Add accounts list placeholder 2024-05-08 10:59:31 +02:00
Thomas Ricouard
f04258ec04 Revert "Delete unused functions in TimelineDatasource.swift (#2037)"
This reverts commit e9a2d3e151.
2024-05-08 10:50:22 +02:00
Cthulhux
8468e51c17
de: Update Localizable.xcstrings (#2057)
(Not entirely sure whether to translate "TimelineFilter" et al.)
2024-05-08 10:39:09 +02:00
Noah Martin
e9a2d3e151
Delete unused functions in TimelineDatasource.swift (#2037) 2024-05-08 10:38:36 +02:00
Igor Camilo
1f56fa1b9b
Add tooltip to sidebar buttons. (#2040) 2024-05-08 10:38:27 +02:00
Jerry Zhang
ccad00a094
Update Simplified Chinese localization (#2052)
* Update Simplified Chinese localization

* Fix

---------

Co-authored-by: Thomas Ricouard <ricouard77@gmail.com>
2024-05-08 10:32:26 +02:00
Thomas Ricouard
51fecb01f5 Bump version to 1.10.39 2024-05-06 09:25:36 +02:00
Thomas Ricouard
c29de44d8c Widget: Mentions only allow large size 2024-05-06 09:20:01 +02:00
Thomas Ricouard
1d79832544 Bump version to 1.10.38 2024-05-06 08:41:33 +02:00
Thomas Ricouard
a37316c56f Lint 2024-05-06 08:38:37 +02:00
Thomas Ricouard
189e10f2b4 Widget: Add mentions widget 2024-05-06 08:37:58 +02:00
Thomas Ricouard
24d5ecd119 Shortcuts: Fix image 2024-05-05 21:13:34 +02:00
Thomas Ricouard
ee6f003073 Widget: Improve text size 2024-05-05 20:03:12 +02:00
Thomas Ricouard
7328c00006 Widget: Remove optional parameters 2024-05-05 19:41:04 +02:00
Thomas Ricouard
a6fd8d1137 Widget: Renaming 2024-05-05 19:37:06 +02:00
Thomas Ricouard
ea31cda3c2 Widget: Add Hashtag widget 2024-05-05 19:31:28 +02:00
Thomas Ricouard
8ab7b5ac69 Fix app group 2024-05-05 19:03:25 +02:00
Thomas Ricouard
7aebe530dd Widget: More UI refinements 2024-05-05 18:29:48 +02:00
Thomas Ricouard
a2afd4f58f Fix widget bundle identifier 2024-05-05 18:16:20 +02:00
Thomas Ricouard
88218cd6ec Style fix 2024-05-05 18:10:32 +02:00
Thomas Ricouard
c4dee39efe More fix for timeline widget 2024-05-05 18:06:47 +02:00
Thomas Ricouard
73651cb7f1 Polish on timeline widget 2024-05-05 17:47:08 +02:00
Thomas Ricouard
dd1615f0e3 Fix widget entitlements 2024-05-05 17:30:09 +02:00
Thomas Ricouard
6bd14e0f8d Don't embed widgets on visionOS 2024-05-05 13:34:22 +02:00
Thomas Ricouard
1ca4a74ff0 Initial widget support 2024-05-05 13:12:19 +02:00
Thomas Ricouard
c3edabb183 Lint 2024-05-04 13:19:19 +02:00
Thomas Ricouard
ba4cc899f8 Add inline post Intent 2024-05-04 13:12:43 +02:00
Thomas Ricouard
5a93184c6d Rename Intent 2024-05-04 11:34:51 +02:00
Thomas Ricouard
66754ecc7c Fix editor progress bar 2024-05-04 11:27:52 +02:00
Thomas Ricouard
e857439a02 Bump version to 1.10.37 2024-05-03 16:25:30 +02:00
Jesús Jiménez Sánchez
ed620e86ca
Update ES localization (#2048)
Co-authored-by: Thomas Ricouard <ricouard77@gmail.com>
2024-05-03 16:21:40 +02:00
Cthulhux
936bc96ff7
de:Update Localizable.xcstrings (#2051)
Time for a few new strings

Co-authored-by: Thomas Ricouard <ricouard77@gmail.com>
2024-05-03 16:19:32 +02:00
Xabi
37b441a43d
Update EU localisation (#2049)
Added recent strings
2024-05-03 16:18:28 +02:00
Thomas Ricouard
07af494dcb Allow text connect 2024-05-02 12:05:48 +02:00
Thomas Ricouard
49a5c6a56a Add more shortcuts 2024-05-02 11:37:38 +02:00
Thomas Ricouard
4e4d903c44 Add AppIntent service + post to Mastodon intent 2024-05-02 09:32:19 +02:00
Thomas Ricouard
abcd4cc321 Add muted and blocked accounts list 2024-05-02 08:43:58 +02:00
Euigyom Kim
6a7df1065d
Fix scrolling issue on emoji picker (#2032)
* Fix scrolling issue in emoji picker

* Fix design on emoji section header
2024-04-22 16:38:31 +02:00
Thomas Ricouard
c0b855ea55 Bump version to 1.10.36 2024-04-21 15:07:48 +02:00
Thomas Ricouard
4c3047b0b9 Fix packages 2024-04-19 06:56:48 -07:00
Thomas Ricouard
899b92e390 Revert "Fix StatusRowContentView invade SwipeActions area (#2007)"
This reverts commit 3782300b27.
2024-04-19 06:46:56 -07:00
Thomas Ricouard
e71c55b488 Bump version to 1.10.35 2024-04-19 06:46:49 -07:00
Thomas Ricouard
361b5f1d84 Fix tests 2024-04-17 11:11:22 -07:00
Thomas Ricouard
ad61600328 Fix localizations 2024-04-17 11:05:21 -07:00
Thomas Ricouard
5f1f71068c Update packages 2024-04-17 10:55:00 -07:00
tkgka
3782300b27
Fix StatusRowContentView invade SwipeActions area (#2007)
* Fix StatusRowContentView invade SwipeActions area

* ./ add padding inside StatusRowMediaPreviewView
2024-04-17 10:54:46 -07:00
Andrzej Rózga
7d47834903
Polish localization update (#2029) 2024-04-07 09:16:47 +02:00
Jesús Jiménez Sánchez
65a83fa636
Update ES localization (#2028) 2024-04-07 09:16:41 +02:00
Nathan Reed
8038e8e6af
Improve deep link handling on cold start (#2026)
Previously, if the app was not already running when the Safari action extension was used to open a post in the app, the post would open in the in-app Safari instead of using the Ice Cubes UI.
The action extension only worked well if Ice Cubes was already running but backgrounded when it was used.
This was because of the `hasConnection(with:)` check used to ensure that the current server has a federation relationship with the server the post is on.
Early in app launch, the list of federated peers has not come back from the API request yet, so `hasConnection(with:)` was always returning `false`.

To fix, issue a request to fetch the peers as part of the URL handling process, before checking `hasConnection(with:)` to make the final navigation decision.
As an optimization, only do this if `hasConnection(with:)` returns `false` initially -- if it returns `true`, we already know a connection exists so no need to check again.
2024-04-02 08:26:58 +02:00
Ahnaf Mahmud
eb82a67671
Update menu bar and copyright (#2025)
* Update menu bar

* Update copyright
2024-04-02 08:25:52 +02:00
Ege Sucu
bc5bb8272a
TR language updated & Changes Reviewed (#2023) 2024-03-29 10:24:44 +01:00
Xabi
d2ead5b6d1
Update EU localisation (#2017)
newest strings
2024-03-28 15:32:06 +01:00
Jerry Zhang
d22370959c
Update Simplified Chinese localization (#2018)
* Update Simplified Chinese localization

* fix SC localization
2024-03-28 15:31:59 +01:00
Alessio Mason
2c9b841f30
Latest Italian localizations (#2020) 2024-03-28 15:31:39 +01:00
Cthulhux
2e3cf4aace
de: translated the new filters (#2022) 2024-03-28 15:31:31 +01:00
Thomas Ricouard
7de563a6eb Fix packages 2024-03-27 09:17:33 +01:00
Thomas Ricouard
3aae2e6623 bump version to 1.10.34 2024-03-27 09:04:13 +01:00
Thomas Ricouard
5c32c24ae5 Add supports for notifications filter API 2024-03-26 15:49:43 +01:00
Roddy Munro
bb56047ee2
Add SwiftPolyglot to validate localizations (#2011)
* Add step to validate translations on PRs without errors

* Move workflow

* Get specific release of SwiftPolyglot
2024-03-25 08:48:44 +01:00
sh95014
924ada6606
Update zh_Hant loc (#2013)
* checkpoint

* checkpoint

* plurals and a couple of minor fixes

* Update Localizable.strings

* Update Localizable.strings

* Update zh-Hant localizations

* improve translation of "by" in "filtered by"

* update zh-Hant localization

* update Hant localization

* Update zh_Hant

* improve status.poll.closes-in

* Update zh_Hant

* Custom layout for App Store links

* update zh-Hant

* update zh_Hant

* update zh_Hant

* update zh_Hant

* update zh_Hant

* update zh_Hant

* update zh_Hant
2024-03-25 08:47:21 +01:00
Jerry Zhang
e6f96d1899
Update Simplified Chinese localization (#2005) 2024-03-14 09:45:11 +01:00
Thomas Ricouard
058500f91e Swiftformat . 2024-03-11 09:05:52 +01:00
Thomas Ricouard
fd3d9fc2bc Add missing localization 2024-03-11 09:02:32 +01:00
Thomas Ricouard
9a7e6b7cb0 Various fixes for Xcode 15.3 2024-03-11 08:59:29 +01:00
Max von Webel
bc2a09891a
Added a "Moved To" Button to accounts that moved to other instances (#2001)
* added moved information to Account model

* Added "Moved To" button to account details for accounts that have moved
2024-03-11 08:57:35 +01:00
Ahnaf Mahmud
7c343eb4e9
Update visionOS availability (#1999) 2024-03-11 08:56:50 +01:00
Thai D. V
15d7d1dabd
handle edge cases for StatusRowCardView (#1985) 2024-02-26 11:50:10 +01:00
Xabi
f4ec69a37f
Update EU localisation (#1986) 2024-02-26 11:49:32 +01:00
Thomas Ricouard
732a253c7a More EN locale fix 2024-02-26 09:17:59 +01:00
Thomas Ricouard
9c67af8451 Fix EN locale 2024-02-26 09:16:16 +01:00
Thomas Ricouard
b56da94a7c Add more sheets to shared + link to filters in timeline top filters 2024-02-21 09:45:29 +01:00
Alessio Mason
e612fbdf7c
Italian localization fix (#1982)
* General Italian localization overhaul

* Quick IT fix

* Another quick IT fix

* Italian localization fix
2024-02-17 19:26:14 +01:00
Cthulhux
f46a0cee17
de: two more missing strings (#1975)
While using the app, I found that I had not seen two strings. Probably they were marked "translated" too early. Sorry! Here they are.
2024-02-16 08:50:41 +01:00
Andrzej Rózga
4a90d979e3
Polish localization update (#1976)
* Polish localization update

* pl: two more missing strings
2024-02-16 08:50:34 +01:00
Jerry Zhang
9e4323f317
Update Simplified Chinese localization (#1974) 2024-02-14 13:34:19 +01:00
Thomas Ricouard
24ce872849 Add previews + refactor placeholder view 2024-02-14 13:34:06 +01:00
Thomas Ricouard
1f858414d8 format . 2024-02-14 12:48:14 +01:00
Thomas Ricouard
2d988d48c1 Remove some button from status row 2024-02-14 10:48:17 +01:00
Thomas Ricouard
21d9fd7b59 Bump version to 1.10.33 2024-02-14 07:37:15 +01:00
Thomas Ricouard
cca6472a32 Update to Nuke 12.4.0 2024-02-13 18:51:00 +01:00
Thomas Ricouard
c769e80bb6 Add preview for status row 2024-02-13 18:50:51 +01:00
Thomas Ricouard
2986d2b177 Fix env 2024-02-13 17:21:33 +01:00
sh95014
29312d1be2
select a contrasting color for label of "show sensitive content" button (#1965)
* Custom layout for App Store links

* select a contrasting color for label of "show sensitive content" button

fix https://github.com/Dimillian/IceCubesApp/issues/1932

* move contrasting color to Theme and cache computed var
2024-02-13 11:33:59 +01:00
Cthulhux
9ddf0e65fc
Update Localizable.xcstrings (#1969) 2024-02-13 07:50:05 +01:00
Thomas Ricouard
bc74a50a6a Fix some English strings 2024-02-12 07:22:28 +01:00
sh95014
d55d6a0371
Use horizontal link preview card for Apple Podcasts as well (#1966)
* Custom layout for App Store links

* generalize the logic to include links known to be associated with square icons

- such as Apple Music and Spotify

* show Apple Podcasts in horizontal link preview
2024-02-12 07:18:18 +01:00
sh95014
773fdc318b
Plurals for various strings (#1968)
fix https://github.com/Dimillian/IceCubesApp/issues/1936
2024-02-12 07:18:08 +01:00
Thomas Ricouard
7423aba92a Fix crash on visionOS in AboutView 2024-02-11 18:59:34 +01:00
Thomas Ricouard
77aa50ef19 Fix #1873 2024-02-11 18:52:58 +01:00
Thomas Ricouard
dfc213a19a Remove spacer 2024-02-11 18:45:38 +01:00
Andrzej Rózga
20900f573f
Polish localization update (#1958) 2024-02-11 11:14:44 +01:00
Ege Sucu
046a41e8ef
TR Localizations are Updated & some are formatted (#1957) 2024-02-11 11:14:36 +01:00
Thomas Ricouard
fcd56ab7a0 Fix #1960 2024-02-11 11:13:03 +01:00
Thomas Ricouard
923927cddd Cleanup 2024-02-11 11:12:34 +01:00
Thomas Ricouard
219703ecc7 Refactor to NextPageView + handle next page loading failure 2024-02-11 10:58:51 +01:00
Thomas Ricouard
0739264005 Fix background 2024-02-10 12:16:32 +01:00
Thomas Ricouard
6f8bec4737 Add localization 2024-02-10 11:34:49 +01:00
Thomas Ricouard
d8e6e6cfb1 Share Sheet: set cursor before shared content 2024-02-10 11:32:58 +01:00
Thomas Ricouard
e7bc857231 News trending links experience 2024-02-10 11:26:22 +01:00
Thomas Ricouard
35d249f7c9 Bump to 1.10.32 2024-02-10 09:57:56 +01:00
Thomas Ricouard
7b7e65bf31
Update LICENSE 2024-02-10 08:53:49 +01:00
Thomas Ricouard
9542002534 Merge branch 'main' of https://github.com/Dimillian/IceCubesApp 2024-02-06 19:19:54 +01:00
Thomas Ricouard
3020d831e4 Various fixes 2024-02-06 19:19:53 +01:00
Thomas Ricouard
a0e022b8de Fix #1948 2024-02-06 17:32:42 +01:00
Thomas Ricouard
b9b3d0e727 Enhance visionOS support 2024-02-06 15:17:20 +01:00
Jerry Zhang
4bf476daea
Update Simplified Chinese localization (#1947) 2024-02-06 13:30:00 +01:00
Ege Sucu
d1fd97794a
Updated TR Localization (#1945) 2024-02-06 13:29:54 +01:00
Thomas Ricouard
f14ca6e529 Various visionOS fixes 2024-02-06 09:15:22 +01:00
Thomas Ricouard
75bb4f43dd More fix for #1943 2024-02-05 14:24:29 +01:00
Thomas Ricouard
cfd6eed159 Fix #1943 2024-02-05 08:59:27 +01:00
Thomas Ricouard
d10adf1fd9 Update packages 2024-02-05 08:56:38 +01:00
Thomas Ricouard
3b07d56b1d Bump version to 1.10.31 2024-02-05 08:56:03 +01:00
Thomas Ricouard
b4dbda8722 Migrate EmojiText API 2024-02-05 08:55:24 +01:00
David Walter
827765f251
EmojiText 4.0.0 (#1941) 2024-02-05 08:49:29 +01:00
Chanhwi Joo
e7702e1ad0
Update Korean localization (#1942) 2024-02-05 08:49:14 +01:00
Thomas Ricouard
70f58aa08d Fix #1939 2024-02-04 12:02:14 +01:00
Thomas Ricouard
cf81054366 Fix isCompact 2024-02-02 18:39:39 +01:00
Thomas Ricouard
f67163e4b0 Cleanup print + use OSLog 2024-02-02 18:26:24 +01:00
Thomas Ricouard
9bd967cddf Fix #1938 2024-02-02 08:53:59 +01:00
Thomas Ricouard
551e6b1412
Delete .github/workflows directory 2024-01-31 10:30:04 +01:00
Thomas Ricouard
1c76d50bde
Create ios.yml 2024-01-31 10:27:51 +01:00
Thomas Ricouard
2a6afb4092 Card title limit to two lines instead of one 2024-01-31 07:57:59 +01:00
Thomas Ricouard
b348f37f1a Add block confirmation 2024-01-31 07:56:50 +01:00
sh95014
de757c58f8
update zh_Hant (#1934)
* checkpoint

* checkpoint

* plurals and a couple of minor fixes

* Update Localizable.strings

* Update Localizable.strings

* Update zh-Hant localizations

* improve translation of "by" in "filtered by"

* update zh-Hant localization

* update Hant localization

* Update zh_Hant

* improve status.poll.closes-in

* Update zh_Hant

* Custom layout for App Store links

* update zh-Hant

* update zh_Hant

* update zh_Hant

* update zh_Hant
2024-01-30 09:22:32 +01:00
Thai D. V
7268b5a38e
Improve StatusPollView (#1929)
* fix `StatusPollView`

* fix text alignment
2024-01-30 09:22:20 +01:00
Thomas Ricouard
b8cf446406 Bump version to 1.10.30 2024-01-29 08:59:35 +01:00
Thomas Ricouard
6e497fae5b Adjust action buttons size 2024-01-29 08:48:24 +01:00
Thai D. V
586e4f525e
Fix timeline media size (#1928)
* fix layout for post with 1 media item

* fix corner radius

* Fixes

---------

Co-authored-by: Thomas Ricouard <ricouard77@gmail.com>
2024-01-28 17:32:16 +01:00
Thomas Ricouard
7f689bbb9c Bump version to 1.10.29 2024-01-27 10:32:30 +01:00
Thomas Ricouard
9dfd9c27c7 Fix actions button on macOS 2024-01-27 10:31:25 +01:00
Thomas Ricouard
9cf16b2f30 Fix memory leak related to video #1925 2024-01-27 10:20:12 +01:00
Thomas Ricouard
1299202bba Fix #1927 2024-01-27 09:52:27 +01:00
Thomas Ricouard
f16f0d514b Fix Swift strict concurrency warnings 2024-01-26 13:01:23 +01:00
Thomas Ricouard
096996c242 Video: Increase compression when in extension 2024-01-24 16:56:35 +01:00
Thomas Ricouard
c7bd5a1d94 Cache Account display name 2024-01-24 16:22:44 +01:00
Thomas Ricouard
20f4eb9c71 Remove section 2024-01-24 13:38:46 +01:00
Thomas Ricouard
74590542bc Custom emojis, botom sheet only 2024-01-24 09:25:34 +01:00
Thomas Ricouard
49b1b0e96c Bump version to 1.10.28 2024-01-24 08:11:32 +01:00
Thomas Ricouard
3eec5c0eec new top / bottom bar 2024-01-23 08:51:58 +01:00
Thomas Ricouard
016e4d5d57 Refactor CancelToolbarItem 2024-01-23 08:13:45 +01:00
Thomas Ricouard
ba071eb4c8 Fix status menu on Catalyst 2024-01-23 06:55:12 +01:00
Thomas Ricouard
d2014d3aec Fix #1918 2024-01-23 06:32:58 +01:00
Thomas Ricouard
621f0d0864 Play video on a separate window on macOS 2024-01-22 22:04:28 +01:00
Thomas Ricouard
eeff60bf98 Add quick look for videos 2024-01-22 21:54:28 +01:00
Thomas Ricouard
245d35db82 Fix buttons touch zone 2024-01-22 21:20:43 +01:00
Thai D. V
62eeba5334
use default frame for preview images that API returns incorrect (width: 0, height: 0) (#1915) 2024-01-22 13:58:01 +01:00
Thomas Ricouard
46b8fbde29 New status row context menu 2024-01-22 09:14:45 +01:00
Thomas Ricouard
9a8568d3fa Fix notifications layout 2024-01-22 09:05:22 +01:00
Thomas Ricouard
a6ccdc029b Timeline filter: Add ControlGroup 2024-01-22 06:38:56 +01:00
Le-Roy Karunaratne
ed9a4a598d
Resolve #359 Optional Missing Alt-Text warning (#1895)
* Resolve #359 Optional Missing Alt-Text warning

Add toggle in settings to require alt text (default off)
If setting is enabled, posting show an error if any attached media is missing alt text

* Re-localized strings
2024-01-22 06:28:03 +01:00
Thai D. V
13af2d7e3f
fix indentation lines (#1914) 2024-01-22 06:27:56 +01:00
Thomas Ricouard
2b446833da Notifications: Full media size + autoplay 2024-01-21 19:46:29 +01:00
Thomas Ricouard
0b96b76641 Bump version to 1.10.27 2024-01-21 19:26:57 +01:00
Thomas Ricouard
78eee1e855 Fix status embed 2024-01-21 18:49:45 +01:00
Thomas Ricouard
b7937e3580 Fix language sheet 2024-01-21 18:27:55 +01:00
Thomas Ricouard
9320b2f114 Fix local timeline -> home switch 2024-01-21 17:05:05 +01:00
Thomas Ricouard
ad7bc999d3 Fix alternate icon 2024-01-21 12:11:36 +01:00
Thomas Ricouard
b41fd2d6ce Bump version to 1.10.26 2024-01-21 12:02:37 +01:00
Thomas Ricouard
a79a181d6f Content Filter view: Blurred background 2024-01-21 11:22:07 +01:00
Thomas Ricouard
fb944f9c48 Editor: Cleanup focus state 2024-01-21 11:13:47 +01:00
Thomas Ricouard
3c82af0273 Custom emojis: blurred background 2024-01-21 11:13:38 +01:00
Thomas Ricouard
3577254f08 VisionOS: Disable theming 2024-01-21 11:13:25 +01:00
Thomas Ricouard
abff6218a4 Merge branch 'main' of https://github.com/Dimillian/IceCubesApp 2024-01-21 10:49:46 +01:00
Thomas Ricouard
1be9a7b941 Fix custom emojis loading 2024-01-21 10:49:40 +01:00
Cthulhux
18381e22e2
de: tab 1-5 were untranslated (#1908) 2024-01-21 10:45:19 +01:00
Jerry Zhang
e2273c436a
Update SC Localization (#1909) 2024-01-21 10:45:12 +01:00
Ege Sucu
2296dd4658
Stale localization string removed (#1910) 2024-01-21 10:45:07 +01:00
Thai D. V
92662665b9
fix divide by zero (#1911) 2024-01-21 10:45:00 +01:00
Thomas Ricouard
17387626b8 New App Icon 2024-01-21 09:31:50 +01:00
Thomas Ricouard
e00fd49d89 fix movie supported type 2024-01-20 19:41:44 +01:00
Thomas Ricouard
97798b2c35 Refactor NSItemProvider handler 2024-01-20 19:17:59 +01:00
Thomas Ricouard
90a2a19bb1 Fill poll view 2024-01-20 08:55:12 +01:00
Thomas Ricouard
21d54cc546 Merge branch 'main' of https://github.com/Dimillian/IceCubesApp 2024-01-20 07:31:46 +01:00
Thomas Ricouard
76638911ee Bump version to 1.10.25 2024-01-20 07:31:39 +01:00
Thai D. V
0b7fed2e9a
Fix Preview Image Size of StatusRowCardView. (#1904)
* fix preview image size and text spacing

* Fix bg

---------

Co-authored-by: Thomas Ricouard <ricouard77@gmail.com>
2024-01-19 17:48:52 +01:00
Ghulam Mustafa
328ee2d090
Fix #1885 blank options on profile page on macos (#1906) 2024-01-19 17:48:20 +01:00
Thomas Ricouard
ebdd5b9feb Fix #1905 2024-01-19 12:35:41 +01:00
Thai D. V
f79117eff1
fix StatusRowCardView layout (#1901) 2024-01-19 09:01:40 +01:00
Thomas Ricouard
709dd79e25 Fix for visionOS + Remove shimmer 2024-01-19 08:51:29 +01:00
Thai D. V
bf7cdc3712
add scroll bar in StatusRowMediaPreviewView for macOS version (#1896) 2024-01-18 06:43:40 +01:00
Alessio Mason
f12d0600f7
General Italian localization overhaul (#1897)
* General Italian localization overhaul

* Quick IT fix

* Another quick IT fix
2024-01-18 06:42:03 +01:00
emmanuel
b6f11e4e08
Update README.md (#1898) 2024-01-18 06:41:55 +01:00
Thai D. V
76a8f45478
hide context indicator for statuses inside StatusDetailView (#1899) 2024-01-18 06:41:40 +01:00
Thomas Ricouard
e03747aa45 Fix hover effect 2024-01-16 20:55:55 +01:00
Thomas Ricouard
8568d6cc59 Bump to 1.10.24 2024-01-16 19:59:35 +01:00
Thomas Ricouard
1a0b52d268 VisionOS Fixes 2024-01-16 19:32:36 +01:00
Thomas Ricouard
0dea624060 VisionOS fixes 2024-01-16 18:43:09 +01:00
Thomas Ricouard
a4927fd30c VisionOS fixes 2024-01-15 21:15:40 +01:00
Thomas Ricouard
b8be6b79af Bump to 1.10.23 2024-01-15 17:37:33 +01:00
440 changed files with 19291 additions and 5501 deletions

View file

@ -0,0 +1,35 @@
name: Validate Translations
on:
pull_request:
types: [synchronize, opened, reopened, labeled, unlabeled, edited]
jobs:
main:
name: Validate Translations
runs-on: macOS-latest
steps:
- name: git checkout
uses: actions/checkout@v3
- name: ruby versions
run: |
ruby --version
gem --version
bundler --version
- name: ruby setup
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.3
bundler-cache: true
# additional steps here, if needed
- name: Clone SwiftPolyglot
run: git clone https://github.com/appdecostudio/SwiftPolyglot.git --branch 0.2.0
- name: Build and Run SwiftPolyglot
run: |
swift build --package-path ./SwiftPolyglot --configuration release
swift run --package-path ./SwiftPolyglot swiftpolyglot "en,eu,be,ca,zh-Hans,zh-Hant,nl,en-GB,fr,de,it,ja,ko,nb,pl,pt-BR,es,tr,uk"

View file

@ -13,7 +13,7 @@ import Models
import Network import Network
// Sample code was sending this from a thread to another, let asume @Sendable for this // Sample code was sending this from a thread to another, let asume @Sendable for this
extension NSExtensionContext: @unchecked Sendable {} extension NSExtensionContext: @unchecked @retroactive Sendable {}
final class ActionRequestHandler: NSObject, NSExtensionRequestHandling, Sendable { final class ActionRequestHandler: NSObject, NSExtensionRequestHandling, Sendable {
enum Error: Swift.Error { enum Error: Swift.Error {

View file

@ -26,8 +26,6 @@
9F24EEB829360C330042359D /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9F24EEB729360C330042359D /* Preview Assets.xcassets */; }; 9F24EEB829360C330042359D /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9F24EEB729360C330042359D /* Preview Assets.xcassets */; };
9F295540292B6C3400E0E81B /* Timeline in Frameworks */ = {isa = PBXBuildFile; productRef = 9F29553F292B6C3400E0E81B /* Timeline */; }; 9F295540292B6C3400E0E81B /* Timeline in Frameworks */ = {isa = PBXBuildFile; productRef = 9F29553F292B6C3400E0E81B /* Timeline */; };
9F2A540729699698009B2D7C /* SupportAppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F2A540629699698009B2D7C /* SupportAppView.swift */; }; 9F2A540729699698009B2D7C /* SupportAppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F2A540629699698009B2D7C /* SupportAppView.swift */; };
9F2A540A29699705009B2D7C /* ReceiptParser in Frameworks */ = {isa = PBXBuildFile; productRef = 9F2A540929699705009B2D7C /* ReceiptParser */; };
9F2A540C29699705009B2D7C /* RevenueCat in Frameworks */ = {isa = PBXBuildFile; productRef = 9F2A540B29699705009B2D7C /* RevenueCat */; };
9F2A540E2969A0B0009B2D7C /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9F2A540D2969A0B0009B2D7C /* StoreKit.framework */; }; 9F2A540E2969A0B0009B2D7C /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9F2A540D2969A0B0009B2D7C /* StoreKit.framework */; };
9F2A5411296A1429009B2D7C /* PushNotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F2A5410296A1429009B2D7C /* PushNotificationsView.swift */; }; 9F2A5411296A1429009B2D7C /* PushNotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F2A5410296A1429009B2D7C /* PushNotificationsView.swift */; };
9F2A5419296AB631009B2D7C /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F2A5418296AB631009B2D7C /* NotificationService.swift */; }; 9F2A5419296AB631009B2D7C /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F2A5418296AB631009B2D7C /* NotificationService.swift */; };
@ -44,6 +42,11 @@
9F35DB4729506F6600B3281A /* NotificationTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F35DB4629506F6600B3281A /* NotificationTab.swift */; }; 9F35DB4729506F6600B3281A /* NotificationTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F35DB4629506F6600B3281A /* NotificationTab.swift */; };
9F35DB4A29506FA100B3281A /* Notifications in Frameworks */ = {isa = PBXBuildFile; productRef = 9F35DB4929506FA100B3281A /* Notifications */; }; 9F35DB4A29506FA100B3281A /* Notifications in Frameworks */ = {isa = PBXBuildFile; productRef = 9F35DB4929506FA100B3281A /* Notifications */; };
9F35DB4C2952005C00B3281A /* MessagesTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F35DB4B2952005C00B3281A /* MessagesTab.swift */; }; 9F35DB4C2952005C00B3281A /* MessagesTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F35DB4B2952005C00B3281A /* MessagesTab.swift */; };
9F37BDDB2BE36E22007F28AD /* PostIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F37BDDA2BE36E22007F28AD /* PostIntent.swift */; };
9F37BDDD2BE37193007F28AD /* AppIntentService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F37BDDC2BE37193007F28AD /* AppIntentService.swift */; };
9F37BDDF2BE37C35007F28AD /* TabIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F37BDDE2BE37C35007F28AD /* TabIntent.swift */; };
9F37BDE12BE38646007F28AD /* PostImageIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F37BDE02BE38646007F28AD /* PostImageIntent.swift */; };
9F37BDE32BE393A7007F28AD /* AppShortcuts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F37BDE22BE393A7007F28AD /* AppShortcuts.swift */; };
9F38A7332ACEA26100DBCD66 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 9F38A7322ACEA26100DBCD66 /* Localizable.xcstrings */; }; 9F38A7332ACEA26100DBCD66 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 9F38A7322ACEA26100DBCD66 /* Localizable.xcstrings */; };
9F38A7342ACEA26100DBCD66 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 9F38A7322ACEA26100DBCD66 /* Localizable.xcstrings */; }; 9F38A7342ACEA26100DBCD66 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 9F38A7322ACEA26100DBCD66 /* Localizable.xcstrings */; };
9F38A7352ACEA26100DBCD66 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 9F38A7322ACEA26100DBCD66 /* Localizable.xcstrings */; }; 9F38A7352ACEA26100DBCD66 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 9F38A7322ACEA26100DBCD66 /* Localizable.xcstrings */; };
@ -54,6 +57,9 @@
9F4A48192976B21900A1A038 /* ProfileTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F4A48182976B21900A1A038 /* ProfileTab.swift */; }; 9F4A48192976B21900A1A038 /* ProfileTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F4A48182976B21900A1A038 /* ProfileTab.swift */; };
9F55C68D2955968700F94077 /* ExploreTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F55C68C2955968700F94077 /* ExploreTab.swift */; }; 9F55C68D2955968700F94077 /* ExploreTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F55C68C2955968700F94077 /* ExploreTab.swift */; };
9F55C6902955993C00F94077 /* Explore in Frameworks */ = {isa = PBXBuildFile; productRef = 9F55C68F2955993C00F94077 /* Explore */; }; 9F55C6902955993C00F94077 /* Explore in Frameworks */ = {isa = PBXBuildFile; productRef = 9F55C68F2955993C00F94077 /* Explore */; };
9F5BE6272BF492CF0074387E /* ListEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F5BE6252BF48FE10074387E /* ListEntity.swift */; };
9F5BE6282BF492D10074387E /* ListsWidgetConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F5BE6232BF48FC40074387E /* ListsWidgetConfiguration.swift */; };
9F5BE6292BF492D40074387E /* ListsWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F5BE6212BF48FBA0074387E /* ListsWidget.swift */; };
9F5E581929545BE700A53960 /* Env in Frameworks */ = {isa = PBXBuildFile; productRef = 9F5E581829545BE700A53960 /* Env */; }; 9F5E581929545BE700A53960 /* Env in Frameworks */ = {isa = PBXBuildFile; productRef = 9F5E581829545BE700A53960 /* Env */; };
9F6028562B3F36AE00476078 /* AppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F6028552B3F36AE00476078 /* AppView.swift */; }; 9F6028562B3F36AE00476078 /* AppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F6028552B3F36AE00476078 /* AppView.swift */; };
9F6028582B3F3B7600476078 /* ToolbarTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F6028572B3F3B7600476078 /* ToolbarTab.swift */; }; 9F6028582B3F3B7600476078 /* ToolbarTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F6028572B3F3B7600476078 /* ToolbarTab.swift */; };
@ -63,10 +69,32 @@
9F7335EF29674F7100AFF0BA /* QuickLook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9F7335EE29674F7100AFF0BA /* QuickLook.framework */; }; 9F7335EF29674F7100AFF0BA /* QuickLook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9F7335EE29674F7100AFF0BA /* QuickLook.framework */; };
9F7335F22967608F00AFF0BA /* AddRemoteTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7335F12967608F00AFF0BA /* AddRemoteTimelineView.swift */; }; 9F7335F22967608F00AFF0BA /* AddRemoteTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7335F12967608F00AFF0BA /* AddRemoteTimelineView.swift */; };
9F7335F92968576500AFF0BA /* DisplaySettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7335F82968576500AFF0BA /* DisplaySettingsView.swift */; }; 9F7335F92968576500AFF0BA /* DisplaySettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7335F82968576500AFF0BA /* DisplaySettingsView.swift */; };
9F7788C02BE63935004E6BEF /* InlinePostIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7788BF2BE63935004E6BEF /* InlinePostIntent.swift */; };
9F7788C72BE652B1004E6BEF /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9F7788C62BE652B1004E6BEF /* WidgetKit.framework */; };
9F7788C92BE652B1004E6BEF /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9F7788C82BE652B1004E6BEF /* SwiftUI.framework */; };
9F7788CC2BE652B1004E6BEF /* IceCubesAppWidgetsExtensionBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7788CB2BE652B1004E6BEF /* IceCubesAppWidgetsExtensionBundle.swift */; };
9F7788CE2BE652B1004E6BEF /* LatestPostsWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7788CD2BE652B1004E6BEF /* LatestPostsWidget.swift */; };
9F7788D02BE652B1004E6BEF /* LatestPostsWidgetConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7788CF2BE652B1004E6BEF /* LatestPostsWidgetConfiguration.swift */; };
9F7788D22BE652B2004E6BEF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9F7788D12BE652B2004E6BEF /* Assets.xcassets */; };
9F7788D62BE652B2004E6BEF /* IceCubesAppWidgetsExtensionExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 9F7788C52BE652B1004E6BEF /* IceCubesAppWidgetsExtensionExtension.appex */; platformFilters = (ios, maccatalyst, ); settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
9F7788DE2BE6543D004E6BEF /* Account in Frameworks */ = {isa = PBXBuildFile; productRef = 9F7788DD2BE6543D004E6BEF /* Account */; };
9F7788E02BE6543D004E6BEF /* AppAccount in Frameworks */ = {isa = PBXBuildFile; productRef = 9F7788DF2BE6543D004E6BEF /* AppAccount */; };
9F7788E22BE6543D004E6BEF /* Env in Frameworks */ = {isa = PBXBuildFile; productRef = 9F7788E12BE6543D004E6BEF /* Env */; };
9F7788E42BE6543D004E6BEF /* Models in Frameworks */ = {isa = PBXBuildFile; productRef = 9F7788E32BE6543D004E6BEF /* Models */; };
9F7788E62BE6543D004E6BEF /* Network in Frameworks */ = {isa = PBXBuildFile; productRef = 9F7788E52BE6543D004E6BEF /* Network */; };
9F7788E82BE65533004E6BEF /* AppAccountEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7788E72BE65533004E6BEF /* AppAccountEntity.swift */; };
9F7788EA2BE65585004E6BEF /* AppAccountEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7788E72BE65533004E6BEF /* AppAccountEntity.swift */; };
9F7788ED2BE78D75004E6BEF /* TimelineFilterEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7788EC2BE78D75004E6BEF /* TimelineFilterEntity.swift */; };
9F7788EE2BE78D7B004E6BEF /* TimelineFilterEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7788EC2BE78D75004E6BEF /* TimelineFilterEntity.swift */; };
9F7788F02BE78E77004E6BEF /* Timeline in Frameworks */ = {isa = PBXBuildFile; productRef = 9F7788EF2BE78E77004E6BEF /* Timeline */; };
9F7D93942980063100EE6B7A /* AppAccount in Frameworks */ = {isa = PBXBuildFile; productRef = 9F7D93932980063100EE6B7A /* AppAccount */; }; 9F7D93942980063100EE6B7A /* AppAccount in Frameworks */ = {isa = PBXBuildFile; productRef = 9F7D93932980063100EE6B7A /* AppAccount */; };
9F7D939A29805DBD00EE6B7A /* AccountSettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7D939929805DBD00EE6B7A /* AccountSettingView.swift */; }; 9F7D939A29805DBD00EE6B7A /* AccountSettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7D939929805DBD00EE6B7A /* AccountSettingView.swift */; };
9F8B92122BF77DBE003D37A2 /* AccountWidgetConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F8B920E2BF77DB4003D37A2 /* AccountWidgetConfiguration.swift */; };
9F8B92132BF77DBE003D37A2 /* AccountWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F8B92102BF77DBB003D37A2 /* AccountWidget.swift */; };
9F8B92162BF77F0B003D37A2 /* AccountWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F8B92142BF77F05003D37A2 /* AccountWidgetView.swift */; };
9F9191562C6DDE1F001C89E7 /* WishlistView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9191552C6DDE1C001C89E7 /* WishlistView.swift */; };
9F9191592C6DDF20001C89E7 /* WishKit in Frameworks */ = {isa = PBXBuildFile; productRef = 9F9191582C6DDF20001C89E7 /* WishKit */; };
9FA6FD6229C04A8800E2312C /* TranslationSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA6FD6129C04A8800E2312C /* TranslationSettingsView.swift */; }; 9FA6FD6229C04A8800E2312C /* TranslationSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA6FD6129C04A8800E2312C /* TranslationSettingsView.swift */; };
9FAD85832971BF7200496AB1 /* Secret.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9FAD85822971BF7200496AB1 /* Secret.plist */; };
9FAD858B29743F7400496AB1 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FAD858A29743F7400496AB1 /* ShareViewController.swift */; }; 9FAD858B29743F7400496AB1 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FAD858A29743F7400496AB1 /* ShareViewController.swift */; };
9FAD858E29743F7400496AB1 /* (null) in Resources */ = {isa = PBXBuildFile; }; 9FAD858E29743F7400496AB1 /* (null) in Resources */ = {isa = PBXBuildFile; };
9FAD859229743F7400496AB1 /* IceCubesShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 9FAD858829743F7400496AB1 /* IceCubesShareExtension.appex */; platformFilters = (ios, maccatalyst, ); settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 9FAD859229743F7400496AB1 /* IceCubesShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 9FAD858829743F7400496AB1 /* IceCubesShareExtension.appex */; platformFilters = (ios, maccatalyst, ); settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
@ -98,6 +126,13 @@
9FE3DB57296FEFCA00628CB0 /* AppAccount in Frameworks */ = {isa = PBXBuildFile; productRef = 9FE3DB56296FEFCA00628CB0 /* AppAccount */; }; 9FE3DB57296FEFCA00628CB0 /* AppAccount in Frameworks */ = {isa = PBXBuildFile; productRef = 9FE3DB56296FEFCA00628CB0 /* AppAccount */; };
9FE4CCAB2B4C848A00DA5F13 /* GiphyUISDK in Frameworks */ = {isa = PBXBuildFile; platformFilters = (ios, maccatalyst, ); productRef = 9FE4CCAA2B4C848A00DA5F13 /* GiphyUISDK */; }; 9FE4CCAB2B4C848A00DA5F13 /* GiphyUISDK in Frameworks */ = {isa = PBXBuildFile; platformFilters = (ios, maccatalyst, ); productRef = 9FE4CCAA2B4C848A00DA5F13 /* GiphyUISDK */; };
9FE4CCAD2B4C849F00DA5F13 /* GiphyUISDK in Frameworks */ = {isa = PBXBuildFile; productRef = 9FE4CCAC2B4C849F00DA5F13 /* GiphyUISDK */; }; 9FE4CCAD2B4C849F00DA5F13 /* GiphyUISDK in Frameworks */ = {isa = PBXBuildFile; productRef = 9FE4CCAC2B4C849F00DA5F13 /* GiphyUISDK */; };
9FE6A42E2BD043A90055D388 /* RevenueCat in Frameworks */ = {isa = PBXBuildFile; productRef = 9FE6A42D2BD043A90055D388 /* RevenueCat */; };
9FF2FB622BE7F5D5001560CE /* HashtagPostsWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FF2FB602BE7F5A7001560CE /* HashtagPostsWidget.swift */; };
9FF2FB632BE7F5D9001560CE /* HashtagPostsWidgetConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FF2FB5E2BE7F56F001560CE /* HashtagPostsWidgetConfiguration.swift */; };
9FF2FB672BE7F816001560CE /* PostsWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FF2FB652BE7F805001560CE /* PostsWidgetView.swift */; };
9FF2FB6A2BE7F84E001560CE /* SharedUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FF2FB682BE7F842001560CE /* SharedUtils.swift */; };
9FF2FB702BE8AE9D001560CE /* MentionWidgetConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FF2FB6E2BE8AE9B001560CE /* MentionWidgetConfiguration.swift */; };
9FF2FB712BE8AEA0001560CE /* MentionWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FF2FB6C2BE8AE90001560CE /* MentionWidget.swift */; };
9FFF677C299B7B2C00FE700A /* Notifications in Frameworks */ = {isa = PBXBuildFile; productRef = 9FFF677B299B7B2C00FE700A /* Notifications */; }; 9FFF677C299B7B2C00FE700A /* Notifications in Frameworks */ = {isa = PBXBuildFile; productRef = 9FFF677B299B7B2C00FE700A /* Notifications */; };
9FFF6780299B7D2B00FE700A /* DesignSystem in Frameworks */ = {isa = PBXBuildFile; productRef = 9FFF677F299B7D2B00FE700A /* DesignSystem */; }; 9FFF6780299B7D2B00FE700A /* DesignSystem in Frameworks */ = {isa = PBXBuildFile; productRef = 9FFF677F299B7D2B00FE700A /* DesignSystem */; };
9FFF6782299B7D3A00FE700A /* Account in Frameworks */ = {isa = PBXBuildFile; productRef = 9FFF6781299B7D3A00FE700A /* Account */; }; 9FFF6782299B7D3A00FE700A /* Account in Frameworks */ = {isa = PBXBuildFile; productRef = 9FFF6781299B7D3A00FE700A /* Account */; };
@ -123,6 +158,13 @@
remoteGlobalIDString = 9F2A5415296AB631009B2D7C; remoteGlobalIDString = 9F2A5415296AB631009B2D7C;
remoteInfo = IceCubesNotifications; remoteInfo = IceCubesNotifications;
}; };
9F7788D42BE652B2004E6BEF /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 9FBFE631292A715500C250E9 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 9F7788C42BE652B1004E6BEF;
remoteInfo = IceCubesAppWidgetsExtensionExtension;
};
9FAD859029743F7400496AB1 /* PBXContainerItemProxy */ = { 9FAD859029743F7400496AB1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 9FBFE631292A715500C250E9 /* Project object */; containerPortal = 9FBFE631292A715500C250E9 /* Project object */;
@ -149,6 +191,7 @@
E9DF420729830FEC0003AAD2 /* IceCubesActionExtension.appex in Embed Foundation Extensions */, E9DF420729830FEC0003AAD2 /* IceCubesActionExtension.appex in Embed Foundation Extensions */,
9F2A541D296AB631009B2D7C /* IceCubesNotifications.appex in Embed Foundation Extensions */, 9F2A541D296AB631009B2D7C /* IceCubesNotifications.appex in Embed Foundation Extensions */,
9FAD859229743F7400496AB1 /* IceCubesShareExtension.appex in Embed Foundation Extensions */, 9FAD859229743F7400496AB1 /* IceCubesShareExtension.appex in Embed Foundation Extensions */,
9F7788D62BE652B2004E6BEF /* IceCubesAppWidgetsExtensionExtension.appex in Embed Foundation Extensions */,
); );
name = "Embed Foundation Extensions"; name = "Embed Foundation Extensions";
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -197,6 +240,11 @@
9F35DB4629506F6600B3281A /* NotificationTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationTab.swift; sourceTree = "<group>"; }; 9F35DB4629506F6600B3281A /* NotificationTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationTab.swift; sourceTree = "<group>"; };
9F35DB4829506F7F00B3281A /* Notifications */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Notifications; path = Packages/Notifications; sourceTree = "<group>"; }; 9F35DB4829506F7F00B3281A /* Notifications */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Notifications; path = Packages/Notifications; sourceTree = "<group>"; };
9F35DB4B2952005C00B3281A /* MessagesTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesTab.swift; sourceTree = "<group>"; }; 9F35DB4B2952005C00B3281A /* MessagesTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesTab.swift; sourceTree = "<group>"; };
9F37BDDA2BE36E22007F28AD /* PostIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostIntent.swift; sourceTree = "<group>"; };
9F37BDDC2BE37193007F28AD /* AppIntentService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIntentService.swift; sourceTree = "<group>"; };
9F37BDDE2BE37C35007F28AD /* TabIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabIntent.swift; sourceTree = "<group>"; };
9F37BDE02BE38646007F28AD /* PostImageIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostImageIntent.swift; sourceTree = "<group>"; };
9F37BDE22BE393A7007F28AD /* AppShortcuts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppShortcuts.swift; sourceTree = "<group>"; };
9F38A7322ACEA26100DBCD66 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; }; 9F38A7322ACEA26100DBCD66 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
9F398AA32935F90100A889F2 /* Models */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Models; path = Packages/Models; sourceTree = "<group>"; }; 9F398AA32935F90100A889F2 /* Models */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Models; path = Packages/Models; sourceTree = "<group>"; };
9F398AA52935FE8A00A889F2 /* AppRegistry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRegistry.swift; sourceTree = "<group>"; }; 9F398AA52935FE8A00A889F2 /* AppRegistry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRegistry.swift; sourceTree = "<group>"; };
@ -205,6 +253,9 @@
9F4A48182976B21900A1A038 /* ProfileTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileTab.swift; sourceTree = "<group>"; }; 9F4A48182976B21900A1A038 /* ProfileTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileTab.swift; sourceTree = "<group>"; };
9F55C68C2955968700F94077 /* ExploreTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExploreTab.swift; sourceTree = "<group>"; }; 9F55C68C2955968700F94077 /* ExploreTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExploreTab.swift; sourceTree = "<group>"; };
9F55C68E295598F900F94077 /* Explore */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Explore; path = Packages/Explore; sourceTree = "<group>"; }; 9F55C68E295598F900F94077 /* Explore */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Explore; path = Packages/Explore; sourceTree = "<group>"; };
9F5BE6212BF48FBA0074387E /* ListsWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListsWidget.swift; sourceTree = "<group>"; };
9F5BE6232BF48FC40074387E /* ListsWidgetConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListsWidgetConfiguration.swift; sourceTree = "<group>"; };
9F5BE6252BF48FE10074387E /* ListEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListEntity.swift; sourceTree = "<group>"; };
9F5E581729545B5500A53960 /* Env */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Env; path = Packages/Env; sourceTree = "<group>"; }; 9F5E581729545B5500A53960 /* Env */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Env; path = Packages/Env; sourceTree = "<group>"; };
9F6028552B3F36AE00476078 /* AppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppView.swift; sourceTree = "<group>"; }; 9F6028552B3F36AE00476078 /* AppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppView.swift; sourceTree = "<group>"; };
9F6028572B3F3B7600476078 /* ToolbarTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarTab.swift; sourceTree = "<group>"; }; 9F6028572B3F3B7600476078 /* ToolbarTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarTab.swift; sourceTree = "<group>"; };
@ -215,10 +266,25 @@
9F7335EE29674F7100AFF0BA /* QuickLook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuickLook.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.2.sdk/System/Library/Frameworks/QuickLook.framework; sourceTree = DEVELOPER_DIR; }; 9F7335EE29674F7100AFF0BA /* QuickLook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuickLook.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.2.sdk/System/Library/Frameworks/QuickLook.framework; sourceTree = DEVELOPER_DIR; };
9F7335F12967608F00AFF0BA /* AddRemoteTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddRemoteTimelineView.swift; sourceTree = "<group>"; }; 9F7335F12967608F00AFF0BA /* AddRemoteTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddRemoteTimelineView.swift; sourceTree = "<group>"; };
9F7335F82968576500AFF0BA /* DisplaySettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplaySettingsView.swift; sourceTree = "<group>"; }; 9F7335F82968576500AFF0BA /* DisplaySettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplaySettingsView.swift; sourceTree = "<group>"; };
9F7788BF2BE63935004E6BEF /* InlinePostIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InlinePostIntent.swift; sourceTree = "<group>"; };
9F7788C52BE652B1004E6BEF /* IceCubesAppWidgetsExtensionExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = IceCubesAppWidgetsExtensionExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
9F7788C62BE652B1004E6BEF /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
9F7788C82BE652B1004E6BEF /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
9F7788CB2BE652B1004E6BEF /* IceCubesAppWidgetsExtensionBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IceCubesAppWidgetsExtensionBundle.swift; sourceTree = "<group>"; };
9F7788CD2BE652B1004E6BEF /* LatestPostsWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LatestPostsWidget.swift; sourceTree = "<group>"; };
9F7788CF2BE652B1004E6BEF /* LatestPostsWidgetConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LatestPostsWidgetConfiguration.swift; sourceTree = "<group>"; };
9F7788D12BE652B2004E6BEF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
9F7788D32BE652B2004E6BEF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9F7788D72BE652B2004E6BEF /* IceCubesAppWidgetsExtensionExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = IceCubesAppWidgetsExtensionExtension.entitlements; sourceTree = "<group>"; };
9F7788E72BE65533004E6BEF /* AppAccountEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppAccountEntity.swift; sourceTree = "<group>"; };
9F7788EC2BE78D75004E6BEF /* TimelineFilterEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineFilterEntity.swift; sourceTree = "<group>"; };
9F7D939529800B0300EE6B7A /* IceCubesApp-release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "IceCubesApp-release.xcconfig"; sourceTree = "<group>"; }; 9F7D939529800B0300EE6B7A /* IceCubesApp-release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "IceCubesApp-release.xcconfig"; sourceTree = "<group>"; };
9F7D939929805DBD00EE6B7A /* AccountSettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountSettingView.swift; sourceTree = "<group>"; }; 9F7D939929805DBD00EE6B7A /* AccountSettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountSettingView.swift; sourceTree = "<group>"; };
9F8B920E2BF77DB4003D37A2 /* AccountWidgetConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountWidgetConfiguration.swift; sourceTree = "<group>"; };
9F8B92102BF77DBB003D37A2 /* AccountWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountWidget.swift; sourceTree = "<group>"; };
9F8B92142BF77F05003D37A2 /* AccountWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountWidgetView.swift; sourceTree = "<group>"; };
9F9191552C6DDE1C001C89E7 /* WishlistView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WishlistView.swift; sourceTree = "<group>"; };
9FA6FD6129C04A8800E2312C /* TranslationSettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TranslationSettingsView.swift; sourceTree = "<group>"; }; 9FA6FD6129C04A8800E2312C /* TranslationSettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TranslationSettingsView.swift; sourceTree = "<group>"; };
9FAD85822971BF7200496AB1 /* Secret.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Secret.plist; sourceTree = "<group>"; };
9FAD858829743F7400496AB1 /* IceCubesShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = IceCubesShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 9FAD858829743F7400496AB1 /* IceCubesShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = IceCubesShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
9FAD858A29743F7400496AB1 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; }; 9FAD858A29743F7400496AB1 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; };
9FAD858F29743F7400496AB1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 9FAD858F29743F7400496AB1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@ -243,6 +309,12 @@
9FE0346A2ADD59AC00529EA8 /* MediaUI */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = MediaUI; path = Packages/MediaUI; sourceTree = "<group>"; }; 9FE0346A2ADD59AC00529EA8 /* MediaUI */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = MediaUI; path = Packages/MediaUI; sourceTree = "<group>"; };
9FE151A5293C90F900E9683D /* IconSelectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconSelectorView.swift; sourceTree = "<group>"; }; 9FE151A5293C90F900E9683D /* IconSelectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconSelectorView.swift; sourceTree = "<group>"; };
9FE3DB55296FEF5800628CB0 /* AppAccount */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = AppAccount; path = Packages/AppAccount; sourceTree = "<group>"; }; 9FE3DB55296FEF5800628CB0 /* AppAccount */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = AppAccount; path = Packages/AppAccount; sourceTree = "<group>"; };
9FF2FB5E2BE7F56F001560CE /* HashtagPostsWidgetConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashtagPostsWidgetConfiguration.swift; sourceTree = "<group>"; };
9FF2FB602BE7F5A7001560CE /* HashtagPostsWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashtagPostsWidget.swift; sourceTree = "<group>"; };
9FF2FB652BE7F805001560CE /* PostsWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostsWidgetView.swift; sourceTree = "<group>"; };
9FF2FB682BE7F842001560CE /* SharedUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedUtils.swift; sourceTree = "<group>"; };
9FF2FB6C2BE8AE90001560CE /* MentionWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionWidget.swift; sourceTree = "<group>"; };
9FF2FB6E2BE8AE9B001560CE /* MentionWidgetConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionWidgetConfiguration.swift; sourceTree = "<group>"; };
B0BAB49E29B3D7A9008F54D7 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/InfoPlist.strings"; sourceTree = "<group>"; }; B0BAB49E29B3D7A9008F54D7 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
C4CBB90B298A0DA3007E1707 /* en-GB */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "en-GB"; path = "en-GB.lproj/InfoPlist.strings"; sourceTree = "<group>"; }; C4CBB90B298A0DA3007E1707 /* en-GB */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "en-GB"; path = "en-GB.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
C4FBCF6F298FD88A0015DF22 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; }; C4FBCF6F298FD88A0015DF22 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
@ -278,6 +350,21 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
9F7788C22BE652B1004E6BEF /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9F7788E42BE6543D004E6BEF /* Models in Frameworks */,
9F7788E62BE6543D004E6BEF /* Network in Frameworks */,
9F7788E02BE6543D004E6BEF /* AppAccount in Frameworks */,
9F7788DE2BE6543D004E6BEF /* Account in Frameworks */,
9F7788E22BE6543D004E6BEF /* Env in Frameworks */,
9F7788C92BE652B1004E6BEF /* SwiftUI.framework in Frameworks */,
9F7788C72BE652B1004E6BEF /* WidgetKit.framework in Frameworks */,
9F7788F02BE78E77004E6BEF /* Timeline in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
9FAD858529743F7400496AB1 /* Frameworks */ = { 9FAD858529743F7400496AB1 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -300,7 +387,6 @@
9F7335EF29674F7100AFF0BA /* QuickLook.framework in Frameworks */, 9F7335EF29674F7100AFF0BA /* QuickLook.framework in Frameworks */,
9FE4CCAB2B4C848A00DA5F13 /* GiphyUISDK in Frameworks */, 9FE4CCAB2B4C848A00DA5F13 /* GiphyUISDK in Frameworks */,
9F7335ED2967463400AFF0BA /* AVKit.framework in Frameworks */, 9F7335ED2967463400AFF0BA /* AVKit.framework in Frameworks */,
9F2A540C29699705009B2D7C /* RevenueCat in Frameworks */,
9F2A540E2969A0B0009B2D7C /* StoreKit.framework in Frameworks */, 9F2A540E2969A0B0009B2D7C /* StoreKit.framework in Frameworks */,
9F55C6902955993C00F94077 /* Explore in Frameworks */, 9F55C6902955993C00F94077 /* Explore in Frameworks */,
9FAE4ACE29379A5A00772766 /* KeychainSwift in Frameworks */, 9FAE4ACE29379A5A00772766 /* KeychainSwift in Frameworks */,
@ -311,8 +397,9 @@
9FD542E72962D2FF0045321A /* Lists in Frameworks */, 9FD542E72962D2FF0045321A /* Lists in Frameworks */,
9F398AAB2935FFDB00A889F2 /* Models in Frameworks */, 9F398AAB2935FFDB00A889F2 /* Models in Frameworks */,
9F5E581929545BE700A53960 /* Env in Frameworks */, 9F5E581929545BE700A53960 /* Env in Frameworks */,
9F2A540A29699705009B2D7C /* ReceiptParser in Frameworks */,
DA0B24FB2A6876D50045BDD7 /* SFSafeSymbols in Frameworks */, DA0B24FB2A6876D50045BDD7 /* SFSafeSymbols in Frameworks */,
9FE6A42E2BD043A90055D388 /* RevenueCat in Frameworks */,
9F9191592C6DDF20001C89E7 /* WishKit in Frameworks */,
9F295540292B6C3400E0E81B /* Timeline in Frameworks */, 9F295540292B6C3400E0E81B /* Timeline in Frameworks */,
9F35DB4A29506FA100B3281A /* Notifications in Frameworks */, 9F35DB4A29506FA100B3281A /* Notifications in Frameworks */,
9FC2A38B2B49D19A00DFD1C1 /* StatusKit in Frameworks */, 9FC2A38B2B49D19A00DFD1C1 /* StatusKit in Frameworks */,
@ -351,6 +438,22 @@
path = IceCubesNotifications; path = IceCubesNotifications;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
9F37BDD92BE36E08007F28AD /* IceCubesAppIntents */ = {
isa = PBXGroup;
children = (
9F7788E72BE65533004E6BEF /* AppAccountEntity.swift */,
9F37BDDC2BE37193007F28AD /* AppIntentService.swift */,
9F37BDE22BE393A7007F28AD /* AppShortcuts.swift */,
9F7788BF2BE63935004E6BEF /* InlinePostIntent.swift */,
9F37BDE02BE38646007F28AD /* PostImageIntent.swift */,
9F37BDDA2BE36E22007F28AD /* PostIntent.swift */,
9F37BDDE2BE37C35007F28AD /* TabIntent.swift */,
9F7788EC2BE78D75004E6BEF /* TimelineFilterEntity.swift */,
9F5BE6252BF48FE10074387E /* ListEntity.swift */,
);
path = IceCubesAppIntents;
sourceTree = "<group>";
};
9F398AB429360A5800A889F2 /* App */ = { 9F398AB429360A5800A889F2 /* App */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -375,6 +478,15 @@
path = Resources; path = Resources;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
9F5BE6202BF48FB20074387E /* ListsWidget */ = {
isa = PBXGroup;
children = (
9F5BE6212BF48FBA0074387E /* ListsWidget.swift */,
9F5BE6232BF48FC40074387E /* ListsWidgetConfiguration.swift */,
);
path = ListsWidget;
sourceTree = "<group>";
};
9F654BF0299AC46200D27FA5 /* Report */ = { 9F654BF0299AC46200D27FA5 /* Report */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -392,6 +504,33 @@
path = Timeline; path = Timeline;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
9F7788CA2BE652B1004E6BEF /* IceCubesAppWidgetsExtension */ = {
isa = PBXGroup;
children = (
9F8B920D2BF77DA8003D37A2 /* AccountWidget */,
9F5BE6202BF48FB20074387E /* ListsWidget */,
9FF2FB6B2BE8AE78001560CE /* MentionWidget */,
9FF2FB642BE7F7FA001560CE /* Shared */,
9FF2FB5D2BE7F559001560CE /* HashtagPostsWidget */,
9FF2FB5C2BE7F549001560CE /* LatestPostsWidget */,
9F7788D72BE652B2004E6BEF /* IceCubesAppWidgetsExtensionExtension.entitlements */,
9F7788CB2BE652B1004E6BEF /* IceCubesAppWidgetsExtensionBundle.swift */,
9F7788D12BE652B2004E6BEF /* Assets.xcassets */,
9F7788D32BE652B2004E6BEF /* Info.plist */,
);
path = IceCubesAppWidgetsExtension;
sourceTree = "<group>";
};
9F8B920D2BF77DA8003D37A2 /* AccountWidget */ = {
isa = PBXGroup;
children = (
9F8B920E2BF77DB4003D37A2 /* AccountWidgetConfiguration.swift */,
9F8B92102BF77DBB003D37A2 /* AccountWidget.swift */,
9F8B92142BF77F05003D37A2 /* AccountWidgetView.swift */,
);
path = AccountWidget;
sourceTree = "<group>";
};
9FA0D2AC29921C1F008A143B /* Embeds */ = { 9FA0D2AC29921C1F008A143B /* Embeds */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -456,9 +595,11 @@
DD31E2E5297FB68B00A4BE29 /* IceCubesApp.xcconfig */, DD31E2E5297FB68B00A4BE29 /* IceCubesApp.xcconfig */,
9F7D939529800B0300EE6B7A /* IceCubesApp-release.xcconfig */, 9F7D939529800B0300EE6B7A /* IceCubesApp-release.xcconfig */,
9FBFE63B292A715500C250E9 /* IceCubesApp */, 9FBFE63B292A715500C250E9 /* IceCubesApp */,
9F37BDD92BE36E08007F28AD /* IceCubesAppIntents */,
E9DF41FD29830FEC0003AAD2 /* IceCubesActionExtension */, E9DF41FD29830FEC0003AAD2 /* IceCubesActionExtension */,
9F2A5417296AB631009B2D7C /* IceCubesNotifications */, 9F2A5417296AB631009B2D7C /* IceCubesNotifications */,
9FAD858929743F7400496AB1 /* IceCubesShareExtension */, 9FAD858929743F7400496AB1 /* IceCubesShareExtension */,
9F7788CA2BE652B1004E6BEF /* IceCubesAppWidgetsExtension */,
9FBFE63A292A715500C250E9 /* Products */, 9FBFE63A292A715500C250E9 /* Products */,
9FBFE64C292A72BD00C250E9 /* Frameworks */, 9FBFE64C292A72BD00C250E9 /* Frameworks */,
9FE3DB55296FEF5800628CB0 /* AppAccount */, 9FE3DB55296FEF5800628CB0 /* AppAccount */,
@ -484,6 +625,7 @@
9F2A5416296AB631009B2D7C /* IceCubesNotifications.appex */, 9F2A5416296AB631009B2D7C /* IceCubesNotifications.appex */,
9FAD858829743F7400496AB1 /* IceCubesShareExtension.appex */, 9FAD858829743F7400496AB1 /* IceCubesShareExtension.appex */,
E9DF41FA29830FEC0003AAD2 /* IceCubesActionExtension.appex */, E9DF41FA29830FEC0003AAD2 /* IceCubesActionExtension.appex */,
9F7788C52BE652B1004E6BEF /* IceCubesAppWidgetsExtensionExtension.appex */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@ -496,7 +638,6 @@
9FAE4AC8293774FF00772766 /* Info.plist */, 9FAE4AC8293774FF00772766 /* Info.plist */,
9F398AB429360A5800A889F2 /* App */, 9F398AB429360A5800A889F2 /* App */,
9F398AB529360A6100A889F2 /* Resources */, 9F398AB529360A6100A889F2 /* Resources */,
9FAD85822971BF7200496AB1 /* Secret.plist */,
); );
path = IceCubesApp; path = IceCubesApp;
sourceTree = "<group>"; sourceTree = "<group>";
@ -509,6 +650,8 @@
9F7335EE29674F7100AFF0BA /* QuickLook.framework */, 9F7335EE29674F7100AFF0BA /* QuickLook.framework */,
9F7335EB2967461B00AFF0BA /* AVKit.framework */, 9F7335EB2967461B00AFF0BA /* AVKit.framework */,
E9DF41FB29830FEC0003AAD2 /* UniformTypeIdentifiers.framework */, E9DF41FB29830FEC0003AAD2 /* UniformTypeIdentifiers.framework */,
9F7788C62BE652B1004E6BEF /* WidgetKit.framework */,
9F7788C82BE652B1004E6BEF /* SwiftUI.framework */,
); );
name = Frameworks; name = Frameworks;
sourceTree = "<group>"; sourceTree = "<group>";
@ -516,6 +659,7 @@
9FE151A4293C90EA00E9683D /* Settings */ = { 9FE151A4293C90EA00E9683D /* Settings */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
9F9191552C6DDE1C001C89E7 /* WishlistView.swift */,
069709A9298C9AD7006E4CB5 /* AboutView.swift */, 069709A9298C9AD7006E4CB5 /* AboutView.swift */,
9F7D939929805DBD00EE6B7A /* AccountSettingView.swift */, 9F7D939929805DBD00EE6B7A /* AccountSettingView.swift */,
9F2B92F9295DA7D700DE16D0 /* AddAccountsView.swift */, 9F2B92F9295DA7D700DE16D0 /* AddAccountsView.swift */,
@ -538,6 +682,42 @@
path = Settings; path = Settings;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
9FF2FB5C2BE7F549001560CE /* LatestPostsWidget */ = {
isa = PBXGroup;
children = (
9F7788CD2BE652B1004E6BEF /* LatestPostsWidget.swift */,
9F7788CF2BE652B1004E6BEF /* LatestPostsWidgetConfiguration.swift */,
);
path = LatestPostsWidget;
sourceTree = "<group>";
};
9FF2FB5D2BE7F559001560CE /* HashtagPostsWidget */ = {
isa = PBXGroup;
children = (
9FF2FB5E2BE7F56F001560CE /* HashtagPostsWidgetConfiguration.swift */,
9FF2FB602BE7F5A7001560CE /* HashtagPostsWidget.swift */,
);
path = HashtagPostsWidget;
sourceTree = "<group>";
};
9FF2FB642BE7F7FA001560CE /* Shared */ = {
isa = PBXGroup;
children = (
9FF2FB652BE7F805001560CE /* PostsWidgetView.swift */,
9FF2FB682BE7F842001560CE /* SharedUtils.swift */,
);
path = Shared;
sourceTree = "<group>";
};
9FF2FB6B2BE8AE78001560CE /* MentionWidget */ = {
isa = PBXGroup;
children = (
9FF2FB6C2BE8AE90001560CE /* MentionWidget.swift */,
9FF2FB6E2BE8AE9B001560CE /* MentionWidgetConfiguration.swift */,
);
path = MentionWidget;
sourceTree = "<group>";
};
E9B576C029743F2A00BCE646 /* Localization */ = { E9B576C029743F2A00BCE646 /* Localization */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -589,6 +769,31 @@
productReference = 9F2A5416296AB631009B2D7C /* IceCubesNotifications.appex */; productReference = 9F2A5416296AB631009B2D7C /* IceCubesNotifications.appex */;
productType = "com.apple.product-type.app-extension"; productType = "com.apple.product-type.app-extension";
}; };
9F7788C42BE652B1004E6BEF /* IceCubesAppWidgetsExtensionExtension */ = {
isa = PBXNativeTarget;
buildConfigurationList = 9F7788D82BE652B2004E6BEF /* Build configuration list for PBXNativeTarget "IceCubesAppWidgetsExtensionExtension" */;
buildPhases = (
9F7788C12BE652B1004E6BEF /* Sources */,
9F7788C22BE652B1004E6BEF /* Frameworks */,
9F7788C32BE652B1004E6BEF /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = IceCubesAppWidgetsExtensionExtension;
packageProductDependencies = (
9F7788DD2BE6543D004E6BEF /* Account */,
9F7788DF2BE6543D004E6BEF /* AppAccount */,
9F7788E12BE6543D004E6BEF /* Env */,
9F7788E32BE6543D004E6BEF /* Models */,
9F7788E52BE6543D004E6BEF /* Network */,
9F7788EF2BE78E77004E6BEF /* Timeline */,
);
productName = IceCubesAppWidgetsExtensionExtension;
productReference = 9F7788C52BE652B1004E6BEF /* IceCubesAppWidgetsExtensionExtension.appex */;
productType = "com.apple.product-type.app-extension";
};
9FAD858729743F7400496AB1 /* IceCubesShareExtension */ = { 9FAD858729743F7400496AB1 /* IceCubesShareExtension */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 9FAD859329743F7400496AB1 /* Build configuration list for PBXNativeTarget "IceCubesShareExtension" */; buildConfigurationList = 9FAD859329743F7400496AB1 /* Build configuration list for PBXNativeTarget "IceCubesShareExtension" */;
@ -631,6 +836,7 @@
9F2A541C296AB631009B2D7C /* PBXTargetDependency */, 9F2A541C296AB631009B2D7C /* PBXTargetDependency */,
9FAD859129743F7400496AB1 /* PBXTargetDependency */, 9FAD859129743F7400496AB1 /* PBXTargetDependency */,
E9DF420629830FEC0003AAD2 /* PBXTargetDependency */, E9DF420629830FEC0003AAD2 /* PBXTargetDependency */,
9F7788D52BE652B2004E6BEF /* PBXTargetDependency */,
); );
name = IceCubesApp; name = IceCubesApp;
packageProductDependencies = ( packageProductDependencies = (
@ -644,12 +850,12 @@
9F55C68F2955993C00F94077 /* Explore */, 9F55C68F2955993C00F94077 /* Explore */,
9FD542E62962D2FF0045321A /* Lists */, 9FD542E62962D2FF0045321A /* Lists */,
9F7335E92966B3F800AFF0BA /* Conversations */, 9F7335E92966B3F800AFF0BA /* Conversations */,
9F2A540929699705009B2D7C /* ReceiptParser */,
9F2A540B29699705009B2D7C /* RevenueCat */,
9FE3DB56296FEFCA00628CB0 /* AppAccount */, 9FE3DB56296FEFCA00628CB0 /* AppAccount */,
DA0B24FA2A6876D50045BDD7 /* SFSafeSymbols */, DA0B24FA2A6876D50045BDD7 /* SFSafeSymbols */,
9FC2A38A2B49D19A00DFD1C1 /* StatusKit */, 9FC2A38A2B49D19A00DFD1C1 /* StatusKit */,
9FE4CCAA2B4C848A00DA5F13 /* GiphyUISDK */, 9FE4CCAA2B4C848A00DA5F13 /* GiphyUISDK */,
9FE6A42D2BD043A90055D388 /* RevenueCat */,
9F9191582C6DDF20001C89E7 /* WishKit */,
); );
productName = IceCubesApp; productName = IceCubesApp;
productReference = 9FBFE639292A715500C250E9 /* Ice Cubes.app */; productReference = 9FBFE639292A715500C250E9 /* Ice Cubes.app */;
@ -683,12 +889,15 @@
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
BuildIndependentTargetsInParallel = 1; BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1420; LastSwiftUpdateCheck = 1530;
LastUpgradeCheck = 1500; LastUpgradeCheck = 1600;
TargetAttributes = { TargetAttributes = {
9F2A5415296AB631009B2D7C = { 9F2A5415296AB631009B2D7C = {
CreatedOnToolsVersion = 14.2; CreatedOnToolsVersion = 14.2;
}; };
9F7788C42BE652B1004E6BEF = {
CreatedOnToolsVersion = 15.3;
};
9FAD858729743F7400496AB1 = { 9FAD858729743F7400496AB1 = {
CreatedOnToolsVersion = 14.2; CreatedOnToolsVersion = 14.2;
}; };
@ -724,13 +933,15 @@
be, be,
uk, uk,
"zh-Hant", "zh-Hant",
Base,
); );
mainGroup = 9FBFE630292A715500C250E9; mainGroup = 9FBFE630292A715500C250E9;
packageReferences = ( packageReferences = (
9FAE4ACC29379A5A00772766 /* XCRemoteSwiftPackageReference "keychain-swift" */, 9FAE4ACC29379A5A00772766 /* XCRemoteSwiftPackageReference "keychain-swift" */,
9F2A540829699705009B2D7C /* XCRemoteSwiftPackageReference "purchases-ios" */,
DA0B24F92A6876D40045BDD7 /* XCRemoteSwiftPackageReference "SFSafeSymbols" */, DA0B24F92A6876D40045BDD7 /* XCRemoteSwiftPackageReference "SFSafeSymbols" */,
9FE4CCA92B4C848A00DA5F13 /* XCRemoteSwiftPackageReference "giphy-ios-sdk" */, 9FE4CCA92B4C848A00DA5F13 /* XCRemoteSwiftPackageReference "giphy-ios-sdk" */,
9FE6A42C2BD043A80055D388 /* XCRemoteSwiftPackageReference "purchases-ios" */,
9F9191572C6DDF20001C89E7 /* XCRemoteSwiftPackageReference "wishkit-ios" */,
); );
productRefGroup = 9FBFE63A292A715500C250E9 /* Products */; productRefGroup = 9FBFE63A292A715500C250E9 /* Products */;
projectDirPath = ""; projectDirPath = "";
@ -740,6 +951,7 @@
E9DF41F929830FEC0003AAD2 /* IceCubesActionExtension */, E9DF41F929830FEC0003AAD2 /* IceCubesActionExtension */,
9F2A5415296AB631009B2D7C /* IceCubesNotifications */, 9F2A5415296AB631009B2D7C /* IceCubesNotifications */,
9FAD858729743F7400496AB1 /* IceCubesShareExtension */, 9FAD858729743F7400496AB1 /* IceCubesShareExtension */,
9F7788C42BE652B1004E6BEF /* IceCubesAppWidgetsExtensionExtension */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
@ -755,6 +967,14 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
9F7788C32BE652B1004E6BEF /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
9F7788D22BE652B2004E6BEF /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
9FAD858629743F7400496AB1 /* Resources */ = { 9FAD858629743F7400496AB1 /* Resources */ = {
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -778,7 +998,6 @@
9F18801829AE477F00D85459 /* favorite.wav in Resources */, 9F18801829AE477F00D85459 /* favorite.wav in Resources */,
9F24EEB829360C330042359D /* Preview Assets.xcassets in Resources */, 9F24EEB829360C330042359D /* Preview Assets.xcassets in Resources */,
069709A8298C87B5006E4CB5 /* OpenDyslexic-Regular.otf in Resources */, 069709A8298C87B5006E4CB5 /* OpenDyslexic-Regular.otf in Resources */,
9FAD85832971BF7200496AB1 /* Secret.plist in Resources */,
9F18801229AE477F00D85459 /* tabSelection.wav in Resources */, 9F18801229AE477F00D85459 /* tabSelection.wav in Resources */,
9F18801429AE477F00D85459 /* bookmark.wav in Resources */, 9F18801429AE477F00D85459 /* bookmark.wav in Resources */,
9F18801629AE477F00D85459 /* refresh.wav in Resources */, 9F18801629AE477F00D85459 /* refresh.wav in Resources */,
@ -809,6 +1028,30 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
9F7788C12BE652B1004E6BEF /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
9F5BE6272BF492CF0074387E /* ListEntity.swift in Sources */,
9FF2FB622BE7F5D5001560CE /* HashtagPostsWidget.swift in Sources */,
9FF2FB712BE8AEA0001560CE /* MentionWidget.swift in Sources */,
9F8B92162BF77F0B003D37A2 /* AccountWidgetView.swift in Sources */,
9F8B92122BF77DBE003D37A2 /* AccountWidgetConfiguration.swift in Sources */,
9F8B92132BF77DBE003D37A2 /* AccountWidget.swift in Sources */,
9F7788EA2BE65585004E6BEF /* AppAccountEntity.swift in Sources */,
9FF2FB6A2BE7F84E001560CE /* SharedUtils.swift in Sources */,
9F7788CE2BE652B1004E6BEF /* LatestPostsWidget.swift in Sources */,
9F7788EE2BE78D7B004E6BEF /* TimelineFilterEntity.swift in Sources */,
9F5BE6292BF492D40074387E /* ListsWidget.swift in Sources */,
9F7788CC2BE652B1004E6BEF /* IceCubesAppWidgetsExtensionBundle.swift in Sources */,
9FF2FB702BE8AE9D001560CE /* MentionWidgetConfiguration.swift in Sources */,
9F7788D02BE652B1004E6BEF /* LatestPostsWidgetConfiguration.swift in Sources */,
9FF2FB672BE7F816001560CE /* PostsWidgetView.swift in Sources */,
9FF2FB632BE7F5D9001560CE /* HashtagPostsWidgetConfiguration.swift in Sources */,
9F5BE6282BF492D10074387E /* ListsWidgetConfiguration.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
9FAD858429743F7400496AB1 /* Sources */ = { 9FAD858429743F7400496AB1 /* Sources */ = {
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -830,6 +1073,11 @@
9F15D6042B3DC2180008C220 /* NavigationSheet.swift in Sources */, 9F15D6042B3DC2180008C220 /* NavigationSheet.swift in Sources */,
9FA6FD6229C04A8800E2312C /* TranslationSettingsView.swift in Sources */, 9FA6FD6229C04A8800E2312C /* TranslationSettingsView.swift in Sources */,
9F35DB4C2952005C00B3281A /* MessagesTab.swift in Sources */, 9F35DB4C2952005C00B3281A /* MessagesTab.swift in Sources */,
9F37BDDB2BE36E22007F28AD /* PostIntent.swift in Sources */,
9F37BDDD2BE37193007F28AD /* AppIntentService.swift in Sources */,
9F37BDE12BE38646007F28AD /* PostImageIntent.swift in Sources */,
9F37BDDF2BE37C35007F28AD /* TabIntent.swift in Sources */,
9F7788C02BE63935004E6BEF /* InlinePostIntent.swift in Sources */,
9FAD85CF2975B68900496AB1 /* SideBarView.swift in Sources */, 9FAD85CF2975B68900496AB1 /* SideBarView.swift in Sources */,
9FAE4ACB293783B000772766 /* SettingsTab.swift in Sources */, 9FAE4ACB293783B000772766 /* SettingsTab.swift in Sources */,
9FC14EF42B494D940006CEE1 /* RemoteTimelinesSettingView.swift in Sources */, 9FC14EF42B494D940006CEE1 /* RemoteTimelinesSettingView.swift in Sources */,
@ -848,9 +1096,13 @@
9F2B92FA295DA7D700DE16D0 /* AddAccountsView.swift in Sources */, 9F2B92FA295DA7D700DE16D0 /* AddAccountsView.swift in Sources */,
639CDF9C296AC82F00C35E58 /* SafariRouter.swift in Sources */, 639CDF9C296AC82F00C35E58 /* SafariRouter.swift in Sources */,
9F35DB4729506F6600B3281A /* NotificationTab.swift in Sources */, 9F35DB4729506F6600B3281A /* NotificationTab.swift in Sources */,
9F7788ED2BE78D75004E6BEF /* TimelineFilterEntity.swift in Sources */,
9F37BDE32BE393A7007F28AD /* AppShortcuts.swift in Sources */,
9F654BEF299AC45B00D27FA5 /* ReportView.swift in Sources */, 9F654BEF299AC45B00D27FA5 /* ReportView.swift in Sources */,
9F9191562C6DDE1F001C89E7 /* WishlistView.swift in Sources */,
D08A9C3529956CFA00204A4A /* SwipeActionsSettingsView.swift in Sources */, D08A9C3529956CFA00204A4A /* SwipeActionsSettingsView.swift in Sources */,
9F7335F22967608F00AFF0BA /* AddRemoteTimelineView.swift in Sources */, 9F7335F22967608F00AFF0BA /* AddRemoteTimelineView.swift in Sources */,
9F7788E82BE65533004E6BEF /* AppAccountEntity.swift in Sources */,
9FC14EF62B494DFF0006CEE1 /* RecenTagsSettingView.swift in Sources */, 9FC14EF62B494DFF0006CEE1 /* RecenTagsSettingView.swift in Sources */,
9F6028562B3F36AE00476078 /* AppView.swift in Sources */, 9F6028562B3F36AE00476078 /* AppView.swift in Sources */,
9F55C68D2955968700F94077 /* ExploreTab.swift in Sources */, 9F55C68D2955968700F94077 /* ExploreTab.swift in Sources */,
@ -877,6 +1129,15 @@
target = 9F2A5415296AB631009B2D7C /* IceCubesNotifications */; target = 9F2A5415296AB631009B2D7C /* IceCubesNotifications */;
targetProxy = 9F2A541B296AB631009B2D7C /* PBXContainerItemProxy */; targetProxy = 9F2A541B296AB631009B2D7C /* PBXContainerItemProxy */;
}; };
9F7788D52BE652B2004E6BEF /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
platformFilters = (
ios,
maccatalyst,
);
target = 9F7788C42BE652B1004E6BEF /* IceCubesAppWidgetsExtensionExtension */;
targetProxy = 9F7788D42BE652B2004E6BEF /* PBXContainerItemProxy */;
};
9FAD859129743F7400496AB1 /* PBXTargetDependency */ = { 9FAD859129743F7400496AB1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency; isa = PBXTargetDependency;
platformFilters = ( platformFilters = (
@ -940,7 +1201,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 1.10.22; MARKETING_VERSION = 1.11.0;
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_PREFIX).IceCubesApp.IceCubesNotifications"; PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_PREFIX).IceCubesApp.IceCubesNotifications";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos; SDKROOT = iphoneos;
@ -950,7 +1211,7 @@
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2,7"; TARGETED_DEVICE_FAMILY = "1,2,7";
}; };
name = Debug; name = Debug;
@ -975,7 +1236,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 1.10.22; MARKETING_VERSION = 1.11.0;
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_PREFIX).IceCubesApp.IceCubesNotifications"; PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_PREFIX).IceCubesApp.IceCubesNotifications";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos; SDKROOT = iphoneos;
@ -985,12 +1246,84 @@
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2,7"; TARGETED_DEVICE_FAMILY = "1,2,7";
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
}; };
name = Release; name = Release;
}; };
9F7788D92BE652B2004E6BEF /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CODE_SIGN_ENTITLEMENTS = IceCubesAppWidgetsExtension/IceCubesAppWidgetsExtensionExtension.entitlements;
CODE_SIGN_IDENTITY = "-";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 730;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = IceCubesAppWidgetsExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = IceCubesAppWidgetsExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.11.0;
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_PREFIX).IceCubesApp.IceCubesAppWidgetsExtension";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SUPPORTS_MACCATALYST = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
9F7788DA2BE652B2004E6BEF /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CODE_SIGN_ENTITLEMENTS = IceCubesAppWidgetsExtension/IceCubesAppWidgetsExtensionExtension.entitlements;
CODE_SIGN_IDENTITY = "-";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 730;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = IceCubesAppWidgetsExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = IceCubesAppWidgetsExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.11.0;
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_PREFIX).IceCubesApp.IceCubesAppWidgetsExtension";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SUPPORTS_MACCATALYST = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
9FAD859429743F7400496AB1 /* Debug */ = { 9FAD859429743F7400496AB1 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
@ -1011,7 +1344,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 1.10.22; MARKETING_VERSION = 1.11.0;
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_PREFIX).IceCubesApp.IceCubesShareExtension"; PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_PREFIX).IceCubesApp.IceCubesShareExtension";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos; SDKROOT = iphoneos;
@ -1020,7 +1353,7 @@
SUPPORTS_MACCATALYST = YES; SUPPORTS_MACCATALYST = YES;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
}; };
name = Debug; name = Debug;
@ -1045,7 +1378,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 1.10.22; MARKETING_VERSION = 1.11.0;
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_PREFIX).IceCubesApp.IceCubesShareExtension"; PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_PREFIX).IceCubesApp.IceCubesShareExtension";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos; SDKROOT = iphoneos;
@ -1054,7 +1387,7 @@
SUPPORTS_MACCATALYST = YES; SUPPORTS_MACCATALYST = YES;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
}; };
@ -1123,6 +1456,7 @@
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_STRICT_CONCURRENCY = complete; SWIFT_STRICT_CONCURRENCY = complete;
SWIFT_VERSION = "";
}; };
name = Debug; name = Debug;
}; };
@ -1182,17 +1516,18 @@
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_STRICT_CONCURRENCY = complete; SWIFT_STRICT_CONCURRENCY = complete;
SWIFT_VERSION = "";
}; };
name = Release; name = Release;
}; };
9FBFE649292A715600C250E9 /* Debug */ = { 9FBFE649292A715600C250E9 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "AppIconAlternate0 AppIconAlternate6 AppIconAlternate7 AppIconAlternate8 AppIconAlternate10 AppIconAlternate11 AppIconAlternate12 AppIconAlternate13 AppIconAlternate14 AppIconAlternate15 AppIconAlternate16 AppIconAlternate17 AppIconAlternate19 AppIconAlternate18 AppIconAlternate20 AppIconAlternate21 AppIconAlternate22 AppIconAlternate23 AppIconAlternate24 AppIconAlternate25 AppIconAlternate26 AppIconAlternate27 AppIconAlternate28 AppIconAlternate29 AppIconAlternate30 AppIconAlternate31 AppIconAlternate32 AppIconAlternate33 AppIconAlternate34 AppIconAlternate35 AppIconAlternate36 AppIconAlternate37 AppIconAlternate38 AppIconAlternate39 AppIconAlternate40 AppIconAlternate42 AppIconAlternate2 AppIconAlternate41 AppIconAlternate45 AppIconAlternate44 AppIconAlternate1 AppIconAlternate4 AppIconAlternate3 AppIconAlternate5 AppIconAlternate9 AppIconAlternate43";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
ASSETCATALOG_COMPILER_STANDALONE_ICON_BEHAVIOR = all;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = NO;
CODE_SIGN_ENTITLEMENTS = IceCubesApp/App/IceCubesApp.entitlements; CODE_SIGN_ENTITLEMENTS = IceCubesApp/App/IceCubesApp.entitlements;
CODE_SIGN_IDENTITY = "-"; CODE_SIGN_IDENTITY = "-";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
@ -1208,7 +1543,8 @@
INFOPLIST_FILE = IceCubesApp/Info.plist; INFOPLIST_FILE = IceCubesApp/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Ice Cubes"; INFOPLIST_KEY_CFBundleDisplayName = "Ice Cubes";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
INFOPLIST_KEY_NSCameraUsageDescription = "Upload photos & videos to Mastodon"; INFOPLIST_KEY_NSCameraUsageDescription = "Upload photos & videos to attach to your Mastodon posts.";
INFOPLIST_KEY_NSHumanReadableCopyright = "© 2024 Thomas Ricouard";
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "Upload photos & videos to Mastodon"; INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "Upload photos & videos to Mastodon";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
@ -1225,7 +1561,7 @@
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 13.0; MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.10.22; MARKETING_VERSION = 1.11.0;
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_PREFIX).IceCubesApp"; PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_PREFIX).IceCubesApp";
PRODUCT_NAME = "Ice Cubes"; PRODUCT_NAME = "Ice Cubes";
SDKROOT = auto; SDKROOT = auto;
@ -1234,19 +1570,30 @@
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_STRICT_CONCURRENCY = complete; SWIFT_STRICT_CONCURRENCY = complete;
SWIFT_VERSION = 5.0; SWIFT_UPCOMING_FEATURE_CONCISE_MAGIC_FILE = YES;
SWIFT_UPCOMING_FEATURE_DEPRECATE_APPLICATION_MAIN = YES;
SWIFT_UPCOMING_FEATURE_DISABLE_OUTWARD_ACTOR_ISOLATION = YES;
SWIFT_UPCOMING_FEATURE_FORWARD_TRAILING_CLOSURES = YES;
SWIFT_UPCOMING_FEATURE_GLOBAL_CONCURRENCY = YES;
SWIFT_UPCOMING_FEATURE_IMPLICIT_OPEN_EXISTENTIALS = YES;
SWIFT_UPCOMING_FEATURE_IMPORT_OBJC_FORWARD_DECLS = YES;
SWIFT_UPCOMING_FEATURE_INFER_SENDABLE_FROM_CAPTURES = YES;
SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES;
SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES;
SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2,7"; TARGETED_DEVICE_FAMILY = "1,2,7";
_EXPERIMENTAL_SWIFT_EXPLICIT_MODULES = NO;
}; };
name = Debug; name = Debug;
}; };
9FBFE64A292A715600C250E9 /* Release */ = { 9FBFE64A292A715600C250E9 /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "AppIconAlternate0 AppIconAlternate6 AppIconAlternate7 AppIconAlternate8 AppIconAlternate10 AppIconAlternate11 AppIconAlternate12 AppIconAlternate13 AppIconAlternate14 AppIconAlternate15 AppIconAlternate16 AppIconAlternate17 AppIconAlternate19 AppIconAlternate18 AppIconAlternate20 AppIconAlternate21 AppIconAlternate22 AppIconAlternate23 AppIconAlternate24 AppIconAlternate25 AppIconAlternate26 AppIconAlternate27 AppIconAlternate28 AppIconAlternate29 AppIconAlternate30 AppIconAlternate31 AppIconAlternate32 AppIconAlternate33 AppIconAlternate34 AppIconAlternate35 AppIconAlternate36 AppIconAlternate37 AppIconAlternate38 AppIconAlternate39 AppIconAlternate40 AppIconAlternate42 AppIconAlternate2 AppIconAlternate41 AppIconAlternate45 AppIconAlternate44 AppIconAlternate1 AppIconAlternate4 AppIconAlternate3 AppIconAlternate5 AppIconAlternate9 AppIconAlternate43";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
ASSETCATALOG_COMPILER_STANDALONE_ICON_BEHAVIOR = all;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = NO;
CODE_SIGN_ENTITLEMENTS = "IceCubesApp/App/IceCubesApp-release.entitlements"; CODE_SIGN_ENTITLEMENTS = "IceCubesApp/App/IceCubesApp-release.entitlements";
CODE_SIGN_IDENTITY = "-"; CODE_SIGN_IDENTITY = "-";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
@ -1262,7 +1609,8 @@
INFOPLIST_FILE = IceCubesApp/Info.plist; INFOPLIST_FILE = IceCubesApp/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Ice Cubes"; INFOPLIST_KEY_CFBundleDisplayName = "Ice Cubes";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
INFOPLIST_KEY_NSCameraUsageDescription = "Upload photos & videos to Mastodon"; INFOPLIST_KEY_NSCameraUsageDescription = "Upload photos & videos to attach to your Mastodon posts.";
INFOPLIST_KEY_NSHumanReadableCopyright = "© 2024 Thomas Ricouard";
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "Upload photos & videos to Mastodon"; INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "Upload photos & videos to Mastodon";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
@ -1279,7 +1627,7 @@
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 13.0; MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.10.22; MARKETING_VERSION = 1.11.0;
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_PREFIX).IceCubesApp"; PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_PREFIX).IceCubesApp";
PRODUCT_NAME = "Ice Cubes"; PRODUCT_NAME = "Ice Cubes";
SDKROOT = auto; SDKROOT = auto;
@ -1288,8 +1636,19 @@
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_STRICT_CONCURRENCY = complete; SWIFT_STRICT_CONCURRENCY = complete;
SWIFT_VERSION = 5.0; SWIFT_UPCOMING_FEATURE_CONCISE_MAGIC_FILE = YES;
SWIFT_UPCOMING_FEATURE_DEPRECATE_APPLICATION_MAIN = YES;
SWIFT_UPCOMING_FEATURE_DISABLE_OUTWARD_ACTOR_ISOLATION = YES;
SWIFT_UPCOMING_FEATURE_FORWARD_TRAILING_CLOSURES = YES;
SWIFT_UPCOMING_FEATURE_GLOBAL_CONCURRENCY = YES;
SWIFT_UPCOMING_FEATURE_IMPLICIT_OPEN_EXISTENTIALS = YES;
SWIFT_UPCOMING_FEATURE_IMPORT_OBJC_FORWARD_DECLS = YES;
SWIFT_UPCOMING_FEATURE_INFER_SENDABLE_FROM_CAPTURES = YES;
SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES;
SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES;
SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2,7"; TARGETED_DEVICE_FAMILY = "1,2,7";
_EXPERIMENTAL_SWIFT_EXPLICIT_MODULES = NO;
}; };
name = Release; name = Release;
}; };
@ -1314,7 +1673,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 1.10.22; MARKETING_VERSION = 1.11.0;
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_PREFIX).IceCubesApp.IceCubesActionExtension"; PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_PREFIX).IceCubesApp.IceCubesActionExtension";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos; SDKROOT = iphoneos;
@ -1323,7 +1682,7 @@
SUPPORTS_MACCATALYST = YES; SUPPORTS_MACCATALYST = YES;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
}; };
name = Debug; name = Debug;
@ -1349,7 +1708,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 1.10.22; MARKETING_VERSION = 1.11.0;
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_PREFIX).IceCubesApp.IceCubesActionExtension"; PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_PREFIX).IceCubesApp.IceCubesActionExtension";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos; SDKROOT = iphoneos;
@ -1358,7 +1717,7 @@
SUPPORTS_MACCATALYST = YES; SUPPORTS_MACCATALYST = YES;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
}; };
@ -1376,6 +1735,15 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
9F7788D82BE652B2004E6BEF /* Build configuration list for PBXNativeTarget "IceCubesAppWidgetsExtensionExtension" */ = {
isa = XCConfigurationList;
buildConfigurations = (
9F7788D92BE652B2004E6BEF /* Debug */,
9F7788DA2BE652B2004E6BEF /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
9FAD859329743F7400496AB1 /* Build configuration list for PBXNativeTarget "IceCubesShareExtension" */ = { 9FAD859329743F7400496AB1 /* Build configuration list for PBXNativeTarget "IceCubesShareExtension" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
@ -1415,12 +1783,12 @@
/* End XCConfigurationList section */ /* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */ /* Begin XCRemoteSwiftPackageReference section */
9F2A540829699705009B2D7C /* XCRemoteSwiftPackageReference "purchases-ios" */ = { 9F9191572C6DDF20001C89E7 /* XCRemoteSwiftPackageReference "wishkit-ios" */ = {
isa = XCRemoteSwiftPackageReference; isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/RevenueCat/purchases-ios.git"; repositoryURL = "https://github.com/wishkit/wishkit-ios.git";
requirement = { requirement = {
kind = upToNextMajorVersion; kind = upToNextMajorVersion;
minimumVersion = 4.0.0; minimumVersion = 4.1.1;
}; };
}; };
9FAE4ACC29379A5A00772766 /* XCRemoteSwiftPackageReference "keychain-swift" */ = { 9FAE4ACC29379A5A00772766 /* XCRemoteSwiftPackageReference "keychain-swift" */ = {
@ -1436,7 +1804,15 @@
repositoryURL = "https://github.com/Giphy/giphy-ios-sdk"; repositoryURL = "https://github.com/Giphy/giphy-ios-sdk";
requirement = { requirement = {
kind = upToNextMajorVersion; kind = upToNextMajorVersion;
minimumVersion = 2.2.7; minimumVersion = 2.2.8;
};
};
9FE6A42C2BD043A80055D388 /* XCRemoteSwiftPackageReference "purchases-ios" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/RevenueCat/purchases-ios";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 4.40.1;
}; };
}; };
DA0B24F92A6876D40045BDD7 /* XCRemoteSwiftPackageReference "SFSafeSymbols" */ = { DA0B24F92A6876D40045BDD7 /* XCRemoteSwiftPackageReference "SFSafeSymbols" */ = {
@ -1454,16 +1830,6 @@
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
productName = Timeline; productName = Timeline;
}; };
9F2A540929699705009B2D7C /* ReceiptParser */ = {
isa = XCSwiftPackageProductDependency;
package = 9F2A540829699705009B2D7C /* XCRemoteSwiftPackageReference "purchases-ios" */;
productName = ReceiptParser;
};
9F2A540B29699705009B2D7C /* RevenueCat */ = {
isa = XCSwiftPackageProductDependency;
package = 9F2A540829699705009B2D7C /* XCRemoteSwiftPackageReference "purchases-ios" */;
productName = RevenueCat;
};
9F2A5423296AB67A009B2D7C /* Env */ = { 9F2A5423296AB67A009B2D7C /* Env */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
productName = Env; productName = Env;
@ -1501,10 +1867,39 @@
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
productName = Conversations; productName = Conversations;
}; };
9F7788DD2BE6543D004E6BEF /* Account */ = {
isa = XCSwiftPackageProductDependency;
productName = Account;
};
9F7788DF2BE6543D004E6BEF /* AppAccount */ = {
isa = XCSwiftPackageProductDependency;
productName = AppAccount;
};
9F7788E12BE6543D004E6BEF /* Env */ = {
isa = XCSwiftPackageProductDependency;
productName = Env;
};
9F7788E32BE6543D004E6BEF /* Models */ = {
isa = XCSwiftPackageProductDependency;
productName = Models;
};
9F7788E52BE6543D004E6BEF /* Network */ = {
isa = XCSwiftPackageProductDependency;
productName = Network;
};
9F7788EF2BE78E77004E6BEF /* Timeline */ = {
isa = XCSwiftPackageProductDependency;
productName = Timeline;
};
9F7D93932980063100EE6B7A /* AppAccount */ = { 9F7D93932980063100EE6B7A /* AppAccount */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
productName = AppAccount; productName = AppAccount;
}; };
9F9191582C6DDF20001C89E7 /* WishKit */ = {
isa = XCSwiftPackageProductDependency;
package = 9F9191572C6DDF20001C89E7 /* XCRemoteSwiftPackageReference "wishkit-ios" */;
productName = WishKit;
};
9FAD8599297440CB00496AB1 /* KeychainSwift */ = { 9FAD8599297440CB00496AB1 /* KeychainSwift */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = 9FAE4ACC29379A5A00772766 /* XCRemoteSwiftPackageReference "keychain-swift" */; package = 9FAE4ACC29379A5A00772766 /* XCRemoteSwiftPackageReference "keychain-swift" */;
@ -1569,6 +1964,11 @@
package = 9FE4CCA92B4C848A00DA5F13 /* XCRemoteSwiftPackageReference "giphy-ios-sdk" */; package = 9FE4CCA92B4C848A00DA5F13 /* XCRemoteSwiftPackageReference "giphy-ios-sdk" */;
productName = GiphyUISDK; productName = GiphyUISDK;
}; };
9FE6A42D2BD043A90055D388 /* RevenueCat */ = {
isa = XCSwiftPackageProductDependency;
package = 9FE6A42C2BD043A80055D388 /* XCRemoteSwiftPackageReference "purchases-ios" */;
productName = RevenueCat;
};
9FFF677B299B7B2C00FE700A /* Notifications */ = { 9FFF677B299B7B2C00FE700A /* Notifications */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
productName = Notifications; productName = Notifications;

View file

@ -1,12 +1,13 @@
{ {
"originHash" : "b7af8c2ab18771d4cebfbeb66d91559df500516a12027cd67834b2a576eb3df0",
"pins" : [ "pins" : [
{ {
"identity" : "bodega", "identity" : "bodega",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/mergesort/Bodega", "location" : "https://github.com/mergesort/Bodega",
"state" : { "state" : {
"revision" : "f0554077c178088ba11557bbdbb71775cc6a1b84", "revision" : "bfd8871e9c2590d31b200e54c75428a71483afdf",
"version" : "2.1.0" "version" : "2.1.3"
} }
}, },
{ {
@ -14,8 +15,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/Dean151/ButtonKit", "location" : "https://github.com/Dean151/ButtonKit",
"state" : { "state" : {
"revision" : "377f5bab4ed047704316d531e0826d4de5ebf6a4", "revision" : "d567519b297777c38dee56ef10201fef4962ff75",
"version" : "0.1.1" "version" : "0.4.1"
} }
}, },
{ {
@ -23,8 +24,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/divadretlaw/EmojiText", "location" : "https://github.com/divadretlaw/EmojiText",
"state" : { "state" : {
"revision" : "d0664390e3236ff6241ea0586d80f4e92702973b", "revision" : "174a7bc7bd75650ad1acb5679dbb754296093de0",
"version" : "3.2.1" "version" : "4.0.0"
} }
}, },
{ {
@ -32,8 +33,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/Giphy/giphy-ios-sdk", "location" : "https://github.com/Giphy/giphy-ios-sdk",
"state" : { "state" : {
"revision" : "95c32b862185e76107841b49bfff8ff7230f3b68", "revision" : "fb61ec12738133eb3b9bf62ed11d1bf93d9b4b20",
"version" : "2.2.7" "version" : "2.2.10"
} }
}, },
{ {
@ -42,7 +43,7 @@
"location" : "https://github.com/evgenyneu/keychain-swift", "location" : "https://github.com/evgenyneu/keychain-swift",
"state" : { "state" : {
"branch" : "master", "branch" : "master",
"revision" : "f38cb0ada97847ac5068b915b8d2793b35435668" "revision" : "5e1b02b6a9dac2a759a1d5dbc175c86bd192a608"
} }
}, },
{ {
@ -59,8 +60,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/nicklockwood/LRUCache", "location" : "https://github.com/nicklockwood/LRUCache",
"state" : { "state" : {
"revision" : "6d2b5246c9c98dcd498552bb22f08d55b12a8371", "revision" : "542f0449556327415409ededc9c43a4bd0a397dc",
"version" : "1.0.4" "version" : "1.0.7"
} }
}, },
{ {
@ -68,17 +69,17 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/kean/Nuke", "location" : "https://github.com/kean/Nuke",
"state" : { "state" : {
"revision" : "1694798e876113d44f6ec6ead965d7286695981d", "revision" : "0ead44350d2737db384908569c012fe67c421e4d",
"version" : "12.2.0" "version" : "12.8.0"
} }
}, },
{ {
"identity" : "purchases-ios", "identity" : "purchases-ios",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/RevenueCat/purchases-ios.git", "location" : "https://github.com/RevenueCat/purchases-ios",
"state" : { "state" : {
"revision" : "b8d20ba1c8e13cc73d72e37cf98607d01fd357b6", "revision" : "7d55b964114a3d4a76791227cdc28577617596db",
"version" : "4.31.2" "version" : "4.43.2"
} }
}, },
{ {
@ -95,8 +96,35 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/stephencelis/SQLite.swift.git", "location" : "https://github.com/stephencelis/SQLite.swift.git",
"state" : { "state" : {
"revision" : "7a2e3cd27de56f6d396e84f63beefd0267b55ccb", "revision" : "a95fc6df17d108bd99210db5e8a9bac90fe984b8",
"version" : "0.14.1" "version" : "0.15.3"
}
},
{
"identity" : "swift-cmark",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-cmark.git",
"state" : {
"revision" : "3ccff77b2dc5b96b77db3da0d68d28068593fa53",
"version" : "0.5.0"
}
},
{
"identity" : "swift-markdown",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-markdown",
"state" : {
"revision" : "8f79cb175981458a0a27e76cb42fee8e17b1a993",
"version" : "0.5.0"
}
},
{
"identity" : "swiftsdk",
"kind" : "remoteSourceControl",
"location" : "https://github.com/TelemetryDeck/SwiftSDK",
"state" : {
"revision" : "13a26cf125b70d695913eb9bea9f9b9c29da5790",
"version" : "2.3.0"
} }
}, },
{ {
@ -104,28 +132,46 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/scinfu/SwiftSoup.git", "location" : "https://github.com/scinfu/SwiftSoup.git",
"state" : { "state" : {
"revision" : "8b6cf29eead8841a1fa7822481cb3af4ddaadba6", "revision" : "3c2c7e1e72b8abd96eafbae80323c5c1e5317437",
"version" : "2.6.1" "version" : "2.7.5"
} }
}, },
{ {
"identity" : "swiftui-introspect", "identity" : "swiftui-introspect",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/siteline/SwiftUI-Introspect.git", "location" : "https://github.com/siteline/swiftui-introspect",
"state" : { "state" : {
"revision" : "9e1cc02a65b22e09a8251261cccbccce02731fc5", "revision" : "668a65735751432b640260c56dfa621cec568368",
"version" : "1.1.1" "version" : "1.2.0"
} }
}, },
{ {
"identity" : "swiftui-shimmer", "identity" : "wishkit-ios",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/markiv/SwiftUI-Shimmer", "location" : "https://github.com/wishkit/wishkit-ios.git",
"state" : { "state" : {
"revision" : "965a7cbcbf094cbcf22b9251a2323bdc3432e171", "revision" : "2b5eb8d1fb13706f8c14767a5239e34e403375f1",
"version" : "1.1.0" "version" : "4.2.2"
}
},
{
"identity" : "wishkit-ios-shared",
"kind" : "remoteSourceControl",
"location" : "https://github.com/wishkit/wishkit-ios-shared.git",
"state" : {
"revision" : "118c9c482e4ad57c65d664283516425b98616483",
"version" : "1.4.3"
}
},
{
"identity" : "wrappinghstack",
"kind" : "remoteSourceControl",
"location" : "https://github.com/dkk/WrappingHStack",
"state" : {
"revision" : "425d9488ba55f58f0b34498c64c054c77fc2a44b",
"version" : "2.2.11"
} }
} }
], ],
"version" : 2 "version" : 3
} }

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1500" LastUpgradeVersion = "1600"
wasCreatedForAppExtension = "YES" wasCreatedForAppExtension = "YES"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1500" LastUpgradeVersion = "1600"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View file

@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1600"
wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "9F7788C42BE652B1004E6BEF"
BuildableName = "IceCubesAppWidgetsExtensionExtension.appex"
BlueprintName = "IceCubesAppWidgetsExtensionExtension"
ReferencedContainer = "container:IceCubesApp.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "9FBFE638292A715500C250E9"
BuildableName = "Ice Cubes.app"
BlueprintName = "IceCubesApp"
ReferencedContainer = "container:IceCubesApp.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
launchStyle = "0"
askForAppToLaunch = "Yes"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "9FBFE638292A715500C250E9"
BuildableName = "Ice Cubes.app"
BlueprintName = "IceCubesApp"
ReferencedContainer = "container:IceCubesApp.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<EnvironmentVariables>
<EnvironmentVariable
key = "_XCWidgetKind"
value = ""
isEnabled = "YES">
</EnvironmentVariable>
<EnvironmentVariable
key = "_XCWidgetDefaultView"
value = "timeline"
isEnabled = "YES">
</EnvironmentVariable>
<EnvironmentVariable
key = "_XCWidgetFamily"
value = "systemMedium"
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
askForAppToLaunch = "Yes"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "9FBFE638292A715500C250E9"
BuildableName = "Ice Cubes.app"
BlueprintName = "IceCubesApp"
ReferencedContainer = "container:IceCubesApp.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1500" LastUpgradeVersion = "1600"
wasCreatedForAppExtension = "YES" wasCreatedForAppExtension = "YES"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
@ -56,8 +56,12 @@
debugServiceExtension = "internal" debugServiceExtension = "internal"
allowLocationSimulation = "YES" allowLocationSimulation = "YES"
launchAutomaticallySubstyle = "2"> launchAutomaticallySubstyle = "2">
<BuildableProductRunnable <RemoteRunnable
runnableDebuggingMode = "0"> runnableDebuggingMode = "1"
BundleIdentifier = "com.thomasricouard.IceCubesApp"
RemotePath = "/Users/dimillian/Library/Developer/CoreSimulator/Devices/8EF923D0-4CF1-49B6-B287-5F05AD5440C1/data/Containers/Bundle/Application/C447A1D1-9BC9-49C9-8FA5-130E8403972F/Ice Cubes.app">
</RemoteRunnable>
<MacroExpansion>
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "9FBFE638292A715500C250E9" BlueprintIdentifier = "9FBFE638292A715500C250E9"
@ -65,7 +69,7 @@
BlueprintName = "IceCubesApp" BlueprintName = "IceCubesApp"
ReferencedContainer = "container:IceCubesApp.xcodeproj"> ReferencedContainer = "container:IceCubesApp.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </MacroExpansion>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Release" buildConfiguration = "Release"

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1500" LastUpgradeVersion = "1600"
wasCreatedForAppExtension = "YES" wasCreatedForAppExtension = "YES"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction

View file

@ -8,6 +8,7 @@ import LinkPresentation
import Lists import Lists
import MediaUI import MediaUI
import Models import Models
import Notifications
import StatusKit import StatusKit
import SwiftUI import SwiftUI
import Timeline import Timeline
@ -18,11 +19,13 @@ extension View {
navigationDestination(for: RouterDestination.self) { destination in navigationDestination(for: RouterDestination.self) { destination in
switch destination { switch destination {
case let .accountDetail(id): case let .accountDetail(id):
AccountDetailView(accountId: id, scrollToTopSignal: .constant(0)) AccountDetailView(accountId: id)
case let .accountDetailWithAccount(account): case let .accountDetailWithAccount(account):
AccountDetailView(account: account, scrollToTopSignal: .constant(0)) AccountDetailView(account: account)
case let .accountSettingsWithAccount(account, appAccount): case let .accountSettingsWithAccount(account, appAccount):
AccountSettingsView(account: account, appAccount: appAccount) AccountSettingsView(account: account, appAccount: appAccount)
case let .accountMediaGridView(account, initialMedia):
AccountDetailMediaGridView(account: account, initialMediaStatuses: initialMedia)
case let .statusDetail(id): case let .statusDetail(id):
StatusDetailView(statusId: id) StatusDetailView(statusId: id)
case let .statusDetailWithStatus(status): case let .statusDetailWithStatus(status):
@ -35,13 +38,16 @@ extension View {
TimelineView(timeline: .constant(.hashtag(tag: tag, accountId: accountId)), TimelineView(timeline: .constant(.hashtag(tag: tag, accountId: accountId)),
pinnedFilters: .constant([]), pinnedFilters: .constant([]),
selectedTagGroup: .constant(nil), selectedTagGroup: .constant(nil),
scrollToTopSignal: .constant(0),
canFilterTimeline: false) canFilterTimeline: false)
case let .list(list): case let .list(list):
TimelineView(timeline: .constant(.list(list: list)), TimelineView(timeline: .constant(.list(list: list)),
pinnedFilters: .constant([]), pinnedFilters: .constant([]),
selectedTagGroup: .constant(nil), selectedTagGroup: .constant(nil),
scrollToTopSignal: .constant(0), canFilterTimeline: false)
case let .linkTimeline(url, title):
TimelineView(timeline: .constant(.link(url: url, title: title)),
pinnedFilters: .constant([]),
selectedTagGroup: .constant(nil),
canFilterTimeline: false) canFilterTimeline: false)
case let .following(id): case let .following(id):
AccountsListView(mode: .following(accountId: id)) AccountsListView(mode: .following(accountId: id))
@ -57,12 +63,20 @@ extension View {
TimelineView(timeline: .constant(.trending), TimelineView(timeline: .constant(.trending),
pinnedFilters: .constant([]), pinnedFilters: .constant([]),
selectedTagGroup: .constant(nil), selectedTagGroup: .constant(nil),
scrollToTopSignal: .constant(0),
canFilterTimeline: false) canFilterTimeline: false)
case let .trendingLinks(cards): case let .trendingLinks(cards):
CardsListView(cards: cards) TrendingLinksListView(cards: cards)
case let .tagsList(tags): case let .tagsList(tags):
TagsListView(tags: tags) TagsListView(tags: tags)
case .notificationsRequests:
NotificationsRequestsListView()
case let .notificationForAccount(accountId):
NotificationsListView(lockedType: nil,
lockedAccountId: accountId)
case .blockedAccounts:
AccountsListView(mode: .blocked)
case .mutedAccounts:
AccountsListView(mode: .muted)
} }
} }
} }
@ -74,7 +88,13 @@ extension View {
StatusEditor.MainView(mode: .replyTo(status: status)) StatusEditor.MainView(mode: .replyTo(status: status))
.withEnvironments() .withEnvironments()
case let .newStatusEditor(visibility): case let .newStatusEditor(visibility):
StatusEditor.MainView(mode: .new(visibility: visibility)) StatusEditor.MainView(mode: .new(text: nil, visibility: visibility))
.withEnvironments()
case let .prefilledStatusEditor(text, visibility):
StatusEditor.MainView(mode: .new(text: text, visibility: visibility))
.withEnvironments()
case let .imageURL(urls, visibility):
StatusEditor.MainView(mode: .imageURL(urls: urls, visibility: visibility))
.withEnvironments() .withEnvironments()
case let .editStatusEditor(status): case let .editStatusEditor(status):
StatusEditor.MainView(mode: .edit(status: status)) StatusEditor.MainView(mode: .edit(status: status))
@ -82,6 +102,9 @@ extension View {
case let .quoteStatusEditor(status): case let .quoteStatusEditor(status):
StatusEditor.MainView(mode: .quote(status: status)) StatusEditor.MainView(mode: .quote(status: status))
.withEnvironments() .withEnvironments()
case let .quoteLinkStatusEditor(link):
StatusEditor.MainView(mode: .quoteLink(link: link))
.withEnvironments()
case let .mentionStatusEditor(account, visibility): case let .mentionStatusEditor(account, visibility):
StatusEditor.MainView(mode: .mention(account: account, visibility: visibility)) StatusEditor.MainView(mode: .mention(account: account, visibility: visibility))
.withEnvironments() .withEnvironments()
@ -107,7 +130,7 @@ extension View {
StatusEditHistoryView(statusId: status) StatusEditHistoryView(statusId: status)
.withEnvironments() .withEnvironments()
case .settings: case .settings:
SettingsTabs(popToRootTab: .constant(.settings), isModal: true) SettingsTabs(isModal: true)
.withEnvironments() .withEnvironments()
.preferredColorScheme(Theme.shared.selectedScheme == .dark ? .dark : .light) .preferredColorScheme(Theme.shared.selectedScheme == .dark ? .dark : .light)
case .accountPushNotficationsSettings: case .accountPushNotficationsSettings:
@ -135,6 +158,13 @@ extension View {
case .timelineContentFilter: case .timelineContentFilter:
NavigationSheet { TimelineContentFilterView() } NavigationSheet { TimelineContentFilterView() }
.presentationDetents([.medium]) .presentationDetents([.medium])
.presentationBackground(.thinMaterial)
.withEnvironments()
case .accountEditInfo:
EditAccountView()
.withEnvironments()
case .accountFiltersList:
FiltersListView()
.withEnvironments() .withEnvironments()
} }
} }
@ -201,7 +231,7 @@ struct ActivityView: UIViewControllerRepresentable {
func updateUIViewController(_: UIActivityViewController, context _: UIViewControllerRepresentableContext<ActivityView>) {} func updateUIViewController(_: UIActivityViewController, context _: UIViewControllerRepresentableContext<ActivityView>) {}
} }
extension URL: Identifiable { extension URL: @retroactive Identifiable {
public var id: String { public var id: String {
absoluteString absoluteString
} }

View file

@ -18,63 +18,49 @@ struct AppView: View {
@Environment(Theme.self) private var theme @Environment(Theme.self) private var theme
@Environment(StreamWatcher.self) private var watcher @Environment(StreamWatcher.self) private var watcher
@Environment(\.openWindow) var openWindow
@Environment(\.horizontalSizeClass) private var horizontalSizeClass @Environment(\.horizontalSizeClass) private var horizontalSizeClass
@Binding var selectedTab: AppTab
@Binding var selectedTab: Tab
@Binding var appRouterPath: RouterPath @Binding var appRouterPath: RouterPath
@State var popToRootTab: Tab = .other
@State var iosTabs = iOSTabs.shared @State var iosTabs = iOSTabs.shared
@State var sidebarTabs = SidebarTabs.shared @State var sidebarTabs = SidebarTabs.shared
@State var selectedTabScrollToTop: Int = -1
var body: some View { var body: some View {
#if os(visionOS) #if os(visionOS)
tabBarView
#else
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
sidebarView
} else {
tabBarView tabBarView
} #else
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
sidebarView
} else {
tabBarView
}
#endif #endif
} }
var availableTabs: [Tab] { var availableTabs: [AppTab] {
guard appAccountsManager.currentClient.isAuth else { guard appAccountsManager.currentClient.isAuth else {
return Tab.loggedOutTab() return AppTab.loggedOutTab()
} }
if UIDevice.current.userInterfaceIdiom == .phone || horizontalSizeClass == .compact { if UIDevice.current.userInterfaceIdiom == .phone || horizontalSizeClass == .compact {
return iosTabs.tabs return iosTabs.tabs
} else if UIDevice.current.userInterfaceIdiom == .vision { } else if UIDevice.current.userInterfaceIdiom == .vision {
return Tab.visionOSTab() return AppTab.visionOSTab()
} }
return sidebarTabs.tabs.map{ $0.tab } return sidebarTabs.tabs.map { $0.tab }
} }
@ViewBuilder
var tabBarView: some View { var tabBarView: some View {
TabView(selection: .init(get: { TabView(selection: .init(get: {
selectedTab selectedTab
}, set: { newTab in }, set: { newTab in
if newTab == .post { updateTab(with: newTab)
appRouterPath.presentedSheet = .newStatusEditor(visibility: userPreferences.postVisibility)
return
}
if newTab == selectedTab {
/// Stupid hack to trigger onChange binding in tab views.
popToRootTab = .other
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
popToRootTab = selectedTab
}
}
HapticManager.shared.fireHaptic(.tabSelection)
SoundEffectManager.shared.playSound(.tabSelection)
selectedTab = newTab
})) { })) {
ForEach(availableTabs) { tab in ForEach(availableTabs) { tab in
tab.makeContentView(selectedTab: $selectedTab, popToRootTab: $popToRootTab) tab.makeContentView(selectedTab: $selectedTab)
.tabItem { .tabItem {
if userPreferences.showiPhoneTabLabel { if userPreferences.showiPhoneTabLabel {
tab.label tab.label
@ -85,14 +71,40 @@ struct AppView: View {
} }
.tag(tab) .tag(tab)
.badge(badgeFor(tab: tab)) .badge(badgeFor(tab: tab))
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.50), for: .tabBar) .toolbarBackground(theme.primaryBackgroundColor.opacity(0.30), for: .tabBar)
} }
} }
.id(appAccountsManager.currentClient.id) .id(appAccountsManager.currentClient.id)
.withSheetDestinations(sheetDestinations: $appRouterPath.presentedSheet) .withSheetDestinations(sheetDestinations: $appRouterPath.presentedSheet)
.environment(\.selectedTabScrollToTop, selectedTabScrollToTop)
} }
private func badgeFor(tab: Tab) -> Int { private func updateTab(with newTab: AppTab) {
if newTab == .post {
#if os(visionOS)
openWindow(value: WindowDestinationEditor.newStatusEditor(visibility: userPreferences.postVisibility))
#else
appRouterPath.presentedSheet = .newStatusEditor(visibility: userPreferences.postVisibility)
#endif
return
}
HapticManager.shared.fireHaptic(.tabSelection)
SoundEffectManager.shared.playSound(.tabSelection)
if selectedTab == newTab {
selectedTabScrollToTop = newTab.rawValue
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
selectedTabScrollToTop = -1
}
} else {
selectedTabScrollToTop = -1
}
selectedTab = newTab
}
private func badgeFor(tab: AppTab) -> Int {
if tab == .notifications, selectedTab != tab, if tab == .notifications, selectedTab != tab,
let token = appAccountsManager.currentAccount.oauthToken let token = appAccountsManager.currentAccount.oauthToken
{ {
@ -102,43 +114,65 @@ struct AppView: View {
} }
#if !os(visionOS) #if !os(visionOS)
var sidebarView: some View { var sidebarView: some View {
SideBarView(selectedTab: $selectedTab, SideBarView(selectedTab: .init(get: {
popToRootTab: $popToRootTab, selectedTab
tabs: availableTabs) }, set: { newTab in
{ updateTab(with: newTab)
HStack(spacing: 0) { }), tabs: availableTabs)
TabView(selection: $selectedTab) { {
ForEach(availableTabs) { tab in HStack(spacing: 0) {
tab if #available(iOS 18.0, *) {
.makeContentView(selectedTab: $selectedTab, popToRootTab: $popToRootTab) baseTabView
.tabItem { #if targetEnvironment(macCatalyst)
tab.label .tabViewStyle(.sidebarAdaptable)
} .introspect(.tabView, on: .iOS(.v17, .v18)) { (tabview: UITabBarController) in
.tag(tab) tabview.sidebar.isHidden = true
}
#else
.tabViewStyle(.tabBarOnly)
#endif
} else {
baseTabView
}
if horizontalSizeClass == .regular,
appAccountsManager.currentClient.isAuth,
userPreferences.showiPadSecondaryColumn
{
Divider().edgesIgnoringSafeArea(.all)
notificationsSecondaryColumn
} }
} }
.introspect(.tabView, on: .iOS(.v17)) { (tabview: UITabBarController) in
tabview.tabBar.isHidden = horizontalSizeClass == .regular
tabview.customizableViewControllers = []
tabview.moreNavigationController.isNavigationBarHidden = true
}
if horizontalSizeClass == .regular,
appAccountsManager.currentClient.isAuth,
userPreferences.showiPadSecondaryColumn
{
Divider().edgesIgnoringSafeArea(.all)
notificationsSecondaryColumn
}
} }
.environment(appRouterPath)
.environment(\.selectedTabScrollToTop, selectedTabScrollToTop)
} }
.environment(appRouterPath)
}
#endif #endif
private var baseTabView: some View {
TabView(selection: $selectedTab) {
ForEach(availableTabs) { tab in
tab
.makeContentView(selectedTab: $selectedTab)
.toolbar(horizontalSizeClass == .regular ? .hidden : .visible, for: .tabBar)
.tabItem {
tab.label
}
.tag(tab)
}
}
#if !os(visionOS)
.introspect(.tabView, on: .iOS(.v17, .v18)) { (tabview: UITabBarController) in
tabview.tabBar.isHidden = horizontalSizeClass == .regular
tabview.customizableViewControllers = []
tabview.moreNavigationController.isNavigationBarHidden = true
}
#endif
}
var notificationsSecondaryColumn: some View { var notificationsSecondaryColumn: some View {
NotificationsTab(selectedTab: .constant(.notifications), NotificationsTab(selectedTab: .constant(.notifications)
popToRootTab: $popToRootTab, lockedType: nil) , lockedType: nil)
.environment(\.isSecondaryColumn, true) .environment(\.isSecondaryColumn, true)
.frame(maxWidth: .secondaryColumnWidth) .frame(maxWidth: .secondaryColumnWidth)
.id(appAccountsManager.currentAccount.id) .id(appAccountsManager.currentAccount.id)

View file

@ -4,6 +4,12 @@ import SwiftUI
extension IceCubesApp { extension IceCubesApp {
@CommandsBuilder @CommandsBuilder
var appMenu: some Commands { var appMenu: some Commands {
CommandGroup(replacing: .appSettings) {
Button("menu.settings") {
appRouterPath.presentedSheet = .settings
}
.keyboardShortcut(",", modifiers: .command)
}
CommandGroup(replacing: .newItem) { CommandGroup(replacing: .newItem) {
Button("menu.new-window") { Button("menu.new-window") {
openWindow(id: "MainWindow") openWindow(id: "MainWindow")
@ -54,5 +60,11 @@ extension IceCubesApp {
} }
.keyboardShortcut("l", modifiers: .shift) .keyboardShortcut("l", modifiers: .shift)
} }
CommandGroup(replacing: .help) {
Button("menu.help.github") {
let url = URL(string: "https://github.com/Dimillian/IceCubesApp/issues")!
UIApplication.shared.open(url)
}
}
} }
} }

View file

@ -1,3 +1,4 @@
import AppIntents
import Env import Env
import MediaUI import MediaUI
import StatusKit import StatusKit
@ -22,13 +23,23 @@ extension IceCubesApp {
.environment(theme) .environment(theme)
.environment(watcher) .environment(watcher)
.environment(pushNotificationsService) .environment(pushNotificationsService)
.environment(appIntentService)
.environment(\.isSupporter, isSupporter) .environment(\.isSupporter, isSupporter)
.sheet(item: $quickLook.selectedMediaAttachment) { selectedMediaAttachment in .sheet(item: $quickLook.selectedMediaAttachment) { selectedMediaAttachment in
MediaUIView(selectedAttachment: selectedMediaAttachment, if #available(iOS 18.0, *) {
attachments: quickLook.mediaAttachments) MediaUIView(selectedAttachment: selectedMediaAttachment,
attachments: quickLook.mediaAttachments)
.presentationBackground(.ultraThinMaterial)
.presentationCornerRadius(16)
.presentationSizing(.page)
.withEnvironments()
} else {
MediaUIView(selectedAttachment: selectedMediaAttachment,
attachments: quickLook.mediaAttachments)
.presentationBackground(.ultraThinMaterial) .presentationBackground(.ultraThinMaterial)
.presentationCornerRadius(16) .presentationCornerRadius(16)
.withEnvironments() .withEnvironments()
}
} }
.onChange(of: pushNotificationsService.handledNotification) { _, newValue in .onChange(of: pushNotificationsService.handledNotification) { _, newValue in
if newValue != nil { if newValue != nil {
@ -47,13 +58,14 @@ extension IceCubesApp {
} }
} }
} }
.onChange(of: appIntentService.handledIntent) { _, _ in
if let intent = appIntentService.handledIntent?.intent {
handleIntent(intent)
appIntentService.handledIntent = nil
}
}
.withModelContainer() .withModelContainer()
} }
#if targetEnvironment(macCatalyst)
.defaultSize(width: userPreferences.showiPadSecondaryColumn ? 1100 : 800, height: 1400)
#elseif os(visionOS)
.defaultSize(width: 800, height: 1200)
#endif
.commands { .commands {
appMenu appMenu
} }
@ -66,6 +78,11 @@ extension IceCubesApp {
watcher.watch(streams: [.user, .direct]) watcher.watch(streams: [.user, .direct])
} }
} }
#if targetEnvironment(macCatalyst)
.windowResize()
#elseif os(visionOS)
.defaultSize(width: 800, height: 1200)
#endif
} }
@SceneBuilder @SceneBuilder
@ -74,7 +91,9 @@ extension IceCubesApp {
Group { Group {
switch destination.wrappedValue { switch destination.wrappedValue {
case let .newStatusEditor(visibility): case let .newStatusEditor(visibility):
StatusEditor.MainView(mode: .new(visibility: visibility)) StatusEditor.MainView(mode: .new(text: nil, visibility: visibility))
case let .prefilledStatusEditor(text, visibility):
StatusEditor.MainView(mode: .new(text: text, visibility: visibility))
case let .editStatusEditor(status): case let .editStatusEditor(status):
StatusEditor.MainView(mode: .edit(status: status)) StatusEditor.MainView(mode: .edit(status: status))
case let .quoteStatusEditor(status): case let .quoteStatusEditor(status):
@ -83,11 +102,15 @@ extension IceCubesApp {
StatusEditor.MainView(mode: .replyTo(status: status)) StatusEditor.MainView(mode: .replyTo(status: status))
case let .mentionStatusEditor(account, visibility): case let .mentionStatusEditor(account, visibility):
StatusEditor.MainView(mode: .mention(account: account, visibility: visibility)) StatusEditor.MainView(mode: .mention(account: account, visibility: visibility))
case let .quoteLinkStatusEditor(link):
StatusEditor.MainView(mode: .quoteLink(link: link))
case .none: case .none:
EmptyView() EmptyView()
} }
} }
.withEnvironments() .withEnvironments()
.environment(\.isCatalystWindow, true)
.environment(RouterPath())
.withModelContainer() .withModelContainer()
.applyTheme(theme) .applyTheme(theme)
.frame(minWidth: 300, minHeight: 400) .frame(minWidth: 300, minHeight: 400)
@ -108,9 +131,39 @@ extension IceCubesApp {
.withEnvironments() .withEnvironments()
.withModelContainer() .withModelContainer()
.applyTheme(theme) .applyTheme(theme)
.environment(\.isCatalystWindow, true)
.frame(minWidth: 300, minHeight: 400) .frame(minWidth: 300, minHeight: 400)
} }
.defaultSize(width: 1200, height: 1000) .defaultSize(width: 1200, height: 1000)
.windowResizability(.contentMinSize) .windowResizability(.contentMinSize)
} }
private func handleIntent(_: any AppIntent) {
if let postIntent = appIntentService.handledIntent?.intent as? PostIntent {
#if os(visionOS) || os(macOS)
openWindow(value: WindowDestinationEditor.prefilledStatusEditor(text: postIntent.content ?? "",
visibility: userPreferences.postVisibility))
#else
appRouterPath.presentedSheet = .prefilledStatusEditor(text: postIntent.content ?? "",
visibility: userPreferences.postVisibility)
#endif
} else if let tabIntent = appIntentService.handledIntent?.intent as? TabIntent {
selectedTab = tabIntent.tab.toAppTab
} else if let imageIntent = appIntentService.handledIntent?.intent as? PostImageIntent,
let urls = imageIntent.images?.compactMap({ $0.fileURL })
{
appRouterPath.presentedSheet = .imageURL(urls: urls,
visibility: userPreferences.postVisibility)
}
}
}
extension Scene {
func windowResize() -> some Scene {
if #available(iOS 18.0, *) {
return self.windowResizability(.contentSize)
} else {
return self.defaultSize(width: 1100, height: 1400)
}
}
} }

View file

@ -10,6 +10,7 @@ import RevenueCat
import StatusKit import StatusKit
import SwiftUI import SwiftUI
import Timeline import Timeline
import WishKit
@main @main
struct IceCubesApp: App { struct IceCubesApp: App {
@ -23,11 +24,12 @@ struct IceCubesApp: App {
@State var currentAccount = CurrentAccount.shared @State var currentAccount = CurrentAccount.shared
@State var userPreferences = UserPreferences.shared @State var userPreferences = UserPreferences.shared
@State var pushNotificationsService = PushNotificationsService.shared @State var pushNotificationsService = PushNotificationsService.shared
@State var appIntentService = AppIntentService.shared
@State var watcher = StreamWatcher.shared @State var watcher = StreamWatcher.shared
@State var quickLook = QuickLook.shared @State var quickLook = QuickLook.shared
@State var theme = Theme.shared @State var theme = Theme.shared
@State var selectedTab: Tab = .timeline @State var selectedTab: AppTab = .timeline
@State var appRouterPath = RouterPath() @State var appRouterPath = RouterPath()
@State var isSupporter: Bool = false @State var isSupporter: Bool = false
@ -79,13 +81,16 @@ struct IceCubesApp: App {
} }
} }
class AppDelegate: NSObject, UIApplicationDelegate { class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_: UIApplication, func application(_: UIApplication,
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool
{ {
try? AVAudioSession.sharedInstance().setCategory(.ambient, options: .mixWithOthers) try? AVAudioSession.sharedInstance().setCategory(.ambient, options: .mixWithOthers)
try? AVAudioSession.sharedInstance().setActive(true) try? AVAudioSession.sharedInstance().setActive(true)
PushNotificationsService.shared.setAccounts(accounts: AppAccountsManager.shared.pushAccounts) PushNotificationsService.shared.setAccounts(accounts: AppAccountsManager.shared.pushAccounts)
Telemetry.setup()
Telemetry.signal("app.launched")
WishKit.configure(with: "AF21AE07-3BA9-4FE2-BFB1-59A3B3941730")
return true return true
} }
@ -113,4 +118,11 @@ class AppDelegate: NSObject, UIApplicationDelegate {
} }
return configuration return configuration
} }
override func buildMenu(with builder: UIMenuBuilder) {
super.buildMenu(with: builder)
builder.remove(menu: .document)
builder.remove(menu: .toolbar)
builder.remove(menu: .sidebar)
}
} }

View file

@ -36,43 +36,37 @@ public struct ReportView: View {
.navigationTitle("report.title") .navigationTitle("report.title")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
#if !os(visionOS) #if !os(visionOS)
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)
.background(theme.secondaryBackgroundColor) .background(theme.secondaryBackgroundColor)
.scrollDismissesKeyboard(.immediately) .scrollDismissesKeyboard(.immediately)
#endif #endif
.toolbar { .toolbar {
ToolbarItem(placement: .navigationBarTrailing) { ToolbarItem(placement: .navigationBarTrailing) {
Button { Button {
isSendingReport = true isSendingReport = true
Task { Task {
do { do {
let _: ReportSent = let _: ReportSent =
try await client.post(endpoint: Statuses.report(accountId: status.account.id, try await client.post(endpoint: Statuses.report(accountId: status.account.id,
statusId: status.id, statusId: status.id,
comment: commentText)) comment: commentText))
dismiss() dismiss()
isSendingReport = false isSendingReport = false
} catch { } catch {
isSendingReport = false isSendingReport = false
}
}
} label: {
if isSendingReport {
ProgressView()
} else {
Text("report.action.send")
} }
} }
} label: {
if isSendingReport {
ProgressView()
} else {
Text("report.action.send")
}
} }
}
ToolbarItem(placement: .navigationBarLeading) { CancelToolbarItem()
Button {
dismiss()
} label: {
Text("action.cancel")
}
} }
}
} }
} }
} }

View file

@ -4,6 +4,8 @@ import Models
import Observation import Observation
import SafariServices import SafariServices
import SwiftUI import SwiftUI
import AppAccount
import WebKit
extension View { extension View {
@MainActor func withSafariRouter() -> some View { @MainActor func withSafariRouter() -> some View {
@ -13,25 +15,35 @@ extension View {
@MainActor @MainActor
private struct SafariRouter: ViewModifier { private struct SafariRouter: ViewModifier {
@Environment(\.isSecondaryColumn) private var isSecondaryColumn: Bool
@Environment(Theme.self) private var theme @Environment(Theme.self) private var theme
@Environment(UserPreferences.self) private var preferences @Environment(UserPreferences.self) private var preferences
@Environment(RouterPath.self) private var routerPath @Environment(RouterPath.self) private var routerPath
@Environment(AppAccountsManager.self) private var appAccount
#if !os(visionOS) #if !os(visionOS)
@State private var safariManager = InAppSafariManager() @State private var safariManager = InAppSafariManager()
#endif #endif
func body(content: Content) -> some View { func body(content: Content) -> some View {
content content
.environment(\.openURL, OpenURLAction { url in .environment(\.openURL, OpenURLAction { url in
// Open internal URL. // Open internal URL.
routerPath.handle(url: url) guard !isSecondaryColumn else { return .discarded }
return routerPath.handle(url: url)
}) })
.onOpenURL { url in .onOpenURL { url in
// Open external URL (from icecubesapp://) // Open external URL (from icecubesapp://)
guard !isSecondaryColumn else { return }
if url.absoluteString == "icecubesapp://subclub" {
#if !os(visionOS)
safariManager.dismiss()
#endif
return
}
let urlString = url.absoluteString.replacingOccurrences(of: AppInfo.scheme, with: "https://") let urlString = url.absoluteString.replacingOccurrences(of: AppInfo.scheme, with: "https://")
guard let url = URL(string: urlString), url.host != nil else { return } guard let url = URL(string: urlString), url.host != nil else { return }
_ = routerPath.handle(url: url) _ = routerPath.handleDeepLink(url: url)
} }
.onAppear { .onAppear {
routerPath.urlHandler = { url in routerPath.urlHandler = { url in
@ -44,6 +56,19 @@ private struct SafariRouter: ViewModifier {
UIApplication.shared.open(url) UIApplication.shared.open(url)
return .handled return .handled
} }
} else if url.query()?.contains("callback=") == false,
url.host() == AppInfo.premiumInstance,
let accountName = appAccount.currentAccount.accountName {
let newURL = url.appending(queryItems: [
.init(name: "callback", value: "icecubesapp://subclub"),
.init(name: "id", value: "@\(accountName)")
])
#if !os(visionOS)
return safariManager.open(newURL)
#else
return .systemAction
#endif
} }
#if !targetEnvironment(macCatalyst) #if !targetEnvironment(macCatalyst)
guard preferences.preferredBrowser == .inAppSafari else { return .systemAction } guard preferences.preferredBrowser == .inAppSafari else { return .systemAction }
@ -52,78 +77,85 @@ private struct SafariRouter: ViewModifier {
return .systemAction return .systemAction
} }
#if os(visionOS) #if os(visionOS)
return .systemAction return .systemAction
#else #else
return safariManager.open(url) return safariManager.open(url)
#endif #endif
#else #else
return .systemAction return .systemAction
#endif #endif
} }
} }
#if !os(visionOS) #if !os(visionOS)
.background { .background {
WindowReader { window in WindowReader { window in
safariManager.windowScene = window.windowScene safariManager.windowScene = window.windowScene
} }
} }
#endif #endif
} }
} }
#if !os(visionOS) #if !os(visionOS)
@MainActor
@Observable private class InAppSafariManager: NSObject, SFSafariViewControllerDelegate {
var windowScene: UIWindowScene?
let viewController: UIViewController = .init()
var window: UIWindow?
@MainActor @MainActor
func open(_ url: URL) -> OpenURLAction.Result { @Observable private class InAppSafariManager: NSObject, SFSafariViewControllerDelegate {
guard let windowScene else { return .systemAction } var windowScene: UIWindowScene?
let viewController: UIViewController = .init()
var window: UIWindow?
window = setupWindow(windowScene: windowScene) @MainActor
func open(_ url: URL) -> OpenURLAction.Result {
guard let windowScene else { return .systemAction }
let configuration = SFSafariViewController.Configuration() window = setupWindow(windowScene: windowScene)
configuration.entersReaderIfAvailable = UserPreferences.shared.inAppBrowserReaderView
let safari = SFSafariViewController(url: url, configuration: configuration) let configuration = SFSafariViewController.Configuration()
safari.preferredBarTintColor = UIColor(Theme.shared.primaryBackgroundColor) configuration.entersReaderIfAvailable = UserPreferences.shared.inAppBrowserReaderView
safari.preferredControlTintColor = UIColor(Theme.shared.tintColor)
safari.delegate = self
DispatchQueue.main.async { [weak self] in let safari = SFSafariViewController(url: url, configuration: configuration)
self?.viewController.present(safari, animated: true) safari.preferredBarTintColor = UIColor(Theme.shared.primaryBackgroundColor)
safari.preferredControlTintColor = UIColor(Theme.shared.tintColor)
safari.delegate = self
DispatchQueue.main.async { [weak self] in
self?.viewController.present(safari, animated: true)
}
return .handled
} }
return .handled func dismiss() {
} viewController.presentedViewController?.dismiss(animated: true)
func setupWindow(windowScene: UIWindowScene) -> UIWindow {
let window = window ?? UIWindow(windowScene: windowScene)
window.rootViewController = viewController
window.makeKeyAndVisible()
switch Theme.shared.selectedScheme {
case .dark:
window.overrideUserInterfaceStyle = .dark
case .light:
window.overrideUserInterfaceStyle = .light
}
self.window = window
return window
}
nonisolated func safariViewControllerDidFinish(_: SFSafariViewController) {
Task { @MainActor in
window?.resignKey() window?.resignKey()
window?.isHidden = false window?.isHidden = false
window = nil window = nil
} }
func setupWindow(windowScene: UIWindowScene) -> UIWindow {
let window = window ?? UIWindow(windowScene: windowScene)
window.rootViewController = viewController
window.makeKeyAndVisible()
switch Theme.shared.selectedScheme {
case .dark:
window.overrideUserInterfaceStyle = .dark
case .light:
window.overrideUserInterfaceStyle = .light
}
self.window = window
return window
}
nonisolated func safariViewControllerDidFinish(_: SFSafariViewController) {
Task { @MainActor in
window?.resignKey()
window?.isHidden = false
window = nil
}
}
} }
}
#endif #endif
private struct WindowReader: UIViewRepresentable { private struct WindowReader: UIViewRepresentable {

View file

@ -18,14 +18,13 @@ struct SideBarView<Content: View>: View {
@Environment(UserPreferences.self) private var userPreferences @Environment(UserPreferences.self) private var userPreferences
@Environment(RouterPath.self) private var routerPath @Environment(RouterPath.self) private var routerPath
@Binding var selectedTab: Tab @Binding var selectedTab: AppTab
@Binding var popToRootTab: Tab var tabs: [AppTab]
var tabs: [Tab]
@ViewBuilder var content: () -> Content @ViewBuilder var content: () -> Content
@State private var sidebarTabs = SidebarTabs.shared @State private var sidebarTabs = SidebarTabs.shared
private func badgeFor(tab: Tab) -> Int { private func badgeFor(tab: AppTab) -> Int {
if tab == .notifications, selectedTab != tab, if tab == .notifications, selectedTab != tab,
let token = appAccounts.currentAccount.oauthToken let token = appAccounts.currentAccount.oauthToken
{ {
@ -34,17 +33,32 @@ struct SideBarView<Content: View>: View {
return 0 return 0
} }
private func makeIconForTab(tab: Tab) -> some View { private func makeIconForTab(tab: AppTab) -> some View {
ZStack(alignment: .topTrailing) { ZStack(alignment: .topTrailing) {
SideBarIcon(systemIconName: tab.iconName, HStack {
isSelected: tab == selectedTab) SideBarIcon(systemIconName: tab.iconName,
isSelected: tab == selectedTab)
if userPreferences.isSidebarExpanded {
Text(tab.title)
.font(.headline)
.foregroundColor(tab == selectedTab ? theme.tintColor : theme.labelColor)
.frame(maxWidth: .infinity, alignment: .leading)
}
}
.frame(width: (userPreferences.isSidebarExpanded ? .sidebarWidthExpanded : .sidebarWidth) - 24, height: 50)
.background(tab == selectedTab ? theme.primaryBackgroundColor : .clear,
in: RoundedRectangle(cornerRadius: 8))
.cornerRadius(8)
.shadow(color: tab == selectedTab ? .black.opacity(0.2) : .clear, radius: 5)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(tab == selectedTab ? theme.labelColor.opacity(0.1) : .clear, lineWidth: 1)
)
let badge = badgeFor(tab: tab) let badge = badgeFor(tab: tab)
if badge > 0 { if badge > 0 {
makeBadgeView(count: badge) makeBadgeView(count: badge)
} }
} }
.contentShape(Rectangle())
.frame(width: .sidebarWidth, height: 50)
} }
private func makeBadgeView(count: Int) -> some View { private func makeBadgeView(count: Int) -> some View {
@ -56,7 +70,7 @@ struct SideBarView<Content: View>: View {
.font(.caption2) .font(.caption2)
} }
.frame(width: 24, height: 24) .frame(width: 24, height: 24)
.offset(x: 14, y: -14) .offset(x: 5, y: -5)
} }
private var postButton: some View { private var postButton: some View {
@ -74,6 +88,7 @@ struct SideBarView<Content: View>: View {
.offset(x: 2, y: -2) .offset(x: 2, y: -2)
} }
.buttonStyle(.borderedProminent) .buttonStyle(.borderedProminent)
.help(AppTab.post.title)
} }
private func makeAccountButton(account: AppAccount, showBadge: Bool) -> some View { private func makeAccountButton(account: AppAccount, showBadge: Bool) -> some View {
@ -90,9 +105,19 @@ struct SideBarView<Content: View>: View {
} }
} label: { } label: {
ZStack(alignment: .topTrailing) { ZStack(alignment: .topTrailing) {
AppAccountView(viewModel: .init(appAccount: account, isCompact: true), if userPreferences.isSidebarExpanded {
isParentPresented: .constant(false)) AppAccountView(viewModel: .init(appAccount: account,
if showBadge, isCompact: false,
isInSettings: false),
isParentPresented: .constant(false))
} else {
AppAccountView(viewModel: .init(appAccount: account,
isCompact: true,
isInSettings: false),
isParentPresented: .constant(false))
}
if !userPreferences.isSidebarExpanded,
showBadge,
let token = account.oauthToken, let token = account.oauthToken,
let notificationsCount = userPreferences.notificationsCount[token], let notificationsCount = userPreferences.notificationsCount[token],
notificationsCount > 0 notificationsCount > 0
@ -100,26 +125,29 @@ struct SideBarView<Content: View>: View {
makeBadgeView(count: notificationsCount) makeBadgeView(count: notificationsCount)
} }
} }
.padding(.leading, userPreferences.isSidebarExpanded ? 16 : 0)
} }
.frame(width: .sidebarWidth, height: 50) .help(accountButtonTitle(accountName: account.accountName))
.frame(width: userPreferences.isSidebarExpanded ? .sidebarWidthExpanded : .sidebarWidth, height: 50)
.padding(.vertical, 8) .padding(.vertical, 8)
.background(selectedTab == .profile && account.id == appAccounts.currentAccount.id ? .background(selectedTab == .profile && account.id == appAccounts.currentAccount.id ?
theme.secondaryBackgroundColor : .clear) theme.secondaryBackgroundColor : .clear)
} }
private func accountButtonTitle(accountName: String?) -> LocalizedStringKey {
if let accountName {
"tab.profile-account-\(accountName)"
} else {
AppTab.profile.title
}
}
private var tabsView: some View { private var tabsView: some View {
ForEach(tabs) { tab in ForEach(tabs) { tab in
if tab != .profile && sidebarTabs.isEnabled(tab) { if tab != .profile && sidebarTabs.isEnabled(tab) {
Button { Button {
// ensure keyboard is always dismissed when selecting a tab // ensure keyboard is always dismissed when selecting a tab
hideKeyboard() hideKeyboard()
if tab == selectedTab {
popToRootTab = .other
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
popToRootTab = tab
}
}
selectedTab = tab selectedTab = tab
SoundEffectManager.shared.playSound(.tabSelection) SoundEffectManager.shared.playSound(.tabSelection)
if tab == .notifications { if tab == .notifications {
@ -131,7 +159,7 @@ struct SideBarView<Content: View>: View {
} label: { } label: {
makeIconForTab(tab: tab) makeIconForTab(tab: tab)
} }
.background(tab == selectedTab ? theme.secondaryBackgroundColor : .clear) .help(tab.title)
} }
} }
} }
@ -153,15 +181,27 @@ struct SideBarView<Content: View>: View {
} }
} }
} }
postButton
.padding(.top, 12)
Spacer()
} }
} }
.frame(width: .sidebarWidth) .frame(width: userPreferences.isSidebarExpanded ? .sidebarWidthExpanded : .sidebarWidth)
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)
.background(.thinMaterial) .background(.thinMaterial)
Divider().edgesIgnoringSafeArea(.all) .safeAreaInset(edge: .bottom, content: {
HStack(spacing: 16) {
postButton
.padding(.vertical, 24)
.padding(.leading, userPreferences.isSidebarExpanded ? 18 : 0)
if userPreferences.isSidebarExpanded {
Text("menu.new-post")
.font(.subheadline)
.foregroundColor(theme.labelColor)
.frame(maxWidth: .infinity, alignment: .leading)
}
}
.frame(width: userPreferences.isSidebarExpanded ? .sidebarWidthExpanded : .sidebarWidth)
.background(.thinMaterial)
})
Divider().edgesIgnoringSafeArea(.all)
} }
content() content()
} }
@ -191,6 +231,7 @@ private struct SideBarIcon: View {
self.isHovered = isHovered self.isHovered = isHovered
} }
} }
.frame(width: 50, height: 40)
} }
} }

View file

@ -4,7 +4,6 @@ import Env
import Explore import Explore
import Models import Models
import Network import Network
import Shimmer
import SwiftUI import SwiftUI
@MainActor @MainActor
@ -14,30 +13,19 @@ struct ExploreTab: View {
@Environment(CurrentAccount.self) private var currentAccount @Environment(CurrentAccount.self) private var currentAccount
@Environment(Client.self) private var client @Environment(Client.self) private var client
@State private var routerPath = RouterPath() @State private var routerPath = RouterPath()
@State private var scrollToTopSignal: Int = 0
@Binding var popToRootTab: Tab
var body: some View { var body: some View {
NavigationStack(path: $routerPath.path) { NavigationStack(path: $routerPath.path) {
ExploreView(scrollToTopSignal: $scrollToTopSignal) ExploreView()
.withAppRouter() .withAppRouter()
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet) .withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.50), for: .navigationBar) .toolbarBackground(theme.primaryBackgroundColor.opacity(0.30), for: .navigationBar)
.toolbar { .toolbar {
ToolbarTab(routerPath: $routerPath) ToolbarTab(routerPath: $routerPath)
} }
} }
.withSafariRouter() .withSafariRouter()
.environment(routerPath) .environment(routerPath)
.onChange(of: $popToRootTab.wrappedValue) { _, newValue in
if newValue == .explore {
if routerPath.path.isEmpty {
scrollToTopSignal += 1
} else {
routerPath.path = []
}
}
}
.onChange(of: client.id) { .onChange(of: client.id) {
routerPath.path = [] routerPath.path = []
} }

View file

@ -5,7 +5,6 @@ import DesignSystem
import Env import Env
import Models import Models
import Network import Network
import Shimmer
import SwiftUI import SwiftUI
@MainActor @MainActor
@ -16,29 +15,18 @@ struct MessagesTab: View {
@Environment(CurrentAccount.self) private var currentAccount @Environment(CurrentAccount.self) private var currentAccount
@Environment(AppAccountsManager.self) private var appAccount @Environment(AppAccountsManager.self) private var appAccount
@State private var routerPath = RouterPath() @State private var routerPath = RouterPath()
@State private var scrollToTopSignal: Int = 0
@Binding var popToRootTab: Tab
var body: some View { var body: some View {
NavigationStack(path: $routerPath.path) { NavigationStack(path: $routerPath.path) {
ConversationsListView(scrollToTopSignal: $scrollToTopSignal) ConversationsListView()
.withAppRouter() .withAppRouter()
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet) .withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
.toolbar { .toolbar {
ToolbarTab(routerPath: $routerPath) ToolbarTab(routerPath: $routerPath)
} }
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.50), for: .navigationBar) .toolbarBackground(theme.primaryBackgroundColor.opacity(0.30), for: .navigationBar)
.id(client.id) .id(client.id)
} }
.onChange(of: $popToRootTab.wrappedValue) { _, newValue in
if newValue == .messages {
if routerPath.path.isEmpty {
scrollToTopSignal += 1
} else {
routerPath.path = []
}
}
}
.onChange(of: client.id) { .onChange(of: client.id) {
routerPath.path = [] routerPath.path = []
} }

View file

@ -1,7 +1,7 @@
import SwiftUI
import Env
import AppAccount import AppAccount
import DesignSystem import DesignSystem
import Env
import SwiftUI
@MainActor @MainActor
struct NavigationSheet<Content: View>: View { struct NavigationSheet<Content: View>: View {
@ -17,13 +17,7 @@ struct NavigationSheet<Content: View>: View {
NavigationStack { NavigationStack {
content() content()
.toolbar { .toolbar {
ToolbarItem(placement: .navigationBarLeading) { CloseToolbarItem()
Button {
dismiss()
} label: {
Image(systemName: "xmark.circle")
}
}
} }
} }
} }

View file

@ -1,8 +1,8 @@
import SwiftUI
import Env
import AppAccount import AppAccount
import DesignSystem import DesignSystem
import Env
import Network import Network
import SwiftUI
@MainActor @MainActor
struct NavigationTab<Content: View>: View { struct NavigationTab<Content: View>: View {
@ -32,7 +32,7 @@ struct NavigationTab<Content: View>: View {
.toolbar { .toolbar {
ToolbarTab(routerPath: $routerPath) ToolbarTab(routerPath: $routerPath)
} }
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.50), for: .navigationBar) .toolbarBackground(theme.primaryBackgroundColor.opacity(0.30), for: .navigationBar)
.onChange(of: client.id) { .onChange(of: client.id) {
routerPath.path = [] routerPath.path = []
} }

View file

@ -20,16 +20,14 @@ struct NotificationsTab: View {
@Environment(UserPreferences.self) private var userPreferences @Environment(UserPreferences.self) private var userPreferences
@Environment(PushNotificationsService.self) private var pushNotificationsService @Environment(PushNotificationsService.self) private var pushNotificationsService
@State private var routerPath = RouterPath() @State private var routerPath = RouterPath()
@State private var scrollToTopSignal: Int = 0
@Binding var selectedTab: Tab @Binding var selectedTab: AppTab
@Binding var popToRootTab: Tab
let lockedType: Models.Notification.NotificationType? let lockedType: Models.Notification.NotificationType?
var body: some View { var body: some View {
NavigationStack(path: $routerPath.path) { NavigationStack(path: $routerPath.path) {
NotificationsListView(lockedType: lockedType, scrollToTopSignal: $scrollToTopSignal) NotificationsListView(lockedType: lockedType)
.withAppRouter() .withAppRouter()
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet) .withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
.toolbar { .toolbar {
@ -42,7 +40,7 @@ struct NotificationsTab: View {
} }
ToolbarTab(routerPath: $routerPath) ToolbarTab(routerPath: $routerPath)
} }
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.50), for: .navigationBar) .toolbarBackground(theme.primaryBackgroundColor.opacity(0.30), for: .navigationBar)
.id(client.id) .id(client.id)
} }
.onAppear { .onAppear {
@ -51,18 +49,9 @@ struct NotificationsTab: View {
} }
.withSafariRouter() .withSafariRouter()
.environment(routerPath) .environment(routerPath)
.onChange(of: $popToRootTab.wrappedValue) { _, newValue in .onChange(of: selectedTab) { _, _ in
if newValue == .notifications {
if routerPath.path.isEmpty {
scrollToTopSignal += 1
} else {
routerPath.path = []
}
}
}
.onChange(of: selectedTab, { _, newValue in
clearNotifications() clearNotifications()
}) }
.onChange(of: pushNotificationsService.handledNotification) { _, newValue in .onChange(of: pushNotificationsService.handledNotification) { _, newValue in
if let newValue, let type = newValue.notification.supportedType { if let newValue, let type = newValue.notification.supportedType {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
@ -92,10 +81,12 @@ struct NotificationsTab: View {
private func clearNotifications() { private func clearNotifications() {
if selectedTab == .notifications || isSecondaryColumn { if selectedTab == .notifications || isSecondaryColumn {
if let token = appAccount.currentAccount.oauthToken { if let token = appAccount.currentAccount.oauthToken, userPreferences.notificationsCount[token] ?? 0 > 0 {
userPreferences.notificationsCount[token] = 0 userPreferences.notificationsCount[token] = 0
} }
watcher.unreadNotificationsCount = 0 if watcher.unreadNotificationsCount > 0 {
watcher.unreadNotificationsCount = 0
}
} }
} }
} }

View file

@ -5,7 +5,6 @@ import DesignSystem
import Env import Env
import Models import Models
import Network import Network
import Shimmer
import SwiftUI import SwiftUI
@MainActor @MainActor
@ -15,32 +14,21 @@ struct ProfileTab: View {
@Environment(Client.self) private var client @Environment(Client.self) private var client
@Environment(CurrentAccount.self) private var currentAccount @Environment(CurrentAccount.self) private var currentAccount
@State private var routerPath = RouterPath() @State private var routerPath = RouterPath()
@State private var scrollToTopSignal: Int = 0
@Binding var popToRootTab: Tab
var body: some View { var body: some View {
NavigationStack(path: $routerPath.path) { NavigationStack(path: $routerPath.path) {
if let account = currentAccount.account { if let account = currentAccount.account {
AccountDetailView(account: account, scrollToTopSignal: $scrollToTopSignal) AccountDetailView(account: account)
.withAppRouter() .withAppRouter()
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet) .withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.50), for: .navigationBar) .toolbarBackground(theme.primaryBackgroundColor.opacity(0.30), for: .navigationBar)
.id(account.id) .id(account.id)
} else { } else {
AccountDetailView(account: .placeholder(), scrollToTopSignal: $scrollToTopSignal) AccountDetailView(account: .placeholder())
.redacted(reason: .placeholder) .redacted(reason: .placeholder)
.allowsHitTesting(false) .allowsHitTesting(false)
} }
} }
.onChange(of: $popToRootTab.wrappedValue) { _, newValue in
if newValue == .profile {
if routerPath.path.isEmpty {
scrollToTopSignal += 1
} else {
routerPath.path = []
}
}
}
.onChange(of: client.id) { .onChange(of: client.id) {
routerPath.path = [] routerPath.path = []
} }

View file

@ -27,27 +27,27 @@ struct AboutView: View {
var body: some View { var body: some View {
List { List {
Section { Section {
#if !targetEnvironment(macCatalyst) #if !targetEnvironment(macCatalyst) && !os(visionOS)
HStack { HStack {
Spacer() Spacer()
Image(uiImage: .init(named: "AppIconAlternate0")!) Image(uiImage: .init(named: "AppIconAlternate0-image") ?? .init())
.resizable() .resizable()
.frame(width: 50, height: 50) .frame(width: 50, height: 50)
.cornerRadius(4) .cornerRadius(4)
Image(uiImage: .init(named: "AppIconAlternate4")!) Image(uiImage: .init(named: "AppIconAlternate46-image") ?? .init())
.resizable() .resizable()
.frame(width: 50, height: 50) .frame(width: 50, height: 50)
.cornerRadius(4) .cornerRadius(4)
Image(uiImage: .init(named: "AppIconAlternate17")!) Image(uiImage: .init(named: "AppIconAlternate17-image") ?? .init())
.resizable() .resizable()
.frame(width: 50, height: 50) .frame(width: 50, height: 50)
.cornerRadius(4) .cornerRadius(4)
Image(uiImage: .init(named: "AppIconAlternate23")!) Image(uiImage: .init(named: "AppIconAlternate23-image") ?? .init())
.resizable() .resizable()
.frame(width: 50, height: 50) .frame(width: 50, height: 50)
.cornerRadius(4) .cornerRadius(4)
Spacer() Spacer()
} }
#endif #endif
Link(destination: URL(string: "https://github.com/Dimillian/IceCubesApp/blob/main/PRIVACY.MD")!) { Link(destination: URL(string: "https://github.com/Dimillian/IceCubesApp/blob/main/PRIVACY.MD")!) {
Label("settings.support.privacy-policy", systemImage: "lock") Label("settings.support.privacy-policy", systemImage: "lock")
@ -57,7 +57,7 @@ struct AboutView: View {
Label("settings.support.terms-of-use", systemImage: "checkmark.shield") Label("settings.support.terms-of-use", systemImage: "checkmark.shield")
} }
} footer: { } footer: {
Text("\(versionNumber)©2023 Thomas Ricouard") Text("\(versionNumber)© 2024 Thomas Ricouard")
} }
#if !os(visionOS) #if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)
@ -65,6 +65,18 @@ struct AboutView: View {
followAccountsSection followAccountsSection
Section("Telemetry") {
Link(destination: .init(string: "https://telemetrydeck.com")!) {
Label("Telemetry by TelemetryDeck", systemImage: "link")
}
Link(destination: .init(string: "https://telemetrydeck.com/privacy/")!) {
Label("Privacy Policy", systemImage: "checkmark.shield")
}
}
#if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor)
#endif
Section { Section {
Text(""" Text("""
[EmojiText](https://github.com/divadretlaw/EmojiText) [EmojiText](https://github.com/divadretlaw/EmojiText)
@ -107,14 +119,14 @@ struct AboutView: View {
} }
.listStyle(.insetGrouped) .listStyle(.insetGrouped)
#if !os(visionOS) #if !os(visionOS)
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)
.background(theme.secondaryBackgroundColor) .background(theme.secondaryBackgroundColor)
#endif #endif
.navigationTitle(Text("settings.about.title")) .navigationTitle(Text("settings.about.title"))
.navigationBarTitleDisplayMode(.large) .navigationBarTitleDisplayMode(.large)
.environment(\.openURL, OpenURLAction { url in .environment(\.openURL, OpenURLAction { url in
routerPath.handle(url: url) routerPath.handle(url: url)
}) })
} }
@ViewBuilder @ViewBuilder
@ -140,13 +152,13 @@ struct AboutView: View {
private func fetchAccounts() async { private func fetchAccounts() async {
await withThrowingTaskGroup(of: Void.self) { group in await withThrowingTaskGroup(of: Void.self) { group in
group.addTask { group.addTask {
let viewModel = try await fetchAccountViewModel(account: "dimillian@mastodon.social") let viewModel = try await fetchAccountViewModel(client, account: "dimillian@mastodon.social")
await MainActor.run { await MainActor.run {
dimillianAccount = viewModel dimillianAccount = viewModel
} }
} }
group.addTask { group.addTask {
let viewModel = try await fetchAccountViewModel(account: "icecubesapp@mastodon.online") let viewModel = try await fetchAccountViewModel(client, account: "icecubesapp@mastodon.online")
await MainActor.run { await MainActor.run {
iceCubesAccount = viewModel iceCubesAccount = viewModel
} }
@ -154,7 +166,7 @@ struct AboutView: View {
} }
} }
private func fetchAccountViewModel(account: String) async throws -> AccountsListRowViewModel { private func fetchAccountViewModel(_ client: Client, account: String) async throws -> AccountsListRowViewModel {
let dimillianAccount: Account = try await client.get(endpoint: Accounts.lookup(name: account)) let dimillianAccount: Account = try await client.get(endpoint: Accounts.lookup(name: account))
let rel: [Relationship] = try await client.get(endpoint: Accounts.relationships(ids: [dimillianAccount.id])) let rel: [Relationship] = try await client.get(endpoint: Accounts.relationships(ids: [dimillianAccount.id]))
return .init(account: dimillianAccount, relationShip: rel.first) return .init(account: dimillianAccount, relationShip: rel.first)

View file

@ -17,9 +17,8 @@ struct AccountSettingsView: View {
@Environment(Theme.self) private var theme @Environment(Theme.self) private var theme
@Environment(AppAccountsManager.self) private var appAccountsManager @Environment(AppAccountsManager.self) private var appAccountsManager
@Environment(Client.self) private var client @Environment(Client.self) private var client
@Environment(RouterPath.self) private var routerPath
@State private var isEditingAccount: Bool = false
@State private var isEditingFilters: Bool = false
@State private var cachedPostsCount: Int = 0 @State private var cachedPostsCount: Int = 0
@State private var timelineCache = TimelineCache() @State private var timelineCache = TimelineCache()
@ -30,7 +29,7 @@ struct AccountSettingsView: View {
Form { Form {
Section { Section {
Button { Button {
isEditingAccount = true routerPath.presentedSheet = .accountEditInfo
} label: { } label: {
Label("account.action.edit-info", systemImage: "pencil") Label("account.action.edit-info", systemImage: "pencil")
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
@ -40,7 +39,7 @@ struct AccountSettingsView: View {
if currentInstance.isFiltersSupported { if currentInstance.isFiltersSupported {
Button { Button {
isEditingFilters = true routerPath.presentedSheet = .accountFiltersList
} label: { } label: {
Label("account.action.edit-filters", systemImage: "line.3.horizontal.decrease.circle") Label("account.action.edit-filters", systemImage: "line.3.horizontal.decrease.circle")
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
@ -86,22 +85,17 @@ struct AccountSettingsView: View {
await sub.deleteSubscription() await sub.deleteSubscription()
} }
appAccountsManager.delete(account: appAccount) appAccountsManager.delete(account: appAccount)
Telemetry.signal("account.removed")
dismiss() dismiss()
} }
} }
} label: { } label: {
Text("account.action.logout") Label("account.action.logout", systemImage: "trash")
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
} }
} }
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)
} }
.sheet(isPresented: $isEditingAccount, content: {
EditAccountView()
})
.sheet(isPresented: $isEditingFilters, content: {
FiltersListView()
})
.toolbar { .toolbar {
ToolbarItem(placement: .principal) { ToolbarItem(placement: .principal) {
HStack { HStack {
@ -116,8 +110,8 @@ struct AccountSettingsView: View {
} }
.navigationTitle(account.safeDisplayName) .navigationTitle(account.safeDisplayName)
#if !os(visionOS) #if !os(visionOS)
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)
.background(theme.secondaryBackgroundColor) .background(theme.secondaryBackgroundColor)
#endif #endif
} }
} }

View file

@ -1,4 +1,5 @@
import AppAccount import AppAccount
import AuthenticationServices
import Combine import Combine
import DesignSystem import DesignSystem
import Env import Env
@ -6,15 +7,14 @@ import Models
import Network import Network
import NukeUI import NukeUI
import SafariServices import SafariServices
import Shimmer
import SwiftUI import SwiftUI
@MainActor @MainActor
struct AddAccountView: View { struct AddAccountView: View {
@Environment(\.webAuthenticationSession) private var webAuthenticationSession
@Environment(\.dismiss) private var dismiss @Environment(\.dismiss) private var dismiss
@Environment(\.scenePhase) private var scenePhase @Environment(\.scenePhase) private var scenePhase
@Environment(\.openURL) private var openURL @Environment(\.openURL) private var openURL
@Environment(\.webAuthenticationSession) private var webAuthenticationSession
@Environment(AppAccountsManager.self) private var appAccountsManager @Environment(AppAccountsManager.self) private var appAccountsManager
@Environment(CurrentAccount.self) private var currentAccount @Environment(CurrentAccount.self) private var currentAccount
@ -83,77 +83,77 @@ struct AddAccountView: View {
.navigationTitle("account.add.navigation-title") .navigationTitle("account.add.navigation-title")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
#if !os(visionOS) #if !os(visionOS)
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)
.background(theme.secondaryBackgroundColor) .background(theme.secondaryBackgroundColor)
.scrollDismissesKeyboard(.immediately) .scrollDismissesKeyboard(.immediately)
#endif #endif
.toolbar { .toolbar {
if !appAccountsManager.availableAccounts.isEmpty { CancelToolbarItem()
ToolbarItem(placement: .navigationBarLeading) {
Button("action.cancel", action: { dismiss() })
}
} }
} .onAppear {
.onAppear { isInstanceURLFieldFocused = true
isInstanceURLFieldFocused = true let instanceName = instanceName
Task { Task {
let instances = await instanceSocialClient.fetchInstances(keyword: instanceName) let instances = await instanceSocialClient.fetchInstances(keyword: instanceName)
withAnimation { withAnimation {
self.instances = instances self.instances = instances
}
} }
isSigninIn = false
} }
isSigninIn = false .onChange(of: instanceName) {
} searchingTask.cancel()
.onChange(of: instanceName) { let instanceName = instanceName
searchingTask.cancel() let instanceSocialClient = instanceSocialClient
searchingTask = Task { searchingTask = Task {
try? await Task.sleep(for: .seconds(0.1)) try? await Task.sleep(for: .seconds(0.1))
guard !Task.isCancelled else { return } guard !Task.isCancelled else { return }
let instances = await instanceSocialClient.fetchInstances(keyword: instanceName) let instances = await instanceSocialClient.fetchInstances(keyword: instanceName)
withAnimation { withAnimation {
self.instances = instances self.instances = instances
}
} }
}
getInstanceDetailTask.cancel() getInstanceDetailTask.cancel()
getInstanceDetailTask = Task { getInstanceDetailTask = Task {
try? await Task.sleep(for: .seconds(0.1)) try? await Task.sleep(for: .seconds(0.1))
guard !Task.isCancelled else { return } guard !Task.isCancelled else { return }
do { do {
// bare bones preflight for domain validity // bare bones preflight for domain validity
let instanceDetailClient = Client(server: sanitizedName) let instanceDetailClient = Client(server: sanitizedName)
if if
instanceDetailClient.server.contains("."), instanceDetailClient.server.contains("."),
instanceDetailClient.server.last != "." instanceDetailClient.server.last != "."
{ {
let instance: Instance = try await instanceDetailClient.get(endpoint: Instances.instance) let instance: Instance = try await instanceDetailClient.get(endpoint: Instances.instance)
withAnimation { withAnimation {
self.instance = instance self.instance = instance
instanceName = sanitizedName // clean up the text box, principally to chop off the username if present so it's clear that you might not wind up siging in as the thing in the box self.instanceName = sanitizedName // clean up the text box, principally to chop off the username if present so it's clear that you might not wind up siging in as the thing in the box
}
instanceFetchError = nil
} else {
instance = nil
instanceFetchError = nil
} }
instanceFetchError = nil } catch _ as ServerError {
} else { instance = nil
instanceFetchError = "account.add.error.instance-not-supported"
} catch {
instance = nil instance = nil
instanceFetchError = nil instanceFetchError = nil
} }
} catch _ as DecodingError {
instance = nil
instanceFetchError = "account.add.error.instance-not-supported"
} catch {
instance = nil
} }
} }
} .onChange(of: scenePhase) { _, newValue in
.onChange(of: scenePhase) { _, newValue in switch newValue {
switch newValue { case .active:
case .active: isSigninIn = false
isSigninIn = false default:
default: break
break }
} }
}
} }
} }
@ -217,9 +217,9 @@ struct AddAccountView: View {
.foregroundColor(.primary) .foregroundColor(.primary)
Spacer() Spacer()
(Text("instance.list.users-\(formatAsNumber(instance.users))") (Text("instance.list.users-\(formatAsNumber(instance.users))")
+ Text("") + Text("")
+ Text("instance.list.posts-\(formatAsNumber(instance.statuses))")) + Text("instance.list.posts-\(formatAsNumber(instance.statuses))"))
.foregroundStyle(theme.tintColor) .foregroundStyle(theme.tintColor)
} }
.padding(.bottom, 5) .padding(.bottom, 5)
Text(instance.info?.shortDescription?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "") Text(instance.info?.shortDescription?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "")
@ -265,9 +265,8 @@ struct AddAccountView: View {
} }
.redacted(reason: .placeholder) .redacted(reason: .placeholder)
.allowsHitTesting(false) .allowsHitTesting(false)
.shimmering()
#if !os(visionOS) #if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)
#endif #endif
} }
@ -292,6 +291,7 @@ struct AddAccountView: View {
let oauthToken = try await client.continueOauthFlow(url: url) let oauthToken = try await client.continueOauthFlow(url: url)
let client = Client(server: client.server, oauthToken: oauthToken) let client = Client(server: client.server, oauthToken: oauthToken)
let account: Account = try await client.get(endpoint: Accounts.verifyCredentials) let account: Account = try await client.get(endpoint: Accounts.verifyCredentials)
Telemetry.signal("account.added")
appAccountsManager.add(account: AppAccount(server: client.server, appAccountsManager.add(account: AppAccount(server: client.server,
accountName: "\(account.acct)@\(client.server)", accountName: "\(account.acct)@\(client.server)",
oauthToken: oauthToken)) oauthToken: oauthToken))
@ -306,13 +306,3 @@ struct AddAccountView: View {
} }
} }
} }
struct SafariView: UIViewControllerRepresentable {
let url: URL
func makeUIViewController(context _: UIViewControllerRepresentableContext<SafariView>) -> SFSafariViewController {
SFSafariViewController(url: url)
}
func updateUIViewController(_: SFSafariViewController, context _: UIViewControllerRepresentableContext<SafariView>) {}
}

View file

@ -5,8 +5,8 @@ import Models
import Network import Network
import NukeUI import NukeUI
import SwiftUI import SwiftUI
import UserNotifications
import Timeline import Timeline
import UserNotifications
@MainActor @MainActor
struct ContentSettingsView: View { struct ContentSettingsView: View {
@ -41,7 +41,7 @@ struct ContentSettingsView: View {
} }
} }
} }
#if !os(visionOS) #if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)
#endif #endif
@ -59,6 +59,7 @@ struct ContentSettingsView: View {
userPreferences.appAutoExpandMedia = userPreferences.autoExpandMedia userPreferences.appAutoExpandMedia = userPreferences.autoExpandMedia
userPreferences.appDefaultPostsSensitive = userPreferences.postIsSensitive userPreferences.appDefaultPostsSensitive = userPreferences.postIsSensitive
userPreferences.appDefaultPostVisibility = userPreferences.postVisibility userPreferences.appDefaultPostVisibility = userPreferences.postVisibility
userPreferences.appRequireAltText = userPreferences.appRequireAltText
} }
} }
@ -112,6 +113,10 @@ struct ContentSettingsView: View {
Text("settings.content.default-sensitive") Text("settings.content.default-sensitive")
} }
.disabled(userPreferences.useInstanceContentSettings) .disabled(userPreferences.useInstanceContentSettings)
Toggle(isOn: $userPreferences.appRequireAltText) {
Text("settings.content.require-alt-text")
}
} }
#if !os(visionOS) #if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)
@ -137,8 +142,8 @@ struct ContentSettingsView: View {
} }
.navigationTitle("settings.content.navigation-title") .navigationTitle("settings.content.navigation-title")
#if !os(visionOS) #if !os(visionOS)
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)
.background(theme.secondaryBackgroundColor) .background(theme.secondaryBackgroundColor)
#endif #endif
} }
} }

View file

@ -7,6 +7,7 @@ import Observation
import StatusKit import StatusKit
import SwiftUI import SwiftUI
@MainActor
@Observable class DisplaySettingsLocalValues { @Observable class DisplaySettingsLocalValues {
var tintColor = Theme.shared.tintColor var tintColor = Theme.shared.tintColor
var primaryBackgroundColor = Theme.shared.primaryBackgroundColor var primaryBackgroundColor = Theme.shared.primaryBackgroundColor
@ -35,11 +36,13 @@ struct DisplaySettingsView: View {
var body: some View { var body: some View {
ZStack(alignment: .top) { ZStack(alignment: .top) {
Form { Form {
StatusRowView(viewModel: previewStatusViewModel) #if !os(visionOS)
.allowsHitTesting(false) StatusRowExternalView(viewModel: previewStatusViewModel)
.opacity(0) .allowsHitTesting(false)
.hidden() .opacity(0)
themeSection .hidden()
themeSection
#endif
fontSection fontSection
layoutSection layoutSection
platformsSection platformsSection
@ -47,40 +50,42 @@ struct DisplaySettingsView: View {
} }
.navigationTitle("settings.display.navigation-title") .navigationTitle("settings.display.navigation-title")
#if !os(visionOS) #if !os(visionOS)
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)
.background(theme.secondaryBackgroundColor) .background(theme.secondaryBackgroundColor)
#endif
.task(id: localValues.tintColor) {
do { try await Task.sleep(for: .microseconds(500)) } catch {}
theme.tintColor = localValues.tintColor
}
.task(id: localValues.primaryBackgroundColor) {
do { try await Task.sleep(for: .microseconds(500)) } catch {}
theme.primaryBackgroundColor = localValues.primaryBackgroundColor
}
.task(id: localValues.secondaryBackgroundColor) {
do { try await Task.sleep(for: .microseconds(500)) } catch {}
theme.secondaryBackgroundColor = localValues.secondaryBackgroundColor
}
.task(id: localValues.labelColor) {
do { try await Task.sleep(for: .microseconds(500)) } catch {}
theme.labelColor = localValues.labelColor
}
.task(id: localValues.lineSpacing) {
do { try await Task.sleep(for: .microseconds(500)) } catch {}
theme.lineSpacing = localValues.lineSpacing
}
.task(id: localValues.fontSizeScale) {
do { try await Task.sleep(for: .microseconds(500)) } catch {}
theme.fontSizeScale = localValues.fontSizeScale
}
#if !os(visionOS)
examplePost
#endif #endif
.task(id: localValues.tintColor) {
do { try await Task.sleep(for: .microseconds(500)) } catch {}
theme.tintColor = localValues.tintColor
}
.task(id: localValues.primaryBackgroundColor) {
do { try await Task.sleep(for: .microseconds(500)) } catch {}
theme.primaryBackgroundColor = localValues.primaryBackgroundColor
}
.task(id: localValues.secondaryBackgroundColor) {
do { try await Task.sleep(for: .microseconds(500)) } catch {}
theme.secondaryBackgroundColor = localValues.secondaryBackgroundColor
}
.task(id: localValues.labelColor) {
do { try await Task.sleep(for: .microseconds(500)) } catch {}
theme.labelColor = localValues.labelColor
}
.task(id: localValues.lineSpacing) {
do { try await Task.sleep(for: .microseconds(500)) } catch {}
theme.lineSpacing = localValues.lineSpacing
}
.task(id: localValues.fontSizeScale) {
do { try await Task.sleep(for: .microseconds(500)) } catch {}
theme.fontSizeScale = localValues.fontSizeScale
}
examplePost
} }
} }
private var examplePost: some View { private var examplePost: some View {
VStack(spacing: 0) { VStack(spacing: 0) {
StatusRowView(viewModel: previewStatusViewModel) StatusRowExternalView(viewModel: previewStatusViewModel)
.allowsHitTesting(false) .allowsHitTesting(false)
.padding(.layoutPadding) .padding(.layoutPadding)
.background(theme.primaryBackgroundColor) .background(theme.primaryBackgroundColor)
@ -232,6 +237,8 @@ struct DisplaySettingsView: View {
} }
} }
Toggle("settings.display.show-account-popover", isOn: $userPreferences.showAccountPopover) Toggle("settings.display.show-account-popover", isOn: $userPreferences.showAccountPopover)
Toggle("Show Content Gradient", isOn: $theme.showContentGradient)
Toggle("Compact Layout", isOn: $theme.compactLayoutPadding)
} }
#if !os(visionOS) #if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)

View file

@ -23,8 +23,8 @@ struct HapticSettingsView: View {
} }
.navigationTitle("settings.haptic.navigation-title") .navigationTitle("settings.haptic.navigation-title")
#if !os(visionOS) #if !os(visionOS)
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)
.background(theme.secondaryBackgroundColor) .background(theme.secondaryBackgroundColor)
#endif #endif
} }
} }

View file

@ -26,10 +26,16 @@ struct IconSelectorView: View {
case alt38 case alt38
case alt39, alt40, alt41, alt42, alt43 case alt39, alt40, alt41, alt42, alt43
case alt44, alt45 case alt44, alt45
case alt46, alt47, alt48
case alt49
var appIconName: String { var appIconName: String {
return "AppIconAlternate\(rawValue)" return "AppIconAlternate\(rawValue)"
} }
var previewImageName: String {
return "AppIconAlternate\(rawValue)-image"
}
} }
struct IconSelector: Identifiable { struct IconSelector: Identifiable {
@ -39,7 +45,7 @@ struct IconSelectorView: View {
static let items = [ static let items = [
IconSelector(title: "settings.app.icon.official".localized, icons: [ IconSelector(title: "settings.app.icon.official".localized, icons: [
.primary, .alt1, .alt2, .alt3, .alt4, .primary, .alt46, .alt1, .alt2, .alt3, .alt4,
.alt5, .alt6, .alt7, .alt8, .alt5, .alt6, .alt7, .alt8,
.alt9, .alt10, .alt11, .alt12, .alt13, .alt14, .alt15, .alt9, .alt10, .alt11, .alt12, .alt13, .alt14, .alt15,
.alt16, .alt17, .alt18, .alt19, .alt20, .alt21]), .alt16, .alt17, .alt18, .alt19, .alt20, .alt21]),
@ -50,6 +56,8 @@ struct IconSelectorView: View {
IconSelector(title: "\("settings.app.icon.designed-by".localized) Duncan Horne", icons: [.alt38]), IconSelector(title: "\("settings.app.icon.designed-by".localized) Duncan Horne", icons: [.alt38]),
IconSelector(title: "\("settings.app.icon.designed-by".localized) BeAware@social.beaware.live", icons: [.alt39, .alt40, .alt41, .alt42, .alt43]), IconSelector(title: "\("settings.app.icon.designed-by".localized) BeAware@social.beaware.live", icons: [.alt39, .alt40, .alt41, .alt42, .alt43]),
IconSelector(title: "\("settings.app.icon.designed-by".localized) Simone Margio", icons: [.alt44, .alt45]), IconSelector(title: "\("settings.app.icon.designed-by".localized) Simone Margio", icons: [.alt44, .alt45]),
IconSelector(title: "\("settings.app.icon.designed-by".localized) Peter Broqvist (@PKB)", icons: [.alt47, .alt48]),
IconSelector(title: "\("settings.app.icon.designed-by".localized) Oz Tsori (@oztsori)", icons: [.alt49]),
] ]
} }
@ -93,7 +101,7 @@ struct IconSelectorView: View {
} }
} label: { } label: {
ZStack(alignment: .bottomTrailing) { ZStack(alignment: .bottomTrailing) {
Image(uiImage: .init(named: icon.appIconName) ?? .init()) Image(icon.previewImageName)
.resizable() .resizable()
.aspectRatio(contentMode: .fit) .aspectRatio(contentMode: .fit)
.frame(minHeight: 125, maxHeight: 1024) .frame(minHeight: 125, maxHeight: 1024)

View file

@ -14,8 +14,8 @@ struct InstanceInfoView: View {
} }
.navigationTitle("instance.info.navigation-title") .navigationTitle("instance.info.navigation-title")
#if !os(visionOS) #if !os(visionOS)
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)
.background(theme.secondaryBackgroundColor) .background(theme.secondaryBackgroundColor)
#endif #endif
} }
} }

View file

@ -111,12 +111,12 @@ struct PushNotificationsView: View {
} }
.navigationTitle("settings.push.navigation-title") .navigationTitle("settings.push.navigation-title")
#if !os(visionOS) #if !os(visionOS)
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)
.background(theme.secondaryBackgroundColor) .background(theme.secondaryBackgroundColor)
#endif #endif
.task { .task {
await subscription.fetchSubscription() await subscription.fetchSubscription()
} }
} }
private func updateSubscription() { private func updateSubscription() {

View file

@ -1,8 +1,8 @@
import SwiftUI
import SwiftData
import Models
import Env
import DesignSystem import DesignSystem
import Env
import Models
import SwiftData
import SwiftUI
struct RecenTagsSettingView: View { struct RecenTagsSettingView: View {
@Environment(\.modelContext) private var context @Environment(\.modelContext) private var context
@ -35,10 +35,10 @@ struct RecenTagsSettingView: View {
.navigationTitle("settings.general.recent-tags") .navigationTitle("settings.general.recent-tags")
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)
#if !os(visionOS) #if !os(visionOS)
.background(theme.secondaryBackgroundColor) .background(theme.secondaryBackgroundColor)
#endif #endif
.toolbar { .toolbar {
EditButton() EditButton()
} }
} }
} }

View file

@ -1,8 +1,8 @@
import SwiftUI
import SwiftData
import Models
import Env
import DesignSystem import DesignSystem
import Env
import Models
import SwiftData
import SwiftUI
struct RemoteTimelinesSettingView: View { struct RemoteTimelinesSettingView: View {
@Environment(\.modelContext) private var context @Environment(\.modelContext) private var context
@ -36,10 +36,10 @@ struct RemoteTimelinesSettingView: View {
.navigationTitle("settings.general.remote-timelines") .navigationTitle("settings.general.remote-timelines")
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)
#if !os(visionOS) #if !os(visionOS)
.background(theme.secondaryBackgroundColor) .background(theme.secondaryBackgroundColor)
#endif #endif
.toolbar { .toolbar {
EditButton() EditButton()
} }
} }
} }

View file

@ -28,10 +28,10 @@ struct SettingsTabs: View {
@State private var cachedRemoved = false @State private var cachedRemoved = false
@State private var timelineCache = TimelineCache() @State private var timelineCache = TimelineCache()
@Binding var popToRootTab: Tab
let isModal: Bool let isModal: Bool
@State private var startingPoint: SettingsStartingPoint? = nil
var body: some View { var body: some View {
NavigationStack(path: $routerPath.path) { NavigationStack(path: $routerPath.path) {
Form { Form {
@ -39,31 +39,59 @@ struct SettingsTabs: View {
accountsSection accountsSection
generalSection generalSection
otherSections otherSections
postStreamingSection
AISection
cacheSection cacheSection
} }
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)
#if !os(visionOS) #if !os(visionOS)
.background(theme.secondaryBackgroundColor) .background(theme.secondaryBackgroundColor)
#endif #endif
.navigationTitle(Text("settings.title")) .navigationTitle(Text("settings.title"))
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.50), for: .navigationBar) .toolbarBackground(theme.primaryBackgroundColor.opacity(0.30), for: .navigationBar)
.toolbar { .toolbar {
if isModal { if isModal {
ToolbarItem { ToolbarItem {
Button { Button {
dismiss() dismiss()
} label: { } label: {
Text("action.done").bold() Text("action.done").bold()
}
} }
} }
if UIDevice.current.userInterfaceIdiom == .pad, !preferences.showiPadSecondaryColumn, !isModal {
SecondaryColumnToolbarItem()
}
} }
if UIDevice.current.userInterfaceIdiom == .pad, !preferences.showiPadSecondaryColumn, !isModal { .withAppRouter()
SecondaryColumnToolbarItem() .withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
.onAppear {
startingPoint = RouterPath.settingsStartingPoint
RouterPath.settingsStartingPoint = nil
}
.navigationDestination(item: $startingPoint) { targetView in
switch targetView {
case .display:
DisplaySettingsView()
case .haptic:
HapticSettingsView()
case .remoteTimelines:
RemoteTimelinesSettingView()
case .tagGroups:
TagsGroupSettingView()
case .recentTags:
RecenTagsSettingView()
case .content:
ContentSettingsView()
case .swipeActions:
SwipeActionsSettingsView()
case .tabAndSidebarEntries:
EmptyView()
case .translation:
TranslationSettingsView()
}
} }
}
.withAppRouter()
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
} }
.onAppear { .onAppear {
routerPath.client = client routerPath.client = client
@ -75,11 +103,6 @@ struct SettingsTabs: View {
} }
.withSafariRouter() .withSafariRouter()
.environment(routerPath) .environment(routerPath)
.onChange(of: $popToRootTab.wrappedValue) { _, newValue in
if newValue == .notifications {
routerPath.path = []
}
}
} }
private var accountsSection: some View { private var accountsSection: some View {
@ -108,10 +131,10 @@ struct SettingsTabs: View {
} }
} }
} }
addAccountButton
if !appAccountsManager.availableAccounts.isEmpty { if !appAccountsManager.availableAccounts.isEmpty {
editAccountButton editAccountButton
} }
addAccountButton
} }
#if !os(visionOS) #if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)
@ -126,6 +149,7 @@ struct SettingsTabs: View {
await timelineCache.clearCache(for: client.id) await timelineCache.clearCache(for: client.id)
await sub.deleteSubscription() await sub.deleteSubscription()
appAccountsManager.delete(account: account) appAccountsManager.delete(account: account)
Telemetry.signal("account.removed")
} }
} }
@ -206,9 +230,6 @@ struct SettingsTabs: View {
} }
.disabled(preferences.preferredBrowser != PreferredBrowser.inAppSafari) .disabled(preferences.preferredBrowser != PreferredBrowser.inAppSafari)
#endif #endif
Toggle(isOn: $preferences.isOpenAIEnabled) {
Label("settings.other.hide-openai", systemImage: "faxmachine")
}
Toggle(isOn: $preferences.isSocialKeyboardEnabled) { Toggle(isOn: $preferences.isSocialKeyboardEnabled) {
Label("settings.other.social-keyboard", systemImage: "keyboard") Label("settings.other.social-keyboard", systemImage: "keyboard")
} }
@ -228,6 +249,40 @@ struct SettingsTabs: View {
#endif #endif
} }
@ViewBuilder
private var postStreamingSection: some View {
@Bindable var preferences = preferences
Section {
Toggle(isOn: $preferences.isPostsStreamingEnabled) {
Label("Posts streaming", systemImage: "clock.badge")
}
} header: {
Text("Streaming")
} footer: {
Text("Enabling post streaming will automatically add new posts at the top of your home timeline. Disable if you get performance issues.")
}
#if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor)
#endif
}
@ViewBuilder
private var AISection: some View {
@Bindable var preferences = preferences
Section {
Toggle(isOn: $preferences.isOpenAIEnabled) {
Label("settings.other.hide-openai", systemImage: "faxmachine")
}
} header: {
Text("AI")
} footer: {
Text("Disable to hide AI assisted tool options such as copywritting and alt-image description generated using AI. Uses OpenAI API. See our Privacy Policy for more information.")
}
#if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor)
#endif
}
private var appSection: some View { private var appSection: some View {
Section { Section {
#if !targetEnvironment(macCatalyst) && !os(visionOS) #if !targetEnvironment(macCatalyst) && !os(visionOS)
@ -236,10 +291,14 @@ struct SettingsTabs: View {
Text("settings.app.icon") Text("settings.app.icon")
} icon: { } icon: {
let icon = IconSelectorView.Icon(string: UIApplication.shared.alternateIconName ?? "AppIcon") let icon = IconSelectorView.Icon(string: UIApplication.shared.alternateIconName ?? "AppIcon")
Image(uiImage: .init(named: icon.appIconName)!) if let image: UIImage = .init(named: icon.previewImageName) {
.resizable() Image(uiImage: image)
.frame(width: 25, height: 25) .resizable()
.cornerRadius(4) .frame(width: 25, height: 25)
.cornerRadius(4)
} else {
EmptyView()
}
} }
} }
#endif #endif
@ -262,10 +321,18 @@ struct SettingsTabs: View {
.tint(theme.labelColor) .tint(theme.labelColor)
} }
NavigationLink(destination: AboutView()) { NavigationLink {
AboutView()
} label: {
Label("settings.app.about", systemImage: "info.circle") Label("settings.app.about", systemImage: "info.circle")
} }
NavigationLink {
WishlistView()
} label: {
Label("Feature Requests", systemImage: "list.bullet.rectangle.portrait")
}
} header: { } header: {
Text("settings.section.app") Text("settings.section.app")
} footer: { } footer: {
@ -282,7 +349,7 @@ struct SettingsTabs: View {
Button { Button {
addAccountSheetPresented.toggle() addAccountSheetPresented.toggle()
} label: { } label: {
Text("settings.account.add") Label("settings.account.add", systemImage: "person.badge.plus")
} }
.sheet(isPresented: $addAccountSheetPresented) { .sheet(isPresented: $addAccountSheetPresented) {
AddAccountView() AddAccountView()
@ -290,21 +357,23 @@ struct SettingsTabs: View {
} }
private var editAccountButton: some View { private var editAccountButton: some View {
Button(role: isEditingAccount ? .none : .destructive) { Button(role: .destructive) {
withAnimation { withAnimation {
isEditingAccount.toggle() isEditingAccount.toggle()
} }
} label: { } label: {
if isEditingAccount { if isEditingAccount {
Text("action.done") Label("action.done", systemImage: "person.badge.minus")
.foregroundStyle(.red)
} else { } else {
Text("account.action.logout") Label("account.action.logout", systemImage: "person.badge.minus")
.foregroundStyle(.red)
} }
} }
} }
private var cacheSection: some View { private var cacheSection: some View {
Section("settings.section.cache") { Section {
if cachedRemoved { if cachedRemoved {
Text("action.done") Text("action.done")
.transition(.move(edge: .leading)) .transition(.move(edge: .leading))
@ -316,6 +385,10 @@ struct SettingsTabs: View {
} }
} }
} }
} header: {
Text("settings.section.cache")
} footer: {
Text("Remove all cached images and videos")
} }
#if !os(visionOS) #if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)

View file

@ -2,6 +2,7 @@ import DesignSystem
import Env import Env
import SwiftUI import SwiftUI
@MainActor
struct SidebarEntriesSettingsView: View { struct SidebarEntriesSettingsView: View {
@Environment(Theme.self) private var theme @Environment(Theme.self) private var theme
@Environment(UserPreferences.self) private var userPreferences @Environment(UserPreferences.self) private var userPreferences
@ -28,8 +29,8 @@ struct SidebarEntriesSettingsView: View {
.environment(\.editMode, .constant(.active)) .environment(\.editMode, .constant(.active))
.navigationTitle("settings.general.sidebarEntries") .navigationTitle("settings.general.sidebarEntries")
#if !os(visionOS) #if !os(visionOS)
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)
.background(theme.secondaryBackgroundColor) .background(theme.secondaryBackgroundColor)
#endif #endif
} }

View file

@ -1,7 +1,6 @@
import DesignSystem import DesignSystem
import Env import Env
import RevenueCat import RevenueCat
import Shimmer
import SwiftUI import SwiftUI
@MainActor @MainActor
@ -70,24 +69,24 @@ struct SupportAppView: View {
} }
.navigationTitle("settings.support.navigation-title") .navigationTitle("settings.support.navigation-title")
#if !os(visionOS) #if !os(visionOS)
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)
.background(theme.secondaryBackgroundColor) .background(theme.secondaryBackgroundColor)
#endif #endif
.alert("settings.support.alert.title", isPresented: $purchaseSuccessDisplayed, actions: { .alert("settings.support.alert.title", isPresented: $purchaseSuccessDisplayed, actions: {
Button { purchaseSuccessDisplayed = false } label: { Text("alert.button.ok") } Button { purchaseSuccessDisplayed = false } label: { Text("alert.button.ok") }
}, message: { }, message: {
Text("settings.support.alert.message") Text("settings.support.alert.message")
}) })
.alert("alert.error", isPresented: $purchaseErrorDisplayed, actions: { .alert("alert.error", isPresented: $purchaseErrorDisplayed, actions: {
Button { purchaseErrorDisplayed = false } label: { Text("alert.button.ok") } Button { purchaseErrorDisplayed = false } label: { Text("alert.button.ok") }
}, message: { }, message: {
Text("settings.support.alert.error.message") Text("settings.support.alert.error.message")
}) })
.onAppear { .onAppear {
loadingProducts = true loadingProducts = true
fetchStoreProducts() fetchStoreProducts()
refreshUserInfo() refreshUserInfo()
} }
} }
private func purchase(product: StoreProduct) async { private func purchase(product: StoreProduct) async {
@ -280,6 +279,5 @@ struct SupportAppView: View {
} }
.redacted(reason: .placeholder) .redacted(reason: .placeholder)
.allowsHitTesting(false) .allowsHitTesting(false)
.shimmering()
} }
} }

View file

@ -70,8 +70,8 @@ struct SwipeActionsSettingsView: View {
} }
.navigationTitle("settings.swipeactions.navigation-title") .navigationTitle("settings.swipeactions.navigation-title")
#if !os(visionOS) #if !os(visionOS)
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)
.background(theme.secondaryBackgroundColor) .background(theme.secondaryBackgroundColor)
#endif #endif
} }

View file

@ -14,28 +14,38 @@ struct TabbarEntriesSettingsView: View {
Form { Form {
Section { Section {
Picker("settings.tabs.first-tab", selection: $tabs.firstTab) { Picker("settings.tabs.first-tab", selection: $tabs.firstTab) {
ForEach(Tab.allCases) { tab in ForEach(AppTab.allCases) { tab in
tab.label.tag(tab) if tab == tabs.firstTab || !tabs.tabs.contains(tab) {
tab.label.tag(tab)
}
} }
} }
Picker("settings.tabs.second-tab", selection: $tabs.secondTab) { Picker("settings.tabs.second-tab", selection: $tabs.secondTab) {
ForEach(Tab.allCases) { tab in ForEach(AppTab.allCases) { tab in
tab.label.tag(tab) if tab == tabs.secondTab || !tabs.tabs.contains(tab) {
tab.label.tag(tab)
}
} }
} }
Picker("settings.tabs.third-tab", selection: $tabs.thirdTab) { Picker("settings.tabs.third-tab", selection: $tabs.thirdTab) {
ForEach(Tab.allCases) { tab in ForEach(AppTab.allCases) { tab in
tab.label.tag(tab) if tab == tabs.thirdTab || !tabs.tabs.contains(tab) {
tab.label.tag(tab)
}
} }
} }
Picker("settings.tabs.fourth-tab", selection: $tabs.fourthTab) { Picker("settings.tabs.fourth-tab", selection: $tabs.fourthTab) {
ForEach(Tab.allCases) { tab in ForEach(AppTab.allCases) { tab in
tab.label.tag(tab) if tab == tabs.fourthTab || !tabs.tabs.contains(tab) {
tab.label.tag(tab)
}
} }
} }
Picker("settings.tabs.fifth-tab", selection: $tabs.fifthTab) { Picker("settings.tabs.fifth-tab", selection: $tabs.fifthTab) {
ForEach(Tab.allCases) { tab in ForEach(AppTab.allCases) { tab in
tab.label.tag(tab) if tab == tabs.fifthTab || !tabs.tabs.contains(tab) {
tab.label.tag(tab)
}
} }
} }
} }
@ -52,8 +62,8 @@ struct TabbarEntriesSettingsView: View {
} }
.navigationTitle("settings.general.tabbarEntries") .navigationTitle("settings.general.tabbarEntries")
#if !os(visionOS) #if !os(visionOS)
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)
.background(theme.secondaryBackgroundColor) .background(theme.secondaryBackgroundColor)
#endif #endif
} }
} }

View file

@ -1,8 +1,8 @@
import SwiftUI
import SwiftData
import Models
import Env
import DesignSystem import DesignSystem
import Env
import Models
import SwiftData
import SwiftUI
struct TagsGroupSettingView: View { struct TagsGroupSettingView: View {
@Environment(\.modelContext) private var context @Environment(\.modelContext) private var context
@ -41,10 +41,10 @@ struct TagsGroupSettingView: View {
.navigationTitle("timeline.filter.tag-groups") .navigationTitle("timeline.filter.tag-groups")
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)
#if !os(visionOS) #if !os(visionOS)
.background(theme.secondaryBackgroundColor) .background(theme.secondaryBackgroundColor)
#endif #endif
.toolbar { .toolbar {
EditButton() EditButton()
} }
} }
} }

View file

@ -11,16 +11,13 @@ struct TranslationSettingsView: View {
var body: some View { var body: some View {
Form { Form {
deepLToggle translationSelector
if preferences.alwaysUseDeepl { if preferences.preferredTranslationType == .useDeepl {
Section("settings.translation.user-api-key") { Section("settings.translation.user-api-key") {
deepLPicker deepLPicker
SecureField("settings.translation.user-api-key", text: $apiKey) SecureField("settings.translation.user-api-key", text: $apiKey)
.textContentType(.password) .textContentType(.password)
} }
.onAppear {
readValue()
}
#if !os(visionOS) #if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)
#endif #endif
@ -37,30 +34,51 @@ struct TranslationSettingsView: View {
#endif #endif
} }
} }
backgroundAPIKey
autoDetectSection autoDetectSection
} }
.navigationTitle("settings.translation.navigation-title") .navigationTitle("settings.translation.navigation-title")
#if !os(visionOS) #if !os(visionOS)
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)
.background(theme.secondaryBackgroundColor) .background(theme.secondaryBackgroundColor)
#endif #endif
.onChange(of: apiKey) { .onChange(of: apiKey) {
writeNewValue() writeNewValue()
} }
.onAppear(perform: updatePrefs) .onAppear(perform: updatePrefs)
.onAppear(perform: readValue)
} }
@ViewBuilder @ViewBuilder
private var deepLToggle: some View { private var translationSelector: some View {
@Bindable var preferences = preferences @Bindable var preferences = preferences
Toggle(isOn: $preferences.alwaysUseDeepl) { Picker("Translation Service", selection: $preferences.preferredTranslationType) {
Text("settings.translation.always-deepl") ForEach(allTTCases, id: \.self) { type in
Text(type.description).tag(type)
}
} }
#if !os(visionOS) #if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)
#endif #endif
} }
var allTTCases: [TranslationType] {
TranslationType.allCases.filter { type in
if type != .useApple {
return true
}
#if canImport(_Translation_SwiftUI)
if #available(iOS 17.4, *) {
return true
} else {
return false
}
#else
return false
#endif
}
}
@ViewBuilder @ViewBuilder
private var deepLPicker: some View { private var deepLPicker: some View {
@Bindable var preferences = preferences @Bindable var preferences = preferences
@ -80,6 +98,34 @@ struct TranslationSettingsView: View {
} footer: { } footer: {
Text("settings.translation.auto-detect-post-language-footer") Text("settings.translation.auto-detect-post-language-footer")
} }
#if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor)
#endif
}
@ViewBuilder
private var backgroundAPIKey: some View {
if preferences.preferredTranslationType != .useDeepl,
!apiKey.isEmpty
{
Section {
Text("The DeepL API Key is still stored!")
if preferences.preferredTranslationType == .useServerIfPossible {
Text("It can however still be used as a fallback for your instance's translation service.")
}
Button(role: .destructive) {
withAnimation {
writeNewValue(value: "")
readValue()
}
} label: {
Text("action.delete")
}
}
#if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor)
#endif
}
} }
private func writeNewValue() { private func writeNewValue() {
@ -91,11 +137,7 @@ struct TranslationSettingsView: View {
} }
private func readValue() { private func readValue() {
if let apiKey = DeepLUserAPIHandler.readIfAllowed() { apiKey = DeepLUserAPIHandler.readKey()
self.apiKey = apiKey
} else {
apiKey = ""
}
} }
private func updatePrefs() { private func updatePrefs() {

View file

@ -0,0 +1,8 @@
import SwiftUI
import WishKit
struct WishlistView: View {
var body: some View {
WishKit.view
}
}

View file

@ -1,4 +1,5 @@
import Account import Account
import AppIntents
import DesignSystem import DesignSystem
import Explore import Explore
import Foundation import Foundation
@ -6,7 +7,7 @@ import StatusKit
import SwiftUI import SwiftUI
@MainActor @MainActor
enum Tab: Int, Identifiable, Hashable, CaseIterable, Codable { enum AppTab: Int, Identifiable, Hashable, CaseIterable, Codable {
case timeline, notifications, mentions, explore, messages, settings, other case timeline, notifications, mentions, explore, messages, settings, other
case trending, federated, local case trending, federated, local
case profile case profile
@ -15,42 +16,43 @@ enum Tab: Int, Identifiable, Hashable, CaseIterable, Codable {
case post case post
case followedTags case followedTags
case lists case lists
case links
nonisolated var id: Int { nonisolated var id: Int {
rawValue rawValue
} }
static func loggedOutTab() -> [Tab] { static func loggedOutTab() -> [AppTab] {
[.timeline, .settings] [.timeline, .settings]
} }
static func visionOSTab() -> [Tab] { static func visionOSTab() -> [AppTab] {
[.profile, .timeline, .notifications, .mentions, .explore, .messages, .settings] [.profile, .timeline, .notifications, .mentions, .explore, .post, .settings]
} }
@ViewBuilder @ViewBuilder
func makeContentView(selectedTab: Binding<Tab>, popToRootTab: Binding<Tab>) -> some View { func makeContentView(selectedTab: Binding<AppTab>) -> some View {
switch self { switch self {
case .timeline: case .timeline:
TimelineTab(popToRootTab: popToRootTab) TimelineTab()
case .trending: case .trending:
TimelineTab(popToRootTab: popToRootTab, timeline: .trending) TimelineTab(timeline: .trending)
case .local: case .local:
TimelineTab(popToRootTab: popToRootTab, timeline: .local) TimelineTab(timeline: .local)
case .federated: case .federated:
TimelineTab(popToRootTab: popToRootTab, timeline: .federated) TimelineTab(timeline: .federated)
case .notifications: case .notifications:
NotificationsTab(selectedTab: selectedTab, popToRootTab: popToRootTab, lockedType: nil) NotificationsTab(selectedTab: selectedTab, lockedType: nil)
case .mentions: case .mentions:
NotificationsTab(selectedTab: selectedTab, popToRootTab: popToRootTab, lockedType: .mention) NotificationsTab(selectedTab: selectedTab, lockedType: .mention)
case .explore: case .explore:
ExploreTab(popToRootTab: popToRootTab) ExploreTab()
case .messages: case .messages:
MessagesTab(popToRootTab: popToRootTab) MessagesTab()
case .settings: case .settings:
SettingsTabs(popToRootTab: popToRootTab, isModal: false) SettingsTabs(isModal: false)
case .profile: case .profile:
ProfileTab(popToRootTab: popToRootTab) ProfileTab()
case .bookmarks: case .bookmarks:
NavigationTab { NavigationTab {
AccountStatusesListView(mode: .bookmarks) AccountStatusesListView(mode: .bookmarks)
@ -67,8 +69,10 @@ enum Tab: Int, Identifiable, Hashable, CaseIterable, Codable {
NavigationTab { NavigationTab {
ListsListView() ListsListView()
} }
case .links:
NavigationTab { TrendingLinksListView(cards: []) }
case .post: case .post:
VStack { } VStack {}
case .other: case .other:
EmptyView() EmptyView()
} }
@ -76,40 +80,47 @@ enum Tab: Int, Identifiable, Hashable, CaseIterable, Codable {
@ViewBuilder @ViewBuilder
var label: some View { var label: some View {
if self != .other {
Label(title, systemImage: iconName)
}
}
var title: LocalizedStringKey {
switch self { switch self {
case .timeline: case .timeline:
Label("tab.timeline", systemImage: iconName) "tab.timeline"
case .trending: case .trending:
Label("tab.trending", systemImage: iconName) "tab.trending"
case .local: case .local:
Label("tab.local", systemImage: iconName) "tab.local"
case .federated: case .federated:
Label("tab.federated", systemImage: iconName) "tab.federated"
case .notifications: case .notifications:
Label("tab.notifications", systemImage: iconName) "tab.notifications"
case .mentions: case .mentions:
Label("tab.mentions", systemImage: iconName) "tab.mentions"
case .explore: case .explore:
Label("tab.explore", systemImage: iconName) "tab.explore"
case .messages: case .messages:
Label("tab.messages", systemImage: iconName) "tab.messages"
case .settings: case .settings:
Label("tab.settings", systemImage: iconName) "tab.settings"
case .profile: case .profile:
Label("tab.profile", systemImage: iconName) "tab.profile"
case .bookmarks: case .bookmarks:
Label("accessibility.tabs.profile.picker.bookmarks", systemImage: iconName) "accessibility.tabs.profile.picker.bookmarks"
case .favorites: case .favorites:
Label("accessibility.tabs.profile.picker.favorites", systemImage: iconName) "accessibility.tabs.profile.picker.favorites"
case .post: case .post:
Label("menu.new-post", systemImage: iconName) "menu.new-post"
case .followedTags: case .followedTags:
Label("timeline.filter.tags", systemImage: iconName) "timeline.filter.tags"
case .lists: case .lists:
Label("timeline.filter.lists", systemImage: iconName) "timeline.filter.lists"
case .links:
"explore.section.trending.links"
case .other: case .other:
EmptyView() ""
} }
} }
@ -145,16 +156,19 @@ enum Tab: Int, Identifiable, Hashable, CaseIterable, Codable {
"tag" "tag"
case .lists: case .lists:
"list.bullet" "list.bullet"
case .links:
"newspaper"
case .other: case .other:
"" ""
} }
} }
} }
@MainActor
@Observable @Observable
class SidebarTabs { class SidebarTabs {
struct SidedebarTab: Hashable, Codable { struct SidedebarTab: Hashable, Codable {
let tab: Tab let tab: AppTab
var enabled: Bool var enabled: Bool
} }
@ -172,6 +186,7 @@ class SidebarTabs {
.init(tab: .favorites, enabled: true), .init(tab: .favorites, enabled: true),
.init(tab: .followedTags, enabled: true), .init(tab: .followedTags, enabled: true),
.init(tab: .lists, enabled: true), .init(tab: .lists, enabled: true),
.init(tab: .links, enabled: true),
.init(tab: .settings, enabled: true), .init(tab: .settings, enabled: true),
.init(tab: .profile, enabled: true), .init(tab: .profile, enabled: true),
@ -187,7 +202,7 @@ class SidebarTabs {
} }
} }
func isEnabled(_ tab: Tab) -> Bool { func isEnabled(_ tab: AppTab) -> Bool {
tabs.first(where: { $0.tab.id == tab.id })?.enabled == true tabs.first(where: { $0.tab.id == tab.id })?.enabled == true
} }
@ -196,6 +211,7 @@ class SidebarTabs {
} }
} }
@MainActor
@Observable @Observable
class iOSTabs { class iOSTabs {
enum TabEntries: String { enum TabEntries: String {
@ -203,45 +219,45 @@ class iOSTabs {
} }
class Storage { class Storage {
@AppStorage(TabEntries.first.rawValue) var firstTab = Tab.timeline @AppStorage(TabEntries.first.rawValue) var firstTab = AppTab.timeline
@AppStorage(TabEntries.second.rawValue) var secondTab = Tab.notifications @AppStorage(TabEntries.second.rawValue) var secondTab = AppTab.notifications
@AppStorage(TabEntries.third.rawValue) var thirdTab = Tab.explore @AppStorage(TabEntries.third.rawValue) var thirdTab = AppTab.explore
@AppStorage(TabEntries.fourth.rawValue) var fourthTab = Tab.messages @AppStorage(TabEntries.fourth.rawValue) var fourthTab = AppTab.links
@AppStorage(TabEntries.fifth.rawValue) var fifthTab = Tab.profile @AppStorage(TabEntries.fifth.rawValue) var fifthTab = AppTab.profile
} }
private let storage = Storage() private let storage = Storage()
public static let shared = iOSTabs() public static let shared = iOSTabs()
var tabs: [Tab] { var tabs: [AppTab] {
[firstTab, secondTab, thirdTab, fourthTab, fifthTab] [firstTab, secondTab, thirdTab, fourthTab, fifthTab]
} }
var firstTab: Tab { var firstTab: AppTab {
didSet { didSet {
storage.firstTab = firstTab storage.firstTab = firstTab
} }
} }
var secondTab: Tab { var secondTab: AppTab {
didSet { didSet {
storage.secondTab = secondTab storage.secondTab = secondTab
} }
} }
var thirdTab: Tab { var thirdTab: AppTab {
didSet { didSet {
storage.thirdTab = thirdTab storage.thirdTab = thirdTab
} }
} }
var fourthTab: Tab { var fourthTab: AppTab {
didSet { didSet {
storage.fourthTab = fourthTab storage.fourthTab = fourthTab
} }
} }
var fifthTab: Tab { var fifthTab: AppTab {
didSet { didSet {
storage.fifthTab = fifthTab storage.fifthTab = fifthTab
} }

View file

@ -5,7 +5,6 @@ import Models
import Network import Network
import NukeUI import NukeUI
import SFSafeSymbols import SFSafeSymbols
import Shimmer
import SwiftData import SwiftData
import SwiftUI import SwiftUI
@ -39,7 +38,9 @@ struct EditTagGroupView: View {
focusedField: $focusedField focusedField: $focusedField
) )
} }
#if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)
#endif
Section("add-tag-groups.edit.tags") { Section("add-tag-groups.edit.tags") {
TagsInputView( TagsInputView(
@ -48,7 +49,9 @@ struct EditTagGroupView: View {
focusedField: $focusedField focusedField: $focusedField
) )
} }
#if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)
#endif
} }
.formStyle(.grouped) .formStyle(.grouped)
.navigationTitle( .navigationTitle(
@ -58,22 +61,20 @@ struct EditTagGroupView: View {
) )
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
#if !os(visionOS) #if !os(visionOS)
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)
.background(theme.secondaryBackgroundColor) .background(theme.secondaryBackgroundColor)
.scrollDismissesKeyboard(.interactively) .scrollDismissesKeyboard(.interactively)
#endif #endif
.toolbar { .toolbar {
ToolbarItem(placement: .navigationBarLeading) { CancelToolbarItem()
Button("action.cancel", action: { dismiss() }) ToolbarItem(placement: .navigationBarTrailing) {
Button("action.save", action: { save() })
.disabled(!tagGroup.isValid)
}
} }
ToolbarItem(placement: .navigationBarTrailing) { .onAppear {
Button("action.save", action: { save() }) focusedField = .title
.disabled(!tagGroup.isValid)
} }
}
.onAppear {
focusedField = .title
}
} }
} }

View file

@ -4,7 +4,6 @@ import Env
import Models import Models
import Network import Network
import NukeUI import NukeUI
import Shimmer
import SwiftUI import SwiftUI
@MainActor @MainActor
@ -38,6 +37,11 @@ struct AddRemoteTimelineView: View {
.foregroundColor(.green) .foregroundColor(.green)
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)
} }
if !instanceName.isEmpty && instance == nil {
Label("timeline.\(instanceName)-not-valid", systemImage: "xmark.seal.fill")
.foregroundColor(.red)
.listRowBackground(theme.primaryBackgroundColor)
}
Button { Button {
guard instance != nil else { return } guard instance != nil else { return }
context.insert(LocalTimeline(instance: instanceName)) context.insert(LocalTimeline(instance: instanceName))
@ -46,6 +50,7 @@ struct AddRemoteTimelineView: View {
Text("timeline.add.action.add") Text("timeline.add.action.add")
} }
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)
.disabled(instance == nil)
instancesListView instancesListView
} }
@ -53,31 +58,30 @@ struct AddRemoteTimelineView: View {
.navigationTitle("timeline.add-remote.title") .navigationTitle("timeline.add-remote.title")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
#if !os(visionOS) #if !os(visionOS)
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)
.background(theme.secondaryBackgroundColor) .background(theme.secondaryBackgroundColor)
.scrollDismissesKeyboard(.immediately) .scrollDismissesKeyboard(.immediately)
#endif #endif
.toolbar { .toolbar {
ToolbarItem(placement: .navigationBarLeading) { CancelToolbarItem()
Button("action.cancel", action: { dismiss() })
} }
} .onChange(of: instanceName) { _, newValue in
.onChange(of: instanceName) { _, newValue in instanceNamePublisher.send(newValue)
instanceNamePublisher.send(newValue)
}
.onReceive(instanceNamePublisher.debounce(for: .milliseconds(500), scheduler: DispatchQueue.main)) { newValue in
Task {
let client = Client(server: newValue)
instance = try? await client.get(endpoint: Instances.instance)
} }
} .onReceive(instanceNamePublisher.debounce(for: .milliseconds(500), scheduler: DispatchQueue.main)) { newValue in
.onAppear { Task {
isInstanceURLFieldFocused = true let client = Client(server: newValue)
let client = InstanceSocialClient() instance = try? await client.get(endpoint: Instances.instance)
Task { }
instances = await client.fetchInstances(keyword: instanceName) }
.onAppear {
isInstanceURLFieldFocused = true
let client = InstanceSocialClient()
let instanceName = instanceName
Task {
instances = await client.fetchInstances(keyword: instanceName)
}
} }
}
} }
} }

View file

@ -18,12 +18,10 @@ struct TimelineTab: View {
@Environment(UserPreferences.self) private var preferences @Environment(UserPreferences.self) private var preferences
@Environment(Client.self) private var client @Environment(Client.self) private var client
@State private var routerPath = RouterPath() @State private var routerPath = RouterPath()
@Binding var popToRootTab: Tab
@State private var didAppear: Bool = false @State private var didAppear: Bool = false
@State private var timeline: TimelineFilter = .home @State private var timeline: TimelineFilter = .home
@State private var selectedTagGroup: TagGroup? @State private var selectedTagGroup: TagGroup?
@State private var scrollToTopSignal: Int = 0
@Query(sort: \LocalTimeline.creationDate, order: .reverse) var localTimelines: [LocalTimeline] @Query(sort: \LocalTimeline.creationDate, order: .reverse) var localTimelines: [LocalTimeline]
@Query(sort: \TagGroup.creationDate, order: .reverse) var tagGroups: [TagGroup] @Query(sort: \TagGroup.creationDate, order: .reverse) var tagGroups: [TagGroup]
@ -33,9 +31,8 @@ struct TimelineTab: View {
private let canFilterTimeline: Bool private let canFilterTimeline: Bool
init(popToRootTab: Binding<Tab>, timeline: TimelineFilter? = nil) { init(timeline: TimelineFilter? = nil) {
canFilterTimeline = timeline == nil canFilterTimeline = timeline == nil
_popToRootTab = popToRootTab
_timeline = .init(initialValue: timeline ?? .home) _timeline = .init(initialValue: timeline ?? .home)
} }
@ -44,14 +41,13 @@ struct TimelineTab: View {
TimelineView(timeline: $timeline, TimelineView(timeline: $timeline,
pinnedFilters: $pinnedFilters, pinnedFilters: $pinnedFilters,
selectedTagGroup: $selectedTagGroup, selectedTagGroup: $selectedTagGroup,
scrollToTopSignal: $scrollToTopSignal,
canFilterTimeline: canFilterTimeline) canFilterTimeline: canFilterTimeline)
.withAppRouter() .withAppRouter()
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet) .withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
.toolbar { .toolbar {
toolbarView toolbarView
} }
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.50), for: .navigationBar) .toolbarBackground(theme.primaryBackgroundColor.opacity(0.30), for: .navigationBar)
.id(client.id) .id(client.id)
} }
.onAppear { .onAppear {
@ -61,31 +57,22 @@ struct TimelineTab: View {
if client.isAuth { if client.isAuth {
timeline = lastTimelineFilter timeline = lastTimelineFilter
} else { } else {
timeline = .federated timeline = .trending
} }
} }
Task {
await currentAccount.fetchLists()
}
if !client.isAuth { if !client.isAuth {
routerPath.presentedSheet = .addAccount routerPath.presentedSheet = .addAccount
} }
} }
.task {
await currentAccount.fetchLists()
}
.onChange(of: client.isAuth) { .onChange(of: client.isAuth) {
resetTimelineFilter() resetTimelineFilter()
} }
.onChange(of: currentAccount.account?.id) { .onChange(of: currentAccount.account?.id) {
resetTimelineFilter() resetTimelineFilter()
} }
.onChange(of: $popToRootTab.wrappedValue) { _, newValue in
if newValue == .timeline {
if routerPath.path.isEmpty {
scrollToTopSignal += 1
} else {
routerPath.path = []
}
}
}
.onChange(of: client.id) { .onChange(of: client.id) {
routerPath.path = [] routerPath.path = []
} }
@ -95,7 +82,7 @@ struct TimelineTab: View {
} }
switch newValue { switch newValue {
case let .tagGroup(title, _, _): case let .tagGroup(title, _, _):
if let group = tagGroups.first(where: { $0.title == title}) { if let group = tagGroups.first(where: { $0.title == title }) {
selectedTagGroup = group selectedTagGroup = group
} }
default: default:
@ -123,16 +110,16 @@ struct TimelineTab: View {
@ViewBuilder @ViewBuilder
private var timelineFilterButton: some View { private var timelineFilterButton: some View {
latestOrResumeButtons headerGroup
contentFilterButton
Divider()
pinMenuButton
Divider()
timelineFiltersButtons timelineFiltersButtons
listsFiltersButons if client.isAuth {
tagsFiltersButtons listsFiltersButons
tagsFiltersButtons
}
localTimelinesFiltersButtons localTimelinesFiltersButtons
tagGroupsFiltersButtons tagGroupsFiltersButtons
Divider()
contentFilterButton
} }
private var addAccountButton: some View { private var addAccountButton: some View {
@ -189,12 +176,14 @@ struct TimelineTab: View {
} }
@ViewBuilder @ViewBuilder
private var latestOrResumeButtons: some View { private var headerGroup: some View {
if timeline.supportNewestPagination { ControlGroup {
Button { if timeline.supportNewestPagination {
timeline = .latest Button {
} label: { timeline = .latest
Label(TimelineFilter.latest.localizedTitle(), systemImage: TimelineFilter.latest.iconName()) } label: {
Label(TimelineFilter.latest.localizedTitle(), systemImage: TimelineFilter.latest.iconName())
}
} }
if timeline == .home { if timeline == .home {
Button { Button {
@ -206,22 +195,25 @@ struct TimelineTab: View {
} }
} }
} }
pinButton
} }
} }
@ViewBuilder @ViewBuilder
private var pinMenuButton: some View { private var pinButton: some View {
let index = pinnedFilters.firstIndex(where: { $0.id == timeline.id}) let index = pinnedFilters.firstIndex(where: { $0.id == timeline.id })
Button { Button {
withAnimation { withAnimation {
if let index { if let index {
pinnedFilters.remove(at: index) let timeline = pinnedFilters.remove(at: index)
Telemetry.signal("timeline.pin.removed", parameters: ["timeline" : timeline.rawValue])
} else { } else {
pinnedFilters.append(timeline) pinnedFilters.append(timeline)
Telemetry.signal("timeline.pin.added", parameters: ["timeline" : timeline.rawValue])
} }
} }
} label: { } label: {
if index != nil { if index != nil {
Label("status.action.unpin", systemImage: "pin.slash") Label("status.action.unpin", systemImage: "pin.slash")
} else { } else {
Label("status.action.pin", systemImage: "pin") Label("status.action.pin", systemImage: "pin")
@ -324,7 +316,7 @@ struct TimelineTab: View {
if client.isAuth, canFilterTimeline { if client.isAuth, canFilterTimeline {
timeline = lastTimelineFilter timeline = lastTimelineFilter
} else if !client.isAuth { } else if !client.isAuth {
timeline = .federated timeline = .trending
} }
} }
} }

View file

@ -1,7 +1,7 @@
import SwiftUI
import Env
import AppAccount import AppAccount
import DesignSystem import DesignSystem
import Env
import SwiftUI
@MainActor @MainActor
struct ToolbarTab: ToolbarContent { struct ToolbarTab: ToolbarContent {
@ -9,17 +9,36 @@ struct ToolbarTab: ToolbarContent {
@Environment(\.horizontalSizeClass) private var horizontalSizeClass @Environment(\.horizontalSizeClass) private var horizontalSizeClass
@Environment(UserPreferences.self) private var userPreferences @Environment(UserPreferences.self) private var userPreferences
@Environment(Theme.self) private var theme
@Binding var routerPath: RouterPath @Binding var routerPath: RouterPath
var body: some ToolbarContent { var body: some ToolbarContent {
if !isSecondaryColumn { if !isSecondaryColumn {
if horizontalSizeClass == .regular {
ToolbarItem(placement: .topBarLeading) {
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
Button {
withAnimation {
userPreferences.isSidebarExpanded.toggle()
}
} label: {
if userPreferences.isSidebarExpanded {
Image(systemName: "sidebar.squares.left")
} else {
Image(systemName: "sidebar.left")
}
}
}
}
}
statusEditorToolbarItem(routerPath: routerPath, statusEditorToolbarItem(routerPath: routerPath,
visibility: userPreferences.postVisibility) visibility: userPreferences.postVisibility)
if UIDevice.current.userInterfaceIdiom != .pad || if UIDevice.current.userInterfaceIdiom != .pad ||
(UIDevice.current.userInterfaceIdiom == .pad && horizontalSizeClass == .compact) { (UIDevice.current.userInterfaceIdiom == .pad && horizontalSizeClass == .compact)
{
ToolbarItem(placement: .navigationBarLeading) { ToolbarItem(placement: .navigationBarLeading) {
AppAccountsSelectorView(routerPath: routerPath) AppAccountsSelectorView(routerPath: routerPath, avatarConfig: theme.avatarShape == .circle ? .badge : .badgeRounded)
} }
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View file

Before

Width:  |  Height:  |  Size: 156 KiB

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 KiB

View file

@ -1,67 +1,91 @@
{ {
"images" : [ "images" : [
{ {
"filename" : "AppIcon.png", "filename" : "AppIcon-fs8.png",
"idiom" : "universal", "idiom" : "universal",
"platform" : "ios", "platform" : "ios",
"size" : "1024x1024" "size" : "1024x1024"
}, },
{ {
"filename" : "Icon-16.png", "appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "dark.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "tinted"
}
],
"filename" : "tinted.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"filename" : "16.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "1x", "scale" : "1x",
"size" : "16x16" "size" : "16x16"
}, },
{ {
"filename" : "Icon-32.png", "filename" : "32.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "2x", "scale" : "2x",
"size" : "16x16" "size" : "16x16"
}, },
{ {
"filename" : "Icon-32 1.png", "filename" : "32 1.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "1x", "scale" : "1x",
"size" : "32x32" "size" : "32x32"
}, },
{ {
"filename" : "Icon-64.png", "filename" : "64.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "2x", "scale" : "2x",
"size" : "32x32" "size" : "32x32"
}, },
{ {
"filename" : "Icon-128.png", "filename" : "128.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "1x", "scale" : "1x",
"size" : "128x128" "size" : "128x128"
}, },
{ {
"filename" : "Icon-256 1.png", "filename" : "256 1.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "2x", "scale" : "2x",
"size" : "128x128" "size" : "128x128"
}, },
{ {
"filename" : "Icon-256.png", "filename" : "256.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "1x", "scale" : "1x",
"size" : "256x256" "size" : "256x256"
}, },
{ {
"filename" : "Icon-512 1.png", "filename" : "512 1.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "2x", "scale" : "2x",
"size" : "256x256" "size" : "256x256"
}, },
{ {
"filename" : "Icon-512.png", "filename" : "512.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "1x", "scale" : "1x",
"size" : "512x512" "size" : "512x512"
}, },
{ {
"filename" : "Icon-1024.png", "filename" : "Content.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "2x", "scale" : "2x",
"size" : "512x512" "size" : "512x512"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 501 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 734 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 545 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 764 KiB

View file

@ -1,7 +1,7 @@
{ {
"images" : [ "images" : [
{ {
"filename" : "Back.png", "filename" : "Background.png",
"idiom" : "vision", "idiom" : "vision",
"scale" : "2x" "scale" : "2x"
} }

View file

@ -1,7 +1,7 @@
{ {
"images" : [ "images" : [
{ {
"filename" : "Front.png", "filename" : "Layer 1.png",
"idiom" : "vision", "idiom" : "vision",
"scale" : "2x" "scale" : "2x"
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 543 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 KiB

View file

@ -1,7 +1,6 @@
{ {
"images" : [ "images" : [
{ {
"filename" : "Middle.png",
"idiom" : "vision", "idiom" : "vision",
"scale" : "2x" "scale" : "2x"
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "AppIcon-fs8.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "1024.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "AppIconAlternate10.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "icon15.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "icon16.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "icon17.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "icon18.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "AppIconAlternate15.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "icon.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "Alternate43-fs8.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

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