A SwiftUI Mastodon client
Find a file
Thomas Ricouard 24cccfad1d
Ice Cubes 2.0 + iOS 26 supports (#2280)
* iOS 26 compiles

* New compose accessory view

* Better GlassEffectContainer transition

* Fixes

* Drop iOS 17 + Timeline filters at bottom

* Glass status observer

* Fixes

* More fixes

* Disable tabbar collapse

* Refacor timeline checkpoint

* Tyding code

* Set version to 2.0

* Remove fast timeline setting

* Perf fixes

* Remove custom Sidebar

* Perf boost + remove content gradient

* Fixes

* Remove steaming

* Fix TL

* Use Tab

* Fix separators

* Better sheet

* Editor enhance

* Leading status row actions

* More iOS 26 fixes

* Fix context menu tint color

* Fix app account sheet

* Fix extension send button

* New Icons

* AppIcon

* Add back VisionOS Icon

* Working icon

* Update Claude.MD

* WIP Playground

* Replace OpenAI with FoundationModels

* Stream response

* Prewarm Assistant on editor open

* Add more LLM tools

* Fixes

* Remove contentWarning prompt

* Update packages to Swift 6.2

* Various iOS 26 fixes

* Prepare birictional gap

* Add sections for iPad sidebar

* Fix profile status update

* Make StatusesState Equatable

* Disable LLM on macCatalyst for now

* Add Tags and Lists to sideabar

* Add local timeline and tags group in the sidebar

* Account: Refine header view

* Show non LLM tag

* Support V2 notifications group

* Refactor NotificationsViewModel

* Fix initial gap

* Notifications list: Add glassEffect

* Set editor glass effect to interactive

* Refactor TimelineView

* Notifications: Merge new group

* Notifications: Refactor VM

* Notifications: Cleanup code

* Liquid glass DM View

* Add direct access to DM in notifications top menu

* Editor: Fix sizing on mention/tags

* Better DM detail view

* DM: More refactor view

* DM: Even better views

* DM: Rework media attachements

* DM: Interactive textfield

* Notifications: Refactor and remove ViewModel

* DM: Refactor and remove ViewModel

* DM Detail: Refactor without ViewModel

* Remove sub.club support

* DM Detail: Fix loading

* Icons cleanup

* Tweak icons

* Account Detail: Refactor sub tabs

* More icons

* Account Detail: Remove ViewModel

* Account Detail: Refactor to smaller views

* Explore: Refactor to components + inline state

* Accounts Statuses: Refactor + remove VM

* Edit note: Remove VM

* Trim AccountDetail

* Account: Set button to primary color

* Fixes

* Improve UI consistency and context menus in media and notifications

Refactored MediaView to use context menus instead of Menu for media items and updated alt/discard marker buttons for iOS 26 compatibility. Added .tint(.label) to notification filter buttons for consistent appearance. Minor code style and import order improvements in AppView.

* Add .glassProminent

* Fix warnings

* Refactor compressVideo to use async/await

Updated the compressVideo function to use Swift's async/await syntax instead of withCheckedContinuation, simplifying the code and improving readability.

* Rename SPM Network -> NetworkClient

* Fix build

* Client -> MastodonClient

* Rename file

* Refactor media container to use state-based model

Replaces the previous MediaContainer property model with a state-based enum to better represent the lifecycle of media (pending, uploading, uploaded, failed). Updates MediaView and ViewModel to use the new state model, improving clarity and error handling for media uploads, progress, and failures. Adds convenience initializers and factory methods for creating containers in various states, and updates UI logic to match the new structure.

* Add media upload progress tracking and UI updates

Introduces progress tracking for media uploads in MastodonClient by adding new upload methods with progress handlers and a URLSession delegate. Updates StatusEditor ViewModel to pass progress handlers and update media container state during uploads. Enhances MediaView to display both circular and linear progress indicators with animation.

* Refactor message view to use glass effect on iOS 26+

Introduces a conditional to use .glassEffect for message backgrounds on iOS 26 and above, while maintaining the previous background logic for earlier versions. Extracts the message text rendering into a reusable textView property for cleaner code.

* Test removing legacy app icon

* Revert "Test removing legacy app icon"

This reverts commit 27c552d3cb.

* Refactor timeline pills and tab bar for iOS 26 compatibility

Moved TimelineQuickAccessPills logic from AppView to TimelineView and updated implementation to use new iOS 26 APIs where available. Simplified tab bar view in AppView and improved conditional logic for iPad and Mac layouts.

* Update glassEffect to use .regular.interactive()

Replaces the default glassEffect modifier with .regular.interactive() for improved visual consistency and interaction feedback on FollowButton and related controls.

* Improve progress indicator logic and remove iOS version check

Refines the display logic for progress indicators in MediaView, showing a linear progress bar only when progress is between 0 and 1, and otherwise showing a circular indicator. Also removes an unnecessary iOS version check in TimelineView for toolbar background visibility.

* Update screenshots

* Update toolbar tint and improve account fields UI

Added `.tint(.label)` to several toolbar items for consistent icon coloring. Refactored AccountFieldsView to support iOS 26+ visual effects and improved accessibility and background handling. Removed redundant `.tint(.label)` from NotificationsListView.

* Add zoom transition for MediaUI

* Remove Old AppIcon

* Remove alternate icons assets

* Update sign-in button style and layout in AddAccountView

Refactors the sign-in button to use a new 'signinButton' view, applying .glassProminent style on iOS 26+ and .borderedProminent otherwise. Adjusts button layout for full width, sets a fixed height, and updates row insets and background for improved appearance.

* Remove iPhone tab label preference setting

Eliminated the 'showiPhoneTabLabel' toggle from TabbarEntriesSettingsView and related property from UserPreferences. This streamlines settings by removing an unused or deprecated option.

* Fix text replacement in StatusEditor ViewModel

Updated the async stream handling in StatusEditor to use the 'content' property of the streamed object when replacing text, ensuring correct text updates.

* Update UI for iOS 26 and improve avatar effects

Refactored ToolbarTab and AppAccountsSelectorView to use .embed avatarConfig and apply glassEffect on iOS 26+. Updated contentShape to .circle for better interaction. Added theme-based tint to notification list buttons for improved visual consistency.

* Add optional caption to Mastodon post intent (#2292)

* Add app shortcut and intent for inline image posting on Mastodon (#2293)

* Add optional alt text to image upload intents (#2294)

* Adjust toolbar label offset for iOS 26 (#2296)

* Improve background handling in Explore and Editor views

Updated ExploreView to use edgesIgnoringSafeArea for the background color and made minor formatting improvements. Refactored MainView in StatusEditor to use a computed backgroundColor view for better background management based on presentationDetent.

* Remove macCatalyst conditional compilation for AI features

Eliminated #if !targetEnvironment(macCatalyst) checks from AI-related components in the status editor, making AI features available on all platforms where iOS 26+ is supported. Also added new localization keys related to image posting and descriptions.

* Add ToolbarSpacer and improve toolbar styling

Introduces ToolbarSpacer with .topBarTrailing placement for iOS 26.0+ in NotificationTab, TimelineTab, and TimelineView to improve toolbar layout. Updates toolbar item placements and adds theme-based foreground styling to toolbar icons. Removes unnecessary line limit in NotificationRowContentView and adjusts line limit logic in StatusRowTextView for better text display. Refactors some pattern matching for clarity.
2025-08-27 07:37:20 +02:00
.github Add SwiftPolyglot to validate localizations (#2011) 2024-03-25 08:48:44 +01:00
.vscode Add CLAUDE.MD 2025-06-05 06:59:54 +02:00
AlternateIcons Ice Cubes 2.0 + iOS 26 supports (#2280) 2025-08-27 07:37:20 +02:00
AppIcon.icon Ice Cubes 2.0 + iOS 26 supports (#2280) 2025-08-27 07:37:20 +02:00
ci_scripts Only upload on EmergeTools workflow 2024-09-27 09:29:05 +02:00
IceCubesActionExtension Ice Cubes 2.0 + iOS 26 supports (#2280) 2025-08-27 07:37:20 +02:00
IceCubesApp Ice Cubes 2.0 + iOS 26 supports (#2280) 2025-08-27 07:37:20 +02:00
IceCubesApp.xcodeproj Ice Cubes 2.0 + iOS 26 supports (#2280) 2025-08-27 07:37:20 +02:00
IceCubesAppIntents Ice Cubes 2.0 + iOS 26 supports (#2280) 2025-08-27 07:37:20 +02:00
IceCubesAppWidgetsExtension Ice Cubes 2.0 + iOS 26 supports (#2280) 2025-08-27 07:37:20 +02:00
IceCubesNotifications Ice Cubes 2.0 + iOS 26 supports (#2280) 2025-08-27 07:37:20 +02:00
IceCubesShareExtension Ice Cubes 2.0 + iOS 26 supports (#2280) 2025-08-27 07:37:20 +02:00
Images New App Icon 2024-01-21 09:31:50 +01:00
Packages Ice Cubes 2.0 + iOS 26 supports (#2280) 2025-08-27 07:37:20 +02:00
screenshots.pco Ice Cubes 2.0 + iOS 26 supports (#2280) 2025-08-27 07:37:20 +02:00
.gitignore Add VSCode settings file 2024-10-28 10:42:47 +01:00
.swiftformat Swiftformat 2023-01-17 11:36:01 +01:00
CLAUDE.md Ice Cubes 2.0 + iOS 26 supports (#2280) 2025-08-27 07:37:20 +02:00
IceCubesApp-release.xcconfig xcconfig Support (#342) 2023-01-24 17:29:20 +01:00
IceCubesApp.xcconfig.template xcconfig Support (#342) 2023-01-24 17:29:20 +01:00
LICENSE Update LICENSE 2024-02-10 08:53:49 +01:00
PRIVACY.MD Add TelemetryDeck 2024-08-14 17:23:10 +02:00
README.md Add more readme badges 2024-10-10 08:59:40 +02:00
TERMS.MD Add supporter subscription + supporter badge 2023-03-01 20:07:40 +01:00

IceCubesApp

Download on the App Store

Swift Version License: AGPL v3

IceCubesApp is an open-source application for accessing the decentralized social network Mastodon! It's built entirely in SwiftUI, making it fast, lightweight, and easy to use.

You can connect to any Mastodon instance, browse your timeline, interact with other users, and post updates and media.

It's multiplatform and works on iOS, macOS, iPadOS, and visionOS. It has a dedicated UI with a sidebar on macOS and iPadOS.

Features

Timeline

  • A navigation bar title menu lets you easily swap between your home, local, federated, and trending timeline.
  • You can also easily access your lists, followed tags, and tag groups.
  • Tag groups are custom timelines made of multiple tags, a feature unique to Ice Cubes.
  • Quote post!
  • You can also add a remote local timeline. A helpful feature to browse the public timeline of other instances. Another Ice Cubes only feature.
  • Ice Cubes relies heavily on the streaming events of Mastodon to do stuff like showing new posts live in the home timeline and editing and deleting your posts.
  • The timeline sync is semi-automatic; your position is sent to the Mastodon marker API, and from another device running Ice Cubes, you can resume your home timeline position.
  • The home timeline is cached using the third-party library Bodega. A lite SQLite wrappers. The current position is saved in user default, so when you switch accounts or launch the app, your cached home timeline and position are restored. Then new posts will be fetched and displayed with an unread counter.
  • iCloud sync of tag groups, remote timelines and drafts.
  • Server side filters support.
  • Create and switch to your lists.

Code -> Status & Timeline package

Editor / Composer

  • Full-featured post editor.
  • You can write threads up to 5 posts.
  • Upload up to 4 images.
  • AI-assisted tools using OpenAI API for text correction, hashtag generation, and more.
  • Generate image description using AI!
  • Custom emojis support.
  • Add polls and content warnings.
  • Save/restore from drafts.
  • Use the Apple language detection feature to suggest the language before posting.

Code -> Status package -> StatusEditor component Code -> OpenAIClient

Notifications

  • Full support for push notifications.
  • Ice Cubes runs its proxy between Mastodon and APNS, which is necessary for Mastodon to route push notifications to the user's device.
  • Push notifications are never and can't be read by the proxy.
  • Push notifications content/body is decoded on the device. Look for NotificationServiceSupport
  • Push notifications are rich, and use Apple INSendMessageIntent API for contact pictures.
  • Push notifications are grouped by activities, like mentions, favorites, boosts, etc...
  • Notifications within the app are also grouped/stacked.
  • You can select which kind of push notifications you want to receive within the app.
  • Route to the correct post and switch to the proper account when taping notifications.

Code -> Notifications package and NotificationService extension.

  • Dedicated explore/search tab for trending users, tags, posts, and links.
  • Easy access to all those categories from the top area.
  • You can search for everything or filter by users, tags, and posts.
  • See a graph for the activities on the trending tags.
  • See more from each category to access the full-screen view.

Code -> Explore package

Direct Messages

  • Dedicated tab for direct/private messages.
  • Chat like UI
  • You can use the inline composer for a quick chat or the full editor.

Code -> Conversations package

Profile

  • Rich profile support.
  • Fully access & tweak your privacy settings.
  • Edit your profile, from your bio to your custom fields.
  • Easy access to Mastometrics.
  • Add a custom server-side note visible only to you for any profile.
  • Translate the bio of any profile to your language.
  • Easy access to edit your server-side timeline filters.
  • Easy access to share your profile outside of the app.

Code -> Account package

Multi Accounts

  • Support for an unlimited number of Mastodon accounts.
  • Easily browse/discover instances and log in!
  • Swap account from any screen on iOS.
  • Swap your account from the macOS/iPadOS sidebar with just one click.
  • Full server-side and client-side account settings support.
  • Swipe to delete an account from the settings.
  • Safe authentication using Apple's WebAuthenticationSession
  • The account token is securely stored in the keychain.

Code -> Account & AppAcount packages

Other

  • You can support this project with tips in the app and Github sponsoring.
  • Massive amount of customization settings.
  • You can tweak the display settings like the font, line spacing, status actions buttons, etc...
  • Many built-in themes.
  • Make your theme.
  • Customize your swipe gestures.
  • Customize your tabbar entries.
  • Sound & haptic feedback support.

A note on the architecture

The project is split into different Swift Packages to make managing and maintaining the codebase easier. Each package focuses on a specific application aspect, such as the UI, network communication, or data models. This modular approach allows for easier collaboration and ensures the code is organized and easily understood.

It's a great starting point for learning SwiftUI. The app covers many of the basic concepts of SwiftUI, such as building layouts, working with data, and handling user interaction. By exploring the code, you can understand how to use SwiftUI in your daily life. Plus, the open-source nature of IceCubesApp means you can see how real-world applications are built and get a sense of best practices for using SwiftUI.

The architecture is straightforward MVVM for most parts, there is no redux on this one ;)

Thanks!

Building the project

To build the project, you need to clone the repo and create a copy of the included .xcconfig file to create your config before you can compile the project. Otherwise, you will get an error.

Here are the steps:

  1. Clone the repo
  2. In the same folder that contains the IceCubesApp.xcconfig.template, run this command:
cp IceCubesApp.xcconfig.template IceCubesApp.xcconfig
  1. Fill in the DEVELOPMENT_TEAM and BUNDLE_ID_PREFIX values. The first should have your Apple Team ID (which you can find by logging into the Apple Developer Portal). The latter is your domain in reverse notation or whatever you use as the prefix for your projects.
  2. Save your changes, and then you should be able to compile the project without any issues.