Merge branch 'release-1.4.6' into feature/package-refactor
# Conflicts: # .arkana.yml # AppShared/Info.plist # Documentation/Setup.md # Gemfile # Gemfile.lock # Mastodon.xcodeproj/project.pbxproj # Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist # Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved # MastodonSDK/Package.swift # MastodonSDK/Sources/MastodonCore/AppSecret.swift # MastodonSDK/Sources/MastodonCore/Service/Notification/NotificationService.swift # Podfile # Podfile.lock
This commit is contained in:
commit
060aec6bcb
|
@ -13,4 +13,5 @@ global_secrets:
|
|||
# nothing
|
||||
environment_secrets:
|
||||
# Will lookup for <Key>Debug and <Key>Release env vars (assuming no flavor was declared)
|
||||
# Mastodon Push Notification Endpoint
|
||||
- NotificationEndpoint
|
||||
|
|
|
@ -122,4 +122,7 @@ xcuserdata
|
|||
|
||||
# Localization/StringsConvertor/input
|
||||
Localization/StringsConvertor/output
|
||||
.DS_Store
|
||||
.DS_Store
|
||||
|
||||
env/**/**
|
||||
!env/.env
|
|
@ -7,8 +7,6 @@
|
|||
- [CommonOSLog](https://github.com/mainasuk/CommonOSLog)
|
||||
- [CryptoSwift](https://github.com/krzyzanowskim/CryptoSwift)
|
||||
- [DateToolSwift](https://github.com/MatthewYork/DateTools)
|
||||
- [DiffableDataSources](https://github.com/ra1028/DiffableDataSources)
|
||||
- [DifferenceKit](https://github.com/ra1028/DifferenceKit)
|
||||
- [FLAnimatedImage](https://github.com/Flipboard/FLAnimatedImage)
|
||||
- [FLEX](https://github.com/FLEXTool/FLEX)
|
||||
- [FPSIndicator](https://github.com/MainasuK/FPSIndicator)
|
||||
|
|
|
@ -50,10 +50,11 @@ bundle install
|
|||
```zsh
|
||||
# make a clean build
|
||||
bundle install
|
||||
bundle exec pod clean
|
||||
|
||||
# setup notification endpoint
|
||||
# setup arkana
|
||||
# please check the `.env.example` to create your's or use the empty example directly
|
||||
bundle exec arkana -e `<your-dot-env-file-path>`
|
||||
bundle exec arkana -e ./env/.env
|
||||
|
||||
# clean pods
|
||||
bundle exec pod clean
|
||||
|
@ -65,13 +66,14 @@ bundle exec pod install --repo-update
|
|||
open Mastodon.xcworkspace
|
||||
```
|
||||
|
||||
The CocoaPods-Key plugin will request the push notification endpoint. You can fufill the empty string and set it later. To setup the push notification. Please check section `Push Notification` below.
|
||||
The Arkana plugin will setup the push notification endpoint. You can use the empty template from `./env/.env` or use your own `.env` file. To setup the push notification. Please check section `Push Notification` below.
|
||||
|
||||
The app requires the `App Group` capability. To make sure it works for your developer membership. Please check [AppSecret.swift](../MastodonSDK/Sources/MastodonCore/AppSecret.swift) file and set another unique `groupID` and update `App Group` settings.
|
||||
|
||||
#### Push Notification (Optional)
|
||||
The app is compatible with [toot-relay](https://github.com/DagAgren/toot-relay) APNs. You can set your push notification endpoint via Arkana. There are one endpoint:
|
||||
- NotificationEndpoint: (e.g. https://<your-domain>/relay-to/production)
|
||||
The app is compatible with [toot-relay](https://github.com/DagAgren/toot-relay) APNs. You can set your push notification endpoint via Arkana. There are two endpoints:
|
||||
- NotificationEndpointDebug: for `DEBUG` usage. e.g. `https://<your.domin>/relay-to/development`
|
||||
- NotificationEndpointRelease: for `RELEASE` usage. e.g. `https://<your.domin>/relay-to/production`
|
||||
|
||||
Please check the [Establishing a Certificate-Based Connection to APNs
|
||||
](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/establishing_a_certificate-based_connection_to_apns) document to generate the certificate and exports the p12 file.
|
||||
|
@ -87,4 +89,4 @@ Please check and set the `notification.Topic` to the app BundleID in [toot-relay
|
|||
|
||||
## What's next
|
||||
|
||||
We welcome contributions! And if you have an interest to contribute codes. Here is a document that describes the app architecture and what's tech stack it uses.
|
||||
We welcome contributions! And if you have an interest to contribute codes. Here is a document that describes the app architecture and what's tech stack it uses.
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -3,3 +3,5 @@ source "https://rubygems.org"
|
|||
gem 'arkana'
|
||||
gem "cocoapods"
|
||||
gem "cocoapods-clean"
|
||||
gem "xcpretty"
|
||||
|
||||
|
|
24
Gemfile.lock
24
Gemfile.lock
|
@ -3,14 +3,14 @@ GEM
|
|||
specs:
|
||||
CFPropertyList (3.0.5)
|
||||
rexml
|
||||
activesupport (6.1.5.1)
|
||||
activesupport (6.1.7)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
tzinfo (~> 2.0)
|
||||
zeitwerk (~> 2.3)
|
||||
addressable (2.8.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
addressable (2.8.1)
|
||||
public_suffix (>= 2.0.2, < 6.0)
|
||||
algoliasearch (1.27.5)
|
||||
httpclient (~> 2.8, >= 2.8.3)
|
||||
json (>= 1.5.1)
|
||||
|
@ -70,38 +70,42 @@ GEM
|
|||
fuzzy_match (2.0.4)
|
||||
gh_inspector (1.1.3)
|
||||
httpclient (2.8.3)
|
||||
i18n (1.10.0)
|
||||
i18n (1.12.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
json (2.6.1)
|
||||
minitest (5.15.0)
|
||||
json (2.6.2)
|
||||
minitest (5.16.3)
|
||||
molinillo (0.8.0)
|
||||
nanaimo (0.3.0)
|
||||
nap (1.1.0)
|
||||
netrc (0.11.0)
|
||||
public_suffix (4.0.7)
|
||||
rexml (3.2.5)
|
||||
rouge (2.0.7)
|
||||
ruby-macho (2.5.1)
|
||||
typhoeus (1.4.0)
|
||||
ethon (>= 0.9.0)
|
||||
tzinfo (2.0.4)
|
||||
tzinfo (2.0.5)
|
||||
concurrent-ruby (~> 1.0)
|
||||
xcodeproj (1.21.0)
|
||||
xcodeproj (1.22.0)
|
||||
CFPropertyList (>= 2.3.3, < 4.0)
|
||||
atomos (~> 0.1.3)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
nanaimo (~> 0.3.0)
|
||||
rexml (~> 3.2.4)
|
||||
xcpretty (0.3.0)
|
||||
rouge (~> 2.0.7)
|
||||
yaml (0.2.0)
|
||||
zeitwerk (2.5.4)
|
||||
zeitwerk (2.6.3)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
arm64-darwin-21
|
||||
|
||||
DEPENDENCIES
|
||||
arkana
|
||||
cocoapods
|
||||
cocoapods-clean
|
||||
xcpretty
|
||||
|
||||
BUNDLED WITH
|
||||
2.3.17
|
||||
|
|
|
@ -224,17 +224,17 @@
|
|||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>ld</string>
|
||||
<key>zero</key>
|
||||
<string>لا إعاد تدوين</string>
|
||||
<string>لَا إعادَةُ تَدوين</string>
|
||||
<key>one</key>
|
||||
<string>إعادةُ تدوينٍ واحِدة</string>
|
||||
<string>إعادَةُ تَدوينٍ واحِدَة</string>
|
||||
<key>two</key>
|
||||
<string>إعادتا تدوين</string>
|
||||
<string>إعادَتَا تَدوين</string>
|
||||
<key>few</key>
|
||||
<string>%ld إعاداتِ تدوين</string>
|
||||
<string>%ld إعادَاتِ تَدوين</string>
|
||||
<key>many</key>
|
||||
<string>%ld إعادةٍ للتدوين</string>
|
||||
<string>%ld إعادَةٍ لِلتَّدوين</string>
|
||||
<key>other</key>
|
||||
<string>%ld إعادة تدوين</string>
|
||||
<string>%ld إعادَة تَدوين</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>plural.count.reply</key>
|
||||
|
|
|
@ -348,7 +348,7 @@
|
|||
"Publishing": "Publication en cours ...",
|
||||
"accessibility": {
|
||||
"logo_label": "Bouton logo",
|
||||
"logo_hint": "Tap to scroll to top and tap again to previous location"
|
||||
"logo_hint": "Appuyez pour faire défiler vers le haut et appuyez à nouveau vers l'emplacement précédent"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -546,10 +546,10 @@
|
|||
"show_mentions": "Afficher les mentions"
|
||||
},
|
||||
"follow_request": {
|
||||
"accept": "Accept",
|
||||
"accepted": "Accepted",
|
||||
"reject": "reject",
|
||||
"rejected": "Rejected"
|
||||
"accept": "Accepter",
|
||||
"accepted": "Accepté",
|
||||
"reject": "rejeter",
|
||||
"rejected": "Rejeté"
|
||||
}
|
||||
},
|
||||
"thread": {
|
||||
|
|
|
@ -546,10 +546,10 @@
|
|||
"show_mentions": "Qalkirinan nîşan bike"
|
||||
},
|
||||
"follow_request": {
|
||||
"accept": "Accept",
|
||||
"accepted": "Accepted",
|
||||
"reject": "reject",
|
||||
"rejected": "Rejected"
|
||||
"accept": "Bipejirîne",
|
||||
"accepted": "Pejirandî",
|
||||
"reject": "nepejirîne",
|
||||
"rejected": "Nepejirandî"
|
||||
}
|
||||
},
|
||||
"thread": {
|
||||
|
|
|
@ -546,10 +546,10 @@
|
|||
"show_mentions": "แสดงการกล่าวถึง"
|
||||
},
|
||||
"follow_request": {
|
||||
"accept": "Accept",
|
||||
"accepted": "Accepted",
|
||||
"reject": "reject",
|
||||
"rejected": "Rejected"
|
||||
"accept": "ยอมรับ",
|
||||
"accepted": "ยอมรับแล้ว",
|
||||
"reject": "ปฏิเสธ",
|
||||
"rejected": "ปฏิเสธแล้ว"
|
||||
}
|
||||
},
|
||||
"thread": {
|
||||
|
|
|
@ -3866,7 +3866,7 @@
|
|||
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 144;
|
||||
CURRENT_PROJECT_VERSION = 147;
|
||||
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = Mastodon/Info.plist;
|
||||
|
@ -3896,7 +3896,7 @@
|
|||
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 144;
|
||||
CURRENT_PROJECT_VERSION = 147;
|
||||
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = Mastodon/Info.plist;
|
||||
|
@ -4069,7 +4069,7 @@
|
|||
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 144;
|
||||
CURRENT_PROJECT_VERSION = 147;
|
||||
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = Mastodon/Info.plist;
|
||||
|
@ -4136,7 +4136,7 @@
|
|||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 144;
|
||||
CURRENT_PROJECT_VERSION = 147;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = NotificationService/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -4159,7 +4159,7 @@
|
|||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 144;
|
||||
CURRENT_PROJECT_VERSION = 147;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = ShareActionExtension/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -4183,7 +4183,7 @@
|
|||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 144;
|
||||
CURRENT_PROJECT_VERSION = 147;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = MastodonIntent/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -4207,7 +4207,7 @@
|
|||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 144;
|
||||
CURRENT_PROJECT_VERSION = 147;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = MastodonIntent/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -4231,7 +4231,7 @@
|
|||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 144;
|
||||
CURRENT_PROJECT_VERSION = 147;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = MastodonIntent/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -4255,7 +4255,7 @@
|
|||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 144;
|
||||
CURRENT_PROJECT_VERSION = 147;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = ShareActionExtension/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -4279,7 +4279,7 @@
|
|||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 144;
|
||||
CURRENT_PROJECT_VERSION = 147;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = ShareActionExtension/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -4366,7 +4366,7 @@
|
|||
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 144;
|
||||
CURRENT_PROJECT_VERSION = 147;
|
||||
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = Mastodon/Info.plist;
|
||||
|
@ -4426,13 +4426,43 @@
|
|||
};
|
||||
name = "Release Snapshot";
|
||||
};
|
||||
DBEB19E527E4658E00B0E80E /* Release Snapshot */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3E08A432F40BA7B9CAA9DB68 /* Pods-AppShared.release snapshot.xcconfig */;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 147;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 147;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = AppShared/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.AppShared;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = "Release Snapshot";
|
||||
};
|
||||
DBEB19E627E4658E00B0E80E /* Release Snapshot */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 144;
|
||||
CURRENT_PROJECT_VERSION = 147;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = NotificationService/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -4455,7 +4485,7 @@
|
|||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 144;
|
||||
CURRENT_PROJECT_VERSION = 147;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = ShareActionExtension/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -4479,7 +4509,7 @@
|
|||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 144;
|
||||
CURRENT_PROJECT_VERSION = 147;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = MastodonIntent/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -4504,7 +4534,7 @@
|
|||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 144;
|
||||
CURRENT_PROJECT_VERSION = 147;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = NotificationService/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -4528,7 +4558,7 @@
|
|||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 144;
|
||||
CURRENT_PROJECT_VERSION = 147;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = NotificationService/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
|
|
@ -99,6 +99,11 @@
|
|||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>MastodonIntent.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>20</integer>
|
||||
</dict>
|
||||
<key>MastodonIntents.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
|
@ -112,12 +117,12 @@
|
|||
<key>NotificationService.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>18</integer>
|
||||
<integer>24</integer>
|
||||
</dict>
|
||||
<key>ShareActionExtension.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>17</integer>
|
||||
<integer>25</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
|
|
|
@ -20,7 +20,7 @@ final public class SceneCoordinator {
|
|||
|
||||
private weak var scene: UIScene!
|
||||
private weak var sceneDelegate: SceneDelegate!
|
||||
private weak var appContext: AppContext!
|
||||
private(set) weak var appContext: AppContext!
|
||||
|
||||
private(set) var authContext: AuthContext?
|
||||
|
||||
|
|
|
@ -2,19 +2,6 @@
|
|||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSExceptionDomains</key>
|
||||
<dict>
|
||||
<key>onion</key>
|
||||
<dict>
|
||||
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
||||
<true/>
|
||||
<key>NSIncludesSubdomains</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
|
@ -30,7 +17,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.4.5</string>
|
||||
<string>1.4.6</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
|
@ -43,7 +30,7 @@
|
|||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>144</string>
|
||||
<string>147</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
|
@ -59,6 +46,19 @@
|
|||
</array>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSExceptionDomains</key>
|
||||
<dict>
|
||||
<key>onion</key>
|
||||
<dict>
|
||||
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
||||
<true/>
|
||||
<key>NSIncludesSubdomains</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>NSUserActivityTypes</key>
|
||||
<array>
|
||||
<string>SendPostIntent</string>
|
||||
|
@ -103,6 +103,10 @@
|
|||
</array>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>remote-notification</string>
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>Main</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
|
|
|
@ -79,7 +79,7 @@ final class ProfileHeaderView: UIView {
|
|||
let followsYouLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = UIFont.systemFont(ofSize: 15, weight: .regular)
|
||||
label.text = "Follows You" // TODO: i18n
|
||||
label.text = L10n.Scene.Profile.Header.followsYou
|
||||
return label
|
||||
}()
|
||||
let followsYouMaskView = UIView()
|
||||
|
|
|
@ -106,6 +106,14 @@ extension AppDelegate: UNUserNotificationCenterDelegate {
|
|||
completionHandler([.sound])
|
||||
}
|
||||
|
||||
|
||||
// notification present in the background (or resume from background)
|
||||
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) async -> UIBackgroundFetchResult {
|
||||
let shortcutItems = try? await appContext.notificationService.unreadApplicationShortcutItems()
|
||||
UIApplication.shared.shortcutItems = shortcutItems
|
||||
return .noData
|
||||
}
|
||||
|
||||
// response to user action for notification (e.g. redirect to post)
|
||||
func userNotificationCenter(
|
||||
_ center: UNUserNotificationCenter,
|
||||
|
|
|
@ -10,6 +10,7 @@ import UIKit
|
|||
import Combine
|
||||
import CoreDataStack
|
||||
import MastodonCore
|
||||
import MastodonExtension
|
||||
|
||||
#if PROFILE
|
||||
import FPSIndicator
|
||||
|
@ -110,7 +111,9 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||
AppContext.shared.statusFilterService.filterUpdatePublisher.send()
|
||||
|
||||
if let shortcutItem = savedShortCutItem {
|
||||
_ = handler(shortcutItem: shortcutItem)
|
||||
Task {
|
||||
_ = await handler(shortcutItem: shortcutItem)
|
||||
}
|
||||
savedShortCutItem = nil
|
||||
}
|
||||
}
|
||||
|
@ -134,14 +137,43 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||
}
|
||||
|
||||
extension SceneDelegate {
|
||||
func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
|
||||
completionHandler(handler(shortcutItem: shortcutItem))
|
||||
|
||||
func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem) async -> Bool {
|
||||
return await handler(shortcutItem: shortcutItem)
|
||||
}
|
||||
|
||||
private func handler(shortcutItem: UIApplicationShortcutItem) -> Bool {
|
||||
@MainActor
|
||||
private func handler(shortcutItem: UIApplicationShortcutItem) async -> Bool {
|
||||
logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): \(shortcutItem.type)")
|
||||
|
||||
switch shortcutItem.type {
|
||||
case NotificationService.unreadShortcutItemIdentifier:
|
||||
guard let coordinator = self.coordinator else { return false }
|
||||
|
||||
guard let accessToken = shortcutItem.userInfo?["accessToken"] as? String else {
|
||||
assertionFailure()
|
||||
return false
|
||||
}
|
||||
let request = MastodonAuthentication.sortedFetchRequest
|
||||
request.predicate = MastodonAuthentication.predicate(userAccessToken: accessToken)
|
||||
request.fetchLimit = 1
|
||||
|
||||
guard let authentication = try? coordinator.appContext.managedObjectContext.fetch(request).first else {
|
||||
assertionFailure()
|
||||
return false
|
||||
}
|
||||
|
||||
let _isActive = try? await coordinator.appContext.authenticationService.activeMastodonUser(
|
||||
domain: authentication.domain,
|
||||
userID: authentication.userID
|
||||
)
|
||||
|
||||
guard _isActive == true else {
|
||||
return false
|
||||
}
|
||||
|
||||
coordinator.switchToTabBar(tab: .notification)
|
||||
|
||||
case "org.joinmastodon.app.new-post":
|
||||
if coordinator?.tabBarController.topMost is ComposeViewController {
|
||||
logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): composing…")
|
||||
|
@ -158,6 +190,7 @@ extension SceneDelegate {
|
|||
logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): not authenticated")
|
||||
}
|
||||
}
|
||||
|
||||
case "org.joinmastodon.app.search":
|
||||
coordinator?.switchToTabBar(tab: .search)
|
||||
logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): select search tab")
|
||||
|
@ -166,6 +199,7 @@ extension SceneDelegate {
|
|||
searchViewController.searchBarTapPublisher.send()
|
||||
logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): trigger search")
|
||||
}
|
||||
|
||||
default:
|
||||
assertionFailure()
|
||||
break
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.4.5</string>
|
||||
<string>1.4.6</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>144</string>
|
||||
<string>147</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionAttributes</key>
|
||||
|
|
|
@ -73,7 +73,7 @@ let package = Package(
|
|||
.target(
|
||||
name: "MastodonCommon",
|
||||
dependencies: [
|
||||
"MastodonExtension"
|
||||
"MastodonExtension",
|
||||
]
|
||||
),
|
||||
.target(
|
||||
|
|
|
@ -130,17 +130,17 @@ public enum Asset {
|
|||
}
|
||||
public enum Scene {
|
||||
public enum Compose {
|
||||
public static let earth = ImageAsset(name: "Scene/Compose/Earth")
|
||||
public static let mention = ImageAsset(name: "Scene/Compose/Mention")
|
||||
public static let more = ImageAsset(name: "Scene/Compose/More")
|
||||
public static let people = ImageAsset(name: "Scene/Compose/People")
|
||||
public static let buttonTint = ColorAsset(name: "Scene/Compose/button.tint")
|
||||
public static let chatWarningFill = ImageAsset(name: "Scene/Compose/chat.warning.fill")
|
||||
public static let chatWarning = ImageAsset(name: "Scene/Compose/chat.warning")
|
||||
public static let earth = ImageAsset(name: "Scene/Compose/earth")
|
||||
public static let emojiFill = ImageAsset(name: "Scene/Compose/emoji.fill")
|
||||
public static let emoji = ImageAsset(name: "Scene/Compose/emoji")
|
||||
public static let media = ImageAsset(name: "Scene/Compose/media")
|
||||
public static let mention = ImageAsset(name: "Scene/Compose/mention")
|
||||
public static let more = ImageAsset(name: "Scene/Compose/more")
|
||||
public static let peopleAdd = ImageAsset(name: "Scene/Compose/people.add")
|
||||
public static let people = ImageAsset(name: "Scene/Compose/people")
|
||||
public static let pollFill = ImageAsset(name: "Scene/Compose/poll.fill")
|
||||
public static let poll = ImageAsset(name: "Scene/Compose/poll")
|
||||
public static let reorderDot = ImageAsset(name: "Scene/Compose/reorder.dot")
|
||||
|
|
|
@ -37,9 +37,11 @@ public final class AppSecret {
|
|||
|
||||
init() {
|
||||
#if DEBUG
|
||||
self.notificationEndpoint = Keys.Debug().notificationEndpoint
|
||||
let keys = Keys.Debug()
|
||||
self.notificationEndpoint = keys.notificationEndpoint
|
||||
#else
|
||||
self.notificationEndpoint = Keys.Release().notificationEndpoint
|
||||
let keys = Keys.Release()
|
||||
self.notificationEndpoint = keys.notificationEndpoint
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -12,9 +12,12 @@ import CoreData
|
|||
import CoreDataStack
|
||||
import MastodonSDK
|
||||
import MastodonCommon
|
||||
import MastodonLocalization
|
||||
|
||||
public final class NotificationService {
|
||||
|
||||
public static let unreadShortcutItemIdentifier = "org.joinmastodon.app.NotificationService.unread-shortcut"
|
||||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
|
||||
let workingQueue = DispatchQueue(label: "org.joinmastodon.app.NotificationService.working-queue")
|
||||
|
@ -75,6 +78,9 @@ public final class NotificationService {
|
|||
|
||||
UserDefaults.shared.notificationBadgeCount = count
|
||||
UIApplication.shared.applicationIconBadgeNumber = count
|
||||
Task { @MainActor in
|
||||
UIApplication.shared.shortcutItems = try? await self.unreadApplicationShortcutItems()
|
||||
}
|
||||
|
||||
self.unreadNotificationCountDidUpdate.send()
|
||||
}
|
||||
|
@ -101,6 +107,37 @@ extension NotificationService {
|
|||
}
|
||||
}
|
||||
|
||||
extension NotificationService {
|
||||
public func unreadApplicationShortcutItems() async throws -> [UIApplicationShortcutItem] {
|
||||
guard let authenticationService = self.authenticationService else { return [] }
|
||||
let managedObjectContext = authenticationService.managedObjectContext
|
||||
return try await managedObjectContext.perform {
|
||||
var items: [UIApplicationShortcutItem] = []
|
||||
for object in authenticationService.mastodonAuthentications {
|
||||
guard let authentication = managedObjectContext.object(with: object.objectID) as? MastodonAuthentication else { continue }
|
||||
let accessToken = authentication.userAccessToken
|
||||
let count = UserDefaults.shared.getNotificationCountWithAccessToken(accessToken: accessToken)
|
||||
guard count > 0 else { continue }
|
||||
|
||||
let title = "@\(authentication.user.acctWithDomain)"
|
||||
let subtitle = L10n.A11y.Plural.Count.Unread.notification(count)
|
||||
|
||||
let item = UIApplicationShortcutItem(
|
||||
type: NotificationService.unreadShortcutItemIdentifier,
|
||||
localizedTitle: title,
|
||||
localizedSubtitle: subtitle,
|
||||
icon: nil,
|
||||
userInfo: [
|
||||
"accessToken": accessToken as NSSecureCoding
|
||||
]
|
||||
)
|
||||
items.append(item)
|
||||
}
|
||||
return items
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension NotificationService {
|
||||
|
||||
func dequeueNotificationViewModel(
|
||||
|
|
|
@ -224,17 +224,17 @@
|
|||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>ld</string>
|
||||
<key>zero</key>
|
||||
<string>لا إعاد تدوين</string>
|
||||
<string>لَا إعادَةُ تَدوين</string>
|
||||
<key>one</key>
|
||||
<string>إعادةُ تدوينٍ واحِدة</string>
|
||||
<string>إعادَةُ تَدوينٍ واحِدَة</string>
|
||||
<key>two</key>
|
||||
<string>إعادتا تدوين</string>
|
||||
<string>إعادَتَا تَدوين</string>
|
||||
<key>few</key>
|
||||
<string>%ld إعاداتِ تدوين</string>
|
||||
<string>%ld إعادَاتِ تَدوين</string>
|
||||
<key>many</key>
|
||||
<string>%ld إعادةٍ للتدوين</string>
|
||||
<string>%ld إعادَةٍ لِلتَّدوين</string>
|
||||
<key>other</key>
|
||||
<string>%ld إعادة تدوين</string>
|
||||
<string>%ld إعادَة تَدوين</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>plural.count.reply</key>
|
||||
|
|
|
@ -216,17 +216,17 @@ téléversé sur Mastodon.";
|
|||
"Scene.Follower.Title" = "abonné·e";
|
||||
"Scene.Following.Footer" = "Les abonnés issus des autres serveurs ne sont pas affichés.";
|
||||
"Scene.Following.Title" = "following";
|
||||
"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location";
|
||||
"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Appuyez pour faire défiler vers le haut et appuyez à nouveau vers l'emplacement précédent";
|
||||
"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Bouton logo";
|
||||
"Scene.HomeTimeline.NavigationBarState.NewPosts" = "Voir les nouvelles publications";
|
||||
"Scene.HomeTimeline.NavigationBarState.Offline" = "Hors ligne";
|
||||
"Scene.HomeTimeline.NavigationBarState.Published" = "Publié!";
|
||||
"Scene.HomeTimeline.NavigationBarState.Publishing" = "Publication en cours ...";
|
||||
"Scene.HomeTimeline.Title" = "Accueil";
|
||||
"Scene.Notification.FollowRequest.Accept" = "Accept";
|
||||
"Scene.Notification.FollowRequest.Accepted" = "Accepted";
|
||||
"Scene.Notification.FollowRequest.Reject" = "reject";
|
||||
"Scene.Notification.FollowRequest.Rejected" = "Rejected";
|
||||
"Scene.Notification.FollowRequest.Accept" = "Accepter";
|
||||
"Scene.Notification.FollowRequest.Accepted" = "Accepté";
|
||||
"Scene.Notification.FollowRequest.Reject" = "rejeter";
|
||||
"Scene.Notification.FollowRequest.Rejected" = "Rejeté";
|
||||
"Scene.Notification.Keyobard.ShowEverything" = "Tout Afficher";
|
||||
"Scene.Notification.Keyobard.ShowMentions" = "Afficher les mentions";
|
||||
"Scene.Notification.NotificationDescription.FavoritedYourPost" = "a ajouté votre message à ses favoris";
|
||||
|
|
|
@ -224,10 +224,10 @@ girêdanê bitikne da ku ajimêra xwe bidî piştrastkirin.";
|
|||
"Scene.HomeTimeline.NavigationBarState.Published" = "Hate weşandin!";
|
||||
"Scene.HomeTimeline.NavigationBarState.Publishing" = "Şandî tê weşandin...";
|
||||
"Scene.HomeTimeline.Title" = "Serrûpel";
|
||||
"Scene.Notification.FollowRequest.Accept" = "Accept";
|
||||
"Scene.Notification.FollowRequest.Accepted" = "Accepted";
|
||||
"Scene.Notification.FollowRequest.Reject" = "reject";
|
||||
"Scene.Notification.FollowRequest.Rejected" = "Rejected";
|
||||
"Scene.Notification.FollowRequest.Accept" = "Bipejirîne";
|
||||
"Scene.Notification.FollowRequest.Accepted" = "Pejirandî";
|
||||
"Scene.Notification.FollowRequest.Reject" = "nepejirîne";
|
||||
"Scene.Notification.FollowRequest.Rejected" = "Nepejirandî";
|
||||
"Scene.Notification.Keyobard.ShowEverything" = "Her tiştî nîşan bide";
|
||||
"Scene.Notification.Keyobard.ShowMentions" = "Qalkirinan nîşan bike";
|
||||
"Scene.Notification.NotificationDescription.FavoritedYourPost" = "şandiya te hez kir";
|
||||
|
|
|
@ -223,10 +223,10 @@
|
|||
"Scene.HomeTimeline.NavigationBarState.Published" = "เผยแพร่แล้ว!";
|
||||
"Scene.HomeTimeline.NavigationBarState.Publishing" = "กำลังเผยแพร่โพสต์...";
|
||||
"Scene.HomeTimeline.Title" = "หน้าแรก";
|
||||
"Scene.Notification.FollowRequest.Accept" = "Accept";
|
||||
"Scene.Notification.FollowRequest.Accepted" = "Accepted";
|
||||
"Scene.Notification.FollowRequest.Reject" = "reject";
|
||||
"Scene.Notification.FollowRequest.Rejected" = "Rejected";
|
||||
"Scene.Notification.FollowRequest.Accept" = "ยอมรับ";
|
||||
"Scene.Notification.FollowRequest.Accepted" = "ยอมรับแล้ว";
|
||||
"Scene.Notification.FollowRequest.Reject" = "ปฏิเสธ";
|
||||
"Scene.Notification.FollowRequest.Rejected" = "ปฏิเสธแล้ว";
|
||||
"Scene.Notification.Keyobard.ShowEverything" = "แสดงทุกอย่าง";
|
||||
"Scene.Notification.Keyobard.ShowMentions" = "แสดงการกล่าวถึง";
|
||||
"Scene.Notification.NotificationDescription.FavoritedYourPost" = "ได้ชื่นชอบโพสต์ของคุณ";
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.4.5</string>
|
||||
<string>1.4.6</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>144</string>
|
||||
<string>147</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.4.5</string>
|
||||
<string>1.4.6</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>144</string>
|
||||
<string>147</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.4.5</string>
|
||||
<string>1.4.6</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>144</string>
|
||||
<string>147</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.4.5</string>
|
||||
<string>1.4.6</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>144</string>
|
||||
<string>147</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionAttributes</key>
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
#!/bin/zsh
|
||||
|
||||
# Xcode Cloud scripts
|
||||
|
||||
set -xeu
|
||||
set -o pipefail
|
||||
|
||||
# list hardware
|
||||
system_profiler SPSoftwareDataType SPHardwareDataType
|
||||
|
||||
echo $PWD
|
||||
cd $CI_WORKSPACE
|
||||
echo $PWD
|
||||
|
||||
# install ruby from homebrew
|
||||
brew install ruby
|
||||
echo 'export PATH="/Users/local/Homebrew/opt/ruby/bin:$PATH"' >> ~/.zshrc
|
||||
source ~/.zshrc
|
||||
|
||||
ruby --version
|
||||
which gem
|
||||
|
||||
# workaround default installation location cannot access without sudo problem
|
||||
echo 'export GEM_HOME=$HOME/gems' >>~/.bash_profile
|
||||
echo 'export PATH=$HOME/gems/bin:$PATH' >>~/.bash_profile
|
||||
export GEM_HOME=$HOME/gems
|
||||
export PATH="$GEM_HOME/bin:$PATH"
|
||||
|
||||
# install bundle gem
|
||||
gem install bundler --install-dir $GEM_HOME
|
||||
|
||||
# setup gems
|
||||
bundle install
|
||||
|
||||
bundle exec arkana
|
||||
bundle exec pod install
|
Loading…
Reference in New Issue