Merge branch 'develop' into performance_experiments

This commit is contained in:
Nathan Mattes 2023-10-11 13:04:29 +02:00
commit 785751aca4
80 changed files with 1469 additions and 748 deletions

View File

@ -7,6 +7,6 @@ set -eo pipefail
xcodebuild -workspace Mastodon.xcworkspace \
-scheme Mastodon \
-destination "platform=iOS Simulator,name=iPhone SE (2nd generation)" \
-destination "platform=iOS Simulator,name=iPhone SE (3rd generation)" \
clean \
build | xcpretty

View File

@ -3,29 +3,29 @@ name: CI
on:
push:
branches:
- master
- develop
- feature/*
- feature-*
- issue/*
- issue-*
- master
- develop
- feature/*
- feature-*
- issue/*
- issue-*
pull_request:
branches:
- develop
- develop
# macOS environments: https://github.com/actions/virtual-environments/tree/main/images/macos
jobs:
build:
name: CI build
runs-on: macos-12
runs-on: macos-13
steps:
- name: checkout
- name: Repository
uses: actions/checkout@v2
- name: setup
env:
- name: Setup Build Environment
env:
NotificationEndpointDebug: ${{ secrets.NotificationEndpointDebug }}
NotificationEndpointRelease: ${{ secrets.NotificationEndpointRelease }}
run: exec ./.github/scripts/setup.sh
- name: build
run: exec ./.github/scripts/build.sh
- name: Build App
run: bundle exec fastlane ios build_only

40
.github/workflows/deploy-appstore.yml vendored Normal file
View File

@ -0,0 +1,40 @@
name: Deploy App Store
on:
workflow_dispatch:
push:
branches:
- develop
- release*
jobs:
deploy_appstore:
name: Deploy App Store
runs-on: macos-13
steps:
- name: Install SSH key
uses: webfactory/ssh-agent@v0.5.3
with:
ssh-private-key: |
${{ secrets.MATCH_SSH_PRIVATE_KEY }}
- name: Checkout Repository
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Setup Build Environment
env:
NotificationEndpointDebug: ${{ secrets.NotificationEndpointDebug }}
NotificationEndpointRelease: ${{ secrets.NotificationEndpointRelease }}
run: exec ./.github/scripts/setup.sh
- name: Select required Xcode version
run: sudo xcode-select -switch /Applications/Xcode_15.0.0.app
- name: Deploy App Store
env:
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
ITC_KEY_ID: ${{ secrets.APPSTORE_KEY_ID }}
ITC_ISSUER_ID: ${{ secrets.APPSTORE_ISSUER_ID }}
ITC_KEY: ${{ secrets.APPSTORE_PRIVATE_KEY }}
run: bundle exec fastlane ios deploy_appstore
- name: Tag commit
uses: tvdias/github-tagger@v0.0.1
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
tag: "${{ env.GITHUB_TAG_NAME }}"

View File

@ -1,74 +0,0 @@
name: Build for Develop TestFlight
on:
push:
branches:
- develop
- release*
- ci-test
jobs:
build:
name: Build
runs-on: macOS-12
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup
env:
NotificationEndpointDebug: ${{ secrets.NotificationEndpointDebug }}
NotificationEndpointRelease: ${{ secrets.NotificationEndpointRelease }}
run: exec ./.github/scripts/setup.sh
- name: Install codemagic-cli-tools
uses: actions/setup-python@v4
with:
python-version: '3.10'
- run: |
pip3 install codemagic-cli-tools
- run: |
codemagic-cli-tools --version || true
- name: Import Code-Signing Certificates
uses: Apple-Actions/import-codesign-certs@v1 # https://github.com/Apple-Actions/import-codesign-certs
with:
keychain: build-p12
p12-file-base64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
p12-password: ${{ secrets.P12_PASSWORD }}
- name: Download Provisioning Profiles
uses: Apple-Actions/download-provisioning-profiles@v1 # https://github.com/Apple-Actions/download-provisioning-profiles
with:
bundle-id: org.joinmastodon.app
issuer-id: ${{ secrets.APPSTORE_ISSUER_ID }}
api-key-id: ${{ secrets.APPSTORE_KEY_ID }}
api-private-key: ${{ secrets.APPSTORE_PRIVATE_KEY }}
- name: Build
env:
ENV_APP_ID: ${{ secrets.APP_ID }}
ENV_ISSUER_ID: ${{ secrets.APPSTORE_ISSUER_ID }}
ENV_API_KEY_ID: ${{ secrets.APPSTORE_KEY_ID }}
ENV_API_PRIVATE_KEY: ${{ secrets.APPSTORE_PRIVATE_KEY }}
ENV_API_PRIVATE_KEY_BASE64: ${{ secrets.APP_STORE_CONNECT_KEY_BASE64 }}
run: exec ./.github/scripts/build-release.sh
- name: Upload TestFlight Build
uses: Apple-Actions/upload-testflight-build@master
with:
app-path: .build/Artifacts/Mastodon.ipa/Mastodon.ipa
issuer-id: ${{ secrets.APPSTORE_ISSUER_ID }}
api-key-id: ${{ secrets.APPSTORE_KEY_ID }}
api-private-key: ${{ secrets.APPSTORE_PRIVATE_KEY }}
- name: Tag commit
uses: tvdias/github-tagger@v0.0.1
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
tag: "${{ env.GITHUB_TAG_NAME }}"
- name: Clean up keychain and provisioning profile
if: ${{ always() }}
run: |
security delete-keychain build-p12.keychain-db

2
.gitignore vendored
View File

@ -88,6 +88,8 @@ fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots/**/*.png
fastlane/test_output
fastlane/.env
fastlane/devices.txt
# Code Injection
# After new code Injection tools there's a generated folder /iOSInjectionProject

View File

@ -0,0 +1,21 @@
# Deployment
## Your Device
### As a Mastodon Collaborator WITH access to the Mastodon Apple Developer Program
To ensure you're able to build the App for your Device please create a `fastlane/devices.txt` and add your device's UDID.
You may use `fastlane/devices.text.example` as a starting point. Please note that fastlane expects you to use tabs in this file.
After adding your device please run `bundle exec fastlane ios register_devices` to add your device(s) to the Apple Develper Account.
Then run `bundle exec fastlane ios update_certificates` to re-generate the Codesigning Provisioning Profiles.
You should now be able to run the App using Xcode on your Device.
### As a Mastodon Contributor WITHOUT access to the Mastodon Apple Developer Program
To run the App on your Device you'll need to take care of Codesigning yourself by adjusting the App's Codesigning Settings in Xcode to your needs.
## App Store
We're using [Fastlane](https://fastlane.tools) to deploy the App to App Store Connect. Please see the [Fastlane README](../fastlane/README.md) on the available commands.

View File

@ -5,3 +5,7 @@ gem "cocoapods"
gem "cocoapods-clean"
gem "xcpretty"
# Fastlane
gem "fastlane"
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
eval_gemfile(plugins_path) if File.exist?(plugins_path)

View File

@ -4,9 +4,14 @@ GEM
CFPropertyList (3.0.6)
rexml
activesupport (7.0.8)
base64
bigdecimal
concurrent-ruby (~> 1.0, >= 1.0.2)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2)
minitest (>= 5.1)
mutex_m
tzinfo (~> 2.0)
addressable (2.8.5)
public_suffix (>= 2.0.2, < 6.0)
@ -17,12 +22,32 @@ GEM
dotenv (~> 2.7)
rainbow (~> 3.1.1)
yaml (~> 0.2)
artifactory (3.0.15)
atomos (0.1.3)
aws-eventstream (1.2.0)
aws-partitions (1.833.0)
aws-sdk-core (3.185.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.72.0)
aws-sdk-core (~> 3, >= 3.184.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.136.0)
aws-sdk-core (~> 3, >= 3.181.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.6)
aws-sigv4 (1.6.0)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
base64 (0.1.1)
bigdecimal (3.1.4)
claide (1.1.0)
cocoapods (1.12.1)
cocoapods (1.13.0)
addressable (~> 2.8)
claide (>= 1.0.2, < 2.0)
cocoapods-core (= 1.12.1)
cocoapods-core (= 1.13.0)
cocoapods-deintegrate (>= 1.0.3, < 2.0)
cocoapods-downloader (>= 1.6.0, < 2.0)
cocoapods-plugins (>= 1.0.0, < 2.0)
@ -36,9 +61,9 @@ GEM
molinillo (~> 0.8.0)
nap (~> 1.0)
ruby-macho (>= 2.3.0, < 3.0)
xcodeproj (>= 1.21.0, < 2.0)
xcodeproj (>= 1.23.0, < 2.0)
cocoapods-clean (0.0.1)
cocoapods-core (1.12.1)
cocoapods-core (1.13.0)
activesupport (>= 5.0, < 8)
addressable (~> 2.8)
algoliasearch (~> 1.0)
@ -57,35 +82,201 @@ GEM
nap (>= 0.8, < 2.0)
netrc (~> 0.11)
cocoapods-try (1.2.0)
colored (1.2)
colored2 (3.1.2)
commander (4.6.0)
highline (~> 2.0.0)
concurrent-ruby (1.2.2)
connection_pool (2.4.1)
declarative (0.0.20)
digest-crc (0.6.5)
rake (>= 12.0.0, < 14.0.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
dotenv (2.8.1)
drb (2.1.1)
ruby2_keywords
emoji_regex (3.2.3)
escape (0.0.4)
ethon (0.16.0)
ffi (>= 1.15.0)
ffi (1.15.5)
excon (0.104.0)
faraday (1.10.3)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
faraday-httpclient (~> 1.0)
faraday-multipart (~> 1.0)
faraday-net_http (~> 1.0)
faraday-net_http_persistent (~> 1.0)
faraday-patron (~> 1.0)
faraday-rack (~> 1.0)
faraday-retry (~> 1.0)
ruby2_keywords (>= 0.0.4)
faraday-cookie_jar (0.0.7)
faraday (>= 0.8.0)
http-cookie (~> 1.0.0)
faraday-em_http (1.0.0)
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.4)
multipart-post (~> 2)
faraday-net_http (1.0.1)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
faraday-rack (1.0.0)
faraday-retry (1.0.3)
faraday_middleware (1.2.0)
faraday (~> 1.0)
fastimage (2.2.7)
fastlane (2.216.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
aws-sdk-s3 (~> 1.0)
babosa (>= 1.0.3, < 2.0.0)
bundler (>= 1.12.0, < 3.0.0)
colored
commander (~> 4.6)
dotenv (>= 2.1.1, < 3.0.0)
emoji_regex (>= 0.1, < 4.0)
excon (>= 0.71.0, < 1.0.0)
faraday (~> 1.0)
faraday-cookie_jar (~> 0.0.6)
faraday_middleware (~> 1.0)
fastimage (>= 2.1.0, < 3.0.0)
gh_inspector (>= 1.1.2, < 2.0.0)
google-apis-androidpublisher_v3 (~> 0.3)
google-apis-playcustomapp_v1 (~> 0.1)
google-cloud-storage (~> 1.31)
highline (~> 2.0)
http-cookie (~> 1.0.5)
json (< 3.0.0)
jwt (>= 2.1.0, < 3)
mini_magick (>= 4.9.4, < 5.0.0)
multipart-post (>= 2.0.0, < 3.0.0)
naturally (~> 2.2)
optparse (~> 0.1.1)
plist (>= 3.1.0, < 4.0.0)
rubyzip (>= 2.0.0, < 3.0.0)
security (= 0.1.3)
simctl (~> 1.6.3)
terminal-notifier (>= 2.0.0, < 3.0.0)
terminal-table (~> 3)
tty-screen (>= 0.6.3, < 1.0.0)
tty-spinner (>= 0.8.0, < 1.0.0)
word_wrap (~> 1.0.0)
xcodeproj (>= 1.13.0, < 2.0.0)
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
fastlane-plugin-versioning (0.5.2)
ffi (1.16.3)
fourflusher (2.3.1)
fuzzy_match (2.0.4)
gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.50.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-core (0.11.1)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
mini_mime (~> 1.0)
representable (~> 3.0)
retriable (>= 2.0, < 4.a)
rexml
webrick
google-apis-iamcredentials_v1 (0.17.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-playcustomapp_v1 (0.13.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-storage_v1 (0.19.0)
google-apis-core (>= 0.9.0, < 2.a)
google-cloud-core (1.6.0)
google-cloud-env (~> 1.0)
google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
google-cloud-errors (1.3.1)
google-cloud-storage (1.44.0)
addressable (~> 2.8)
digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.19.0)
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
googleauth (1.8.1)
faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a)
highline (2.0.3)
http-cookie (1.0.5)
domain_name (~> 0.5)
httpclient (2.8.3)
i18n (1.14.1)
concurrent-ruby (~> 1.0)
jmespath (1.6.2)
json (2.6.3)
jwt (2.7.1)
mini_magick (4.12.0)
mini_mime (1.1.5)
minitest (5.20.0)
molinillo (0.8.0)
multi_json (1.15.0)
multipart-post (2.3.0)
mutex_m (0.1.2)
nanaimo (0.3.0)
nap (1.1.0)
naturally (2.2.1)
netrc (0.11.0)
optparse (0.1.1)
os (1.1.4)
plist (3.7.0)
public_suffix (4.0.7)
rainbow (3.1.1)
rake (13.0.6)
representable (3.2.0)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
rexml (3.2.6)
rouge (2.0.7)
ruby-macho (2.5.1)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
security (0.1.3)
signet (0.18.0)
addressable (~> 2.8)
faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simctl (1.6.10)
CFPropertyList
naturally
terminal-notifier (2.0.0)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
trailblazer-option (0.1.2)
tty-cursor (0.7.1)
tty-screen (0.8.1)
tty-spinner (0.9.3)
tty-cursor (~> 0.7)
typhoeus (1.4.0)
ethon (>= 0.9.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
xcodeproj (1.22.0)
uber (0.1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.8.2)
unicode-display_width (2.5.0)
webrick (1.8.1)
word_wrap (1.0.0)
xcodeproj (1.23.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
@ -94,6 +285,8 @@ GEM
rexml (~> 3.2.4)
xcpretty (0.3.0)
rouge (~> 2.0.7)
xcpretty-travis-formatter (1.0.1)
xcpretty (~> 0.2, >= 0.0.7)
yaml (0.2.1)
PLATFORMS
@ -106,6 +299,8 @@ DEPENDENCIES
arkana
cocoapods
cocoapods-clean
fastlane
fastlane-plugin-versioning
xcpretty
BUNDLED WITH

View File

@ -715,6 +715,7 @@
"notifications": "Notifications",
"support_mastodon": "Support Mastodon",
"about_mastodon": "About Mastodon",
"server_details": "Server Details",
"logout": "Logout %@"
}
@ -725,6 +726,9 @@
"privacy_policy": "Privacy Policy",
"clear_media_storage": "Clear Media Storage"
},
"about_instance": {
"message_admin": "Message Admin"
},
"general": {
"title": "General",
"appearance": {

View File

@ -715,6 +715,7 @@
"notifications": "Notifications",
"support_mastodon": "Support Mastodon",
"about_mastodon": "About Mastodon",
"server_details": "Server Details",
"logout": "Logout %@"
}

View File

@ -715,6 +715,7 @@
"notifications": "Notifications",
"support_mastodon": "Support Mastodon",
"about_mastodon": "About Mastodon",
"server_details": "Server Details",
"logout": "Logout %@"
}
@ -725,6 +726,16 @@
"privacy_policy": "Privacy Policy",
"clear_media_storage": "Clear Media Storage"
},
"server_details": {
"about": "About",
"rules": "Rules"
"about_instance": {
"title": "Adminstrator"
"message_admin": "Message Admin",
"legal_notice": "A legal notice"
}
},
"general": {
"title": "General",
"appearance": {

View File

@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objectVersion = 60;
objects = {
/* Begin PBXBuildFile section */
@ -20,7 +20,6 @@
0FB3D31E25E534C700AAD544 /* PickServerCategoryCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FB3D31D25E534C700AAD544 /* PickServerCategoryCollectionViewCell.swift */; };
0FB3D33825E6401400AAD544 /* PickServerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FB3D33725E6401400AAD544 /* PickServerCell.swift */; };
164F0EBC267D4FE400249499 /* BoopSound.caf in Resources */ = {isa = PBXBuildFile; fileRef = 164F0EBB267D4FE400249499 /* BoopSound.caf */; };
18BC7629F65E6DB12CB8416D /* Pods_Mastodon_MastodonUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C030226D3C73DCC23D67452 /* Pods_Mastodon_MastodonUITests.framework */; };
27D701F5292FC2D60031BCBB /* DataSourceFacade+URL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27D701F4292FC2D60031BCBB /* DataSourceFacade+URL.swift */; };
2A1BF99529F7E68400FA1BA5 /* DataSourceFacade+UserView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1BF99429F7E68400FA1BA5 /* DataSourceFacade+UserView.swift */; };
2A1FE47C2938BB2600784BF1 /* FollowedTagsViewModel+DiffableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1FE47B2938BB2600784BF1 /* FollowedTagsViewModel+DiffableDataSource.swift */; };
@ -109,29 +108,31 @@
5D0393962612D266007FE196 /* WebViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D0393952612D266007FE196 /* WebViewModel.swift */; };
5DA732CC2629CEF500A92342 /* UIView+Remove.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DA732CB2629CEF500A92342 /* UIView+Remove.swift */; };
5DF1056425F887CB00D6C0D4 /* AVPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DF1056325F887CB00D6C0D4 /* AVPlayer.swift */; };
5E0DEC05797A7E6933788DDB /* Pods_MastodonTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 452147B2903DF38070FE56A2 /* Pods_MastodonTests.framework */; };
5E44BF88AD33646E64727BCF /* Pods_MastodonTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD92E0F10BDE4FE7C4B999F2 /* Pods_MastodonTests.framework */; };
6213AF5A28939C8400BCADB6 /* BookmarkViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6213AF5928939C8400BCADB6 /* BookmarkViewModel.swift */; };
6213AF5C28939C8A00BCADB6 /* BookmarkViewModel+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6213AF5B28939C8A00BCADB6 /* BookmarkViewModel+State.swift */; };
6213AF5E2893A8B200BCADB6 /* DataSourceFacade+Bookmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6213AF5D2893A8B200BCADB6 /* DataSourceFacade+Bookmark.swift */; };
62FD27D12893707600B205C5 /* BookmarkViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FD27D02893707600B205C5 /* BookmarkViewController.swift */; };
62FD27D32893707B00B205C5 /* BookmarkViewController+DataSourceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FD27D22893707B00B205C5 /* BookmarkViewController+DataSourceProvider.swift */; };
62FD27D52893708A00B205C5 /* BookmarkViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FD27D42893708A00B205C5 /* BookmarkViewModel+Diffable.swift */; };
71458AF57697DB405CFEC37C /* Pods_Mastodon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C2A2448AEEDA65B4CD099FC /* Pods_Mastodon.framework */; };
7910197261F9D06EFCDCCDBC /* Pods_MastodonTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 89FE8B85A00419CEF4678056 /* Pods_MastodonTests.framework */; };
855149C8295F1C5F00943D96 /* UIInterfaceOrientationMask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 855149C7295F1C5F00943D96 /* UIInterfaceOrientationMask.swift */; };
855149CA29606D6400943D96 /* PortraitAlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 855149C929606D6400943D96 /* PortraitAlertController.swift */; };
85904C02293BC0EB0011C817 /* ImageProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85904C01293BC0EB0011C817 /* ImageProvider.swift */; };
85904C04293BC1940011C817 /* URLActivityItemWithMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85904C03293BC1940011C817 /* URLActivityItemWithMetadata.swift */; };
85BC11B32932414900E191CD /* AltTextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85BC11B22932414900E191CD /* AltTextViewController.swift */; };
87FFDA5D898A5C42ADCB35E7 /* Pods_Mastodon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A4ABE34829701A4496C5BB64 /* Pods_Mastodon.framework */; };
9E44C7202967AD17004B2A72 /* MastodonSDKDynamic in Frameworks */ = {isa = PBXBuildFile; productRef = 9E44C71F2967AD17004B2A72 /* MastodonSDKDynamic */; };
9E44C7222967AD17004B2A72 /* MastodonSDKDynamic in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 9E44C71F2967AD17004B2A72 /* MastodonSDKDynamic */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
C24C97032922F30500BAE8CB /* RefreshControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = C24C97022922F30500BAE8CB /* RefreshControl.swift */; };
D807C6C029DE197900A4E17C /* EducationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D807C6BF29DE197900A4E17C /* EducationViewController.swift */; };
D808B94C296ECFDC0031EB1E /* StatusEditHistoryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D808B94B296ECFDC0031EB1E /* StatusEditHistoryViewModel.swift */; };
D808B94E296EFBBA0031EB1E /* StatusEditHistoryTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D808B94D296EFBBA0031EB1E /* StatusEditHistoryTableViewCell.swift */; };
D80911082AC4BFDE00EB4D15 /* ServerDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D80911072AC4BFDE00EB4D15 /* ServerDetailsViewController.swift */; };
D8099078294BC8A30050219F /* PrivacyTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8099077294BC8A30050219F /* PrivacyTableViewController.swift */; };
D809907A294BC9390050219F /* PrivacyTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8099079294BC9390050219F /* PrivacyTableViewCell.swift */; };
D809907C294D25510050219F /* PrivacyViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D809907B294D25510050219F /* PrivacyViewModel.swift */; };
D81439862AD415DE0071A88F /* AboutInstance.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81439852AD415DE0071A88F /* AboutInstance.swift */; };
D81439882AD450A40071A88F /* AboutInstanceTableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81439872AD450A40071A88F /* AboutInstanceTableViewDataSource.swift */; };
D81A22752AB4643200905D71 /* SearchResultsOverviewTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81A22742AB4643200905D71 /* SearchResultsOverviewTableViewController.swift */; };
D81A22782AB4782400905D71 /* SearchResultOverviewSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81A22772AB4782400905D71 /* SearchResultOverviewSection.swift */; };
D81A227B2AB47B9A00905D71 /* SearchResultDefaultSectionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81A227A2AB47B9A00905D71 /* SearchResultDefaultSectionTableViewCell.swift */; };
@ -144,6 +145,8 @@
D8318A882A4468D300C0FB73 /* NotificationSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8318A872A4468D300C0FB73 /* NotificationSettingsViewController.swift */; };
D8318A8A2A4468DC00C0FB73 /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8318A892A4468DC00C0FB73 /* AboutViewController.swift */; };
D8363B1629469CE200A74079 /* OnboardingNextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8363B1529469CE200A74079 /* OnboardingNextView.swift */; };
D852C23C2AC5D02C00309232 /* AboutInstanceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D852C23B2AC5D02C00309232 /* AboutInstanceViewController.swift */; };
D852C23E2AC5D03300309232 /* InstanceRulesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D852C23D2AC5D03300309232 /* InstanceRulesViewController.swift */; };
D87BFC8B291D5C6B00FEE264 /* MastodonLoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D87BFC8A291D5C6B00FEE264 /* MastodonLoginView.swift */; };
D87BFC8D291EB81200FEE264 /* MastodonLoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D87BFC8C291EB81200FEE264 /* MastodonLoginViewModel.swift */; };
D87BFC8F291EC26A00FEE264 /* MastodonLoginServerTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D87BFC8E291EC26A00FEE264 /* MastodonLoginServerTableViewCell.swift */; };
@ -173,6 +176,10 @@
D8F917112A4C6B40008A5370 /* GeneralSettingToggleTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8F917102A4C6B40008A5370 /* GeneralSettingToggleTableViewCell.swift */; };
D8F917122A4C6B67008A5370 /* GeneralSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8318A832A4468A800C0FB73 /* GeneralSettingsViewController.swift */; };
D8F917142A4D74C3008A5370 /* GeneralSettingsDiffableTableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8F917132A4D74C3008A5370 /* GeneralSettingsDiffableTableViewDataSource.swift */; };
D8FAAE3D2AD042E700DC1832 /* AdminTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8FAAE3C2AD042E700DC1832 /* AdminTableViewCell.swift */; };
D8FAAE3F2AD0430E00DC1832 /* ContactAdminTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8FAAE3E2AD0430E00DC1832 /* ContactAdminTableViewCell.swift */; };
D8FAAE412AD0475900DC1832 /* AboutInstanceTableViewHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8FAAE402AD0475900DC1832 /* AboutInstanceTableViewHeader.swift */; };
D8FAAE432AD047B200DC1832 /* AboutInstanceTableFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8FAAE422AD047B200DC1832 /* AboutInstanceTableFooterView.swift */; };
DB0009A626AEE5DC009B9D2D /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = DB0009A926AEE5DC009B9D2D /* Intents.intentdefinition */; settings = {ATTRIBUTES = (codegen, ); }; };
DB0009A726AEE5DC009B9D2D /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = DB0009A926AEE5DC009B9D2D /* Intents.intentdefinition */; };
DB023D26279FFB0A005AC798 /* ShareActivityProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB023D25279FFB0A005AC798 /* ShareActivityProvider.swift */; };
@ -488,6 +495,7 @@
DBFEEC99279BDCDE004F81DD /* ProfileAboutViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBFEEC98279BDCDE004F81DD /* ProfileAboutViewModel.swift */; };
DBFEEC9B279BDDD9004F81DD /* ProfileAboutViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBFEEC9A279BDDD9004F81DD /* ProfileAboutViewModel+Diffable.swift */; };
DBFEEC9D279C12C1004F81DD /* ProfileFieldEditCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBFEEC9C279C12C1004F81DD /* ProfileFieldEditCollectionViewCell.swift */; };
EF7771EAA493A869D65A105C /* Pods_Mastodon_MastodonUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD12474E169668871A9F6AB4 /* Pods_Mastodon_MastodonUITests.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -713,7 +721,6 @@
2D8434FA25FF46B300EECE90 /* HomeTimelineNavigationBarTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeTimelineNavigationBarTitleView.swift; sourceTree = "<group>"; };
2D84350425FF858100EECE90 /* UIScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIScrollView.swift; sourceTree = "<group>"; };
2D939AB425EDD8A90076FA61 /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = "<group>"; };
2DA7D05025CA545E00804E11 /* LoadMoreConfigurableTableViewContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadMoreConfigurableTableViewContainer.swift; sourceTree = "<group>"; };
2DAC9E37262FC2320062E1A6 /* SuggestionAccountViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionAccountViewController.swift; sourceTree = "<group>"; };
2DAC9E3D262FC2400062E1A6 /* SuggestionAccountViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionAccountViewModel.swift; sourceTree = "<group>"; };
2DAC9E45262FC9FD0062E1A6 /* SuggestionAccountTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionAccountTableViewCell.swift; sourceTree = "<group>"; };
@ -721,9 +728,7 @@
2DE0FACD2615F7AD00CDF649 /* RecommendAccountSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendAccountSection.swift; sourceTree = "<group>"; };
2E1F6A67FDF9771D3E064FDC /* Pods-Mastodon.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.debug.xcconfig"; sourceTree = "<group>"; };
3B7FD8F28DDA8FBCE5562B78 /* Pods-NotificationService.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.asdk - debug.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.asdk - debug.xcconfig"; sourceTree = "<group>"; };
3C030226D3C73DCC23D67452 /* Pods_Mastodon_MastodonUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Mastodon_MastodonUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3E08A432F40BA7B9CAA9DB68 /* Pods-AppShared.release snapshot.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.release snapshot.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.release snapshot.xcconfig"; sourceTree = "<group>"; };
452147B2903DF38070FE56A2 /* Pods_MastodonTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MastodonTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
459EA4F43058CAB47719E963 /* Pods-Mastodon-MastodonUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.debug.xcconfig"; sourceTree = "<group>"; };
46DAB0EBDDFB678347CD96FF /* Pods-MastodonTests.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonTests.asdk - release.xcconfig"; path = "Target Support Files/Pods-MastodonTests/Pods-MastodonTests.asdk - release.xcconfig"; sourceTree = "<group>"; };
5B24BBD7262DB14800A9381B /* ReportViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReportViewModel.swift; sourceTree = "<group>"; };
@ -755,12 +760,13 @@
85904C03293BC1940011C817 /* URLActivityItemWithMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLActivityItemWithMetadata.swift; sourceTree = "<group>"; };
85BC11B22932414900E191CD /* AltTextViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AltTextViewController.swift; sourceTree = "<group>"; };
8850E70A1D5FF51432E43653 /* Pods-Mastodon-MastodonUITests.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.asdk - release.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.asdk - release.xcconfig"; sourceTree = "<group>"; };
89FE8B85A00419CEF4678056 /* Pods_MastodonTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MastodonTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8C2A2448AEEDA65B4CD099FC /* Pods_Mastodon.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Mastodon.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8E79CCBE51FBC3F7FE8CF49F /* Pods-MastodonTests.release snapshot.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonTests.release snapshot.xcconfig"; path = "Target Support Files/Pods-MastodonTests/Pods-MastodonTests.release snapshot.xcconfig"; sourceTree = "<group>"; };
8ED8C4B1F1BA2DCFF2926BB1 /* Pods-Mastodon-NotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-NotificationService.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon-NotificationService/Pods-Mastodon-NotificationService.debug.xcconfig"; sourceTree = "<group>"; };
9780A4C98FFC65B32B50D1C0 /* Pods-MastodonTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonTests.release.xcconfig"; path = "Target Support Files/Pods-MastodonTests/Pods-MastodonTests.release.xcconfig"; sourceTree = "<group>"; };
9A0982D8F349244EB558CDFD /* Pods-AppShared.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.debug.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.debug.xcconfig"; sourceTree = "<group>"; };
9CFF58FD900AC059428700E7 /* Pods-NotificationService.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.asdk - release.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.asdk - release.xcconfig"; sourceTree = "<group>"; };
A4ABE34829701A4496C5BB64 /* Pods_Mastodon.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Mastodon.framework; sourceTree = BUILT_PRODUCTS_DIR; };
A67FD038ECDA0E411AF8DB4D /* Pods-Mastodon-MastodonUITests.asdk.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.asdk.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.asdk.xcconfig"; sourceTree = "<group>"; };
A9B1FB898DFD6063B044298C /* Pods-AppShared.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.asdk - debug.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.asdk - debug.xcconfig"; sourceTree = "<group>"; };
B31D44635FCF6452F7E1B865 /* Pods-Mastodon-AppShared.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-AppShared.release.xcconfig"; path = "Target Support Files/Pods-Mastodon-AppShared/Pods-Mastodon-AppShared.release.xcconfig"; sourceTree = "<group>"; };
@ -769,14 +775,16 @@
BD7598A87F4497045EDEF252 /* Pods-Mastodon.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.asdk - release.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.asdk - release.xcconfig"; sourceTree = "<group>"; };
C24C97022922F30500BAE8CB /* RefreshControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshControl.swift; sourceTree = "<group>"; };
C3789232A52F43529CA67E95 /* Pods-MastodonIntent.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonIntent.asdk - debug.xcconfig"; path = "Target Support Files/Pods-MastodonIntent/Pods-MastodonIntent.asdk - debug.xcconfig"; sourceTree = "<group>"; };
CD92E0F10BDE4FE7C4B999F2 /* Pods_MastodonTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MastodonTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D7D7CF93E262178800077512 /* Pods-Mastodon-AppShared.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-AppShared.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon-AppShared/Pods-Mastodon-AppShared.debug.xcconfig"; sourceTree = "<group>"; };
D807C6BF29DE197900A4E17C /* EducationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EducationViewController.swift; sourceTree = "<group>"; };
D808B94B296ECFDC0031EB1E /* StatusEditHistoryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusEditHistoryViewModel.swift; sourceTree = "<group>"; };
D808B94D296EFBBA0031EB1E /* StatusEditHistoryTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusEditHistoryTableViewCell.swift; sourceTree = "<group>"; };
D80911072AC4BFDE00EB4D15 /* ServerDetailsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerDetailsViewController.swift; sourceTree = "<group>"; };
D8099077294BC8A30050219F /* PrivacyTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyTableViewController.swift; sourceTree = "<group>"; };
D8099079294BC9390050219F /* PrivacyTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyTableViewCell.swift; sourceTree = "<group>"; };
D809907B294D25510050219F /* PrivacyViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyViewModel.swift; sourceTree = "<group>"; };
D81439852AD415DE0071A88F /* AboutInstance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutInstance.swift; sourceTree = "<group>"; };
D81439872AD450A40071A88F /* AboutInstanceTableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutInstanceTableViewDataSource.swift; sourceTree = "<group>"; };
D81A22742AB4643200905D71 /* SearchResultsOverviewTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultsOverviewTableViewController.swift; sourceTree = "<group>"; };
D81A22772AB4782400905D71 /* SearchResultOverviewSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultOverviewSection.swift; sourceTree = "<group>"; };
D81A227A2AB47B9A00905D71 /* SearchResultDefaultSectionTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultDefaultSectionTableViewCell.swift; sourceTree = "<group>"; };
@ -786,7 +794,6 @@
D82463532A52B47B00A3DBDD /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = be; path = be.lproj/WidgetExtension.strings; sourceTree = "<group>"; };
D82463542A52B47B00A3DBDD /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = be; path = be.lproj/InfoPlist.strings; sourceTree = "<group>"; };
D82463552A52B47B00A3DBDD /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = be; path = be.lproj/Intents.stringsdict; sourceTree = "<group>"; };
D82BD7512ABC42D6009A374A /* Coordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = "<group>"; };
D82BD7542ABC73AF009A374A /* NotificationPolicyTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationPolicyTableViewCell.swift; sourceTree = "<group>"; };
D8318A7F2A4466D300C0FB73 /* SettingsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsCoordinator.swift; sourceTree = "<group>"; };
D8318A832A4468A800C0FB73 /* GeneralSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralSettingsViewController.swift; sourceTree = "<group>"; };
@ -794,6 +801,8 @@
D8318A872A4468D300C0FB73 /* NotificationSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsViewController.swift; sourceTree = "<group>"; };
D8318A892A4468DC00C0FB73 /* AboutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = "<group>"; };
D8363B1529469CE200A74079 /* OnboardingNextView.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = OnboardingNextView.swift; sourceTree = "<group>"; tabWidth = 4; };
D852C23B2AC5D02C00309232 /* AboutInstanceViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutInstanceViewController.swift; sourceTree = "<group>"; };
D852C23D2AC5D03300309232 /* InstanceRulesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceRulesViewController.swift; sourceTree = "<group>"; };
D87BFC8A291D5C6B00FEE264 /* MastodonLoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonLoginView.swift; sourceTree = "<group>"; };
D87BFC8C291EB81200FEE264 /* MastodonLoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonLoginViewModel.swift; sourceTree = "<group>"; };
D87BFC8E291EC26A00FEE264 /* MastodonLoginServerTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonLoginServerTableViewCell.swift; sourceTree = "<group>"; };
@ -833,6 +842,10 @@
D8F9170E2A4B47EF008A5370 /* Coordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = "<group>"; };
D8F917102A4C6B40008A5370 /* GeneralSettingToggleTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralSettingToggleTableViewCell.swift; sourceTree = "<group>"; };
D8F917132A4D74C3008A5370 /* GeneralSettingsDiffableTableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralSettingsDiffableTableViewDataSource.swift; sourceTree = "<group>"; };
D8FAAE3C2AD042E700DC1832 /* AdminTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdminTableViewCell.swift; sourceTree = "<group>"; };
D8FAAE3E2AD0430E00DC1832 /* ContactAdminTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactAdminTableViewCell.swift; sourceTree = "<group>"; };
D8FAAE402AD0475900DC1832 /* AboutInstanceTableViewHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutInstanceTableViewHeader.swift; sourceTree = "<group>"; };
D8FAAE422AD047B200DC1832 /* AboutInstanceTableFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutInstanceTableFooterView.swift; sourceTree = "<group>"; };
DB0009A826AEE5DC009B9D2D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; name = Base; path = Base.lproj/Intents.intentdefinition; sourceTree = "<group>"; };
DB0009AD26AEE5E4009B9D2D /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Intents.strings; sourceTree = "<group>"; };
DB023D25279FFB0A005AC798 /* ShareActivityProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareActivityProvider.swift; sourceTree = "<group>"; };
@ -896,7 +909,6 @@
DB1FD44325F26CCC004CFCFC /* PickServerSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerSection.swift; sourceTree = "<group>"; };
DB1FD44F25F26FA1004CFCFC /* MastodonPickServerViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MastodonPickServerViewModel+Diffable.swift"; sourceTree = "<group>"; };
DB1FD45925F27898004CFCFC /* CategoryPickerItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryPickerItem.swift; sourceTree = "<group>"; };
DB1FD45F25F278AF004CFCFC /* CategoryPickerSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryPickerSection.swift; sourceTree = "<group>"; };
DB2B3ABD25E37E15007045F9 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
DB2F073325E8ECF000957B2D /* AuthenticationViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationViewModel.swift; sourceTree = "<group>"; };
DB336F3E278E668C0031E64B /* StatusTableViewCell+ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StatusTableViewCell+ViewModel.swift"; sourceTree = "<group>"; };
@ -1237,6 +1249,7 @@
DBFEEC9A279BDDD9004F81DD /* ProfileAboutViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileAboutViewModel+Diffable.swift"; sourceTree = "<group>"; };
DBFEEC9C279C12C1004F81DD /* ProfileFieldEditCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileFieldEditCollectionViewCell.swift; sourceTree = "<group>"; };
DBFEF06726A58D07006D7ED1 /* ShareActionExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ShareActionExtension.entitlements; sourceTree = "<group>"; };
DD12474E169668871A9F6AB4 /* Pods_Mastodon_MastodonUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Mastodon_MastodonUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
DDB1B139FA8EA26F510D58B6 /* Pods-AppShared.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.asdk - release.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.asdk - release.xcconfig"; sourceTree = "<group>"; };
DF65937EC1FF64462BC002EE /* Pods-MastodonTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonTests.profile.xcconfig"; path = "Target Support Files/Pods-MastodonTests/Pods-MastodonTests.profile.xcconfig"; sourceTree = "<group>"; };
E5C7236E58D14A0322FE00F2 /* Pods-Mastodon-MastodonUITests.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.asdk - debug.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.asdk - debug.xcconfig"; sourceTree = "<group>"; };
@ -1246,7 +1259,6 @@
ECA373ABA86BE3C2D7ED878E /* Pods-AppShared.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.release.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.release.xcconfig"; sourceTree = "<group>"; };
EE13214BC0246BE5210CCC10 /* Pods-AppShared.asdk.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.asdk.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.asdk.xcconfig"; sourceTree = "<group>"; };
F31E7502A7E3945B98C6CBAF /* Pods-NotificationService.asdk.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.asdk.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.asdk.xcconfig"; sourceTree = "<group>"; };
F4A2A2D7000E477CA459ADA9 /* Pods_AppShared.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AppShared.framework; sourceTree = BUILT_PRODUCTS_DIR; };
F920AD4EC23B0D00F5CCA58E /* Pods-MastodonIntent.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonIntent.asdk - release.xcconfig"; path = "Target Support Files/Pods-MastodonIntent/Pods-MastodonIntent.asdk - release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -1277,7 +1289,7 @@
files = (
357FEEAF29523D470021C9DC /* MastodonSDKDynamic in Frameworks */,
DBF96326262EC0A6001D8D25 /* AuthenticationServices.framework in Frameworks */,
87FFDA5D898A5C42ADCB35E7 /* Pods_Mastodon.framework in Frameworks */,
71458AF57697DB405CFEC37C /* Pods_Mastodon.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1286,8 +1298,7 @@
buildActionMask = 2147483647;
files = (
9E44C7202967AD17004B2A72 /* MastodonSDKDynamic in Frameworks */,
5E44BF88AD33646E64727BCF /* Pods_MastodonTests.framework in Frameworks */,
5E0DEC05797A7E6933788DDB /* Pods_MastodonTests.framework in Frameworks */,
7910197261F9D06EFCDCCDBC /* Pods_MastodonTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1295,7 +1306,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
18BC7629F65E6DB12CB8416D /* Pods_Mastodon_MastodonUITests.framework in Frameworks */,
EF7771EAA493A869D65A105C /* Pods_Mastodon_MastodonUITests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1720,15 +1731,14 @@
isa = PBXGroup;
children = (
DBF96325262EC0A6001D8D25 /* AuthenticationServices.framework */,
A4ABE34829701A4496C5BB64 /* Pods_Mastodon.framework */,
3C030226D3C73DCC23D67452 /* Pods_Mastodon_MastodonUITests.framework */,
452147B2903DF38070FE56A2 /* Pods_MastodonTests.framework */,
F4A2A2D7000E477CA459ADA9 /* Pods_AppShared.framework */,
DB8FAB9E26AEC3A2008E5AF4 /* Intents.framework */,
DB8FABA926AEC3A2008E5AF4 /* IntentsUI.framework */,
2A6451022964223800CD8B8A /* UniformTypeIdentifiers.framework */,
2A728121297EA9D7004138C5 /* WidgetKit.framework */,
2A728123297EA9D7004138C5 /* SwiftUI.framework */,
8C2A2448AEEDA65B4CD099FC /* Pods_Mastodon.framework */,
DD12474E169668871A9F6AB4 /* Pods_Mastodon_MastodonUITests.framework */,
89FE8B85A00419CEF4678056 /* Pods_MastodonTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@ -1754,6 +1764,7 @@
D8F916FF2A4AD898008A5370 /* Settings Overview */,
D8F917042A4B0657008A5370 /* General Settings */,
D81D12432A4E181C005009D4 /* Notification Settings */,
D80911062AC4BFD100EB4D15 /* Server Details */,
D8F917092A4B2AFF008A5370 /* About Mastodon */,
D8318A7F2A4466D300C0FB73 /* SettingsCoordinator.swift */,
);
@ -1781,6 +1792,17 @@
path = Bookmark;
sourceTree = "<group>";
};
D80911062AC4BFD100EB4D15 /* Server Details */ = {
isa = PBXGroup;
children = (
D8FAAE3B2AD042CD00DC1832 /* Table View Components */,
D80911072AC4BFDE00EB4D15 /* ServerDetailsViewController.swift */,
D852C23B2AC5D02C00309232 /* AboutInstanceViewController.swift */,
D852C23D2AC5D03300309232 /* InstanceRulesViewController.swift */,
);
path = "Server Details";
sourceTree = "<group>";
};
D8099076294BC2BA0050219F /* Privacy */ = {
isa = PBXGroup;
children = (
@ -1927,6 +1949,19 @@
path = "About Mastodon";
sourceTree = "<group>";
};
D8FAAE3B2AD042CD00DC1832 /* Table View Components */ = {
isa = PBXGroup;
children = (
D8FAAE3C2AD042E700DC1832 /* AdminTableViewCell.swift */,
D8FAAE3E2AD0430E00DC1832 /* ContactAdminTableViewCell.swift */,
D8FAAE402AD0475900DC1832 /* AboutInstanceTableViewHeader.swift */,
D8FAAE422AD047B200DC1832 /* AboutInstanceTableFooterView.swift */,
D81439852AD415DE0071A88F /* AboutInstance.swift */,
D81439872AD450A40071A88F /* AboutInstanceTableViewDataSource.swift */,
);
path = "Table View Components";
sourceTree = "<group>";
};
DB01409B25C40BB600F9F3CF /* Onboarding */ = {
isa = PBXGroup;
children = (
@ -2108,7 +2143,6 @@
DB427DD325BAA00100D1B89D /* Products */,
1EBA4F56E920856A3FC84ACB /* Pods */,
3FE14AD363ED19AE7FF210A6 /* Frameworks */,
DB98335F25C93B0400AD9700 /* Recovered References */,
D8A6FE6029325F5900666A47 /* Localization */,
);
indentWidth = 4;
@ -2635,17 +2669,6 @@
path = Thread;
sourceTree = "<group>";
};
DB98335F25C93B0400AD9700 /* Recovered References */ = {
isa = PBXGroup;
children = (
CD92E0F10BDE4FE7C4B999F2 /* Pods_MastodonTests.framework */,
2DA7D05025CA545E00804E11 /* LoadMoreConfigurableTableViewContainer.swift */,
DB1FD45F25F278AF004CFCFC /* CategoryPickerSection.swift */,
D82BD7512ABC42D6009A374A /* Coordinator.swift */,
);
name = "Recovered References";
sourceTree = "<group>";
};
DB98EB4A27B0F0F50082E365 /* Cell */ = {
isa = PBXGroup;
children = (
@ -3266,7 +3289,7 @@
};
};
buildConfigurationList = DB427DCD25BAA00100D1B89D /* Build configuration list for PBXProject "Mastodon" */;
compatibilityVersion = "Xcode 9.3";
compatibilityVersion = "Xcode 15.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
@ -3612,6 +3635,7 @@
DB023D26279FFB0A005AC798 /* ShareActivityProvider.swift in Sources */,
5D0393962612D266007FE196 /* WebViewModel.swift in Sources */,
5B24BBDA262DB14800A9381B /* ReportViewModel.swift in Sources */,
D80911082AC4BFDE00EB4D15 /* ServerDetailsViewController.swift in Sources */,
2D5A3D3825CF8D9F002347D6 /* ScrollViewContainer.swift in Sources */,
DB6180EF26391CA50018D199 /* MediaPreviewImageViewController.swift in Sources */,
DB1E347825F519300079D7DF /* PickServerItem.swift in Sources */,
@ -3639,11 +3663,14 @@
DB697DD6278F4C29004EF2F7 /* DataSourceProvider.swift in Sources */,
DB0FCB8E2796C0B7006C02E2 /* TrendCollectionViewCell.swift in Sources */,
0F1E2D0B2615C39400C38565 /* DoubleTitleLabelNavigationBarTitleView.swift in Sources */,
D81439862AD415DE0071A88F /* AboutInstance.swift in Sources */,
DBDFF1902805543100557A48 /* DiscoveryPostsViewController.swift in Sources */,
DB697DD9278F4CED004EF2F7 /* HomeTimelineViewController+DataSourceProvider.swift in Sources */,
DB45FAD725CA6C76005A8AC7 /* UIBarButtonItem.swift in Sources */,
D8FAAE432AD047B200DC1832 /* AboutInstanceTableFooterView.swift in Sources */,
D808B94E296EFBBA0031EB1E /* StatusEditHistoryTableViewCell.swift in Sources */,
2D8434F525FF465D00EECE90 /* HomeTimelineNavigationBarTitleViewModel.swift in Sources */,
D852C23E2AC5D03300309232 /* InstanceRulesViewController.swift in Sources */,
DB938F0F2624119800E5B6C1 /* ThreadViewModel+LoadThreadState.swift in Sources */,
DB6180F226391CF40018D199 /* MediaPreviewImageViewModel.swift in Sources */,
62FD27D12893707600B205C5 /* BookmarkViewController.swift in Sources */,
@ -3662,6 +3689,7 @@
DBDFF19C28055BD600557A48 /* DiscoveryViewModel.swift in Sources */,
DBB3BA2A26A81C020004F2D4 /* FLAnimatedImageView.swift in Sources */,
DB3E6FF32806D97400B035AE /* DiscoveryNewsViewModel+State.swift in Sources */,
D8FAAE3F2AD0430E00DC1832 /* ContactAdminTableViewCell.swift in Sources */,
DB6746ED278F45F0008A6B94 /* AutoGenerateProtocolRelayDelegate.swift in Sources */,
DB0618032785A7100030EE79 /* RegisterSection.swift in Sources */,
DB63F76B279A5ED300455B82 /* NotificationTimelineViewModel+LoadOldestState.swift in Sources */,
@ -3690,6 +3718,7 @@
DBFEEC9D279C12C1004F81DD /* ProfileFieldEditCollectionViewCell.swift in Sources */,
DB3E6FEC2806D7F100B035AE /* DiscoveryNewsViewController.swift in Sources */,
DBCBED1726132DB500B49291 /* UserTimelineViewModel+Diffable.swift in Sources */,
D8FAAE412AD0475900DC1832 /* AboutInstanceTableViewHeader.swift in Sources */,
2DE0FACE2615F7AD00CDF649 /* RecommendAccountSection.swift in Sources */,
2DAC9E3E262FC2400062E1A6 /* SuggestionAccountViewModel.swift in Sources */,
DB603113279EBEBA00A935FE /* DataSourceFacade+Block.swift in Sources */,
@ -3853,6 +3882,7 @@
DB68A04A25E9027700CFDF14 /* AdaptiveStatusBarStyleNavigationController.swift in Sources */,
0FB3D33825E6401400AAD544 /* PickServerCell.swift in Sources */,
6213AF5C28939C8A00BCADB6 /* BookmarkViewModel+State.swift in Sources */,
D81439882AD450A40071A88F /* AboutInstanceTableViewDataSource.swift in Sources */,
D807C6C029DE197900A4E17C /* EducationViewController.swift in Sources */,
2D364F7825E66D8300204FDC /* MastodonResendEmailViewModel.swift in Sources */,
DBEFCD7B282A162400C0ABEA /* ReportReasonView.swift in Sources */,
@ -3920,6 +3950,7 @@
D8B5E4F42A4ED0240008970C /* NotificationSettingsViewModel.swift in Sources */,
DBD376B2269302A4007FEC24 /* UITableViewCell.swift in Sources */,
DB4F0966269ED52200D62E92 /* SearchResultViewModel.swift in Sources */,
D852C23C2AC5D02C00309232 /* AboutInstanceViewController.swift in Sources */,
D8F917142A4D74C3008A5370 /* GeneralSettingsDiffableTableViewDataSource.swift in Sources */,
DB6180FA26391F2E0018D199 /* MediaPreviewViewModel.swift in Sources */,
2D7631A825C1535600929FB9 /* StatusTableViewCell.swift in Sources */,
@ -3935,6 +3966,7 @@
DB3E6FE42806A5B800B035AE /* DiscoverySection.swift in Sources */,
DB697DDB278F4DE3004EF2F7 /* DataSourceProvider+StatusTableViewCellDelegate.swift in Sources */,
DB87D4512609CF1E00D12C0D /* ComposeStatusPollOptionAppendEntryCollectionViewCell.swift in Sources */,
D8FAAE3D2AD042E700DC1832 /* AdminTableViewCell.swift in Sources */,
DBB45B5627B39FC9002DC5A7 /* MediaPreviewVideoViewController.swift in Sources */,
D8A6AB6C291C5136003AB663 /* MastodonLoginViewController.swift in Sources */,
DB0FCB8027968F70006C02E2 /* MastodonStatusThreadViewModel.swift in Sources */,
@ -4268,14 +4300,12 @@
CODE_SIGN_ENTITLEMENTS = OpenInActionExtension/OpenInActionExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = OpenInActionExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Open using Mastodon";
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -4284,6 +4314,7 @@
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.OpenInActionExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
@ -4297,15 +4328,11 @@
ASSETCATALOG_COMPILER_APPICON_NAME = Icon;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = OpenInActionExtension/OpenInActionExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = OpenInActionExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Open using Mastodon";
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -4327,15 +4354,13 @@
ASSETCATALOG_COMPILER_APPICON_NAME = Icon;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = OpenInActionExtension/OpenInActionExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 5Z4GVSS33P;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = OpenInActionExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Open using Mastodon";
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -4344,6 +4369,7 @@
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.OpenInActionExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore org.joinmastodon.app.OpenInActionExtension";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
@ -4357,15 +4383,11 @@
ASSETCATALOG_COMPILER_APPICON_NAME = Icon;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = OpenInActionExtension/OpenInActionExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = OpenInActionExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Open using Mastodon";
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -4390,14 +4412,12 @@
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = WidgetExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = WidgetExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -4406,6 +4426,7 @@
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.WidgetExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
@ -4420,15 +4441,11 @@
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = WidgetExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = WidgetExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -4451,15 +4468,13 @@
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 5Z4GVSS33P;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = WidgetExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = WidgetExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -4468,6 +4483,7 @@
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.WidgetExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore org.joinmastodon.app.WidgetExtension";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
@ -4482,15 +4498,11 @@
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = WidgetExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = WidgetExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -4560,7 +4572,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INTENTS_CODEGEN_LANGUAGE = Swift;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
@ -4604,9 +4616,12 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "Apple Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
@ -4618,7 +4633,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INTENTS_CODEGEN_LANGUAGE = Swift;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
@ -4668,10 +4683,9 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 5Z4GVSS33P;
EXCLUDED_SOURCE_FILE_NAMES = "Mastodon/Resources/Preview\\ Assets.xcassets";
INFOPLIST_FILE = Mastodon/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
@ -4683,6 +4697,7 @@
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore org.joinmastodon.app";
SWIFT_OBJC_BRIDGING_HEADER = "Mastodon/Vender/Mastodon-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
@ -4696,6 +4711,7 @@
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 5889;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = MastodonTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@ -4720,6 +4736,7 @@
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 5889;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = MastodonTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@ -4743,6 +4760,7 @@
baseConfigurationReference = 459EA4F43058CAB47719E963 /* Pods-Mastodon-MastodonUITests.debug.xcconfig */;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 5889;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = MastodonUITests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@ -4766,6 +4784,7 @@
baseConfigurationReference = BB482D32A7B9825BF5327C4F /* Pods-Mastodon-MastodonUITests.release.xcconfig */;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 5889;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = MastodonUITests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@ -4837,7 +4856,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INTENTS_CODEGEN_LANGUAGE = Swift;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
@ -4856,8 +4875,6 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = Mastodon/Info.plist;
@ -4884,6 +4901,7 @@
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 5889;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = MastodonTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@ -4907,6 +4925,7 @@
baseConfigurationReference = 728DE51ADA27C395C6E1BAB5 /* Pods-Mastodon-MastodonUITests.profile.xcconfig */;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 5889;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = MastodonUITests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@ -4930,7 +4949,6 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = NotificationService/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@ -4951,7 +4969,6 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = ShareActionExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@ -4973,7 +4990,6 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = MastodonIntent/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@ -4995,6 +5011,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = MastodonIntent/Info.plist;
@ -5005,6 +5022,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.MastodonIntent;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)";
SWIFT_VERSION = 5.0;
@ -5017,8 +5035,9 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements;
CODE_SIGN_STYLE = Automatic;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 5Z4GVSS33P;
INFOPLIST_FILE = MastodonIntent/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@ -5027,6 +5046,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.MastodonIntent;
PRODUCT_NAME = "$(TARGET_NAME)";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore org.joinmastodon.app.MastodonIntent";
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)";
SWIFT_VERSION = 5.0;
@ -5039,6 +5059,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = ShareActionExtension/Info.plist;
@ -5049,6 +5070,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)";
SWIFT_VERSION = 5.0;
@ -5061,8 +5083,9 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 5Z4GVSS33P;
INFOPLIST_FILE = ShareActionExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@ -5071,6 +5094,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore org.joinmastodon.app.ShareActionExtension";
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)";
SWIFT_VERSION = 5.0;
@ -5127,7 +5151,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INTENTS_CODEGEN_LANGUAGE = Swift;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
@ -5147,8 +5171,6 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = Mastodon/Info.plist;
@ -5174,6 +5196,7 @@
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 5889;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = MastodonTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@ -5197,6 +5220,7 @@
baseConfigurationReference = 0827D1674B2523503E8605F6 /* Pods-Mastodon-MastodonUITests.release snapshot.xcconfig */;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 5889;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = MastodonUITests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@ -5220,7 +5244,6 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = NotificationService/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@ -5241,7 +5264,6 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = ShareActionExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@ -5263,7 +5285,6 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = MastodonIntent/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@ -5286,6 +5307,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = NotificationService/Info.plist;
@ -5296,6 +5318,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
@ -5308,8 +5331,9 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 5Z4GVSS33P;
INFOPLIST_FILE = NotificationService/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@ -5318,6 +5342,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService;
PRODUCT_NAME = "$(TARGET_NAME)";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore org.joinmastodon.app.NotificationService";
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";

View File

@ -46,6 +46,15 @@
"version": "3.1.3"
}
},
{
"package": "FXPageControl",
"repositoryURL": "https://github.com/nicklockwood/FXPageControl.git",
"state": {
"branch": null,
"revision": "a94633402ba98c52f86c2a70e61ff086dec9de78",
"version": "1.6.0"
}
},
{
"package": "KeychainAccess",
"repositoryURL": "https://github.com/kishikawakatsumi/KeychainAccess.git",
@ -91,15 +100,6 @@
"version": "10.11.2"
}
},
{
"package": "NukeFLAnimatedImagePlugin",
"repositoryURL": "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git",
"state": {
"branch": null,
"revision": "b59c346a7d536336db3b0f12c72c6e53ee709e16",
"version": "8.0.0"
}
},
{
"package": "Pageboy",
"repositoryURL": "https://github.com/uias/Pageboy",
@ -216,6 +216,15 @@
"revision": "20f513ded04a040cdf5467f0891849b1763ede3b",
"version": "1.4.1"
}
},
{
"package": "XLPagerTabStrip",
"repositoryURL": "https://github.com/xmartlabs/XLPagerTabStrip.git",
"state": {
"branch": null,
"revision": "211ed62aa376722cf93c429802a8b6ff66a8bd52",
"version": "9.1.0"
}
}
]
},

View File

@ -541,7 +541,9 @@ private extension SceneCoordinator {
accountName: accountName,
setting: setting,
appContext: appContext,
authContext: authContext)
authContext: authContext,
sceneCoordinator: self
)
settingsCoordinator.delegate = self
settingsCoordinator.start()
@ -643,7 +645,5 @@ extension SceneCoordinator: SettingsCoordinatorDelegate {
authenticationController.authenticationSession?.start()
self.mastodonAuthenticationController = authenticationController
}
}

View File

@ -9,15 +9,7 @@ import SwiftUI
class AltTextViewController: UIViewController {
let textView = {
let textView: UITextView
if #available(iOS 16, *) {
// TODO: update code below to use TextKit 2 when dropping iOS 15 support
textView = UITextView(usingTextLayoutManager: false)
} else {
textView = UITextView()
}
let textView = UITextView(usingTextLayoutManager: false)
textView.textContainer.maximumNumberOfLines = 0
textView.textContainer.lineBreakMode = .byWordWrapping
textView.font = .preferredFont(forTextStyle: .callout)

View File

@ -31,17 +31,7 @@ final class MediaPreviewImageView: UIScrollView {
private var containerFrame: CGRect?
private var _interaction: UIInteraction? = {
if #available(iOS 16.0, *) {
return ImageAnalysisInteraction()
} else {
return nil
}
}()
@available(iOS 16.0, *)
var liveTextInteraction: ImageAnalysisInteraction {
_interaction as! ImageAnalysisInteraction
}
let liveTextInteraction = ImageAnalysisInteraction()
override init(frame: CGRect) {
super.init(frame: frame)
@ -72,9 +62,7 @@ extension MediaPreviewImageView {
doubleTapGestureRecognizer.delegate = self
imageView.addGestureRecognizer(doubleTapGestureRecognizer)
if #available(iOS 16.0, *) {
imageView.addInteraction(liveTextInteraction)
}
imageView.addInteraction(liveTextInteraction)
delegate = self
}
@ -119,8 +107,7 @@ extension MediaPreviewImageView: UIGestureRecognizerDelegate {
// but only if the Live Text button is toggled off
if let gr = otherGestureRecognizer as? UITapGestureRecognizer,
gr.numberOfTapsRequired == 2,
#available(iOS 16, *),
!liveTextInteraction.selectableItemsHighlighted {
liveTextInteraction.selectableItemsHighlighted == false {
return true
}
return false
@ -151,18 +138,16 @@ extension MediaPreviewImageView {
centerScrollViewContents()
if #available(iOS 16.0, *) {
Task.detached(priority: .userInitiated) {
do {
let analysis = try await ImageAnalyzer.shared.analyze(image, configuration: ImageAnalyzer.Configuration([.text, .machineReadableCode]))
await MainActor.run {
self.liveTextInteraction.analysis = analysis
self.liveTextInteraction.preferredInteractionTypes = .automatic
}
} catch {
await MainActor.run {
self.liveTextInteraction.preferredInteractionTypes = []
}
Task.detached(priority: .userInitiated) {
do {
let analysis = try await ImageAnalyzer.shared.analyze(image, configuration: ImageAnalyzer.Configuration([.text, .machineReadableCode]))
await MainActor.run {
self.liveTextInteraction.analysis = analysis
self.liveTextInteraction.preferredInteractionTypes = .automatic
}
} catch {
await MainActor.run {
self.liveTextInteraction.preferredInteractionTypes = []
}
}
}

View File

@ -40,9 +40,7 @@ extension MediaPreviewImageViewController {
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 16.0, *) {
previewImageView.liveTextInteraction.delegate = self
}
previewImageView.liveTextInteraction.delegate = self
previewImageView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(previewImageView)
NSLayoutConstraint.activate([
@ -90,16 +88,13 @@ extension MediaPreviewImageViewController {
extension MediaPreviewImageViewController: MediaPreviewPage {
func setShowingChrome(_ showingChrome: Bool) {
if #available(iOS 16.0, *) {
UIView.animate(withDuration: 0.3) {
self.previewImageView.liveTextInteraction.setSupplementaryInterfaceHidden(!showingChrome, animated: true)
}
UIView.animate(withDuration: 0.3) {
self.previewImageView.liveTextInteraction.setSupplementaryInterfaceHidden(!showingChrome, animated: true)
}
}
}
// MARK: - ImageAnalysisInteractionDelegate
@available(iOS 16.0, *)
extension MediaPreviewImageViewController: ImageAnalysisInteractionDelegate {
func presentingViewController(for interaction: ImageAnalysisInteraction) -> UIViewController? {
self
@ -109,18 +104,14 @@ extension MediaPreviewImageViewController: ImageAnalysisInteractionDelegate {
// MARK: - UIGestureRecognizerDelegate
extension MediaPreviewImageViewController: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if #available(iOS 16.0, *) {
let location = touch.location(in: previewImageView.imageView)
// for tap gestures, only items that can be tapped are relevant
if gestureRecognizer is UITapGestureRecognizer {
return !previewImageView.liveTextInteraction.hasSupplementaryInterface(at: location)
&& !previewImageView.liveTextInteraction.hasDataDetector(at: location)
} else {
// for long press, block out everything
return !previewImageView.liveTextInteraction.hasInteractiveItem(at: location)
}
let location = touch.location(in: previewImageView.imageView)
// for tap gestures, only items that can be tapped are relevant
if gestureRecognizer is UITapGestureRecognizer {
return !previewImageView.liveTextInteraction.hasSupplementaryInterface(at: location)
&& !previewImageView.liveTextInteraction.hasDataDetector(at: location)
} else {
return true
// for long press, block out everything
return !previewImageView.liveTextInteraction.hasInteractiveItem(at: location)
}
}
}
@ -129,10 +120,8 @@ extension MediaPreviewImageViewController: UIGestureRecognizerDelegate {
extension MediaPreviewImageViewController: UIContextMenuInteractionDelegate {
func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
if #available(iOS 16.0, *) {
if previewImageView.liveTextInteraction.hasInteractiveItem(at: previewImageView.imageView.convert(location, from: previewImageView)) {
return nil
}
if previewImageView.liveTextInteraction.hasInteractiveItem(at: previewImageView.imageView.convert(location, from: previewImageView)) {
return nil
}

View File

@ -10,7 +10,7 @@ import MastodonAsset
import MastodonLocalization
final class ServerRulesTableViewCell: UITableViewCell {
static let reuseIdentifier = "ServerRulesTableViewCell"
static let margin: CGFloat = 23
let indexImageView: UIImageView = {

View File

@ -15,10 +15,7 @@ extension MastodonServerRulesViewModel {
var snapshot = NSDiffableDataSourceSnapshot<ServerRuleSection, ServerRuleItem>()
snapshot.appendSections([.rules])
let ruleItems: [ServerRuleItem] = rules.enumerated().map { i, rule in
let ruleContext = ServerRuleItem.RuleContext(index: i, rule: rule)
return ServerRuleItem.rule(ruleContext)
}
let ruleItems: [ServerRuleItem] = rules.enumerated().map { index, rule in return ServerRuleItem.rule(index: index, rule: rule) }
snapshot.appendItems(ruleItems, toSection: .rules)
diffableDataSource?.apply(snapshot, animatingDifferences: false)
}

View File

@ -9,12 +9,5 @@ import Foundation
import MastodonSDK
enum ServerRuleItem: Hashable {
case rule(RuleContext)
}
extension ServerRuleItem {
struct RuleContext: Hashable {
let index: Int
let rule: Mastodon.Entity.Instance.Rule
}
case rule(index: Int, rule: Mastodon.Entity.Instance.Rule)
}

View File

@ -19,11 +19,11 @@ extension ServerRuleSection {
) -> UITableViewDiffableDataSource<ServerRuleSection, ServerRuleItem> {
return UITableViewDiffableDataSource(tableView: tableView) { tableView, indexPath, item in
switch item {
case .rule(let ruleContext):
case .rule(let index, let rule):
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: ServerRulesTableViewCell.self), for: indexPath) as! ServerRulesTableViewCell
cell.indexImageView.image = UIImage(systemName: "\(ruleContext.index + 1).circle") ?? UIImage(systemName: "questionmark.circle")
cell.indexImageView.image = UIImage(systemName: "\(index + 1).circle") ?? UIImage(systemName: "questionmark.circle")
cell.indexImageView.tintColor = Asset.Colors.Brand.lightBlurple.color
cell.ruleLabel.text = ruleContext.rule.text
cell.ruleLabel.text = rule.text
return cell
}
}

View File

@ -28,13 +28,8 @@ final class ProfileFieldCollectionViewCell: UICollectionViewCell {
let checkmark = UIImageView(image: Asset.Editing.checkmark.image.withRenderingMode(.alwaysTemplate))
var checkmarkPopoverString: String? = nil;
let tapGesture = UITapGestureRecognizer();
private var _editMenuInteraction: Any? = nil
@available(iOS 16, *)
fileprivate var editMenuInteraction: UIEditMenuInteraction {
_editMenuInteraction = _editMenuInteraction ?? UIEditMenuInteraction(delegate: self)
return _editMenuInteraction as! UIEditMenuInteraction
}
var editMenuInteraction: UIEditMenuInteraction!
override func prepareForReuse() {
super.prepareForReuse()
@ -56,6 +51,9 @@ final class ProfileFieldCollectionViewCell: UICollectionViewCell {
extension ProfileFieldCollectionViewCell {
private func _init() {
editMenuInteraction = UIEditMenuInteraction(delegate: self)
// Setup colors
checkmark.tintColor = Asset.Scene.Profile.About.bioAboutFieldVerifiedText.color;
@ -63,10 +61,8 @@ extension ProfileFieldCollectionViewCell {
tapGesture.addTarget(self, action: #selector(ProfileFieldCollectionViewCell.didTapCheckmark(_:)))
checkmark.addGestureRecognizer(tapGesture)
checkmark.isUserInteractionEnabled = true
if #available(iOS 16, *) {
checkmark.addInteraction(editMenuInteraction)
}
checkmark.addInteraction(editMenuInteraction)
// Setup Accessibility
checkmark.isAccessibilityElement = true
checkmark.accessibilityTraits = .none
@ -111,22 +107,7 @@ extension ProfileFieldCollectionViewCell {
}
@objc public func didTapCheckmark(_ recognizer: UITapGestureRecognizer) {
if #available(iOS 16, *) {
editMenuInteraction.presentEditMenu(with: UIEditMenuConfiguration(identifier: nil, sourcePoint: recognizer.location(in: checkmark)))
} else {
guard let editMenuLabel = checkmarkPopoverString else { return }
self.isUserInteractionEnabled = true
self.becomeFirstResponder()
UIMenuController.shared.menuItems = [
UIMenuItem(
title: editMenuLabel,
action: #selector(dismissVerifiedMenu)
)
]
UIMenuController.shared.showMenu(from: checkmark, rect: checkmark.bounds)
}
editMenuInteraction?.presentEditMenu(with: UIEditMenuConfiguration(identifier: nil, sourcePoint: recognizer.location(in: checkmark)))
}
private var valueMetas: [(title: String, Meta)] {
@ -190,7 +171,6 @@ extension ProfileFieldCollectionViewCell: MetaLabelDelegate {
}
// MARK: UIEditMenuInteractionDelegate
@available(iOS 16.0, *)
extension ProfileFieldCollectionViewCell: UIEditMenuInteractionDelegate {
func editMenuInteraction(_ interaction: UIEditMenuInteraction, menuFor configuration: UIEditMenuConfiguration, suggestedActions: [UIMenuElement]) -> UIMenu? {
guard let editMenuLabel = checkmarkPopoverString else { return UIMenu(children: []) }

View File

@ -62,11 +62,7 @@ final class RootSplitViewController: UISplitViewController, NeedsDependency {
// disable edge swipe gesture
presentsWithGesture = false
if #available(iOS 14.5, *) {
displayModeButtonVisibility = .never
} else {
// Fallback on earlier versions
}
displayModeButtonVisibility = .never
setViewController(searchViewController, for: .primary)
setViewController(contentSplitViewController, for: .secondary)

View File

@ -23,7 +23,7 @@ enum AboutSettingsEntry: Hashable {
case .privacyPolicy:
return L10n.Scene.Settings.AboutMastodon.privacyPolicy
case .clearMediaCache(_):
return L10n.Scene.Settings.AboutMastodon.cleaerMediaStorage
return L10n.Scene.Settings.AboutMastodon.clearMediaStorage
}
}

View File

@ -0,0 +1,155 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
import MastodonSDK
protocol AboutInstanceViewControllerDelegate: AnyObject {
func showAdminAccount(_ viewController: AboutInstanceViewController, account: Mastodon.Entity.Account)
func sendEmailToAdmin(_ viewController: AboutInstanceViewController, emailAddress: String)
}
class AboutInstanceViewController: UIViewController {
weak var delegate: AboutInstanceViewControllerDelegate?
var dataSource: AboutInstanceTableViewDataSource?
let tableView: UITableView
let headerView: AboutInstanceTableHeaderView
let footerView: AboutInstanceTableFooterView
var instance: Mastodon.Entity.V2.Instance?
init() {
tableView = UITableView(frame: .zero, style: .insetGrouped)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.register(ContactAdminTableViewCell.self, forCellReuseIdentifier: ContactAdminTableViewCell.reuseIdentifier)
tableView.register(AdminTableViewCell.self, forCellReuseIdentifier: AdminTableViewCell.reuseIdentifier)
headerView = AboutInstanceTableHeaderView()
footerView = AboutInstanceTableFooterView()
super.init(nibName: nil, bundle: nil)
let dataSource = AboutInstanceTableViewDataSource(tableView: tableView) { tableView, indexPath, itemIdentifier in
switch itemIdentifier {
case .adminAccount(let account):
guard let cell = tableView.dequeueReusableCell(withIdentifier: AdminTableViewCell.reuseIdentifier, for: indexPath) as? AdminTableViewCell else { fatalError("WTF?! Wrong cell.") }
cell.condensedUserView.configure(with: account, showFollowers: false)
return cell
case .contactAdmin:
guard let cell = tableView.dequeueReusableCell(withIdentifier: ContactAdminTableViewCell.reuseIdentifier, for: indexPath) as? ContactAdminTableViewCell else { fatalError("WTF?! Wrong cell.") }
cell.configure()
return cell
}
}
tableView.delegate = self
tableView.dataSource = dataSource
self.dataSource = dataSource
view.addSubview(tableView)
setupConstraints()
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
private func setupConstraints() {
let constraints = [
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
view.trailingAnchor.constraint(equalTo: tableView.trailingAnchor),
view.bottomAnchor.constraint(equalTo: tableView.bottomAnchor),
]
NSLayoutConstraint.activate(constraints)
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableHeaderView = headerView
tableView.tableFooterView = footerView
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if let tableHeaderView = tableView.tableHeaderView {
let size = tableHeaderView.systemLayoutSizeFitting(.init(width: self.tableView.frame.width, height: 10_000))
tableHeaderView.frame.size = size
tableView.tableHeaderView = tableHeaderView
}
if let tableFooterView = tableView.tableFooterView {
let size = tableFooterView.systemLayoutSizeFitting(.init(width: self.tableView.frame.width, height: 10_000))
tableFooterView.frame.size = size
tableView.tableFooterView = tableFooterView
}
super.viewWillLayoutSubviews()
}
func update(with instance: Mastodon.Entity.V2.Instance) {
self.instance = instance
var snapshot = NSDiffableDataSourceSnapshot<AboutInstanceSection, AboutInstanceItem>()
snapshot.appendSections([.main])
if let account = instance.contact?.account {
snapshot.appendItems([.adminAccount(account)], toSection: .main)
}
if let email = instance.contact?.email {
snapshot.appendItems([.contactAdmin(email)], toSection: .main)
}
dataSource?.apply(snapshot, animatingDifferences: false)
guard let thumbnailUrlString = instance.thumbnail?.url, let thumbnailUrl = URL(string: thumbnailUrlString) else { return }
DispatchQueue.main.async {
self.headerView.updateImage(with: thumbnailUrl) { [weak self] in
DispatchQueue.main.async {
guard let self else { return }
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
}
}
}
}
func updateFooter(with extendedDescription: Mastodon.Entity.ExtendedDescription) {
DispatchQueue.main.async {
self.footerView.update(with: extendedDescription)
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
}
}
}
extension AboutInstanceViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let snapshot = dataSource?.snapshot() else {
return tableView.deselectRow(at: indexPath, animated: true)
}
switch snapshot.itemIdentifiers(inSection: .main)[indexPath.row] {
case .adminAccount(let account):
delegate?.showAdminAccount(self, account: account)
case .contactAdmin(let email):
delegate?.sendEmailToAdmin(self, emailAddress: email)
}
tableView.deselectRow(at: indexPath, animated: true)
}
}

View File

@ -0,0 +1,58 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
import MastodonSDK
protocol InstanceRulesViewControllerDelegate: AnyObject {
}
class InstanceRulesViewController: UIViewController {
weak var delegate: InstanceRulesViewControllerDelegate?
let tableView: UITableView
var dataSource: UITableViewDiffableDataSource<ServerRuleSection, ServerRuleItem>?
var sections: [ServerRuleSection] = []
init() {
tableView = UITableView(frame: .zero, style: .insetGrouped)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.register(ServerRulesTableViewCell.self, forCellReuseIdentifier: ServerRulesTableViewCell.reuseIdentifier)
super.init(nibName: nil, bundle: nil)
view.addSubview(tableView)
let dataSource = ServerRuleSection.tableViewDiffableDataSource(tableView: tableView)
tableView.dataSource = dataSource
self.dataSource = dataSource
setupConstraints()
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
private func setupConstraints() {
let constraints = [
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
view.trailingAnchor.constraint(equalTo: tableView.trailingAnchor),
view.bottomAnchor.constraint(equalTo: tableView.bottomAnchor),
]
NSLayoutConstraint.activate(constraints)
}
func update(with instance: Mastodon.Entity.V2.Instance) {
guard let dataSource, let rules = instance.rules, rules.isNotEmpty else { return }
var snapshot = NSDiffableDataSourceSnapshot<ServerRuleSection, ServerRuleItem>()
snapshot.appendSections([.rules])
let ruleItems = rules.enumerated().compactMap { index, rule in ServerRuleItem.rule(index: index, rule: rule) }
snapshot.appendItems(ruleItems, toSection: .rules)
dataSource.apply(snapshot)
}
}

View File

@ -0,0 +1,165 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
import MastodonSDK
import MastodonLocalization
import MetaTextKit
enum ServerDetailsTab: Int, CaseIterable {
case about = 0
case rules = 1
var title: String {
switch self {
case .about: return L10n.Scene.Settings.ServerDetails.about
case .rules: return L10n.Scene.Settings.ServerDetails.rules
}
}
}
protocol ServerDetailsViewControllerDelegate: AnyObject {}
class ServerDetailsViewController: UIViewController {
weak var delegate: (ServerDetailsViewControllerDelegate & AboutInstanceViewControllerDelegate & InstanceRulesViewControllerDelegate & MetaLabelDelegate)? {
didSet {
aboutInstanceViewController.delegate = delegate
instanceRulesViewController.delegate = delegate
aboutInstanceViewController.footerView.contentLabel.linkDelegate = delegate
}
}
let pageController: UIPageViewController
private let segmentedControlWrapper: UIView
let segmentedControl: UISegmentedControl
let aboutInstanceViewController: AboutInstanceViewController
let instanceRulesViewController: InstanceRulesViewController
let containerView: UIView
init(domain: String) {
segmentedControl = UISegmentedControl()
segmentedControl.translatesAutoresizingMaskIntoConstraints = false
segmentedControlWrapper = UIView()
segmentedControlWrapper.translatesAutoresizingMaskIntoConstraints = false
segmentedControlWrapper.addSubview(segmentedControl)
containerView = UIView()
containerView.translatesAutoresizingMaskIntoConstraints = false
aboutInstanceViewController = AboutInstanceViewController()
instanceRulesViewController = InstanceRulesViewController()
pageController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal)
pageController.setViewControllers([aboutInstanceViewController], direction: .forward, animated: false)
pageController.view.translatesAutoresizingMaskIntoConstraints = false
super.init(nibName: nil, bundle: nil)
view.addSubview(segmentedControlWrapper)
view.addSubview(containerView)
view.backgroundColor = .systemGroupedBackground
containerView.addSubview(pageController.view)
addChild(pageController)
pageController.didMove(toParent: self)
pageController.delegate = self
pageController.dataSource = self
ServerDetailsTab.allCases.forEach {
segmentedControl.insertSegment(withTitle: $0.title, at: $0.rawValue, animated: false)
}
segmentedControl.selectedSegmentIndex = ServerDetailsTab.about.rawValue
segmentedControl.addTarget(self, action: #selector(ServerDetailsViewController.segmentedControlValueChanged(_:)), for: .valueChanged)
setupConstraints()
title = domain
setupNavigationBarAppearance()
setupNavigationBarBackgroundView()
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
private func setupConstraints() {
let constraints = [
segmentedControlWrapper.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
segmentedControlWrapper.leadingAnchor.constraint(equalTo: view.leadingAnchor),
view.trailingAnchor.constraint(equalTo: segmentedControlWrapper.trailingAnchor),
containerView.topAnchor.constraint(equalTo: segmentedControlWrapper.bottomAnchor),
containerView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
view.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
segmentedControl.topAnchor.constraint(equalTo: segmentedControlWrapper.topAnchor, constant: 4),
segmentedControl.leadingAnchor.constraint(equalTo: segmentedControlWrapper.leadingAnchor, constant: 16),
segmentedControlWrapper.trailingAnchor.constraint(equalTo: segmentedControl.trailingAnchor, constant: 16),
segmentedControlWrapper.bottomAnchor.constraint(equalTo: segmentedControl.bottomAnchor, constant: 8),
pageController.view.topAnchor.constraint(equalTo: containerView.topAnchor),
pageController.view.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
containerView.trailingAnchor.constraint(equalTo: pageController.view.trailingAnchor),
containerView.bottomAnchor.constraint(equalTo: pageController.view.bottomAnchor),
]
NSLayoutConstraint.activate(constraints)
}
//MARK: - Actions
@objc
func segmentedControlValueChanged(_ sender: UISegmentedControl) {
guard let selectedTab = ServerDetailsTab(rawValue: sender.selectedSegmentIndex) else { return }
switch selectedTab {
case .about:
pageController.setViewControllers([aboutInstanceViewController], direction: .reverse, animated: true)
case .rules:
pageController.setViewControllers([instanceRulesViewController], direction: .forward, animated: true)
}
}
func update(with instance: Mastodon.Entity.V2.Instance) {
aboutInstanceViewController.update(with: instance)
instanceRulesViewController.update(with: instance)
}
func updateFooter(with extendedDescription: Mastodon.Entity.ExtendedDescription) {
aboutInstanceViewController.updateFooter(with: extendedDescription)
}
}
//MARK: - UIPageViewControllerDataSource
extension ServerDetailsViewController: UIPageViewControllerDataSource {
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
if viewController == instanceRulesViewController {
return aboutInstanceViewController
} else {
return nil
}
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
if viewController == aboutInstanceViewController {
return instanceRulesViewController
} else {
return nil
}
}
}
//MARK: - UIPageViewControllerDelegate
extension ServerDetailsViewController: UIPageViewControllerDelegate {
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
guard let currentViewController = pageViewController.viewControllers?.first else { return }
if currentViewController == aboutInstanceViewController {
segmentedControl.selectedSegmentIndex = ServerDetailsTab.about.rawValue
} else if currentViewController == instanceRulesViewController {
segmentedControl.selectedSegmentIndex = ServerDetailsTab.rules.rawValue
}
}
}
extension ServerDetailsViewController: OnboardingViewControllerAppearance {}

View File

@ -0,0 +1,18 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import Foundation
import MastodonSDK
import MastodonLocalization
enum AboutInstanceSection: Int, Hashable {
case main = 0
var title: String {
return L10n.Scene.Settings.ServerDetails.AboutInstance.title
}
}
enum AboutInstanceItem: Hashable {
case adminAccount(Mastodon.Entity.Account)
case contactAdmin(String)
}

View File

@ -0,0 +1,68 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
import MetaTextKit
import MastodonSDK
import MastodonMeta
import MastodonCore
import MastodonAsset
import MastodonLocalization
class AboutInstanceTableFooterView: UIView {
let headlineLabel: UILabel
let contentLabel: MetaLabel
init() {
headlineLabel = UILabel()
headlineLabel.translatesAutoresizingMaskIntoConstraints = false
headlineLabel.font = UIFontMetrics(forTextStyle: .title2).scaledFont(for: .systemFont(ofSize: 22, weight: .bold))
contentLabel = MetaLabel(style: .aboutInstance)
contentLabel.numberOfLines = 0
contentLabel.translatesAutoresizingMaskIntoConstraints = false
super.init(frame: .zero)
addSubview(headlineLabel)
addSubview(contentLabel)
setupConstraints()
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
private func setupConstraints() {
let horizontalMargin = 16.0
let verticalMargin = 24.0
let constraints = [
headlineLabel.topAnchor.constraint(equalTo: topAnchor, constant: verticalMargin),
headlineLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: horizontalMargin),
trailingAnchor.constraint(equalTo: headlineLabel.trailingAnchor, constant: horizontalMargin),
contentLabel.topAnchor.constraint(equalTo: headlineLabel.bottomAnchor, constant: 8),
contentLabel.leadingAnchor.constraint(equalTo: headlineLabel.leadingAnchor),
contentLabel.trailingAnchor.constraint(equalTo: headlineLabel.trailingAnchor),
bottomAnchor.constraint(equalTo: contentLabel.bottomAnchor, constant: verticalMargin),
]
NSLayoutConstraint.activate(constraints)
}
func update(with extendedDescription: Mastodon.Entity.ExtendedDescription) {
headlineLabel.text = L10n.Scene.Settings.ServerDetails.AboutInstance.legalNotice
let content = extendedDescription.content
.replacingOccurrences(of: "<br>", with: "\n")
.replacingOccurrences(of: "\n\n", with: "\n")
if let metaContent = try? MastodonMetaContent.convert(document: MastodonContent(content: content, emojis: [:])) {
contentLabel.configure(content: metaContent)
} else {
let content = PlaintextMetaContent(string: content)
contentLabel.configure(content: content)
}
}
}

View File

@ -0,0 +1,16 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
class AboutInstanceTableViewDataSource: UITableViewDiffableDataSource<AboutInstanceSection, AboutInstanceItem> {
override init(tableView: UITableView, cellProvider: @escaping UITableViewDiffableDataSource<AboutInstanceSection, AboutInstanceItem>.CellProvider) {
super.init(tableView: tableView, cellProvider: cellProvider)
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
guard let section = AboutInstanceSection(rawValue: section) else { return nil }
return section.title.uppercased()
}
}

View File

@ -0,0 +1,40 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
import MastodonAsset
import AlamofireImage
class AboutInstanceTableHeaderView: UIView {
let thumbnailImageView: UIImageView
init() {
thumbnailImageView = UIImageView(image: Asset.Settings.aboutInstancePlaceholder.image)
thumbnailImageView.contentMode = .scaleAspectFill
thumbnailImageView.translatesAutoresizingMaskIntoConstraints = false
super.init(frame: .zero)
addSubview(thumbnailImageView)
setupConstraints()
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
private func setupConstraints() {
let constraints = [
thumbnailImageView.topAnchor.constraint(equalTo: topAnchor),
thumbnailImageView.leadingAnchor.constraint(equalTo: leadingAnchor),
trailingAnchor.constraint(equalTo: thumbnailImageView.trailingAnchor),
bottomAnchor.constraint(equalTo: thumbnailImageView.bottomAnchor, constant: 16),
]
NSLayoutConstraint.activate(constraints)
}
func updateImage(with thumbnailURL: URL, completion: (() -> Void)? = nil) {
thumbnailImageView.af.setImage(withURL: thumbnailURL, placeholderImage: Asset.Settings.aboutInstancePlaceholder.image, completion: { _ in
completion?()
})
}
}

View File

@ -0,0 +1,5 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
typealias AdminTableViewCell = SearchResultsProfileTableViewCell

View File

@ -0,0 +1,22 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
import MastodonAsset
import MastodonLocalization
class ContactAdminTableViewCell: UITableViewCell {
static let reuseIdentifier = "ContactAdminTableViewCell"
func configure() {
var configuration = defaultContentConfiguration()
configuration.textProperties.color = Asset.Colors.Brand.blurple.color
configuration.image = UIImage(systemName: "envelope")
configuration.imageProperties.tintColor = Asset.Colors.Brand.blurple.color
configuration.text = L10n.Scene.Settings.ServerDetails.AboutInstance.messageAdmin
backgroundColor = .secondarySystemGroupedBackground
contentConfiguration = configuration
}
}

View File

@ -10,62 +10,78 @@ struct SettingsSection: Hashable {
enum SettingsEntry: Hashable {
case general
case notifications
case serverDetails(domain: String)
case aboutMastodon
case logout(accountName: String)
var title: String {
switch self {
case .general:
return L10n.Scene.Settings.Overview.general
case .notifications:
return L10n.Scene.Settings.Overview.notifications
case .aboutMastodon:
return L10n.Scene.Settings.Overview.aboutMastodon
case .logout(let accountName):
return L10n.Scene.Settings.Overview.logout(accountName)
case .general:
return L10n.Scene.Settings.Overview.general
case .notifications:
return L10n.Scene.Settings.Overview.notifications
case .serverDetails(_):
return L10n.Scene.Settings.Overview.serverDetails
case .aboutMastodon:
return L10n.Scene.Settings.Overview.aboutMastodon
case .logout(let accountName):
return L10n.Scene.Settings.Overview.logout(accountName)
}
}
var secondaryTitle: String? {
switch self {
case .serverDetails(domain: let domain):
return domain
case .general, .notifications, .aboutMastodon, .logout(_):
return nil
}
}
var accessoryType: UITableViewCell.AccessoryType {
switch self {
case .general, .notifications, .aboutMastodon, .logout(_):
return .disclosureIndicator
case .general, .notifications, .serverDetails(_), .aboutMastodon, .logout(_):
return .disclosureIndicator
}
}
var icon: UIImage? {
switch self {
case .general:
return UIImage(systemName: "gear")
case .notifications:
return UIImage(systemName: "bell.badge")
case .aboutMastodon:
return UIImage(systemName: "info.circle.fill")
case .logout(_):
return nil
case .general:
return UIImage(systemName: "gear")
case .notifications:
return UIImage(systemName: "bell.badge")
case .serverDetails(_):
return UIImage(systemName: "server.rack")
case .aboutMastodon:
return UIImage(systemName: "info.circle.fill")
case .logout(_):
return nil
}
}
var iconBackgroundColor: UIColor? {
switch self {
case .general:
return .systemGray
case .notifications:
return .systemRed
case .aboutMastodon:
return .systemPurple
case .logout(_):
return nil
case .general:
return .systemGray
case .notifications:
return .systemRed
case .serverDetails(_):
return .systemTeal
case .aboutMastodon:
return .systemPurple
case .logout(_):
return nil
}
}
var textColor: UIColor {
switch self {
case .general, .notifications, .aboutMastodon:
return .label
case .logout(_):
return .red
case .general, .notifications, .aboutMastodon, .serverDetails(_):
return .label
case .logout(_):
return .red
}
}

View File

@ -9,7 +9,9 @@ class SettingsTableViewCell: UITableViewCell {
let iconImageView: UIImageView
let iconImageBackgroundView: UIView
let titleLabel: UILabel
let secondaryLabel: UILabel
private let labelStackView: UIStackView
private let contentStackView: UIStackView
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
@ -21,8 +23,17 @@ class SettingsTableViewCell: UITableViewCell {
iconImageBackgroundView.addSubview(iconImageView)
titleLabel = UILabel()
titleLabel.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .regular))
secondaryLabel = UILabel()
secondaryLabel.font = UIFontMetrics(forTextStyle: .caption1).scaledFont(for: .systemFont(ofSize: 12, weight: .regular))
secondaryLabel.textColor = .secondaryLabel
contentStackView = UIStackView(arrangedSubviews: [iconImageBackgroundView, titleLabel])
labelStackView = UIStackView(arrangedSubviews: [titleLabel, secondaryLabel])
labelStackView.axis = .vertical
labelStackView.spacing = 2
labelStackView.alignment = .leading
contentStackView = UIStackView(arrangedSubviews: [iconImageBackgroundView, labelStackView])
contentStackView.translatesAutoresizingMaskIntoConstraints = false
contentStackView.axis = .horizontal
contentStackView.alignment = .center
@ -50,8 +61,8 @@ class SettingsTableViewCell: UITableViewCell {
iconImageView.centerXAnchor.constraint(equalTo: iconImageBackgroundView.centerXAnchor),
iconImageView.widthAnchor.constraint(equalToConstant: 20),
titleLabel.topAnchor.constraint(greaterThanOrEqualTo: contentView.topAnchor, constant: 12),
contentView.bottomAnchor.constraint(greaterThanOrEqualTo: titleLabel.bottomAnchor, constant: 12),
labelStackView.topAnchor.constraint(greaterThanOrEqualTo: contentView.topAnchor, constant: 12),
contentView.bottomAnchor.constraint(greaterThanOrEqualTo: labelStackView.bottomAnchor, constant: 12),
]
NSLayoutConstraint.activate(constraints)
@ -61,6 +72,13 @@ class SettingsTableViewCell: UITableViewCell {
titleLabel.textColor = entry.textColor
titleLabel.text = entry.title
if let secondaryTitle = entry.secondaryTitle {
secondaryLabel.isHidden = false
secondaryLabel.text = secondaryTitle
} else {
secondaryLabel.isHidden = true
}
if let icon = entry.icon {
iconImageView.image = icon
iconImageView.tintColor = .white
@ -73,7 +91,6 @@ class SettingsTableViewCell: UITableViewCell {
iconImageBackgroundView.backgroundColor = entry.iconBackgroundColor
accessoryType = entry.accessoryType
}
}

View File

@ -16,11 +16,11 @@ class SettingsViewController: UIViewController {
var tableViewDataSource: UITableViewDiffableDataSource<SettingsSection, SettingsEntry>?
let tableView: UITableView
init(accountName: String) {
init(accountName: String, domain: String) {
sections = [
.init(entries: [.general, .notifications]),
.init(entries: [.aboutMastodon]),
.init(entries: [.serverDetails(domain: domain), .aboutMastodon]),
.init(entries: [.logout(accountName: accountName)])
]

View File

@ -6,6 +6,7 @@ import MastodonCore
import CoreDataStack
import MastodonSDK
import Combine
import MetaTextKit
protocol SettingsCoordinatorDelegate: AnyObject {
func logout(_ settingsCoordinator: SettingsCoordinator)
@ -26,15 +27,17 @@ class SettingsCoordinator: NSObject, Coordinator {
let appContext: AppContext
let authContext: AuthContext
var disposeBag = Set<AnyCancellable>()
let sceneCoordinator: SceneCoordinator
init(presentedOn: UIViewController, accountName: String, setting: Setting, appContext: AppContext, authContext: AuthContext) {
init(presentedOn: UIViewController, accountName: String, setting: Setting, appContext: AppContext, authContext: AuthContext, sceneCoordinator: SceneCoordinator) {
self.presentedOn = presentedOn
navigationController = UINavigationController()
self.setting = setting
self.appContext = appContext
self.authContext = authContext
self.sceneCoordinator = sceneCoordinator
settingsViewController = SettingsViewController(accountName: accountName)
settingsViewController = SettingsViewController(accountName: accountName, domain: authContext.mastodonAuthenticationBox.domain)
}
func start() {
@ -65,8 +68,29 @@ extension SettingsCoordinator: SettingsViewControllerDelegate {
let notificationViewController = NotificationSettingsViewController(currentSetting: currentSetting, notificationsEnabled: notificationsEnabled)
notificationViewController.delegate = self
self.navigationController.pushViewController(notificationViewController, animated: true)
navigationController.pushViewController(notificationViewController, animated: true)
case .serverDetails(let domain):
let serverDetailsViewController = ServerDetailsViewController(domain: domain)
serverDetailsViewController.delegate = self
appContext.apiService.instanceV2(domain: domain)
.sink { _ in
} receiveValue: { content in
serverDetailsViewController.update(with: content.value)
}
.store(in: &disposeBag)
appContext.apiService.extendedDescription(domain: domain)
.sink { _ in
} receiveValue: { content in
serverDetailsViewController.updateFooter(with: content.value)
}
.store(in: &disposeBag)
navigationController.pushViewController(serverDetailsViewController, animated: true)
case .aboutMastodon:
let aboutViewController = AboutViewController()
aboutViewController.delegate = self
@ -135,6 +159,8 @@ extension SettingsCoordinator: NotificationSettingsViewControllerDelegate {
guard viewModel.updated else { return }
//Show spinner?
let authenticationBox = authContext.mastodonAuthenticationBox
guard let subscription = setting.activeSubscription,
setting.domain == authenticationBox.domain,
@ -168,16 +194,10 @@ extension SettingsCoordinator: NotificationSettingsViewControllerDelegate {
})
.store(in: &disposeBag)
}
func showNotificationSettings(_ viewController: UIViewController) {
if #available(iOS 16.0, *) {
if let url = URL(string: UIApplication.openNotificationSettingsURLString) {
UIApplication.shared.open(url)
}
} else {
if let url = URL(string: UIApplication.openSettingsURLString) {
UIApplication.shared.open(url)
}
if let url = URL(string: UIApplication.openNotificationSettingsURLString) {
UIApplication.shared.open(url)
}
}
}
@ -189,3 +209,58 @@ extension SettingsCoordinator: PolicySelectionViewControllerDelegate {
try? self.appContext.managedObjectContext.save()
}
}
//MARK: - ServerDetailsViewControllerDelegate
extension SettingsCoordinator: ServerDetailsViewControllerDelegate {
}
extension SettingsCoordinator: AboutInstanceViewControllerDelegate {
@MainActor func showAdminAccount(_ viewController: AboutInstanceViewController, account: Mastodon.Entity.Account) {
Task {
let user = try await appContext.apiService.fetchUser(username: account.username, domain: authContext.mastodonAuthenticationBox.domain, authenticationBox: authContext.mastodonAuthenticationBox)
let profileViewModel = ProfileViewModel(context: appContext, authContext: authContext, optionalMastodonUser: user)
_ = await MainActor.run {
sceneCoordinator.present(scene: .profile(viewModel: profileViewModel), transition: .show)
}
}
}
func sendEmailToAdmin(_ viewController: AboutInstanceViewController, emailAddress: String) {
if let emailUrl = URL(string: "mailto:\(emailAddress)"), UIApplication.shared.canOpenURL(emailUrl) {
UIApplication.shared.open(emailUrl)
}
}
}
extension SettingsCoordinator: InstanceRulesViewControllerDelegate {
}
extension SettingsCoordinator: MetaLabelDelegate {
@MainActor
func metaLabel(_ metaLabel: MetaLabel, didSelectMeta meta: Meta) {
switch meta {
case .url(_, _, let url, _):
guard let url = URL(string: url) else { return }
_ = sceneCoordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil))
case .mention(_, _, let userInfo):
guard let href = userInfo?["href"] as? String,
let url = URL(string: href) else { return }
_ = sceneCoordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil))
case .hashtag(_, let hashtag, _):
let hashtagTimelineViewModel = HashtagTimelineViewModel(context: appContext, authContext: authContext, hashtag: hashtag)
_ = sceneCoordinator.present(scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel), from: nil, transition: .show)
case .email(let email, _):
if let emailUrl = URL(string: "mailto:\(email)"), UIApplication.shared.canOpenURL(emailUrl) {
UIApplication.shared.open(emailUrl)
}
case .emoji:
break
}
}
}

View File

@ -1,239 +0,0 @@
{
"pins" : [
{
"identity" : "alamofire",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Alamofire/Alamofire.git",
"state" : {
"revision" : "8dd85aee02e39dd280c75eef88ffdb86eed4b07b",
"version" : "5.6.2"
}
},
{
"identity" : "alamofireimage",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Alamofire/AlamofireImage.git",
"state" : {
"revision" : "98cbb00ce0ec5fc8e52a5b50a6bfc08d3e5aee10",
"version" : "4.2.0"
}
},
{
"identity" : "commonoslog",
"kind" : "remoteSourceControl",
"location" : "https://github.com/MainasuK/CommonOSLog",
"state" : {
"revision" : "c121624a30698e9886efe38aebb36ff51c01b6c2",
"version" : "0.1.1"
}
},
{
"identity" : "faviconfinder",
"kind" : "remoteSourceControl",
"location" : "https://github.com/will-lumley/FaviconFinder.git",
"state" : {
"revision" : "1f74844f77f79b95c0bb0130b3a87d4f340e6d3a",
"version" : "3.3.0"
}
},
{
"identity" : "flanimatedimage",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Flipboard/FLAnimatedImage.git",
"state" : {
"revision" : "d4f07b6f164d53c1212c3e54d6460738b1981e9f",
"version" : "1.0.17"
}
},
{
"identity" : "fpsindicator",
"kind" : "remoteSourceControl",
"location" : "https://github.com/MainasuK/FPSIndicator.git",
"state" : {
"revision" : "e4a5067ccd5293b024c767f09e51056afd4a4796",
"version" : "1.1.0"
}
},
{
"identity" : "fuzi",
"kind" : "remoteSourceControl",
"location" : "https://github.com/cezheng/Fuzi.git",
"state" : {
"revision" : "f08c8323da21e985f3772610753bcfc652c2103f",
"version" : "3.1.3"
}
},
{
"identity" : "keychainaccess",
"kind" : "remoteSourceControl",
"location" : "https://github.com/kishikawakatsumi/KeychainAccess.git",
"state" : {
"revision" : "84e546727d66f1adc5439debad16270d0fdd04e7",
"version" : "4.2.2"
}
},
{
"identity" : "metatextkit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/TwidereProject/MetaTextKit.git",
"state" : {
"revision" : "dcd5255d6930c2fab408dc8562c577547e477624",
"version" : "2.2.5"
}
},
{
"identity" : "nextlevelsessionexporter",
"kind" : "remoteSourceControl",
"location" : "https://github.com/NextLevel/NextLevelSessionExporter.git",
"state" : {
"revision" : "b6c0cce1aa37fe1547d694f958fac3c3524b74da",
"version" : "0.4.6"
}
},
{
"identity" : "nuke",
"kind" : "remoteSourceControl",
"location" : "https://github.com/kean/Nuke.git",
"state" : {
"revision" : "a002b7fd786f2df2ed4333fe73a9727499fd9d97",
"version" : "10.11.2"
}
},
{
"identity" : "nuke-flanimatedimage-plugin",
"kind" : "remoteSourceControl",
"location" : "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git",
"state" : {
"revision" : "b59c346a7d536336db3b0f12c72c6e53ee709e16",
"version" : "8.0.0"
}
},
{
"identity" : "pageboy",
"kind" : "remoteSourceControl",
"location" : "https://github.com/uias/Pageboy",
"state" : {
"revision" : "af8fa81788b893205e1ff42ddd88c5b0b315d7c5",
"version" : "3.7.0"
}
},
{
"identity" : "panmodal",
"kind" : "remoteSourceControl",
"location" : "https://github.com/slackhq/PanModal.git",
"state" : {
"revision" : "b012aecb6b67a8e46369227f893c12544846613f",
"version" : "1.2.7"
}
},
{
"identity" : "sdwebimage",
"kind" : "remoteSourceControl",
"location" : "https://github.com/SDWebImage/SDWebImage.git",
"state" : {
"revision" : "9248fe561a2a153916fb9597e3af4434784c6d32",
"version" : "5.13.4"
}
},
{
"identity" : "stripes",
"kind" : "remoteSourceControl",
"location" : "https://github.com/eneko/Stripes.git",
"state" : {
"revision" : "d533fd44b8043a3abbf523e733599173d6f98c11",
"version" : "0.2.0"
}
},
{
"identity" : "swift-collections",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-collections.git",
"state" : {
"revision" : "f504716c27d2e5d4144fa4794b12129301d17729",
"version" : "1.0.3"
}
},
{
"identity" : "swift-nio",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio.git",
"state" : {
"revision" : "546610d52b19be3e19935e0880bb06b9c03f5cef",
"version" : "1.14.4"
}
},
{
"identity" : "swift-nio-zlib-support",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio-zlib-support.git",
"state" : {
"revision" : "37760e9a52030bb9011972c5213c3350fa9d41fd",
"version" : "1.0.0"
}
},
{
"identity" : "swiftsoup",
"kind" : "remoteSourceControl",
"location" : "https://github.com/scinfu/SwiftSoup.git",
"state" : {
"revision" : "6778575285177365cbad3e5b8a72f2a20583cfec",
"version" : "2.4.3"
}
},
{
"identity" : "swiftui-introspect",
"kind" : "remoteSourceControl",
"location" : "https://github.com/siteline/SwiftUI-Introspect.git",
"state" : {
"revision" : "f2616860a41f9d9932da412a8978fec79c06fe24",
"version" : "0.1.4"
}
},
{
"identity" : "tabbarpager",
"kind" : "remoteSourceControl",
"location" : "https://github.com/TwidereProject/TabBarPager.git",
"state" : {
"revision" : "488aa66d157a648901b61721212c0dec23d27ee5",
"version" : "0.1.0"
}
},
{
"identity" : "tabman",
"kind" : "remoteSourceControl",
"location" : "https://github.com/uias/Tabman",
"state" : {
"revision" : "4a4f7c755b875ffd4f9ef10d67a67883669d2465",
"version" : "2.13.0"
}
},
{
"identity" : "tocropviewcontroller",
"kind" : "remoteSourceControl",
"location" : "https://github.com/TimOliver/TOCropViewController.git",
"state" : {
"revision" : "d0470491f56e734731bbf77991944c0dfdee3e0e",
"version" : "2.6.1"
}
},
{
"identity" : "uihostingconfigurationbackport",
"kind" : "remoteSourceControl",
"location" : "https://github.com/woxtu/UIHostingConfigurationBackport.git",
"state" : {
"revision" : "6091f2d38faa4b24fc2ca0389c651e2f666624a3",
"version" : "0.1.0"
}
},
{
"identity" : "uitextview-placeholder",
"kind" : "remoteSourceControl",
"location" : "https://github.com/MainasuK/UITextView-Placeholder.git",
"state" : {
"revision" : "20f513ded04a040cdf5467f0891849b1763ede3b",
"version" : "1.4.1"
}
}
],
"version" : 2
}

View File

@ -18,7 +18,7 @@ let package = Package(
name: "MastodonSDK",
defaultLocalization: "en",
platforms: [
.iOS(.v15),
.iOS(.v16),
],
products: [
// Static Library
@ -42,7 +42,6 @@ let package = Package(
.package(url: "https://github.com/apple/swift-collections.git", from: "1.0.3"),
.package(url: "https://github.com/apple/swift-nio.git", from: "2.0.0"),
.package(url: "https://github.com/Flipboard/FLAnimatedImage.git", from: "1.0.0"),
.package(url: "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git", from: "8.0.0"),
.package(url: "https://github.com/kean/Nuke.git", from: "10.3.1"),
.package(url: "https://github.com/kishikawakatsumi/KeychainAccess.git", from: "4.2.2"),
.package(url: "https://github.com/slackhq/PanModal.git", from: "1.2.7"),
@ -54,6 +53,7 @@ let package = Package(
.package(url: "https://github.com/SDWebImage/SDWebImage.git", from: "5.12.0"),
.package(url: "https://github.com/eneko/Stripes.git", from: "0.2.0"),
.package(url: "https://github.com/NextLevel/NextLevelSessionExporter.git", from: "0.4.6"),
.package(url: "https://github.com/xmartlabs/XLPagerTabStrip.git", from: "9.1.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
@ -126,6 +126,8 @@ let package = Package(
.product(name: "PanModal", package: "PanModal"),
.product(name: "Stripes", package: "Stripes"),
.product(name: "NextLevelSessionExporter", package: "NextLevelSessionExporter"),
.product(name: "SDWebImage", package: "SDWebImage"),
.product(name: "XLPagerTabStrip", package: "XLPagerTabStrip"),
]
),
.testTarget(

View File

@ -1,17 +1,15 @@
{
"images" : [
{
"filename" : "dark.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "dark@2x.png",
"filename" : "about_instance_placeholder@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "dark@3x.png",
"idiom" : "universal",
"scale" : "3x"
}

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

View File

@ -219,9 +219,7 @@ public enum Asset {
}
}
public enum Settings {
public static let automatic = ImageAsset(name: "Settings/automatic")
public static let dark = ImageAsset(name: "Settings/dark")
public static let light = ImageAsset(name: "Settings/light")
public static let aboutInstancePlaceholder = ImageAsset(name: "Settings/about_instance_placeholder")
}
public enum Theme {
public enum System {

View File

@ -24,4 +24,8 @@ extension APIService {
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.V2.Instance>, Error> {
return Mastodon.API.V2.Instance.instance(session: session, domain: domain)
}
public func extendedDescription(domain: String) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.ExtendedDescription>, Error> {
return Mastodon.API.Instance.extendedDescription(session: session, domain: domain)
}
}

View File

@ -7,7 +7,6 @@
import VisionKit
@available(iOS 16.0, *)
extension ImageAnalyzer {
public static let shared = ImageAnalyzer()
}

View File

@ -1418,7 +1418,7 @@ public enum L10n {
public enum Settings {
public enum AboutMastodon {
/// Clear Media Storage
public static let cleaerMediaStorage = L10n.tr("Localizable", "Scene.Settings.AboutMastodon.CleaerMediaStorage", fallback: "Clear Media Storage")
public static let clearMediaStorage = L10n.tr("Localizable", "Scene.Settings.AboutMastodon.ClearMediaStorage", fallback: "Clear Media Storage")
/// Contribute to Mastodon
public static let contributeToMastodon = L10n.tr("Localizable", "Scene.Settings.AboutMastodon.ContributeToMastodon", fallback: "Contribute to Mastodon")
/// Even More Settings
@ -1509,6 +1509,8 @@ public enum L10n {
}
/// Notifications
public static let notifications = L10n.tr("Localizable", "Scene.Settings.Overview.Notifications", fallback: "Notifications")
/// Server Details
public static let serverDetails = L10n.tr("Localizable", "Scene.Settings.Overview.ServerDetails", fallback: "Server Details")
/// Support Mastodon
public static let supportMastodon = L10n.tr("Localizable", "Scene.Settings.Overview.SupportMastodon", fallback: "Support Mastodon")
/// Settings
@ -1592,6 +1594,20 @@ public enum L10n {
public static let title = L10n.tr("Localizable", "Scene.Settings.Section.SpicyZone.Title", fallback: "The Spicy Zone")
}
}
public enum ServerDetails {
/// About
public static let about = L10n.tr("Localizable", "Scene.Settings.ServerDetails.About", fallback: "About")
/// Rules
public static let rules = L10n.tr("Localizable", "Scene.Settings.ServerDetails.Rules", fallback: "Rules")
public enum AboutInstance {
/// A legal notice
public static let legalNotice = L10n.tr("Localizable", "Scene.Settings.ServerDetails.AboutInstance.LegalNotice", fallback: "A legal notice")
/// Message Admin
public static let messageAdmin = L10n.tr("Localizable", "Scene.Settings.ServerDetails.AboutInstance.MessageAdmin", fallback: "Message Admin")
/// Administrator
public static let title = L10n.tr("Localizable", "Scene.Settings.ServerDetails.AboutInstance.Title", fallback: "Administrator")
}
}
}
public enum SuggestionAccount {
/// Follow all

View File

@ -527,6 +527,7 @@ uploaded to Mastodon.";
"Scene.Settings.Overview.General" = "General";
"Scene.Settings.Overview.Notifications" = "Notifications";
"Scene.Settings.Overview.SupportMastodon" = "Support Mastodon";
"Scene.Settings.Overview.ServerDetails" = "Server Details";
"Scene.Settings.Overview.AboutMastodon" = "About Mastodon";
"Scene.Settings.Overview.Logout" = "Logout %@";
@ -534,7 +535,13 @@ uploaded to Mastodon.";
"Scene.Settings.AboutMastodon.MoreSettings" = "Even More Settings";
"Scene.Settings.AboutMastodon.ContributeToMastodon" = "Contribute to Mastodon";
"Scene.Settings.AboutMastodon.PrivacyPolicy" = "Privacy Policy";
"Scene.Settings.AboutMastodon.CleaerMediaStorage" = "Clear Media Storage";
"Scene.Settings.AboutMastodon.ClearMediaStorage" = "Clear Media Storage";
"Scene.Settings.ServerDetails.About" = "About";
"Scene.Settings.ServerDetails.Rules" = "Rules";
"Scene.Settings.ServerDetails.AboutInstance.Title" = "Administrator";
"Scene.Settings.ServerDetails.AboutInstance.MessageAdmin" = "Message Admin";
"Scene.Settings.ServerDetails.AboutInstance.LegalNotice" = "A legal notice";
"Scene.Settings.General.Title" = "General";
"Scene.Settings.General.Appearance.SectionTitle" = "Appearance";

View File

@ -527,6 +527,7 @@ uploaded to Mastodon.";
"Scene.Settings.Overview.General" = "General";
"Scene.Settings.Overview.Notifications" = "Notifications";
"Scene.Settings.Overview.SupportMastodon" = "Support Mastodon";
"Scene.Settings.Overview.ServerDetails" = "Server Details";
"Scene.Settings.Overview.AboutMastodon" = "About Mastodon";
"Scene.Settings.Overview.Logout" = "Logout %@";
@ -534,7 +535,13 @@ uploaded to Mastodon.";
"Scene.Settings.AboutMastodon.MoreSettings" = "Even More Settings";
"Scene.Settings.AboutMastodon.ContributeToMastodon" = "Contribute to Mastodon";
"Scene.Settings.AboutMastodon.PrivacyPolicy" = "Privacy Policy";
"Scene.Settings.AboutMastodon.CleaerMediaStorage" = "Clear Media Storage";
"Scene.Settings.AboutMastodon.ClearMediaStorage" = "Clear Media Storage";
"Scene.Settings.ServerDetails.About" = "About";
"Scene.Settings.ServerDetails.Rules" = "Rules";
"Scene.Settings.ServerDetails.AboutInstance.Title" = "Administrator";
"Scene.Settings.ServerDetails.AboutInstance.MessageAdmin" = "Message Admin";
"Scene.Settings.ServerDetails.AboutInstance.LegalNotice" = "A legal notice";
"Scene.Settings.General.Title" = "General";
"Scene.Settings.General.Appearance.SectionTitle" = "Appearance";

View File

@ -30,11 +30,7 @@ extension Mastodon.API.Instance {
session: URLSession,
domain: String
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Instance>, Error> {
let request = Mastodon.API.get(
url: instanceEndpointURL(domain: domain),
query: nil,
authorization: nil
)
let request = Mastodon.API.get(url: instanceEndpointURL(domain: domain))
return session.dataTaskPublisher(for: request)
.tryMap { data, response in
let value: Mastodon.Entity.Instance
@ -53,5 +49,27 @@ extension Mastodon.API.Instance {
}
.eraseToAnyPublisher()
}
static func extendedDescriptionEndpointURL(domain: String) -> URL {
return Mastodon.API.endpointURL(domain: domain).appendingPathComponent("instance").appendingPathComponent("extended_description")
}
/// Extended description of the server
///
/// - Returns: A ``MastodonSDK.Mastodon.Entity.ExtendedDescription``
///
/// ## Reference:
/// [Document](https://docs.joinmastodon.org/methods/instance/#extended_description)
public static func extendedDescription(
session: URLSession,
domain: String
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.ExtendedDescription>, Error> {
let request = Mastodon.API.get(url: extendedDescriptionEndpointURL(domain: domain))
return session.dataTaskPublisher(for: request)
.tryMap { data, response in
let value = try Mastodon.API.decode(type: Mastodon.Entity.ExtendedDescription.self, from: data, response: response)
return Mastodon.Response.Content(value: value, response: response)
}
.eraseToAnyPublisher()
}
}

View File

@ -0,0 +1,19 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import Foundation
extension Mastodon.Entity {
/// Extended description of the server
/// ## Reference:
/// [Document](https://docs.joinmastodon.org/entities/ExtendedDescription/)
public struct ExtendedDescription: Codable {
public let updatedAt: Date
public let content: String
enum CodingKeys: String, CodingKey {
case updatedAt = "updated_at"
case content
}
}
}

View File

@ -10,12 +10,11 @@ extension Mastodon.Entity.V2 {
/// # Reference
/// [Document](https://docs.joinmastodon.org/entities/instance/)
public struct Instance: Codable {
public let domain: String?
public let title: String
public let description: String
public let shortDescription: String?
public let email: String?
public let version: String?
public let languages: [String]? // (ISO 639 Part 1-5 language codes)
public let registrations: Mastodon.Entity.V2.Instance.Registrations?
@ -25,7 +24,7 @@ extension Mastodon.Entity.V2 {
public let statistics: Mastodon.Entity.Instance.Statistics?
public let thumbnail: Thumbnail?
public let contactAccount: Mastodon.Entity.Account?
public let contact: Mastodon.Entity.V2.Instance.Contact?
public let rules: [Mastodon.Entity.Instance.Rule]?
// https://github.com/mastodon/mastodon/pull/16485
@ -36,7 +35,7 @@ extension Mastodon.Entity.V2 {
self.title = domain
self.description = ""
self.shortDescription = nil
self.email = ""
self.contact = nil
self.version = nil
self.languages = nil
self.registrations = nil
@ -45,7 +44,6 @@ extension Mastodon.Entity.V2 {
self.urls = nil
self.statistics = nil
self.thumbnail = nil
self.contactAccount = nil
self.rules = nil
self.configuration = nil
}
@ -55,7 +53,6 @@ extension Mastodon.Entity.V2 {
case title
case description
case shortDescription = "short_description"
case email
case version
case languages
case registrations
@ -65,7 +62,7 @@ extension Mastodon.Entity.V2 {
case statistics = "stats"
case thumbnail
case contactAccount = "contact_account"
case contact
case rules
case configuration
@ -106,3 +103,10 @@ extension Mastodon.Entity.V2.Instance {
public let url: String?
}
}
extension Mastodon.Entity.V2.Instance {
public struct Contact: Codable {
public let email: String?
public let account: Mastodon.Entity.Account?
}
}

View File

@ -30,6 +30,7 @@ extension MetaLabel {
case accountListUsername
case sidebarHeadline(isSelected: Bool)
case sidebarSubheadline(isSelected: Bool)
case aboutInstance
}
public convenience init(style: Style) {
@ -129,6 +130,10 @@ extension MetaLabel {
case .sidebarSubheadline(let isSelected):
font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 13, weight: .regular), maximumPointSize: 18)
textColor = isSelected ? .white : Asset.Colors.Label.secondary.color
case .aboutInstance:
font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .regular))
textColor = .label
paragraphStyle.paragraphSpacing = 0
}
self.font = font

View File

@ -44,45 +44,15 @@ public struct PollOptionRow: View {
viewModel.textField?.becomeFirstResponder()
}
if #available(iOS 16.0, *) {
field.accessibilityActions {
if let moveUp {
Button(L10n.Scene.Compose.Poll.moveUp, action: moveUp)
}
if let moveDown {
Button(L10n.Scene.Compose.Poll.moveDown, action: moveDown)
}
if let removeOption {
Button(L10n.Scene.Compose.Poll.removeOption, action: removeOption)
}
field.accessibilityActions {
if let moveUp {
Button(L10n.Scene.Compose.Poll.moveUp, action: moveUp)
}
} else {
switch (moveUp, moveDown, removeOption) {
case let (.some(up), .some(down), .some(remove)):
field
.accessibilityAction(named: L10n.Scene.Compose.Poll.moveUp, up)
.accessibilityAction(named: L10n.Scene.Compose.Poll.moveDown, down)
.accessibilityAction(named: L10n.Scene.Compose.Poll.removeOption, remove)
case let (.some(up), .some(down), .none):
field
.accessibilityAction(named: L10n.Scene.Compose.Poll.moveUp, up)
.accessibilityAction(named: L10n.Scene.Compose.Poll.moveDown, down)
case let (.some(up), .none, .some(remove)):
field
.accessibilityAction(named: L10n.Scene.Compose.Poll.moveUp, up)
.accessibilityAction(named: L10n.Scene.Compose.Poll.removeOption, remove)
case let (.some(up), .none, .none):
field.accessibilityAction(named: L10n.Scene.Compose.Poll.moveUp, up)
case let (.none, .some(down), .some(remove)):
field
.accessibilityAction(named: L10n.Scene.Compose.Poll.moveDown, down)
.accessibilityAction(named: L10n.Scene.Compose.Poll.removeOption, remove)
case let (.none, .some(down), .none):
field.accessibilityAction(named: L10n.Scene.Compose.Poll.moveDown, down)
case let (.none, .none, .some(remove)):
field.accessibilityAction(named: L10n.Scene.Compose.Poll.removeOption, remove)
case (.none, .none, .none):
field
if let moveDown {
Button(L10n.Scene.Compose.Poll.moveDown, action: moveDown)
}
if let removeOption {
Button(L10n.Scene.Compose.Poll.removeOption, action: removeOption)
}
}
}

View File

@ -113,13 +113,7 @@ struct ComposeContentToolbarView: View {
showingLanguagePicker = true
}
} label: {
let font: SwiftUI.Font = {
if #available(iOS 16, *) {
return .system(size: 11, weight: .semibold).width(viewModel.language.count == 3 ? .compressed : .standard)
} else {
return .system(size: 11, weight: .semibold)
}
}()
let font = SwiftUI.Font.system(size: 11, weight: .semibold).width(viewModel.language.count == 3 ? .compressed : .standard)
Text(viewModel.language)
.font(font)

View File

@ -37,15 +37,9 @@ struct LanguagePicker: View {
return Text("")
}()
Button(action: { onSelect(lang.id) }) {
if #available(iOS 16.0, *) {
ViewThatFits(in: .horizontal) {
HStack(spacing: 0) { endonym; Text(" "); exonym }
VStack(alignment: .leading) { endonym; exonym }
}
} else {
// less optimal because if youre using an LTR language, RTL languages
// will read as ([exonym])[endonym] (and vice versa in RTL locales)
Text("\(endonym)\(exonym)")
ViewThatFits(in: .horizontal) {
HStack(spacing: 0) { endonym; Text(" "); exonym }
VStack(alignment: .leading) { endonym; exonym }
}
}
.tint(.primary)

View File

@ -163,7 +163,7 @@ public class CondensedUserView: UIView {
}
}
public func configure(with account: Mastodon.Entity.Account) {
public func configure(with account: Mastodon.Entity.Account, showFollowers: Bool = true) {
let displayNameMetaContent: MetaContent
do {
let content = MastodonContent(content: account.displayNameWithFallback, emojis: account.emojis?.asDictionary ?? [:])
@ -174,10 +174,16 @@ public class CondensedUserView: UIView {
displayNameLabel.configure(content: displayNameMetaContent)
acctLabel.text = account.acct
followersLabel.attributedText = NSAttributedString(
format: NSAttributedString(string: L10n.Common.UserList.followersCount("%@"), attributes: [.font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .regular))]),
args: NSAttributedString(string: Self.metricFormatter.string(from: account.followersCount) ?? account.followersCount.formatted(), attributes: [.font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .bold))])
)
if showFollowers {
followersLabel.attributedText = NSAttributedString(
format: NSAttributedString(string: L10n.Common.UserList.followersCount("%@"), attributes: [.font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .regular))]),
args: NSAttributedString(string: Self.metricFormatter.string(from: account.followersCount) ?? account.followersCount.formatted(), attributes: [.font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .bold))])
)
followersLabel.isHidden = false
} else {
followersLabel.isHidden = false
}
avatarImageView.setImage(url: account.avatarImageURL())

View File

@ -328,13 +328,8 @@ extension StatusView.ViewModel {
let paragraphStyle = statusView.contentMetaText.paragraphStyle
if let language = language {
if #available(iOS 16, *) {
let direction = Locale.Language(identifier: language).characterDirection
paragraphStyle.alignment = direction == .rightToLeft ? .right : .left
} else {
let direction = Locale.characterDirection(forLanguage: language)
paragraphStyle.alignment = direction == .rightToLeft ? .right : .left
};
let direction = Locale.Language(identifier: language).characterDirection
paragraphStyle.alignment = direction == .rightToLeft ? .right : .left
} else {
paragraphStyle.alignment = .natural
}

View File

@ -7,11 +7,6 @@ target 'Mastodon' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
# Pods for Mastodon
# UI
pod 'XLPagerTabStrip', '~> 9.0.0'
# misc
pod 'SwiftGen', '~> 6.6.2'
pod 'Kanna', '~> 5.2.2'

View File

@ -4,27 +4,23 @@ PODS:
- Sourcery/CLI-Only (= 1.9.2)
- Sourcery/CLI-Only (1.9.2)
- SwiftGen (6.6.2)
- XLPagerTabStrip (9.0.0)
DEPENDENCIES:
- Kanna (~> 5.2.2)
- Sourcery (~> 1.9)
- SwiftGen (~> 6.6.2)
- XLPagerTabStrip (~> 9.0.0)
SPEC REPOS:
trunk:
- Kanna
- Sourcery
- SwiftGen
- XLPagerTabStrip
SPEC CHECKSUMS:
Kanna: 01cfbddc127f5ff0963692f285fcbc8a9d62d234
Sourcery: 179539341c2261068528cd15a31837b7238fd901
SwiftGen: 1366a7f71aeef49954ca5a63ba4bef6b0f24138c
XLPagerTabStrip: 61c57fd61f611ee5f01ff1495ad6fbee8bf496c5
PODFILE CHECKSUM: 8c962b3cbb4c225f1e57fb2e4ca03d1f22c45e5e
PODFILE CHECKSUM: 597c21d7aa08efec996048577c3c4fbeffbb6305
COCOAPODS: 1.12.1
COCOAPODS: 1.13.0

View File

@ -2,14 +2,14 @@
[![CI](https://github.com/mastodon/mastodon-ios/actions/workflows/main.yml/badge.svg)](https://github.com/mastodon/mastodon-ios/actions/workflows/main.yml) [![Crowdin](https://badges.crowdin.net/mastodon-for-ios/localized.svg)](https://crowdin.com/project/mastodon-for-ios)
<a href="https://apps.apple.com/us/app/mastodon-for-iphone/id1571998974?itsct=apps_box_badge&amp;itscg=30200" style="display: inline-block; overflow: hidden; border-top-left-radius: 13px; border-top-right-radius: 13px; border-bottom-right-radius: 13px; border-bottom-left-radius: 13px; width: 250px; height: 83px;"><img src="https://tools.applemediaservices.com/api/badges/download-on-the-app-store/black/en-us?size=250x83&amp;releaseDate=1627603200&h=72b0c8495c2c0af1291efef280c4c2c1" alt="Download on the App Store" style="border-top-left-radius: 13px; border-top-right-radius: 13px; border-bottom-right-radius: 13px; border-bottom-left-radius: 13px; width: 250px; height: 83px;"></a>
## Introduction
This is the repository for the official iOS App for Mastodon. You can install it from the App Store now. You can build the app from source and file bug report here.
This is the repository for the official iOS App for Mastodon. You can install it from the App Store now. You can build the app from source and file bug report here.
Read this blog post for this app to learn more.
Read this blog post for this app to learn more.
> [Developing an official iOS app for Mastodon](https://blog.joinmastodon.org/2021/02/developing-an-official-ios-app-for-mastodon/)
## Getting Started
@ -17,6 +17,7 @@ Read this blog post for this app to learn more.
- Read the setup guide [here](./Documentation/Setup.md)
- About [contributing](./Documentation/CONTRIBUTING.md)
- [Documentation folder](./Documentation/)
- [App Store Deployment](./Documentation/Deployment.md)
## Acknowledgments

View File

@ -54,10 +54,7 @@ struct FollowersCountEntry: TimelineEntry {
struct FollowersCountWidget: Widget {
private var availableFamilies: [WidgetFamily] {
if #available(iOS 16, *) {
return [.systemSmall, .accessoryRectangular, .accessoryCircular]
}
return [.systemSmall]
return [.systemSmall, .accessoryRectangular, .accessoryCircular]
}
var body: some WidgetConfiguration {

View File

@ -148,9 +148,7 @@ struct FollowersCountWidgetView: View {
private func viewForAccessoryCircular(_ account :FollowersEntryAccountable) -> some View {
ZStack {
if #available(iOS 16, *) {
AccessoryWidgetBackground()
}
AccessoryWidgetBackground()
VStack {
Image("BrandIcon")

View File

@ -146,11 +146,7 @@ struct HashtagWidgetTimelineEntry: TimelineEntry {
struct HashtagWidget: Widget {
private var availableFamilies: [WidgetFamily] {
if #available(iOS 16, *) {
return [.systemMedium, .systemLarge, .accessoryRectangular]
} else {
return [.systemMedium, .systemLarge]
}
return [.systemMedium, .systemLarge, .accessoryRectangular]
}
var body: some WidgetConfiguration {

2
fastlane/Appfile Normal file
View File

@ -0,0 +1,2 @@
app_identifier("org.joinmastodon.app")
team_id("5Z4GVSS33P")

3
fastlane/Deliverfile Normal file
View File

@ -0,0 +1,3 @@
force true
app_identifier "org.joinmastodon.app"
precheck_include_in_app_purchases false

80
fastlane/Fastfile Normal file
View File

@ -0,0 +1,80 @@
opt_out_usage
default_platform(:ios)
$appName = "Mastodon"
platform :ios do
before_all do |lane|
$bundle_id = "org.joinmastodon.app"
$all_bundle_ids = [
$bundle_id,
"org.joinmastodon.app.MastodonIntent",
"org.joinmastodon.app.NotificationService",
"org.joinmastodon.app.ShareActionExtension",
"org.joinmastodon.app.OpenInActionExtension",
"org.joinmastodon.app.WidgetExtension"
]
lanes_for_building = [:deploy_appstore]
if lanes_for_building.include?(lane)
app_store_connect_api_key(
key_id: ENV["ITC_KEY_ID"],
issuer_id: ENV["ITC_ISSUER_ID"],
key_content: ENV["ITC_KEY"],
duration: 1200,
in_house: false
)
ensure_git_status_clean
$version_number = get_version_number_from_xcodeproj(target: $appName)
$build_number = get_build_number()
increment_build_number_in_xcodeproj(
xcodeproj: "#{$appName}.xcodeproj",
build_number: $build_number
)
end
end
desc "Update certificates"
lane :update_certificates do
match(type: "development", app_identifier: $all_bundle_ids, force_for_new_devices: true)
match(type: "appstore", app_identifier: $all_bundle_ids, force_for_new_devices: false)
end
desc "Update devices"
lane :update_devices do
register_devices(devices_file: "./fastlane/devices.txt")
end
lane :build_only do
xcodebuild(
clean: true,
scheme: "Mastodon",
workspace: "Mastodon.xcworkspace"
)
end
desc " Build and deploy the App to App Store Connect & TestFlight"
lane :deploy_appstore do
if is_ci
create_keychain(name: "temp_keychain", password: "temp_123456", default_keychain: true, unlock: true, timeout: 3600, lock_when_sleeps: false)
match(type: "appstore", app_identifier: $all_bundle_ids, force_for_new_devices: true, readonly: true, keychain_name: "temp_keychain", keychain_password: "temp_123456")
else
match(type: "appstore", app_identifier: $all_bundle_ids, force_for_new_devices: true, readonly: false)
end
gym(workspace: "#{$appName}.xcworkspace",
scheme: "#{$appName}",
clean: true,
export_method: "app-store",
export_xcargs: "-allowProvisioningUpdates")
deliver(app_identifier: $bundle_id, skip_screenshots: true, skip_metadata: true)
sh("echo \"GITHUB_TAG_NAME=#{$version_number}-#{$build_number}\" >> $GITHUB_ENV")
end
end
def get_build_number
sh("git rev-list --count HEAD").chomp
end

14
fastlane/Matchfile Normal file
View File

@ -0,0 +1,14 @@
git_url("git@github.com:mastodon/mastodon-ios-match.git")
storage_mode("git")
git_branch("main")
type("appstore") # The default type, can be: appstore, adhoc, enterprise or development
app_identifier([
"org.joinmastodon.app",
"org.joinmastodon.app.MastodonIntent",
"org.joinmastodon.app.NotificationService",
"org.joinmastodon.app.ShareActionExtension",
"org.joinmastodon.app.OpenInActionExtension",
"org.joinmastodon.app.WidgetExtension"
])
# username("fastlane@joinmastodon.org")

5
fastlane/Pluginfile Normal file
View File

@ -0,0 +1,5 @@
# Autogenerated by fastlane
#
# Ensure this file is checked in to source control!
gem 'fastlane-plugin-versioning'

56
fastlane/README.md Normal file
View File

@ -0,0 +1,56 @@
fastlane documentation
----
# Installation
Make sure you have the latest version of the Xcode command line tools installed:
```sh
xcode-select --install
```
For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane)
# Available Actions
## iOS
### ios update_certificates
```sh
[bundle exec] fastlane ios update_certificates
```
Update certificates
### ios update_devices
```sh
[bundle exec] fastlane ios update_devices
```
Update devices
### ios build_only
```sh
[bundle exec] fastlane ios build_only
```
### ios deploy_appstore
```sh
[bundle exec] fastlane ios deploy_appstore
```
Build and deploy the App to App Store Connect & TestFlight
----
This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run.
More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools).
The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools).

View File

@ -0,0 +1,2 @@
Device ID Device Name Device Platform
00000000-0000000000000000 Your-Device-Name ios