├── .github ├── FUNDING.yml └── workflows │ ├── testflight.yaml │ └── tests.yaml ├── .gitignore ├── Bark.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ ├── Bark.xcscheme │ ├── NotificationContentExtension.xcscheme │ └── NotificationServiceExtension.xcscheme ├── Bark.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── Bark ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ └── bark.png │ ├── Colors │ │ ├── Contents.json │ │ ├── background.colorset │ │ │ └── Contents.json │ │ ├── background_seconday.colorset │ │ │ └── Contents.json │ │ ├── black.colorset │ │ │ └── Contents.json │ │ ├── blue_base.colorset │ │ │ └── Contents.json │ │ ├── blue_darken1.colorset │ │ │ └── Contents.json │ │ ├── blue_darken5.colorset │ │ │ └── Contents.json │ │ ├── darkText_primary.colorset │ │ │ └── Contents.json │ │ ├── darkText_secondary.colorset │ │ │ └── Contents.json │ │ ├── grey_base.colorset │ │ │ └── Contents.json │ │ ├── grey_darken1.colorset │ │ │ └── Contents.json │ │ ├── grey_darken2.colorset │ │ │ └── Contents.json │ │ ├── grey_darken3.colorset │ │ │ └── Contents.json │ │ ├── grey_darken4.colorset │ │ │ └── Contents.json │ │ ├── grey_lighten1.colorset │ │ │ └── Contents.json │ │ ├── grey_lighten2.colorset │ │ │ └── Contents.json │ │ ├── grey_lighten3.colorset │ │ │ └── Contents.json │ │ ├── grey_lighten4.colorset │ │ │ └── Contents.json │ │ ├── grey_lighten5.colorset │ │ │ └── Contents.json │ │ ├── lightBlue_darken3.colorset │ │ │ └── Contents.json │ │ ├── notification_copy_color.colorset │ │ │ └── Contents.json │ │ └── white.colorset │ │ │ └── Contents.json │ ├── Contents.json │ ├── back.imageset │ │ ├── Contents.json │ │ ├── back@2x.png │ │ └── back@3x.png │ ├── baseline_check_circle_outline_black_24pt.imageset │ │ ├── Contents.json │ │ ├── baseline_check_circle_outline_black_24pt_1x.png │ │ ├── baseline_check_circle_outline_black_24pt_2x.png │ │ └── baseline_check_circle_outline_black_24pt_3x.png │ ├── baseline_close_white_48pt.imageset │ │ ├── Contents.json │ │ ├── baseline_close_white_48pt_1x.png │ │ ├── baseline_close_white_48pt_2x.png │ │ └── baseline_close_white_48pt_3x.png │ ├── baseline_delete_outline_black_24pt.imageset │ │ ├── Contents.json │ │ ├── baseline_delete_outline_black_24pt_1x.png │ │ ├── baseline_delete_outline_black_24pt_2x.png │ │ └── baseline_delete_outline_black_24pt_3x.png │ ├── baseline_file_copy_white_24pt.imageset │ │ ├── Contents.json │ │ ├── baseline_file_copy_white_24pt_1x.png │ │ ├── baseline_file_copy_white_24pt_2x.png │ │ └── baseline_file_copy_white_24pt_3x.png │ ├── baseline_filter_drama_black_24pt.imageset │ │ ├── Contents.json │ │ ├── baseline_filter_drama_black_24pt_1x.png │ │ ├── baseline_filter_drama_black_24pt_2x.png │ │ └── baseline_filter_drama_black_24pt_3x.png │ ├── baseline_folder_open_black_24pt.imageset │ │ ├── Contents.json │ │ ├── baseline_folder_open_black_24pt_1x.png │ │ ├── baseline_folder_open_black_24pt_2x.png │ │ └── baseline_folder_open_black_24pt_3x.png │ ├── baseline_gite_black_24pt.imageset │ │ ├── Contents.json │ │ ├── baseline_gite_black_24pt_1x.png │ │ ├── baseline_gite_black_24pt_2x.png │ │ └── baseline_gite_black_24pt_3x.png │ ├── baseline_http_black_24pt.imageset │ │ ├── Contents.json │ │ ├── baseline_http_black_24pt_1x.png │ │ ├── baseline_http_black_24pt_2x.png │ │ └── baseline_http_black_24pt_3x.png │ ├── baseline_https_black_24pt.imageset │ │ ├── Contents.json │ │ ├── baseline_https_black_24pt_1x.png │ │ ├── baseline_https_black_24pt_2x.png │ │ └── baseline_https_black_24pt_3x.png │ ├── baseline_keyboard_arrow_down_black_24pt.imageset │ │ ├── Contents.json │ │ ├── baseline_keyboard_arrow_down_black_24pt_1x.png │ │ ├── baseline_keyboard_arrow_down_black_24pt_2x.png │ │ └── baseline_keyboard_arrow_down_black_24pt_3x.png │ ├── baseline_manage_accounts_black_24pt.imageset │ │ ├── Contents.json │ │ ├── baseline_manage_accounts_black_24pt_1x.png │ │ ├── baseline_manage_accounts_black_24pt_2x.png │ │ └── baseline_manage_accounts_black_24pt_3x.png │ ├── baseline_qr_code_scanner_black_24pt.imageset │ │ ├── Contents.json │ │ ├── baseline_qr_code_scanner_black_24pt_1x.png │ │ ├── baseline_qr_code_scanner_black_24pt_2x.png │ │ └── baseline_qr_code_scanner_black_24pt_3x.png │ ├── baseline_radio_button_unchecked_black_24pt.imageset │ │ ├── Contents.json │ │ ├── baseline_radio_button_unchecked_black_24pt_1x.png │ │ ├── baseline_radio_button_unchecked_black_24pt_2x.png │ │ └── baseline_radio_button_unchecked_black_24pt_3x.png │ ├── baseline_remove_black_20pt.imageset │ │ ├── Contents.json │ │ ├── baseline_remove_black_20pt_1x.png │ │ ├── baseline_remove_black_20pt_2x.png │ │ └── baseline_remove_black_20pt_3x.png │ ├── baseline_wifi_black_20pt.imageset │ │ ├── Contents.json │ │ ├── baseline_wifi_black_20pt_1x.png │ │ ├── baseline_wifi_black_20pt_2x.png │ │ └── baseline_wifi_black_20pt_3x.png │ ├── baseline_wifi_off_black_20pt.imageset │ │ ├── Contents.json │ │ ├── baseline_wifi_off_black_20pt_1x.png │ │ ├── baseline_wifi_off_black_20pt_2x.png │ │ └── baseline_wifi_off_black_20pt_3x.png │ ├── copyTest.imageset │ │ ├── Contents.json │ │ ├── preview_copy@3x.png │ │ └── preview_copy_dark@3x.png │ ├── criticalAlert.imageset │ │ ├── Contents.json │ │ ├── IMG_8023.jpg │ │ └── IMG_8024.jpg │ ├── group.imageset │ │ ├── Contents.json │ │ ├── preview_group_dark@3x.png │ │ └── preview_group_default@3x.png │ ├── group_collapse.imageset │ │ ├── Contents.json │ │ ├── folder_code_24dp_5F6368_FILL0_wght400_GRAD0_opsz242 (2).png │ │ └── folder_code_24dp_5F6368_FILL0_wght400_GRAD0_opsz242 (3).png │ ├── group_expand.imageset │ │ ├── Contents.json │ │ ├── folder_code_24dp_5F6368_FILL0_wght400_GRAD0_opsz24 1.png │ │ └── folder_code_24dp_5F6368_FILL0_wght400_GRAD0_opsz24.png │ ├── icon.imageset │ │ ├── Contents.json │ │ ├── preview_icon_dark@3x.png │ │ └── preview_icon_default@3x.png │ ├── keyboard_arrow_right_symbol.symbolset │ │ ├── Contents.json │ │ └── keyboard_arrow_right_keyboard_arrow_right_symbol.svg │ ├── music_note-music_note_symbol.symbolset │ │ ├── Contents.json │ │ └── music_note-music_note_symbol.svg │ ├── offline.imageset │ │ ├── Contents.json │ │ └── offline@3x.png │ ├── online.imageset │ │ ├── Contents.json │ │ └── online@3X.png │ └── warning.imageset │ │ ├── Contents.json │ │ └── warning@3x.png ├── Bark.entitlements ├── Base.lproj │ └── LaunchScreen.storyboard ├── Info.plist ├── Intents │ ├── OptionsProvider.swift │ ├── PushResponse.swift │ ├── PushToCurrentIntent.swift │ └── PushToOtherIntent.swift └── Localizable.xcstrings ├── BarkTests ├── BarkTests.swift ├── HomeViewModelTests.swift ├── Info.plist └── MessageDeleteTimeRangeTest.swift ├── Common ├── ArchiveSettingManager.swift ├── ArchiveSettingRelay.swift ├── BKColor.swift ├── BarkSettings.swift ├── Client.swift ├── CryptoSettingManager.swift ├── CryptoSettingRelay.swift ├── Date+Extension.swift ├── Defines.swift ├── Error+Extension.swift ├── GroupMuteSettingManager.swift ├── MJRefresh+Rx.swift ├── Moya │ ├── BarkApi.swift │ ├── BarkTargetType.swift │ └── Observable+Extension.swift ├── NSLocalizedString+Extension.swift ├── Operators.swift ├── RealmConfiguration.swift ├── Reusable.swift ├── ServerManager.swift ├── SharedDefines.swift ├── String+Extension.swift ├── UIColor+Extension.swift ├── UIFont+Extension.swift └── ViewModelType.swift ├── Controller ├── BarkNavigationController.swift ├── BarkSFSafariViewController.swift ├── BarkSplitViewController.swift ├── BarkTabBarController.swift ├── BaseViewController.swift ├── CrashReportViewController.swift ├── CryptoSettingController.swift ├── CryptoSettingViewModel.swift ├── HomeViewController.swift ├── HomeViewModel.swift ├── MessageListViewController.swift ├── MessageListViewModel.swift ├── MessageSettingsViewController.swift ├── MessageSettingsViewModel.swift ├── NewServerViewController.swift ├── NewServerViewModel.swift ├── QRScannerViewController.swift ├── SectionViewController-iPad.swift ├── SectionViewModel-iPad.swift ├── ServerListViewController.swift ├── ServerListViewModel.swift ├── SoundsViewController.swift └── SoundsViewModel.swift ├── Gemfile ├── LICENSE ├── Model ├── Algorithm.swift ├── Message.swift ├── MessageDeleteTimeRange.swift ├── MessageItemModel.swift ├── MessageSection.swift ├── Object+Dictionary.swift └── PreviewModel.swift ├── NotificationServiceExtension ├── Info.plist ├── NotificationService.swift ├── NotificationServiceExtension.entitlements └── Processor │ ├── ArchiveProcessor.swift │ ├── AutoCopyProcessor.swift │ ├── BadgeProcessor.swift │ ├── CallProcessor.swift │ ├── CiphertextProcessor.swift │ ├── IconProcessor.swift │ ├── ImageDownloader.swift │ ├── ImageProcessor.swift │ ├── LevelProcessor.swift │ ├── MuteProcessor.swift │ └── NotificationContentProcessor.swift ├── Podfile ├── Podfile.lock ├── README.md ├── README.zh.md ├── Sounds ├── alarm.caf ├── anticipate.caf ├── bell.caf ├── birdsong.caf ├── bloom.caf ├── calypso.caf ├── chime.caf ├── choo.caf ├── descent.caf ├── electronic.caf ├── fanfare.caf ├── glass.caf ├── gotosleep.caf ├── healthnotification.caf ├── horn.caf ├── ladder.caf ├── mailsent.caf ├── minuet.caf ├── multiwayinvitation.caf ├── newmail.caf ├── newsflash.caf ├── noir.caf ├── paymentsuccess.caf ├── shake.caf ├── sherwoodforest.caf ├── silence.caf ├── spell.caf ├── suspense.caf ├── telegraph.caf ├── tiptoes.caf ├── typewriters.caf └── update.caf ├── View ├── AddSoundCell.swift ├── ArchiveSettingCell.swift ├── ArchiveSettingCellViewModel.swift ├── BKButton.swift ├── BKDropDownCell.swift ├── BKDropDownCell.xib ├── BKLabel.swift ├── BaseTableViewCell.swift ├── BorderTextField.swift ├── DonateCell.swift ├── DropBoxView.swift ├── GesturePassTextView.swift ├── GradientButton.swift ├── HUD.swift ├── LabelCell.swift ├── MessageList │ ├── CustomTapTextView.swift │ ├── MessageGroupHeaderView.swift │ ├── MessageGroupMoreView.swift │ ├── MessageItemView.swift │ ├── MessageTableViewCell.swift │ └── ShowLessAndClearView.swift ├── MessageSettingFooter.swift ├── MutableTextCell.swift ├── MutableTextCellViewModel.swift ├── PreviewCardCell.swift ├── PreviewCardCellViewModel.swift ├── ServerListTableViewCell.swift ├── ServerListTableViewCellViewModel.swift ├── SettingSectionHeader.swift ├── SoundCell.swift ├── SoundCellViewModel.swift ├── SpacerCell.swift ├── TextCell.swift ├── UINavigationItem+Extension.swift └── iCloudStatusCell.swift ├── docs ├── .nojekyll ├── CNAME ├── README.md ├── _coverpage.md ├── _media │ ├── Icon.png │ ├── environment.png │ ├── example.jpg │ └── shortcuts_cn.png ├── _navbar.md ├── _sidebar.md ├── batch.md ├── build.md ├── cert.md ├── deploy.md ├── en-us │ ├── README.md │ ├── _coverpage.md │ ├── _sidebar.md │ ├── batch.md │ ├── build.md │ ├── cert.md │ ├── deploy.md │ ├── encryption.md │ ├── faq.md │ ├── privacy.md │ └── tutorial.md ├── encryption.md ├── faq.md ├── index.html ├── privacy.md └── tutorial.md ├── fastlane ├── Appfile ├── Fastfile └── Matchfile └── notificationContentExtension ├── Base.lproj └── MainInterface.storyboard ├── Info.plist ├── NotificationContentExtension.entitlements └── NotificationViewController.swift /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [Finb] 4 | -------------------------------------------------------------------------------- /.github/workflows/testflight.yaml: -------------------------------------------------------------------------------- 1 | name: Deploy to App Store 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | storeVersionNumber: 7 | description: 'Store Version Number' 8 | required: true 9 | default: "" 10 | buildNumber: 11 | description: 'Build Number' 12 | required: true 13 | default: "" 14 | 15 | jobs: 16 | deploy: 17 | runs-on: macos-latest 18 | 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v4 22 | 23 | - name: Select Xcode Version 24 | uses: maxim-lobanov/setup-xcode@v1 25 | with: 26 | xcode-version: '16.1' 27 | 28 | - name: Setup ruby 29 | uses: ruby/setup-ruby@v1 30 | with: 31 | ruby-version: 2.7.2 32 | bundler-cache: true 33 | 34 | - uses: actions/cache@v4 35 | id: pods-cache 36 | with: 37 | path: Pods 38 | key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }} 39 | restore-keys: | 40 | ${{ runner.os }}-pods- 41 | 42 | - name: Install Pods 43 | run: pod install 44 | 45 | - name: Build & Distribute to App Store 46 | run: | 47 | export LC_ALL=en_US.UTF-8 48 | export LANG=en_US.UTF-8 49 | bundle exec fastlane beta store_version_number:${{ github.event.inputs.storeVersionNumber }} build_number:${{ github.event.inputs.buildNumber }} 50 | env: 51 | APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }} 52 | APP_STORE_CONNECT_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_KEY_CONTENT }} 53 | BARK_KEY: ${{ secrets.BARK_KEY }} 54 | MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }} 55 | MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} 56 | 57 | - name: Archive artifacts 58 | uses: actions/upload-artifact@v4 59 | with: 60 | name: dSYM 61 | path: Bark.app.dSYM.zip 62 | -------------------------------------------------------------------------------- /.github/workflows/tests.yaml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | tests: 13 | runs-on: macos-latest 14 | 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v4 18 | 19 | - name: Select Xcode Version 20 | uses: maxim-lobanov/setup-xcode@v1 21 | with: 22 | xcode-version: 'latest-stable' 23 | 24 | - name: Setup ruby 25 | uses: ruby/setup-ruby@v1 26 | with: 27 | ruby-version: 2.7.2 28 | bundler-cache: true 29 | 30 | - uses: actions/cache@v4 31 | id: pods-cache 32 | with: 33 | path: Pods 34 | key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }} 35 | restore-keys: | 36 | ${{ runner.os }}-pods- 37 | 38 | - name: Install Pods 39 | run: pod install 40 | 41 | - name: Run Tests 42 | run: | 43 | export LC_ALL=en_US.UTF-8 44 | export LANG=en_US.UTF-8 45 | bundle exec fastlane tests 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.mode*v* 2 | *.pbxuser 3 | *.xccheckout 4 | #*.xcbkptlist 5 | #*.xcscheme 6 | #*.xcworkspacedata 7 | *.xcuserstate 8 | build/ 9 | Pods/ 10 | .DS_Store 11 | ._.* 12 | xcuserdata 13 | -------------------------------------------------------------------------------- /Bark.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Bark.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Bark.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "bark.png", 5 | "idiom" : "universal", 6 | "platform" : "ios", 7 | "size" : "1024x1024" 8 | } 9 | ], 10 | "info" : { 11 | "author" : "xcode", 12 | "version" : 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/AppIcon.appiconset/bark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/AppIcon.appiconset/bark.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/background.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "245", 9 | "green" : "245", 10 | "red" : "245" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0", 27 | "green" : "0", 28 | "red" : "0" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/background_seconday.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "255", 9 | "green" : "255", 10 | "red" : "255" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "22", 27 | "green" : "22", 28 | "red" : "22" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/black.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.000", 9 | "green" : "0.000", 10 | "red" : "0.000" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "1.000", 27 | "green" : "1.000", 28 | "red" : "1.000" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/blue_base.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "243", 9 | "green" : "150", 10 | "red" : "33" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "243", 27 | "green" : "150", 28 | "red" : "33" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/blue_darken1.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "229", 9 | "green" : "136", 10 | "red" : "30" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "245", 27 | "green" : "165", 28 | "red" : "66" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/blue_darken5.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "216", 9 | "green" : "46", 10 | "red" : "34" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "233", 27 | "green" : "44", 28 | "red" : "70" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/darkText_primary.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "0.870", 8 | "blue" : "255", 9 | "green" : "255", 10 | "red" : "255" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "0.870", 26 | "blue" : "0", 27 | "green" : "0", 28 | "red" : "0" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/darkText_secondary.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "0.540", 8 | "blue" : "255", 9 | "green" : "255", 10 | "red" : "255" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "0.540", 26 | "blue" : "0", 27 | "green" : "0", 28 | "red" : "0" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/grey_base.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "158", 9 | "green" : "158", 10 | "red" : "158" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "97", 27 | "green" : "97", 28 | "red" : "97" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/grey_darken1.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "117", 9 | "green" : "117", 10 | "red" : "117" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "189", 27 | "green" : "189", 28 | "red" : "189" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/grey_darken2.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "97", 9 | "green" : "97", 10 | "red" : "97" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "224", 27 | "green" : "224", 28 | "red" : "224" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/grey_darken3.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "66", 9 | "green" : "66", 10 | "red" : "66" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "238", 27 | "green" : "238", 28 | "red" : "238" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/grey_darken4.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "33", 9 | "green" : "33", 10 | "red" : "33" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "245", 27 | "green" : "245", 28 | "red" : "245" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/grey_lighten1.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "189", 9 | "green" : "189", 10 | "red" : "189" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "117", 27 | "green" : "117", 28 | "red" : "117" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/grey_lighten2.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "214", 9 | "green" : "214", 10 | "red" : "214" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "92", 27 | "green" : "92", 28 | "red" : "92" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/grey_lighten3.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "238", 9 | "green" : "238", 10 | "red" : "238" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "66", 27 | "green" : "66", 28 | "red" : "66" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/grey_lighten4.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "245", 9 | "green" : "245", 10 | "red" : "245" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "33", 27 | "green" : "33", 28 | "red" : "33" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/grey_lighten5.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "250", 9 | "green" : "250", 10 | "red" : "250" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "28", 27 | "green" : "28", 28 | "red" : "28" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/lightBlue_darken3.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "189", 9 | "green" : "119", 10 | "red" : "2" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "250", 27 | "green" : "212", 28 | "red" : "129" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/notification_copy_color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.000", 9 | "green" : "0.000", 10 | "red" : "0.000" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "1.000", 27 | "green" : "1.000", 28 | "red" : "1.000" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | }, 33 | { 34 | "color" : { 35 | "color-space" : "srgb", 36 | "components" : { 37 | "alpha" : "1.000", 38 | "blue" : "0.000", 39 | "green" : "0.000", 40 | "red" : "0.000" 41 | } 42 | }, 43 | "idiom" : "iphone" 44 | }, 45 | { 46 | "appearances" : [ 47 | { 48 | "appearance" : "luminosity", 49 | "value" : "dark" 50 | } 51 | ], 52 | "color" : { 53 | "color-space" : "srgb", 54 | "components" : { 55 | "alpha" : "1.000", 56 | "blue" : "1.000", 57 | "green" : "1.000", 58 | "red" : "1.000" 59 | } 60 | }, 61 | "idiom" : "iphone" 62 | }, 63 | { 64 | "color" : { 65 | "color-space" : "srgb", 66 | "components" : { 67 | "alpha" : "1.000", 68 | "blue" : "0.000", 69 | "green" : "0.000", 70 | "red" : "0.000" 71 | } 72 | }, 73 | "idiom" : "ipad" 74 | }, 75 | { 76 | "appearances" : [ 77 | { 78 | "appearance" : "luminosity", 79 | "value" : "dark" 80 | } 81 | ], 82 | "color" : { 83 | "color-space" : "srgb", 84 | "components" : { 85 | "alpha" : "1.000", 86 | "blue" : "1.000", 87 | "green" : "1.000", 88 | "red" : "1.000" 89 | } 90 | }, 91 | "idiom" : "ipad" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Colors/white.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "1.000", 9 | "green" : "1.000", 10 | "red" : "1.000" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0.000", 27 | "green" : "0.000", 28 | "red" : "0.000" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/back.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "back@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "back@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Bark/Assets.xcassets/back.imageset/back@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/back.imageset/back@2x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/back.imageset/back@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/back.imageset/back@3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_check_circle_outline_black_24pt.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "baseline_check_circle_outline_black_24pt_1x.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "baseline_check_circle_outline_black_24pt_2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "baseline_check_circle_outline_black_24pt_3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_check_circle_outline_black_24pt.imageset/baseline_check_circle_outline_black_24pt_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_check_circle_outline_black_24pt.imageset/baseline_check_circle_outline_black_24pt_1x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_check_circle_outline_black_24pt.imageset/baseline_check_circle_outline_black_24pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_check_circle_outline_black_24pt.imageset/baseline_check_circle_outline_black_24pt_2x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_check_circle_outline_black_24pt.imageset/baseline_check_circle_outline_black_24pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_check_circle_outline_black_24pt.imageset/baseline_check_circle_outline_black_24pt_3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_close_white_48pt.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "baseline_close_white_48pt_1x.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "baseline_close_white_48pt_2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "baseline_close_white_48pt_3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_close_white_48pt.imageset/baseline_close_white_48pt_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_close_white_48pt.imageset/baseline_close_white_48pt_1x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_close_white_48pt.imageset/baseline_close_white_48pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_close_white_48pt.imageset/baseline_close_white_48pt_2x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_close_white_48pt.imageset/baseline_close_white_48pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_close_white_48pt.imageset/baseline_close_white_48pt_3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_delete_outline_black_24pt.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "baseline_delete_outline_black_24pt_1x.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "baseline_delete_outline_black_24pt_2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "baseline_delete_outline_black_24pt_3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_delete_outline_black_24pt.imageset/baseline_delete_outline_black_24pt_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_delete_outline_black_24pt.imageset/baseline_delete_outline_black_24pt_1x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_delete_outline_black_24pt.imageset/baseline_delete_outline_black_24pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_delete_outline_black_24pt.imageset/baseline_delete_outline_black_24pt_2x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_delete_outline_black_24pt.imageset/baseline_delete_outline_black_24pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_delete_outline_black_24pt.imageset/baseline_delete_outline_black_24pt_3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_file_copy_white_24pt.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "baseline_file_copy_white_24pt_1x.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "baseline_file_copy_white_24pt_2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "baseline_file_copy_white_24pt_3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_file_copy_white_24pt.imageset/baseline_file_copy_white_24pt_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_file_copy_white_24pt.imageset/baseline_file_copy_white_24pt_1x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_file_copy_white_24pt.imageset/baseline_file_copy_white_24pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_file_copy_white_24pt.imageset/baseline_file_copy_white_24pt_2x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_file_copy_white_24pt.imageset/baseline_file_copy_white_24pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_file_copy_white_24pt.imageset/baseline_file_copy_white_24pt_3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_filter_drama_black_24pt.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "baseline_filter_drama_black_24pt_1x.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "baseline_filter_drama_black_24pt_2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "baseline_filter_drama_black_24pt_3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_filter_drama_black_24pt.imageset/baseline_filter_drama_black_24pt_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_filter_drama_black_24pt.imageset/baseline_filter_drama_black_24pt_1x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_filter_drama_black_24pt.imageset/baseline_filter_drama_black_24pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_filter_drama_black_24pt.imageset/baseline_filter_drama_black_24pt_2x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_filter_drama_black_24pt.imageset/baseline_filter_drama_black_24pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_filter_drama_black_24pt.imageset/baseline_filter_drama_black_24pt_3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_folder_open_black_24pt.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "baseline_folder_open_black_24pt_1x.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "baseline_folder_open_black_24pt_2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "baseline_folder_open_black_24pt_3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_folder_open_black_24pt.imageset/baseline_folder_open_black_24pt_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_folder_open_black_24pt.imageset/baseline_folder_open_black_24pt_1x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_folder_open_black_24pt.imageset/baseline_folder_open_black_24pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_folder_open_black_24pt.imageset/baseline_folder_open_black_24pt_2x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_folder_open_black_24pt.imageset/baseline_folder_open_black_24pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_folder_open_black_24pt.imageset/baseline_folder_open_black_24pt_3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_gite_black_24pt.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "baseline_gite_black_24pt_1x.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "baseline_gite_black_24pt_2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "baseline_gite_black_24pt_3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_gite_black_24pt.imageset/baseline_gite_black_24pt_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_gite_black_24pt.imageset/baseline_gite_black_24pt_1x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_gite_black_24pt.imageset/baseline_gite_black_24pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_gite_black_24pt.imageset/baseline_gite_black_24pt_2x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_gite_black_24pt.imageset/baseline_gite_black_24pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_gite_black_24pt.imageset/baseline_gite_black_24pt_3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_http_black_24pt.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "baseline_http_black_24pt_1x.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "baseline_http_black_24pt_2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "baseline_http_black_24pt_3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_http_black_24pt.imageset/baseline_http_black_24pt_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_http_black_24pt.imageset/baseline_http_black_24pt_1x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_http_black_24pt.imageset/baseline_http_black_24pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_http_black_24pt.imageset/baseline_http_black_24pt_2x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_http_black_24pt.imageset/baseline_http_black_24pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_http_black_24pt.imageset/baseline_http_black_24pt_3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_https_black_24pt.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "baseline_https_black_24pt_1x.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "baseline_https_black_24pt_2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "baseline_https_black_24pt_3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_https_black_24pt.imageset/baseline_https_black_24pt_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_https_black_24pt.imageset/baseline_https_black_24pt_1x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_https_black_24pt.imageset/baseline_https_black_24pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_https_black_24pt.imageset/baseline_https_black_24pt_2x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_https_black_24pt.imageset/baseline_https_black_24pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_https_black_24pt.imageset/baseline_https_black_24pt_3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_keyboard_arrow_down_black_24pt.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "baseline_keyboard_arrow_down_black_24pt_1x.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "baseline_keyboard_arrow_down_black_24pt_2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "baseline_keyboard_arrow_down_black_24pt_3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_keyboard_arrow_down_black_24pt.imageset/baseline_keyboard_arrow_down_black_24pt_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_keyboard_arrow_down_black_24pt.imageset/baseline_keyboard_arrow_down_black_24pt_1x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_keyboard_arrow_down_black_24pt.imageset/baseline_keyboard_arrow_down_black_24pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_keyboard_arrow_down_black_24pt.imageset/baseline_keyboard_arrow_down_black_24pt_2x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_keyboard_arrow_down_black_24pt.imageset/baseline_keyboard_arrow_down_black_24pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_keyboard_arrow_down_black_24pt.imageset/baseline_keyboard_arrow_down_black_24pt_3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_manage_accounts_black_24pt.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "baseline_manage_accounts_black_24pt_1x.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "baseline_manage_accounts_black_24pt_2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "baseline_manage_accounts_black_24pt_3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_manage_accounts_black_24pt.imageset/baseline_manage_accounts_black_24pt_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_manage_accounts_black_24pt.imageset/baseline_manage_accounts_black_24pt_1x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_manage_accounts_black_24pt.imageset/baseline_manage_accounts_black_24pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_manage_accounts_black_24pt.imageset/baseline_manage_accounts_black_24pt_2x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_manage_accounts_black_24pt.imageset/baseline_manage_accounts_black_24pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_manage_accounts_black_24pt.imageset/baseline_manage_accounts_black_24pt_3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_qr_code_scanner_black_24pt.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "baseline_qr_code_scanner_black_24pt_1x.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "baseline_qr_code_scanner_black_24pt_2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "baseline_qr_code_scanner_black_24pt_3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_qr_code_scanner_black_24pt.imageset/baseline_qr_code_scanner_black_24pt_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_qr_code_scanner_black_24pt.imageset/baseline_qr_code_scanner_black_24pt_1x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_qr_code_scanner_black_24pt.imageset/baseline_qr_code_scanner_black_24pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_qr_code_scanner_black_24pt.imageset/baseline_qr_code_scanner_black_24pt_2x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_qr_code_scanner_black_24pt.imageset/baseline_qr_code_scanner_black_24pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_qr_code_scanner_black_24pt.imageset/baseline_qr_code_scanner_black_24pt_3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_radio_button_unchecked_black_24pt.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "baseline_radio_button_unchecked_black_24pt_1x.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "baseline_radio_button_unchecked_black_24pt_2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "baseline_radio_button_unchecked_black_24pt_3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_radio_button_unchecked_black_24pt.imageset/baseline_radio_button_unchecked_black_24pt_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_radio_button_unchecked_black_24pt.imageset/baseline_radio_button_unchecked_black_24pt_1x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_radio_button_unchecked_black_24pt.imageset/baseline_radio_button_unchecked_black_24pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_radio_button_unchecked_black_24pt.imageset/baseline_radio_button_unchecked_black_24pt_2x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_radio_button_unchecked_black_24pt.imageset/baseline_radio_button_unchecked_black_24pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_radio_button_unchecked_black_24pt.imageset/baseline_radio_button_unchecked_black_24pt_3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_remove_black_20pt.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "baseline_remove_black_20pt_1x.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "baseline_remove_black_20pt_2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "baseline_remove_black_20pt_3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_remove_black_20pt.imageset/baseline_remove_black_20pt_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_remove_black_20pt.imageset/baseline_remove_black_20pt_1x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_remove_black_20pt.imageset/baseline_remove_black_20pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_remove_black_20pt.imageset/baseline_remove_black_20pt_2x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_remove_black_20pt.imageset/baseline_remove_black_20pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_remove_black_20pt.imageset/baseline_remove_black_20pt_3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_wifi_black_20pt.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "baseline_wifi_black_20pt_1x.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "baseline_wifi_black_20pt_2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "baseline_wifi_black_20pt_3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_wifi_black_20pt.imageset/baseline_wifi_black_20pt_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_wifi_black_20pt.imageset/baseline_wifi_black_20pt_1x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_wifi_black_20pt.imageset/baseline_wifi_black_20pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_wifi_black_20pt.imageset/baseline_wifi_black_20pt_2x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_wifi_black_20pt.imageset/baseline_wifi_black_20pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_wifi_black_20pt.imageset/baseline_wifi_black_20pt_3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_wifi_off_black_20pt.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "baseline_wifi_off_black_20pt_1x.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "baseline_wifi_off_black_20pt_2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "baseline_wifi_off_black_20pt_3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_wifi_off_black_20pt.imageset/baseline_wifi_off_black_20pt_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_wifi_off_black_20pt.imageset/baseline_wifi_off_black_20pt_1x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_wifi_off_black_20pt.imageset/baseline_wifi_off_black_20pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_wifi_off_black_20pt.imageset/baseline_wifi_off_black_20pt_2x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/baseline_wifi_off_black_20pt.imageset/baseline_wifi_off_black_20pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/baseline_wifi_off_black_20pt.imageset/baseline_wifi_off_black_20pt_3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/copyTest.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "dark" 12 | } 13 | ], 14 | "idiom" : "universal", 15 | "scale" : "1x" 16 | }, 17 | { 18 | "idiom" : "universal", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "appearances" : [ 23 | { 24 | "appearance" : "luminosity", 25 | "value" : "dark" 26 | } 27 | ], 28 | "idiom" : "universal", 29 | "scale" : "2x" 30 | }, 31 | { 32 | "filename" : "preview_copy@3x.png", 33 | "idiom" : "universal", 34 | "scale" : "3x" 35 | }, 36 | { 37 | "appearances" : [ 38 | { 39 | "appearance" : "luminosity", 40 | "value" : "dark" 41 | } 42 | ], 43 | "filename" : "preview_copy_dark@3x.png", 44 | "idiom" : "universal", 45 | "scale" : "3x" 46 | } 47 | ], 48 | "info" : { 49 | "author" : "xcode", 50 | "version" : 1 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/copyTest.imageset/preview_copy@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/copyTest.imageset/preview_copy@3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/copyTest.imageset/preview_copy_dark@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/copyTest.imageset/preview_copy_dark@3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/criticalAlert.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "dark" 12 | } 13 | ], 14 | "idiom" : "universal", 15 | "scale" : "1x" 16 | }, 17 | { 18 | "idiom" : "universal", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "appearances" : [ 23 | { 24 | "appearance" : "luminosity", 25 | "value" : "dark" 26 | } 27 | ], 28 | "idiom" : "universal", 29 | "scale" : "2x" 30 | }, 31 | { 32 | "filename" : "IMG_8023.jpg", 33 | "idiom" : "universal", 34 | "scale" : "3x" 35 | }, 36 | { 37 | "appearances" : [ 38 | { 39 | "appearance" : "luminosity", 40 | "value" : "dark" 41 | } 42 | ], 43 | "filename" : "IMG_8024.jpg", 44 | "idiom" : "universal", 45 | "scale" : "3x" 46 | } 47 | ], 48 | "info" : { 49 | "author" : "xcode", 50 | "version" : 1 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/criticalAlert.imageset/IMG_8023.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/criticalAlert.imageset/IMG_8023.jpg -------------------------------------------------------------------------------- /Bark/Assets.xcassets/criticalAlert.imageset/IMG_8024.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/criticalAlert.imageset/IMG_8024.jpg -------------------------------------------------------------------------------- /Bark/Assets.xcassets/group.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "dark" 12 | } 13 | ], 14 | "idiom" : "universal", 15 | "scale" : "1x" 16 | }, 17 | { 18 | "idiom" : "universal", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "appearances" : [ 23 | { 24 | "appearance" : "luminosity", 25 | "value" : "dark" 26 | } 27 | ], 28 | "idiom" : "universal", 29 | "scale" : "2x" 30 | }, 31 | { 32 | "filename" : "preview_group_default@3x.png", 33 | "idiom" : "universal", 34 | "scale" : "3x" 35 | }, 36 | { 37 | "appearances" : [ 38 | { 39 | "appearance" : "luminosity", 40 | "value" : "dark" 41 | } 42 | ], 43 | "filename" : "preview_group_dark@3x.png", 44 | "idiom" : "universal", 45 | "scale" : "3x" 46 | } 47 | ], 48 | "info" : { 49 | "author" : "xcode", 50 | "version" : 1 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/group.imageset/preview_group_dark@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/group.imageset/preview_group_dark@3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/group.imageset/preview_group_default@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/group.imageset/preview_group_default@3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/group_collapse.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "folder_code_24dp_5F6368_FILL0_wght400_GRAD0_opsz242 (3).png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "folder_code_24dp_5F6368_FILL0_wght400_GRAD0_opsz242 (2).png", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/group_collapse.imageset/folder_code_24dp_5F6368_FILL0_wght400_GRAD0_opsz242 (2).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/group_collapse.imageset/folder_code_24dp_5F6368_FILL0_wght400_GRAD0_opsz242 (2).png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/group_collapse.imageset/folder_code_24dp_5F6368_FILL0_wght400_GRAD0_opsz242 (3).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/group_collapse.imageset/folder_code_24dp_5F6368_FILL0_wght400_GRAD0_opsz242 (3).png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/group_expand.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "folder_code_24dp_5F6368_FILL0_wght400_GRAD0_opsz24 1.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "folder_code_24dp_5F6368_FILL0_wght400_GRAD0_opsz24.png", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/group_expand.imageset/folder_code_24dp_5F6368_FILL0_wght400_GRAD0_opsz24 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/group_expand.imageset/folder_code_24dp_5F6368_FILL0_wght400_GRAD0_opsz24 1.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/group_expand.imageset/folder_code_24dp_5F6368_FILL0_wght400_GRAD0_opsz24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/group_expand.imageset/folder_code_24dp_5F6368_FILL0_wght400_GRAD0_opsz24.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "dark" 12 | } 13 | ], 14 | "idiom" : "universal", 15 | "scale" : "1x" 16 | }, 17 | { 18 | "idiom" : "universal", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "appearances" : [ 23 | { 24 | "appearance" : "luminosity", 25 | "value" : "dark" 26 | } 27 | ], 28 | "idiom" : "universal", 29 | "scale" : "2x" 30 | }, 31 | { 32 | "filename" : "preview_icon_default@3x.png", 33 | "idiom" : "universal", 34 | "scale" : "3x" 35 | }, 36 | { 37 | "appearances" : [ 38 | { 39 | "appearance" : "luminosity", 40 | "value" : "dark" 41 | } 42 | ], 43 | "filename" : "preview_icon_dark@3x.png", 44 | "idiom" : "universal", 45 | "scale" : "3x" 46 | } 47 | ], 48 | "info" : { 49 | "author" : "xcode", 50 | "version" : 1 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/icon.imageset/preview_icon_dark@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/icon.imageset/preview_icon_dark@3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/icon.imageset/preview_icon_default@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/icon.imageset/preview_icon_default@3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/keyboard_arrow_right_symbol.symbolset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "symbols" : [ 7 | { 8 | "filename" : "keyboard_arrow_right_keyboard_arrow_right_symbol.svg", 9 | "idiom" : "universal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/music_note-music_note_symbol.symbolset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "symbols" : [ 7 | { 8 | "filename" : "music_note-music_note_symbol.svg", 9 | "idiom" : "universal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/offline.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "filename" : "offline@3x.png", 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/offline.imageset/offline@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/offline.imageset/offline@3x.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/online.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "filename" : "online@3X.png", 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/online.imageset/online@3X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/online.imageset/online@3X.png -------------------------------------------------------------------------------- /Bark/Assets.xcassets/warning.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "filename" : "warning@3x.png", 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Bark/Assets.xcassets/warning.imageset/warning@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Bark/Assets.xcassets/warning.imageset/warning@3x.png -------------------------------------------------------------------------------- /Bark/Bark.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | development 7 | com.apple.developer.usernotifications.communication 8 | 9 | com.apple.developer.usernotifications.critical-alerts 10 | 11 | com.apple.developer.usernotifications.time-sensitive 12 | 13 | com.apple.security.application-groups 14 | 15 | group.bark 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Bark/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Bark/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPhotoLibraryAddUsageDescription 6 | Save the image to the photo library 7 | CFBundleURLTypes 8 | 9 | 10 | CFBundleURLSchemes 11 | 12 | bark 13 | 14 | CFBundleURLName 15 | me.fin.bark 16 | 17 | 18 | CFBundleDevelopmentRegion 19 | $(DEVELOPMENT_LANGUAGE) 20 | CFBundleDisplayName 21 | Bark 22 | CFBundleExecutable 23 | $(EXECUTABLE_NAME) 24 | CFBundleIdentifier 25 | $(PRODUCT_BUNDLE_IDENTIFIER) 26 | CFBundleInfoDictionaryVersion 27 | 6.0 28 | CFBundleName 29 | $(PRODUCT_NAME) 30 | CFBundlePackageType 31 | APPL 32 | CFBundleShortVersionString 33 | $(MARKETING_VERSION) 34 | CFBundleVersion 35 | $(CURRENT_PROJECT_VERSION) 36 | GitHub Run Id 37 | 0 38 | LSRequiresIPhoneOS 39 | 40 | NSAppTransportSecurity 41 | 42 | NSAllowsArbitraryLoads 43 | 44 | 45 | NSCameraUsageDescription 46 | We are using the camera to scan a QR code 47 | NSUserActivityTypes 48 | 49 | INSendMessageIntent 50 | INStartCallIntent 51 | 52 | UIBackgroundModes 53 | 54 | remote-notification 55 | 56 | UILaunchStoryboardName 57 | LaunchScreen 58 | UIRequiredDeviceCapabilities 59 | 60 | armv7 61 | 62 | UISupportedInterfaceOrientations 63 | 64 | UIInterfaceOrientationPortrait 65 | 66 | UISupportedInterfaceOrientations~ipad 67 | 68 | UIInterfaceOrientationPortrait 69 | UIInterfaceOrientationPortraitUpsideDown 70 | UIInterfaceOrientationLandscapeLeft 71 | UIInterfaceOrientationLandscapeRight 72 | 73 | UIViewControllerBasedStatusBarAppearance 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /Bark/Intents/OptionsProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OptionsProvider.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2/21/25. 6 | // Copyright © 2025 Fin. All rights reserved. 7 | // 8 | import AppIntents 9 | 10 | @available(iOS 16, *) 11 | struct ServerAddressOptionsProvider: DynamicOptionsProvider { 12 | func results() async throws -> [String] { 13 | return ServerManager.shared.servers.map { server in 14 | return server.address + "/" + server.key 15 | } 16 | } 17 | 18 | func defaultResult() async -> String? { 19 | return ServerManager.shared.currentServer.address + "/" + ServerManager.shared.currentServer.key 20 | } 21 | } 22 | 23 | @available(iOS 16, *) 24 | struct SoundOptionsProvider: DynamicOptionsProvider { 25 | func results() async throws -> [String] { 26 | var customSounds: [String] = [] 27 | if let soundsDirectoryUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.bark")?.appendingPathComponent("Library/Sounds").path { 28 | customSounds = getSounds(urls: getFilesInDirectory(directory: soundsDirectoryUrl, suffix: "caf")) 29 | } 30 | let defaultSounds = getSounds(urls: Bundle.main.urls(forResourcesWithExtension: "caf", subdirectory: nil) ?? []) 31 | 32 | return customSounds + defaultSounds 33 | } 34 | 35 | func getSounds(urls: [URL]) -> [String] { 36 | let urls = urls.sorted { u1, u2 -> Bool in 37 | u1.lastPathComponent.localizedStandardCompare(u2.lastPathComponent) == ComparisonResult.orderedAscending 38 | } 39 | return urls.map { $0.deletingPathExtension().lastPathComponent } 40 | } 41 | 42 | func getFilesInDirectory(directory: String, suffix: String) -> [URL] { 43 | let fileManager = FileManager.default 44 | do { 45 | let files = try fileManager.contentsOfDirectory(atPath: directory) 46 | return files.compactMap { file -> URL? in 47 | if file.hasSuffix(suffix), !file.hasPrefix(kBarkSoundPrefix) { 48 | // 不要包含 kBarkSoundPrefix 开头的,这些是为了 call=1 合成的 30s 长铃声,不算用户上传的 49 | return URL(fileURLWithPath: directory).appendingPathComponent(file) 50 | } 51 | return nil 52 | } 53 | } catch { 54 | return [] 55 | } 56 | } 57 | } 58 | 59 | @available(iOS 16, *) 60 | struct VolumeOptionsProvider: DynamicOptionsProvider { 61 | func results() async throws -> [Int] { 62 | return Array(0...10) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Bark/Intents/PushResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PushResponse.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2/21/25. 6 | // Copyright © 2025 Fin. All rights reserved. 7 | // 8 | 9 | struct PushResponse: Decodable { 10 | let message: String? 11 | let code: Int? 12 | } 13 | -------------------------------------------------------------------------------- /BarkTests/BarkTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BarkTests.swift 3 | // BarkTests 4 | // 5 | // Created by huangfeng on 2021/6/24. 6 | // Copyright © 2021 Fin. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class BarkTests: XCTestCase { 12 | override func setUpWithError() throws { 13 | // Put setup code here. This method is called before the invocation of each test method in the class. 14 | } 15 | 16 | override func tearDownWithError() throws { 17 | // Put teardown code here. This method is called after the invocation of each test method in the class. 18 | } 19 | 20 | func testExample() throws { 21 | // This is an example of a functional test case. 22 | // Use XCTAssert and related functions to verify your tests produce the correct results. 23 | } 24 | 25 | func testPerformanceExample() throws { 26 | // This is an example of a performance test case. 27 | measure { 28 | // Put the code you want to measure the time of here. 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /BarkTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Common/ArchiveSettingManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ArchiveSettingManager.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2020/5/29. 6 | // Copyright © 2020 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ArchiveSettingManager: NSObject { 12 | static let shared = ArchiveSettingManager() 13 | let defaults = UserDefaults(suiteName: "group.bark") 14 | var isArchive: Bool { 15 | get { 16 | return defaults?.value(forKey: "isArchive") as? Bool ?? true 17 | } 18 | set { 19 | defaults?.set(newValue, forKey: "isArchive") 20 | } 21 | } 22 | 23 | override private init() { 24 | super.init() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Common/ArchiveSettingRelay.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ArchiveSettingRelay.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2023/1/30. 6 | // Copyright © 2023 Fin. All rights reserved. 7 | // 8 | 9 | import RxCocoa 10 | import UIKit 11 | class ArchiveSettingRelay: NSObject { 12 | static let shared = ArchiveSettingRelay() 13 | let isArchiveRelay: BehaviorRelay 14 | 15 | override private init() { 16 | self.isArchiveRelay = BehaviorRelay(value: ArchiveSettingManager.shared.isArchive) 17 | super.init() 18 | 19 | self.isArchiveRelay.subscribe { val in 20 | ArchiveSettingManager.shared.isArchive = val 21 | }.disposed(by: rx.disposeBag) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Common/BKColor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BKColor.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2021/10/22. 6 | // Copyright © 2021 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class BKColor: NSObject { 12 | 13 | enum grey { 14 | public static let base = UIColor(named: "grey_base")! 15 | public static let darken1 = UIColor(named: "grey_darken1")! 16 | public static let darken2 = UIColor(named: "grey_darken2")! 17 | public static let darken3 = UIColor(named: "grey_darken3")! 18 | public static let darken4 = UIColor(named: "grey_darken4")! 19 | public static let lighten1 = UIColor(named: "grey_lighten1")! 20 | public static let lighten2 = UIColor(named: "grey_lighten2")! 21 | public static let lighten3 = UIColor(named: "grey_lighten3")! 22 | public static let lighten4 = UIColor(named: "grey_lighten4")! 23 | public static let lighten5 = UIColor(named: "grey_lighten5")! 24 | } 25 | 26 | enum blue { 27 | public static let base = UIColor(named: "blue_base")! 28 | public static let darken1 = UIColor(named: "blue_darken1")! 29 | public static let darken5 = UIColor(named: "blue_darken5")! 30 | } 31 | 32 | enum lightBlue { 33 | public static let darken3 = UIColor(named: "lightBlue_darken3")! 34 | } 35 | 36 | public static let white = UIColor(named: "white")! 37 | 38 | public static let black = UIColor(named: "black")! 39 | 40 | enum background { 41 | public static let primary = UIColor(named: "background")! 42 | public static let secondary = UIColor(named: "background_seconday")! 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Common/BarkSettings.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BarkSettings.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2018/6/25. 6 | // Copyright © 2018 Fin. All rights reserved. 7 | // 8 | 9 | import DefaultsKit 10 | import UIKit 11 | 12 | enum BarkSettingKey: String { 13 | /// 存放key , 1.2.6 版本`之后`不再使用 14 | case key = "me.fin.bark.key" 15 | case servers = "me.fin.bark.servers" 16 | 17 | /// 1.2.6 版本`之前`保存当前 server 的 key,不再使用 18 | case currentServer = "me.fin.bark.servers.current" 19 | /// 1.2.6 版本`之后`用于保存 server 的 id 20 | case currentServerId = "me.fin.bark.servers.currentServerId" 21 | 22 | case selectedViewControllerIndex = "me.fin.bark.selectedViewControllerIndex" 23 | } 24 | 25 | class BarkSettings { 26 | static let shared = BarkSettings() 27 | private init() {} 28 | 29 | subscript(key: String) -> String? { 30 | get { 31 | let storeKey = Key(key) 32 | return Defaults.shared.get(for: storeKey) 33 | } 34 | set { 35 | let storeKey = Key(key) 36 | if let value = newValue { 37 | Defaults.shared.set(value, for: storeKey) 38 | } 39 | else { 40 | Defaults.shared.clear(storeKey) 41 | } 42 | } 43 | } 44 | 45 | subscript(key: BarkSettingKey) -> String? { 46 | get { 47 | return self[key.rawValue] 48 | } 49 | set { 50 | self[key.rawValue] = newValue 51 | } 52 | } 53 | 54 | subscript(key: String) -> T? { 55 | get { 56 | let storeKey = Key(key) 57 | return Defaults.shared.get(for: storeKey) 58 | } 59 | set { 60 | let storeKey = Key(key) 61 | if let value = newValue { 62 | Defaults.shared.set(value, for: storeKey) 63 | } 64 | else { 65 | Defaults.shared.clear(storeKey) 66 | } 67 | } 68 | } 69 | 70 | subscript(key: BarkSettingKey) -> T? { 71 | get { 72 | return self[key.rawValue] 73 | } 74 | set { 75 | self[key.rawValue] = newValue 76 | } 77 | } 78 | } 79 | 80 | let Settings = BarkSettings.shared 81 | -------------------------------------------------------------------------------- /Common/CryptoSettingManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CryptoSettingManager.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2023/3/2. 6 | // Copyright © 2023 Fin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class CryptoSettingManager: NSObject { 12 | static let shared = CryptoSettingManager() 13 | let defaults = UserDefaults(suiteName: "group.bark") 14 | var fields: CryptoSettingFields? { 15 | get { 16 | guard let data:Data = defaults?.value(forKey: "cryptoSettingFields") as? Data else { 17 | return nil 18 | } 19 | guard let fields = try? JSONDecoder().decode(CryptoSettingFields.self, from: data) else { 20 | return nil 21 | } 22 | return fields 23 | } 24 | set { 25 | guard let newValue = newValue else { 26 | defaults?.removeObject(forKey: "cryptoSettingFields") 27 | return 28 | } 29 | guard let encoded = try? JSONEncoder().encode(newValue) else{ 30 | return 31 | } 32 | defaults?.set(encoded, forKey: "cryptoSettingFields") 33 | } 34 | } 35 | 36 | override private init() { 37 | super.init() 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /Common/CryptoSettingRelay.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CryptoSettingRelay.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2023/3/7. 6 | // Copyright © 2023 Fin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import RxCocoa 11 | 12 | class CryptoSettingRelay: NSObject { 13 | static let shared = CryptoSettingRelay() 14 | let fields: BehaviorRelay 15 | 16 | override private init() { 17 | self.fields = BehaviorRelay(value: CryptoSettingManager.shared.fields) 18 | super.init() 19 | 20 | self.fields.subscribe { val in 21 | CryptoSettingManager.shared.fields = val 22 | }.disposed(by: rx.disposeBag) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Common/Defines.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Defines.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2018/6/26. 6 | // Copyright © 2018 Fin. All rights reserved. 7 | // 8 | 9 | import RxCocoa 10 | import UIKit 11 | 12 | /// 将代码安全的运行在主线程 13 | func dispatch_sync_safely_main_queue(_ block: () -> ()) { 14 | if Thread.isMainThread { 15 | block() 16 | } else { 17 | DispatchQueue.main.sync { 18 | block() 19 | } 20 | } 21 | } 22 | 23 | extension UIViewController { 24 | func showSnackbar(text: String) { 25 | self.snackbarController?.snackbar.text = text 26 | self.snackbarController?.animate(snackbar: .visible) 27 | self.snackbarController?.animate(snackbar: .hidden, delay: 3) 28 | } 29 | } 30 | 31 | let kNavigationHeight: CGFloat = { 32 | kSafeAreaInsets.top + 44 33 | }() 34 | 35 | let kSafeAreaInsets: UIEdgeInsets = { 36 | UIWindow().safeAreaInsets 37 | }() 38 | 39 | func castOrThrow(_ resultType: T.Type, _ object: Any) throws -> T { 40 | guard let returnValue = object as? T else { 41 | throw RxCocoaError.castingError(object: object, targetType: resultType) 42 | } 43 | 44 | return returnValue 45 | } 46 | -------------------------------------------------------------------------------- /Common/Error+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Error+Extension.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2023/3/3. 6 | // Copyright © 2023 Fin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension String: @retroactive Error {} 12 | 13 | public enum ApiError: Swift.Error { 14 | case Error(info: String) 15 | case AccountBanned(info: String) 16 | } 17 | 18 | extension Swift.Error { 19 | func rawString() -> String { 20 | if let err = self as? String { 21 | return err 22 | } 23 | guard let err = self as? ApiError else { 24 | return self.localizedDescription 25 | } 26 | switch err { 27 | case .Error(let info): 28 | return info 29 | case .AccountBanned(let info): 30 | return info 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Common/GroupMuteSettingManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GroupMuteSettingManager.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 11/6/24. 6 | // Copyright © 2024 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | let kGroupMuteSettingKey = "groupMuteSettings" 12 | 13 | /// 保存各分组的静音截止时间,注意 NotificationServiceExtension 和 NotificationContentExtension 是不同进程,不共享单例的(别用单例) 14 | class GroupMuteSettingManager: NSObject { 15 | let defaults = UserDefaults(suiteName: "group.bark") 16 | 17 | var settings: [String: Date] = [:] { 18 | didSet { 19 | defaults?.set(settings, forKey: kGroupMuteSettingKey) 20 | } 21 | } 22 | 23 | override init() { 24 | super.init() 25 | if let settings = defaults?.dictionary(forKey: kGroupMuteSettingKey) as? [String: Date] { 26 | self.settings = settings 27 | } 28 | // 清理过期的设置 29 | for setting in settings { 30 | if setting.value < Date() { 31 | self.settings.removeValue(forKey: setting.key) 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Common/MJRefresh+Rx.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MJRefresh+Rx.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2020/11/22. 6 | // Copyright © 2020 Fin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import MJRefresh 11 | import RxCocoa 12 | import RxSwift 13 | 14 | extension Reactive where Base: MJRefreshComponent { 15 | var refresh: ControlEvent { 16 | let source = Observable.create { [weak control = self.base] observer -> Disposable in 17 | MainScheduler.ensureExecutingOnScheduler() 18 | guard let control = control else { 19 | observer.onCompleted() 20 | return Disposables.create() 21 | } 22 | control.refreshingBlock = { 23 | observer.onNext(()) 24 | } 25 | return Disposables.create() 26 | } 27 | return ControlEvent(events: source) 28 | } 29 | } 30 | 31 | enum MJRefreshAction { 32 | /// 不做任何事情 33 | case none 34 | /// 开始刷新 35 | case begainRefresh 36 | /// 停止刷新 37 | case endRefresh 38 | /// 开始加载更多 39 | case begainLoadmore 40 | /// 停止加载更多 41 | case endLoadmore 42 | /// 显示无更多数据 43 | case showNomoreData 44 | /// 重置无更多数据 45 | case resetNomoreData 46 | } 47 | 48 | extension Reactive where Base: UIScrollView { 49 | /// 执行的操作类型 50 | var refreshAction: Binder { 51 | return Binder(base) { target, action in 52 | 53 | switch action { 54 | case .begainRefresh: 55 | // 下拉刷新使用 UIRefreshControl 56 | if let control = target.refreshControl { 57 | control.beginRefreshing() 58 | } 59 | case .endRefresh: 60 | if let control = target.refreshControl { 61 | control.endRefreshing() 62 | } 63 | case .begainLoadmore: 64 | if let footer = target.mj_footer { 65 | footer.beginRefreshing() 66 | } 67 | case .endLoadmore: 68 | if let footer = target.mj_footer { 69 | footer.endRefreshing() 70 | } 71 | case .showNomoreData: 72 | if let footer = target.mj_footer { 73 | footer.endRefreshingWithNoMoreData() 74 | } 75 | case .resetNomoreData: 76 | if let footer = target.mj_footer { 77 | footer.resetNoMoreData() 78 | } 79 | case .none: 80 | break 81 | } 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Common/Moya/BarkApi.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BarkApi.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2018/6/25. 6 | // Copyright © 2018 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | enum BarkApi { 12 | case ping(baseURL: String?) 13 | case register(address: String, key: String?, devicetoken: String) // 注册设备 14 | } 15 | 16 | extension BarkApi: BarkTargetType { 17 | var baseURL: URL { 18 | switch self { 19 | case let .ping(urlStr): 20 | if let url = URL(string: urlStr ?? "") { 21 | return url 22 | } 23 | case let .register(address, _, _): 24 | if let url = try? address.asURL() { 25 | return url 26 | } 27 | } 28 | return try! ServerManager.shared.currentServer.address.asURL() 29 | } 30 | 31 | var parameters: [String: Any]? { 32 | switch self { 33 | case let .register(_, key, devicetoken): 34 | var params = ["devicetoken": devicetoken] 35 | if let key = key { 36 | params["key"] = key 37 | } 38 | return params 39 | default: 40 | return nil 41 | } 42 | } 43 | 44 | var path: String { 45 | switch self { 46 | case .ping: 47 | return "/ping" 48 | case .register: 49 | return "/register" 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Common/NSLocalizedString+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSLocalizedString+Extension.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2023/3/3. 6 | // Copyright © 2023 Fin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | func NSLocalizedString(_ key: String) -> String { 12 | return NSLocalizedString(key, comment: "") 13 | } 14 | -------------------------------------------------------------------------------- /Common/RealmConfiguration.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RealmConfiguration.swift 3 | // NotificationServiceExtension 4 | // 5 | // Created by huangfeng on 2024/5/29. 6 | // Copyright © 2024 Fin. All rights reserved. 7 | // 8 | 9 | @_exported import RealmSwift 10 | import UIKit 11 | 12 | let kRealmDefaultConfiguration = { 13 | let groupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.bark") 14 | let fileUrl = groupUrl?.appendingPathComponent("bark.realm") 15 | let config = Realm.Configuration( 16 | fileURL: fileUrl, 17 | schemaVersion: 16, 18 | migrationBlock: { migration, oldSchemaVersion in 19 | switch oldSchemaVersion { 20 | case 0...13: 21 | migration.enumerateObjects(ofType: Message.className()) { oldObject, newObject in 22 | guard let obj = oldObject else { 23 | return 24 | } 25 | guard let isDeleted = obj["isDeleted"] as? Bool else { 26 | return 27 | } 28 | // 旧版软删除的数据,迁移到新版时硬删除掉,新版不再过滤 isDeleted 字段 29 | if isDeleted, let newObject { 30 | migration.delete(newObject) 31 | } 32 | } 33 | default: 34 | break 35 | } 36 | } 37 | ) 38 | return config 39 | }() 40 | -------------------------------------------------------------------------------- /Common/Reusable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Reusable.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2020/11/17. 6 | // Copyright © 2020 Fin. All rights reserved. 7 | // 8 | 9 | import RxCocoa 10 | import RxSwift 11 | import UIKit 12 | 13 | private var prepareForReuseBag: Int8 = 0 14 | 15 | @objc public protocol Reusable: AnyObject { 16 | func prepareForReuse() 17 | } 18 | 19 | extension UITableViewCell: Reusable {} 20 | extension UITableViewHeaderFooterView: Reusable {} 21 | extension UICollectionReusableView: Reusable {} 22 | 23 | extension Reactive where Base: Reusable { 24 | var reuseBag: DisposeBag { 25 | MainScheduler.ensureExecutingOnScheduler() 26 | 27 | if let bag = objc_getAssociatedObject(base, &prepareForReuseBag) as? DisposeBag { 28 | return bag 29 | } 30 | 31 | let bag = DisposeBag() 32 | objc_setAssociatedObject(base, &prepareForReuseBag, bag, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) 33 | 34 | _ = sentMessage(#selector(Base.prepareForReuse)) 35 | .take(until: deallocated) 36 | .subscribe(onNext: { [weak base] _ in 37 | guard let strongBase = base else { 38 | return 39 | } 40 | let newBag = DisposeBag() 41 | objc_setAssociatedObject(strongBase, &prepareForReuseBag, newBag, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) 42 | }) 43 | 44 | return bag 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Common/SharedDefines.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SharedDefines.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2024/7/26. 6 | // Copyright © 2024 Fin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | let kBarkSoundPrefix = "bark.sounds.30s" 12 | -------------------------------------------------------------------------------- /Common/String+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+Extension.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2018/6/26. 6 | // Copyright © 2018 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension String { 12 | // 将原始的url编码为合法的url 13 | func urlEncoded() -> String { 14 | let encodeUrlString = self.addingPercentEncoding(withAllowedCharacters: 15 | .urlQueryAllowed) 16 | return encodeUrlString ?? "" 17 | } 18 | 19 | // 将编码后的url转换回原始的url 20 | func urlDecoded() -> String { 21 | return self.removingPercentEncoding ?? "" 22 | } 23 | } 24 | 25 | // MARK: - NSAttributedString 26 | 27 | extension String { 28 | var bold: NSAttributedString { 29 | return NSMutableAttributedString(string: self, attributes: [.font: UIFont.boldSystemFont(ofSize: UIFont.systemFontSize)]) 30 | } 31 | 32 | var underline: NSAttributedString { 33 | return NSAttributedString(string: self, attributes: [.underlineStyle: NSUnderlineStyle.single.rawValue]) 34 | } 35 | 36 | var strikethrough: NSAttributedString { 37 | return NSAttributedString(string: self, attributes: [.strikethroughStyle: NSNumber(value: NSUnderlineStyle.single.rawValue as Int)]) 38 | } 39 | 40 | var italic: NSAttributedString { 41 | return NSMutableAttributedString(string: self, attributes: [.font: UIFont.italicSystemFont(ofSize: UIFont.systemFontSize)]) 42 | } 43 | 44 | func colored(with color: UIColor) -> NSAttributedString { 45 | return NSMutableAttributedString(string: self, attributes: [.foregroundColor: color]) 46 | } 47 | } 48 | 49 | // MARK: - Format 50 | 51 | extension String { 52 | func format(_ arguments: any CVarArg...) -> String { 53 | return String(format: self, arguments) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Common/UIColor+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+Extension.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2018/6/25. 6 | // Copyright © 2018 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIColor { 12 | public convenience init(r255: CGFloat, g255: CGFloat, b255: CGFloat, a255: CGFloat = 255) { 13 | self.init(red: r255/255, green: g255/255, blue: b255/255, alpha: a255/255) 14 | } 15 | 16 | class func image(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) -> UIImage { 17 | UIGraphicsBeginImageContext(size) 18 | let context = UIGraphicsGetCurrentContext() 19 | context?.setFillColor(color.cgColor) 20 | context?.fill(CGRect(origin: CGPoint.zero, size: size)) 21 | 22 | let image = UIGraphicsGetImageFromCurrentImageContext() 23 | UIGraphicsEndImageContext() 24 | return image! // context应该不会没get到吧~ 所以直接强解了 25 | } 26 | 27 | var image: UIImage { 28 | return UIColor.image(color: self) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Common/UIFont+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIFont+Extension.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 10/25/24. 6 | // Copyright © 2024 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIFont { 12 | class func preferredFont(ofSize size: CGFloat, weight: Weight = .regular) -> UIFont { 13 | return UIFontMetrics.default.scaledFont(for: UIFont.systemFont(ofSize: size, weight: weight)) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Common/ViewModelType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewModelType.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2020/11/17. 6 | // Copyright © 2020 Fin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import RxSwift 11 | 12 | protocol ViewModelType { 13 | associatedtype Input 14 | associatedtype Output 15 | 16 | func transform(input: Input) -> Output 17 | } 18 | 19 | class ViewModel: NSObject {} 20 | -------------------------------------------------------------------------------- /Controller/BarkNavigationController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BarkNavigationController.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2018/6/25. 6 | // Copyright © 2018 Fin. All rights reserved. 7 | // 8 | 9 | import Material 10 | import RxSwift 11 | import UIKit 12 | 13 | class BarkNavigationController: UINavigationController { 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | self.navigationBar.prefersLargeTitles = true 17 | } 18 | } 19 | 20 | class BarkSnackbarController: SnackbarController { 21 | override var childForStatusBarStyle: UIViewController? { 22 | return self.rootViewController 23 | } 24 | } 25 | 26 | enum TabPage: Int { 27 | case unknown = -1 28 | case service = 0 29 | case messageHistory = 1 30 | case settings = 2 31 | } 32 | 33 | class StateStorageTabBarController: UITabBarController, UITabBarControllerDelegate { 34 | // 标记当前显示的页面,再次点击相同的页面时当做页面点击事件。 35 | var currentSelectedIndex: Int = 0 36 | 37 | // 点击当前页面的 tabBarItem , 可以用以点击刷新当前页面等操作 38 | lazy var tabBarItemDidClick: Observable = { 39 | self.rx.didSelect 40 | .flatMapLatest { _ -> Single in 41 | let single = Single.create { single in 42 | if self.currentSelectedIndex == self.selectedIndex { 43 | single(.success(TabPage(rawValue: self.selectedIndex) ?? .unknown)) 44 | } 45 | self.currentSelectedIndex = self.selectedIndex 46 | return Disposables.create() 47 | } 48 | return single 49 | }.share() 50 | }() 51 | 52 | var isFirstAppear = true 53 | override func viewWillAppear(_ animated: Bool) { 54 | super.viewWillAppear(animated) 55 | if isFirstAppear { 56 | isFirstAppear = false 57 | 58 | // 开启APP时,默认选择上次打开的页面 59 | if let index: Int = Settings[.selectedViewControllerIndex] { 60 | self.selectedIndex = index 61 | self.currentSelectedIndex = index 62 | } 63 | // 保存打开的页面Index 64 | self.rx.didSelect.subscribe(onNext: { _ in 65 | Settings[.selectedViewControllerIndex] = self.selectedIndex 66 | }).disposed(by: rx.disposeBag) 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Controller/BarkSFSafariViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BarkSFSafariViewController.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2018/6/26. 6 | // Copyright © 2018 Fin. All rights reserved. 7 | // 8 | 9 | import SafariServices 10 | import UIKit 11 | 12 | class BarkSFSafariViewController: SFSafariViewController { 13 | override var preferredStatusBarStyle: UIStatusBarStyle { 14 | return .default 15 | } 16 | 17 | deinit { 18 | if #available(iOS 16.0, *) { 19 | Task { 20 | await SFSafariViewController.DataStore.default.clearWebsiteData() 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Controller/BarkSplitViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BarkSplitViewController.swift 3 | // Bark 4 | // 5 | // Created by sidguan on 2024/6/30. 6 | // Copyright © 2024 Fin. All rights reserved. 7 | // 8 | 9 | import Material 10 | import UIKit 11 | 12 | @available(iOS 14, *) 13 | class BarkSplitViewController: UISplitViewController { 14 | let sectionViewController = SectionViewController_iPad(viewModel: SectionViewModel()) 15 | // Compact 下替换显示成 BarkTabBarController 16 | let compactController = BarkTabBarController() 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | self.preferredDisplayMode = .oneBesideSecondary 20 | self.preferredSplitBehavior = .tile 21 | self.delegate = self 22 | initViewControllers() 23 | } 24 | 25 | func initViewControllers() { 26 | self.setViewController(sectionViewController, for: .primary) 27 | // 设置默认打开页面 28 | let index: Int = Settings[.selectedViewControllerIndex] ?? 0 29 | self.setViewController(sectionViewController.viewControllers[index], for: .secondary) 30 | DispatchQueue.main.async { 31 | self.sectionViewController.tableView.selectRow(at: IndexPath(row: index, section: 0), animated: false, scrollPosition: .none) 32 | } 33 | self.setViewController(compactController, for: .compact) 34 | } 35 | } 36 | 37 | @available(iOS 14, *) 38 | extension BarkSplitViewController: UISplitViewControllerDelegate { 39 | // 同步 sectionViewController 和 compactController 当前显示页面 40 | func splitViewControllerDidCollapse(_ svc: UISplitViewController) { 41 | guard let index: Int = Settings[.selectedViewControllerIndex] else { 42 | return 43 | } 44 | self.compactController.selectedIndex = index 45 | } 46 | 47 | func splitViewControllerDidExpand(_ svc: UISplitViewController) { 48 | guard let index: Int = Settings[.selectedViewControllerIndex] else { 49 | return 50 | } 51 | self.sectionViewController.tableView.selectRow(at: IndexPath(row: index, section: 0), animated: false, scrollPosition: .none) 52 | self.setViewController(self.sectionViewController.viewControllers[index], for: .secondary) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Controller/BarkTabBarController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BarkTabBarController.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2024/8/20. 6 | // Copyright © 2024 Fin. All rights reserved. 7 | // 8 | 9 | import Material 10 | import UIKit 11 | 12 | class BarkTabBarController: StateStorageTabBarController { 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | self.tabBar.tintColor = BKColor.grey.darken4 16 | 17 | self.viewControllers = [ 18 | BarkNavigationController(rootViewController: HomeViewController(viewModel: HomeViewModel())), 19 | BarkNavigationController(rootViewController: MessageListViewController(viewModel: MessageListViewModel())), 20 | BarkNavigationController(rootViewController: MessageSettingsViewController(viewModel: MessageSettingsViewModel())) 21 | ] 22 | 23 | let tabBarItems = [UITabBarItem(title: NSLocalizedString("service"), image: UIImage(named: "baseline_gite_black_24pt"), tag: 0), 24 | UITabBarItem(title: NSLocalizedString("historyMessage"), image: Icon.history, tag: 1), 25 | UITabBarItem(title: NSLocalizedString("settings"), image: UIImage(named: "baseline_manage_accounts_black_24pt"), tag: 2)] 26 | for (index, viewController) in self.viewControllers!.enumerated() { 27 | viewController.tabBarItem = tabBarItems[index] 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Controller/BaseViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BaseViewController.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2018/6/25. 6 | // Copyright © 2018 Fin. All rights reserved. 7 | // 8 | 9 | import Material 10 | import UIKit 11 | 12 | class BaseViewController: UIViewController where T: ViewModel { 13 | let viewModel: T 14 | init(viewModel: T) { 15 | self.viewModel = viewModel 16 | super.init(nibName: nil, bundle: nil) 17 | } 18 | 19 | @available(*, unavailable) 20 | required init?(coder: NSCoder) { 21 | fatalError("init(coder:) has not been implemented") 22 | } 23 | 24 | override var preferredStatusBarStyle: UIStatusBarStyle { 25 | return .lightContent 26 | } 27 | 28 | override func viewDidLoad() { 29 | super.viewDidLoad() 30 | self.view.backgroundColor = BKColor.background.primary 31 | 32 | if UIDevice.current.userInterfaceIdiom == .pad { 33 | navigationItem.largeTitleDisplayMode = .never 34 | } else { 35 | navigationItem.largeTitleDisplayMode = .automatic 36 | } 37 | makeUI() 38 | } 39 | 40 | var isViewModelBinded = false 41 | override func viewWillAppear(_ animated: Bool) { 42 | super.viewWillAppear(animated) 43 | if !isViewModelBinded { 44 | isViewModelBinded = true 45 | self.bindViewModel() 46 | } 47 | } 48 | 49 | func makeUI() {} 50 | 51 | func bindViewModel() {} 52 | } 53 | -------------------------------------------------------------------------------- /Controller/QRScannerViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QRScannerViewController.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2022/3/10. 6 | // Copyright © 2022 Fin. All rights reserved. 7 | // 8 | 9 | import MercariQRScanner 10 | import RxCocoa 11 | import RxSwift 12 | import UIKit 13 | 14 | class QRScannerViewController: UIViewController { 15 | var scannerDidSuccess: Observable { 16 | return self.rx.methodInvoked(#selector(didSeccess(code:))).map { a in 17 | try castOrThrow(String.self, a[0]) 18 | } 19 | } 20 | 21 | let closeButton: UIButton = { 22 | let closeButton = UIButton(type: .custom) 23 | closeButton.setImage(UIImage(named: "baseline_close_white_48pt"), for: .normal) 24 | closeButton.tintColor = UIColor.white 25 | closeButton.backgroundColor = UIColor(white: 0, alpha: 0.2) 26 | closeButton.layer.cornerRadius = 40 27 | closeButton.clipsToBounds = true 28 | return closeButton 29 | }() 30 | 31 | override func viewDidLoad() { 32 | super.viewDidLoad() 33 | self.view.backgroundColor = UIColor.black 34 | 35 | let qrScannerView = QRScannerView(frame: view.bounds) 36 | qrScannerView.configure(delegate: self) 37 | view.addSubview(qrScannerView) 38 | 39 | view.addSubview(closeButton) 40 | closeButton.snp.makeConstraints { make in 41 | make.bottom.equalToSuperview().offset(-120) 42 | make.centerX.equalToSuperview() 43 | make.width.height.equalTo(80) 44 | } 45 | closeButton.rx.tap.subscribe { [weak self] in 46 | self?.dismiss(animated: true, completion: nil) 47 | } onError: { _ in }.disposed(by: rx.disposeBag) 48 | 49 | qrScannerView.startRunning() 50 | } 51 | } 52 | 53 | extension QRScannerViewController: QRScannerViewDelegate { 54 | func qrScannerView(_ qrScannerView: QRScannerView, didFailure error: QRScannerError) { 55 | self.showSnackbar(text: error.rawString()) 56 | } 57 | 58 | func qrScannerView(_ qrScannerView: QRScannerView, didSuccess code: String) { 59 | self.didSeccess(code: code) 60 | self.dismiss(animated: true, completion: nil) 61 | } 62 | 63 | @objc private func didSeccess(code: String) {} 64 | } 65 | -------------------------------------------------------------------------------- /Controller/SectionViewModel-iPad.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SectionViewModel-iPad.swift 3 | // Bark 4 | // 5 | // Created by sidguan on 2024/7/1. 6 | // Copyright © 2024 Fin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import RxCocoa 11 | import RxDataSources 12 | import RxSwift 13 | import Material 14 | 15 | struct SectionItem { 16 | let image: UIImage? 17 | let title: String 18 | } 19 | 20 | class SectionViewModel: ViewModel, ViewModelType { 21 | struct Input { 22 | // var sectionSelected: Driver 23 | } 24 | 25 | struct Output { 26 | var items: Observable<[SectionModel]> 27 | // var selectedItem: Observable 28 | } 29 | 30 | func initSectionItems() -> Observable<[SectionModel]> { 31 | let sectionItems = [ 32 | SectionItem(image: UIImage(named: "baseline_gite_black_24pt"), title: NSLocalizedString("service")), 33 | SectionItem(image: Icon.history, title: NSLocalizedString("historyMessage")), 34 | SectionItem(image: UIImage(named: "baseline_manage_accounts_black_24pt"), title: NSLocalizedString("settings")), 35 | ] 36 | let section = [SectionModel(model: "", items: sectionItems)] 37 | return Observable.just(section) 38 | } 39 | 40 | func transform(input: Input) -> Output { 41 | let sectionItems = initSectionItems() 42 | return Output( 43 | items: sectionItems 44 | ) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "cocoapods" 4 | gem "fastlane" 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Feng 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Model/Message.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Message.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2020/5/25. 6 | // Copyright © 2020 Fin. All rights reserved. 7 | // 8 | 9 | import RealmSwift 10 | import UIKit 11 | 12 | class Message: Object { 13 | @objc dynamic var id = NSUUID().uuidString 14 | @objc dynamic var title: String? 15 | @objc dynamic var subtitle: String? 16 | @objc dynamic var body: String? 17 | @objc dynamic var url: String? 18 | @objc dynamic var image: String? 19 | @objc dynamic var group: String? 20 | @objc dynamic var createDate: Date? 21 | 22 | override class func primaryKey() -> String? { 23 | return "id" 24 | } 25 | 26 | override class func indexedProperties() -> [String] { 27 | return ["group", "createDate"] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Model/MessageDeleteTimeRange.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MessageDeleteTimeRange.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 1/7/25. 6 | // Copyright © 2025 Fin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum MessageDeleteTimeRange { 12 | /// 最近一小时 13 | case lastHour 14 | /// 今天 15 | case today 16 | /// 今天和昨天 17 | case todayAndYesterday 18 | /// 最近一个月 19 | case lastMonth 20 | /// 全部时间 21 | case allTime 22 | 23 | /// 一小时之前 24 | case beforeOneHour 25 | /// 一天之前 26 | case beforeToday 27 | /// 昨天之前 28 | case beforeYesterday 29 | /// 一月之前 30 | case beforeOneMonth 31 | 32 | var string: String { 33 | switch self { 34 | case .lastHour: 35 | return NSLocalizedString("lastHour") 36 | case .today: 37 | return NSLocalizedString("today") 38 | case .todayAndYesterday: 39 | return NSLocalizedString("todayAndYesterday") 40 | case .lastMonth: 41 | return NSLocalizedString("lastMonth") 42 | case .allTime: 43 | return NSLocalizedString("allTime") 44 | case .beforeOneHour: 45 | return NSLocalizedString("beforeAnHour") 46 | case .beforeToday: 47 | return NSLocalizedString("beforeToday") 48 | case .beforeYesterday: 49 | return NSLocalizedString("beforeYesterday") 50 | case .beforeOneMonth: 51 | return NSLocalizedString("beforeAMonth") 52 | } 53 | } 54 | 55 | var startDate: Date { 56 | switch self { 57 | case .lastHour: 58 | return Date.lastHour 59 | case .today: 60 | return Date().startOfDay 61 | case .todayAndYesterday: 62 | return Date.yesterday 63 | case .lastMonth: 64 | return Date.lastMonth 65 | case .allTime, 66 | .beforeOneHour, 67 | .beforeToday, 68 | .beforeYesterday, 69 | .beforeOneMonth: 70 | return Date(timeIntervalSince1970: 0) 71 | } 72 | } 73 | 74 | var endDate: Date { 75 | switch self { 76 | case .lastHour, 77 | .today, 78 | .todayAndYesterday, 79 | .lastMonth, 80 | .allTime: 81 | return Date() 82 | case .beforeOneHour: 83 | return Date.lastHour 84 | case .beforeToday: 85 | return Date().startOfDay 86 | case .beforeYesterday: 87 | return Date.yesterday 88 | case .beforeOneMonth: 89 | return Date.lastMonth 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Model/MessageSection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MessageTableViewCellViewModel.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2020/11/21. 6 | // Copyright © 2020 Fin. All rights reserved. 7 | // 8 | 9 | import Differentiator 10 | import Foundation 11 | import RxCocoa 12 | import RxDataSources 13 | 14 | enum MessageListCellItem: Equatable { 15 | /// 单条消息 16 | case message(model: MessageItemModel) 17 | /// 一组消息,可以收缩折叠 18 | case messageGroup(name: String, totalCount: Int, messages: [MessageItemModel]) 19 | 20 | // 确定 cell 内部是否需要更新 21 | static func == (lhs: Self, rhs: Self) -> Bool { 22 | switch (lhs, rhs) { 23 | case (.message(let l), .message(let r)): 24 | return l.id == r.id && l.dateText == r.dateText 25 | case (.messageGroup(let l, _, let lMessages), .messageGroup(let r, _, let rMessages)): 26 | if l != r { 27 | return false 28 | } 29 | if lMessages.first?.dateText != rMessages.first?.dateText { 30 | return false 31 | } 32 | if lMessages.count != rMessages.count { 33 | return false 34 | } 35 | for (lMessage, rMessage) in zip(lMessages, rMessages) { 36 | if lMessage.id != rMessage.id { 37 | return false 38 | } 39 | } 40 | return true 41 | default: 42 | return false 43 | } 44 | } 45 | } 46 | 47 | extension MessageListCellItem: IdentifiableType { 48 | typealias Identity = String 49 | 50 | // 确定整个 cell 是否删除或替换 51 | var identity: String { 52 | switch self { 53 | case .message(let model): 54 | return "list_\(model.id)" 55 | case .messageGroup(_, _, let messages): 56 | return "group_\(messages.first?.group ?? NSLocalizedString("Default"))" 57 | } 58 | } 59 | } 60 | 61 | struct MessageSection { 62 | var header: String 63 | var messages: [MessageListCellItem] 64 | } 65 | 66 | extension MessageSection: AnimatableSectionModelType { 67 | typealias Item = MessageListCellItem 68 | typealias Identity = String 69 | 70 | var items: [MessageListCellItem] { 71 | return self.messages 72 | } 73 | 74 | init(original: MessageSection, items: [MessageListCellItem]) { 75 | self = original 76 | self.messages = items 77 | } 78 | 79 | var identity: String { 80 | return header 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Model/Object+Dictionary.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Object+Dictionary.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2022/10/20. 6 | // Copyright © 2022 Fin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import RealmSwift 11 | 12 | extension Object { 13 | func toDictionary() -> [String: AnyObject] { 14 | var dicProps = [String: AnyObject]() 15 | self.objectSchema.properties.forEach { property in 16 | if property.isArray { 17 | var arr: [[String: AnyObject]] = [] 18 | for obj in self.dynamicList(property.name) { 19 | arr.append(obj.toDictionary()) 20 | } 21 | dicProps[property.name] = arr as AnyObject 22 | } else if let value = self[property.name] as? Object { 23 | dicProps[property.name] = value.toDictionary() as AnyObject 24 | } else if let value = self[property.name] as? Date { 25 | dicProps[property.name] = Int64(value.timeIntervalSince1970) as AnyObject 26 | } else { 27 | let value = self[property.name] 28 | dicProps[property.name] = value as AnyObject 29 | } 30 | } 31 | return dicProps 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Model/PreviewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PreviewModel.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2020/11/23. 6 | // Copyright © 2020 Fin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | class PreviewModel: NSObject { 13 | var title: String? 14 | var body: String? 15 | var notice: String? 16 | var queryParameter: String? 17 | var image: UIImage? 18 | var moreInfo: String? 19 | var moreViewModel: ViewModel? 20 | 21 | init(title: String? = nil, 22 | body: String? = nil, 23 | notice: String? = nil, 24 | queryParameter: String? = nil, 25 | image: UIImage? = nil, 26 | moreInfo: String? = nil, 27 | moreViewModel: ViewModel? = nil) 28 | { 29 | self.title = title 30 | self.body = body 31 | self.notice = notice 32 | self.queryParameter = queryParameter 33 | self.image = image 34 | self.moreInfo = moreInfo 35 | self.moreViewModel = moreViewModel 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /NotificationServiceExtension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | NotificationServiceExtension 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | XPC! 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSExtension 24 | 25 | NSExtensionAttributes 26 | 27 | IntentsSupported 28 | 29 | INSendMessageIntent 30 | 31 | 32 | NSExtensionPointIdentifier 33 | com.apple.usernotifications.service 34 | NSExtensionPrincipalClass 35 | $(PRODUCT_MODULE_NAME).NotificationService 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /NotificationServiceExtension/NotificationService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotificationService.swift 3 | // NotificationServiceExtension 4 | // 5 | // Created by huangfeng on 2018/12/17. 6 | // Copyright © 2018 Fin. All rights reserved. 7 | // 8 | 9 | import UserNotifications 10 | 11 | class NotificationService: UNNotificationServiceExtension { 12 | /// 当前正在运行的 Processor 13 | var currentNotificationProcessor: NotificationContentProcessor? = nil 14 | /// 当前 ContentHandler,主要用来 serviceExtensionTimeWillExpire 时,传递给 Processor 用来交付推送。 15 | var currentContentHandler: ((UNNotificationContent) -> Void)? = nil 16 | 17 | override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { 18 | Task { 19 | guard var bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) else { 20 | contentHandler(request.content) 21 | return 22 | } 23 | self.currentContentHandler = contentHandler 24 | 25 | // 所有的 processor, 按顺序从上往下对推送进行处理 26 | // ciphertext 需要放在最前面,有可能所有的推送数据都在密文里 27 | let processors: [NotificationContentProcessorItem] = [ 28 | .ciphertext, 29 | .level, 30 | .badge, 31 | .autoCopy, 32 | .archive, 33 | .setIcon, 34 | .setImage, 35 | .mute, 36 | .call 37 | ] 38 | 39 | // 各个 processor 依次对推送进行处理 40 | for processor in processors.map({ $0.processor }) { 41 | do { 42 | self.currentNotificationProcessor = processor 43 | bestAttemptContent = try await processor.process(identifier: request.identifier, content: bestAttemptContent) 44 | } catch NotificationContentProcessorError.error(let content) { 45 | contentHandler(content) 46 | return 47 | } 48 | } 49 | 50 | // 处理完后交付推送 51 | contentHandler(bestAttemptContent) 52 | } 53 | } 54 | 55 | override func serviceExtensionTimeWillExpire() { 56 | super.serviceExtensionTimeWillExpire() 57 | if let handler = self.currentContentHandler { 58 | self.currentNotificationProcessor?.serviceExtensionTimeWillExpire(contentHandler: handler) 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /NotificationServiceExtension/NotificationServiceExtension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.bark 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /NotificationServiceExtension/Processor/ArchiveProcessor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ArchiveProcessor.swift 3 | // NotificationServiceExtension 4 | // 5 | // Created by huangfeng on 2024/5/29. 6 | // Copyright © 2024 Fin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import RealmSwift 11 | 12 | class ArchiveProcessor: NotificationContentProcessor { 13 | private lazy var realm: Realm? = { 14 | Realm.Configuration.defaultConfiguration = kRealmDefaultConfiguration 15 | return try? Realm() 16 | }() 17 | 18 | func process(identifier: String, content bestAttemptContent: UNMutableNotificationContent) async throws -> UNMutableNotificationContent { 19 | let userInfo = bestAttemptContent.userInfo 20 | 21 | var isArchive: Bool = ArchiveSettingManager.shared.isArchive 22 | if let archive = userInfo["isarchive"] as? String { 23 | isArchive = archive == "1" ? true : false 24 | } 25 | 26 | if isArchive { 27 | let alert = (userInfo["aps"] as? [String: Any])?["alert"] as? [String: Any] 28 | let title = alert?["title"] as? String 29 | let subtitle = alert?["subtitle"] as? String 30 | let body = alert?["body"] as? String 31 | let url = userInfo["url"] as? String 32 | let group = userInfo["group"] as? String 33 | let image = userInfo["image"] as? String 34 | 35 | try? realm?.write { 36 | let message = Message() 37 | message.title = title 38 | message.subtitle = subtitle 39 | message.body = body 40 | message.url = url 41 | message.image = image 42 | message.group = group 43 | message.createDate = Date() 44 | realm?.add(message) 45 | } 46 | } 47 | return bestAttemptContent 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /NotificationServiceExtension/Processor/AutoCopyProcessor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AutoCopyProcessor.swift 3 | // NotificationServiceExtension 4 | // 5 | // Created by huangfeng on 2024/5/29. 6 | // Copyright © 2024 Fin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class AutoCopyProcessor: NotificationContentProcessor { 12 | func process(identifier: String, content bestAttemptContent: UNMutableNotificationContent) async throws -> UNMutableNotificationContent { 13 | let userInfo = bestAttemptContent.userInfo 14 | if userInfo["autocopy"] as? String == "1" 15 | || userInfo["automaticallycopy"] as? String == "1" 16 | { 17 | if let copy = userInfo["copy"] as? String { 18 | UIPasteboard.general.string = copy 19 | } else { 20 | UIPasteboard.general.string = bestAttemptContent.body 21 | } 22 | } 23 | return bestAttemptContent 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /NotificationServiceExtension/Processor/BadgeProcessor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BadgeProcessor.swift 3 | // NotificationServiceExtension 4 | // 5 | // Created by huangfeng on 2024/5/29. 6 | // Copyright © 2024 Fin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// 通知角标 12 | class BadgeProcessor: NotificationContentProcessor { 13 | func process(identifier: String, content bestAttemptContent: UNMutableNotificationContent) async throws -> UNMutableNotificationContent { 14 | if let badgeStr = bestAttemptContent.userInfo["badge"] as? String, let badge = Int(badgeStr) { 15 | bestAttemptContent.badge = NSNumber(value: badge) 16 | } 17 | return bestAttemptContent 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /NotificationServiceExtension/Processor/ImageDownloader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageDownloader.swift 3 | // NotificationServiceExtension 4 | // 5 | // Created by huangfeng on 2024/5/29. 6 | // Copyright © 2024 Fin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Kingfisher 11 | 12 | class ImageDownloader { 13 | /// 保存图片到缓存中 14 | /// - Parameters: 15 | /// - cache: 使用的缓存 16 | /// - data: 图片 Data 数据 17 | /// - key: 缓存 Key 18 | class func storeImage(cache: ImageCache, data: Data, key: String) async { 19 | return await withCheckedContinuation { continuation in 20 | cache.storeToDisk(data, forKey: key, expiration: StorageExpiration.never) { _ in 21 | continuation.resume() 22 | } 23 | } 24 | } 25 | 26 | /// 使用 Kingfisher.ImageDownloader 下载图片 27 | /// - Parameter url: 下载的图片URL 28 | /// - Returns: 返回 Result 29 | class func downloadImage(url: URL) async -> Result { 30 | return await withCheckedContinuation { continuation in 31 | Kingfisher.ImageDownloader.default.downloadImage(with: url, options: nil) { result in 32 | continuation.resume(returning: result) 33 | } 34 | } 35 | } 36 | 37 | /// 下载推送图片 38 | /// - Parameter imageUrl: 图片URL字符串 39 | /// - Returns: 保存在本地中的`图片 File URL` 40 | class func downloadImage(_ imageUrl: String) async -> String? { 41 | guard let groupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.bark"), 42 | let cache = try? ImageCache(name: "shared", cacheDirectoryURL: groupUrl), 43 | let imageResource = URL(string: imageUrl) 44 | else { 45 | return nil 46 | } 47 | 48 | // 先查看图片缓存 49 | if cache.diskStorage.isCached(forKey: imageResource.cacheKey) { 50 | return cache.cachePath(forKey: imageResource.cacheKey) 51 | } 52 | 53 | // 下载图片 54 | guard let result = try? await downloadImage(url: imageResource).get() else { 55 | return nil 56 | } 57 | // 缓存图片 58 | await storeImage(cache: cache, data: result.originalData, key: imageResource.cacheKey) 59 | 60 | return cache.cachePath(forKey: imageResource.cacheKey) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /NotificationServiceExtension/Processor/ImageProcessor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageProcessor.swift 3 | // NotificationServiceExtension 4 | // 5 | // Created by huangfeng on 2024/5/29. 6 | // Copyright © 2024 Fin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import MobileCoreServices 11 | 12 | class ImageProcessor: NotificationContentProcessor { 13 | func process(identifier: String, content bestAttemptContent: UNMutableNotificationContent) async throws -> UNMutableNotificationContent { 14 | let userInfo = bestAttemptContent.userInfo 15 | guard let imageUrl = userInfo["image"] as? String, 16 | let imageFileUrl = await ImageDownloader.downloadImage(imageUrl) 17 | else { 18 | return bestAttemptContent 19 | } 20 | 21 | let copyDestUrl = URL(fileURLWithPath: imageFileUrl).appendingPathExtension(".tmp") 22 | // 将图片缓存复制一份,推送使用完后会自动删除,但图片缓存需要留着以后在历史记录里查看 23 | try? FileManager.default.copyItem( 24 | at: URL(fileURLWithPath: imageFileUrl), 25 | to: copyDestUrl 26 | ) 27 | 28 | if let attachment = try? UNNotificationAttachment( 29 | identifier: "image", 30 | url: copyDestUrl, 31 | options: [UNNotificationAttachmentOptionsTypeHintKey: kUTTypePNG] 32 | ) { 33 | bestAttemptContent.attachments = [attachment] 34 | } 35 | return bestAttemptContent 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /NotificationServiceExtension/Processor/MuteProcessor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MuteProcessor.swift 3 | // NotificationServiceExtension 4 | // 5 | // Created by huangfeng on 11/6/24. 6 | // Copyright © 2024 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class MuteProcessor: NotificationContentProcessor { 12 | func process(identifier: String, content bestAttemptContent: UNMutableNotificationContent) async throws -> UNMutableNotificationContent { 13 | let groupName = bestAttemptContent.threadIdentifier 14 | guard let date = GroupMuteSettingManager().settings[groupName], date > Date() else { 15 | return bestAttemptContent 16 | } 17 | // 需要静音 18 | if #available(iOSApplicationExtension 15.0, *) { 19 | bestAttemptContent.interruptionLevel = .passive 20 | } 21 | return bestAttemptContent 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /NotificationServiceExtension/Processor/NotificationContentProcessor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotificationContentProcessor.swift 3 | // NotificationServiceExtension 4 | // 5 | // Created by huangfeng on 2024/5/29. 6 | // Copyright © 2024 Fin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | @_exported import UserNotifications 11 | 12 | enum NotificationContentProcessorItem { 13 | case ciphertext 14 | case level 15 | case badge 16 | case autoCopy 17 | case archive 18 | case setIcon 19 | case setImage 20 | case call 21 | case mute 22 | 23 | var processor: NotificationContentProcessor { 24 | switch self { 25 | case .ciphertext: 26 | return CiphertextProcessor() 27 | case .level: 28 | return LevelProcessor() 29 | case .badge: 30 | return BadgeProcessor() 31 | case .autoCopy: 32 | return AutoCopyProcessor() 33 | case .archive: 34 | return ArchiveProcessor() 35 | case .setIcon: 36 | return IconProcessor() 37 | case .setImage: 38 | return ImageProcessor() 39 | case .call: 40 | return CallProcessor() 41 | case .mute: 42 | return MuteProcessor() 43 | } 44 | } 45 | } 46 | 47 | enum NotificationContentProcessorError: Swift.Error { 48 | case error(content: UNMutableNotificationContent) 49 | } 50 | 51 | public protocol NotificationContentProcessor { 52 | /// 处理 UNMutableNotificationContent 53 | /// - Parameters: 54 | /// - identifier: request.identifier, 有些 Processor 需要,例如 CallProcessor 需要这个去添加 LocalNotification 55 | /// - bestAttemptContent: 需要处理的 UNMutableNotificationContent 56 | /// - Returns: 处理成功后的 UNMutableNotificationContent 57 | /// - Throws: 处理失败后,应该中断处理 58 | func process(identifier: String, content bestAttemptContent: UNMutableNotificationContent) async throws -> UNMutableNotificationContent 59 | 60 | /// serviceExtension 即将终止,不管 processor 是否处理完成,最好立即调用 contentHandler 交付已完成的部分,否则会原样展示服务器传递过来的推送 61 | func serviceExtensionTimeWillExpire(contentHandler: (UNNotificationContent) -> Void) 62 | } 63 | 64 | extension NotificationContentProcessor { 65 | func serviceExtensionTimeWillExpire(contentHandler: (UNNotificationContent) -> Void) {} 66 | } 67 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | 3 | platform:ios,'13.0' 4 | inhibit_all_warnings! 5 | use_modular_headers! 6 | 7 | 8 | def pods 9 | pod 'SnapKit' 10 | pod 'Material' 11 | pod 'SVProgressHUD' 12 | pod 'FDFullscreenPopGesture' 13 | pod 'Moya/RxSwift' 14 | pod 'ObjectMapper' 15 | pod 'SwiftyJSON' 16 | pod 'DefaultsKit' 17 | pod 'RealmSwift' 18 | pod 'CryptoSwift' 19 | pod 'IQKeyboardManagerSwift/IQKeyboardToolbarManager' 20 | 21 | pod 'RxSwift' 22 | pod 'RxCocoa' 23 | pod 'RxGesture' 24 | pod 'RxDataSources' 25 | pod 'NSObject+Rx' 26 | 27 | pod 'MJRefresh' 28 | pod 'Kingfisher' 29 | pod 'MercariQRScanner', :git => 'https://github.com/Finb/QRScanner' 30 | pod 'DropDown' 31 | pod 'ImageViewer.swift' 32 | 33 | pod 'SwiftyStoreKit' 34 | end 35 | 36 | target 'Bark' do 37 | pods 38 | 39 | target 'BarkTests' do 40 | inherit! :search_paths 41 | end 42 | 43 | end 44 | 45 | 46 | target 'NotificationServiceExtension' do 47 | pod 'RealmSwift' 48 | pod 'Kingfisher' 49 | pod 'CryptoSwift' 50 | pod 'SwiftyJSON' 51 | end 52 | 53 | target 'NotificationContentExtension' do 54 | pod 'Kingfisher' 55 | end 56 | 57 | 58 | post_install do |installer| 59 | installer.pods_project.targets.each do |target| 60 | target.build_configurations.each do |config| 61 | if config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'].to_f < 13.0 62 | config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0' 63 | end 64 | config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO' 65 | end 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /Sounds/alarm.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/alarm.caf -------------------------------------------------------------------------------- /Sounds/anticipate.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/anticipate.caf -------------------------------------------------------------------------------- /Sounds/bell.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/bell.caf -------------------------------------------------------------------------------- /Sounds/birdsong.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/birdsong.caf -------------------------------------------------------------------------------- /Sounds/bloom.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/bloom.caf -------------------------------------------------------------------------------- /Sounds/calypso.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/calypso.caf -------------------------------------------------------------------------------- /Sounds/chime.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/chime.caf -------------------------------------------------------------------------------- /Sounds/choo.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/choo.caf -------------------------------------------------------------------------------- /Sounds/descent.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/descent.caf -------------------------------------------------------------------------------- /Sounds/electronic.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/electronic.caf -------------------------------------------------------------------------------- /Sounds/fanfare.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/fanfare.caf -------------------------------------------------------------------------------- /Sounds/glass.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/glass.caf -------------------------------------------------------------------------------- /Sounds/gotosleep.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/gotosleep.caf -------------------------------------------------------------------------------- /Sounds/healthnotification.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/healthnotification.caf -------------------------------------------------------------------------------- /Sounds/horn.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/horn.caf -------------------------------------------------------------------------------- /Sounds/ladder.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/ladder.caf -------------------------------------------------------------------------------- /Sounds/mailsent.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/mailsent.caf -------------------------------------------------------------------------------- /Sounds/minuet.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/minuet.caf -------------------------------------------------------------------------------- /Sounds/multiwayinvitation.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/multiwayinvitation.caf -------------------------------------------------------------------------------- /Sounds/newmail.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/newmail.caf -------------------------------------------------------------------------------- /Sounds/newsflash.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/newsflash.caf -------------------------------------------------------------------------------- /Sounds/noir.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/noir.caf -------------------------------------------------------------------------------- /Sounds/paymentsuccess.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/paymentsuccess.caf -------------------------------------------------------------------------------- /Sounds/shake.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/shake.caf -------------------------------------------------------------------------------- /Sounds/sherwoodforest.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/sherwoodforest.caf -------------------------------------------------------------------------------- /Sounds/silence.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/silence.caf -------------------------------------------------------------------------------- /Sounds/spell.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/spell.caf -------------------------------------------------------------------------------- /Sounds/suspense.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/suspense.caf -------------------------------------------------------------------------------- /Sounds/telegraph.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/telegraph.caf -------------------------------------------------------------------------------- /Sounds/tiptoes.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/tiptoes.caf -------------------------------------------------------------------------------- /Sounds/typewriters.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/typewriters.caf -------------------------------------------------------------------------------- /Sounds/update.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/Sounds/update.caf -------------------------------------------------------------------------------- /View/AddSoundCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AddSoundCell.swift 3 | // Bark 4 | // 5 | // Created by Fin on 2024/3/29. 6 | // Copyright © 2024 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class AddSoundCell: UITableViewCell { 12 | let button: UIButton = { 13 | let button = UIButton(type: .system) 14 | button.setTitle(NSLocalizedString("uploadSound"), for: .normal) 15 | button.setImage(UIImage(named: "music_note-music_note_symbol"), for: .normal) 16 | button.setTitleColor(BKColor.lightBlue.darken3, for: .normal) 17 | button.tintColor = BKColor.lightBlue.darken3 18 | button.titleLabel?.font = UIFont.preferredFont(ofSize: 16) 19 | button.titleLabel?.adjustsFontForContentSizeCategory = true 20 | // 从 UITableView didSelectRowAt 那响应点击事件 21 | button.isUserInteractionEnabled = false 22 | return button 23 | }() 24 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { 25 | super.init(style: style, reuseIdentifier: reuseIdentifier) 26 | self.selectionStyle = .none 27 | contentView.addSubview(button) 28 | button.snp.makeConstraints { make in 29 | make.edges.equalToSuperview() 30 | make.height.equalTo(44) 31 | } 32 | } 33 | 34 | required init?(coder: NSCoder) { 35 | fatalError("init(coder:) has not been implemented") 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /View/ArchiveSettingCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ArchiveSettingCell.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2020/5/29. 6 | // Copyright © 2020 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ArchiveSettingCell: BaseTableViewCell { 12 | let switchButton: UISwitch = { 13 | let btn = UISwitch() 14 | return btn 15 | }() 16 | 17 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { 18 | super.init(style: style, reuseIdentifier: reuseIdentifier) 19 | self.selectionStyle = .none 20 | self.backgroundColor = BKColor.background.secondary 21 | self.textLabel?.text = NSLocalizedString("defaultArchiveSettings") 22 | 23 | contentView.addSubview(switchButton) 24 | switchButton.snp.makeConstraints { make in 25 | make.right.equalToSuperview().offset(-16) 26 | make.centerY.equalToSuperview() 27 | } 28 | } 29 | 30 | @available(*, unavailable) 31 | required init?(coder aDecoder: NSCoder) { 32 | fatalError("init(coder:) has not been implemented") 33 | } 34 | 35 | override func bindViewModel(model: ArchiveSettingCellViewModel) { 36 | super.bindViewModel(model: model) 37 | (self.switchButton.rx.isOn <-> model.on) 38 | .disposed(by: rx.reuseBag) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /View/ArchiveSettingCellViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ArchiveSettingCellViewModel.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2020/11/20. 6 | // Copyright © 2020 Fin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import RxCocoa 11 | class ArchiveSettingCellViewModel: ViewModel { 12 | var on: BehaviorRelay 13 | init(on: BehaviorRelay) { 14 | self.on = on 15 | super.init() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /View/BKButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BKButton.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2020/9/23. 6 | // Copyright © 2020 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | protocol AlignmentRectInsetsOverridable: AnyObject { 12 | var alignmentRectInsetsOverride: UIEdgeInsets? { get set } 13 | } 14 | 15 | protocol HitTestSlopable: AnyObject { 16 | var hitTestSlop: UIEdgeInsets { get set } 17 | } 18 | 19 | class BKButton: UIButton, HitTestSlopable, AlignmentRectInsetsOverridable { 20 | var hitTestSlop = UIEdgeInsets.zero 21 | override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { 22 | if hitTestSlop == UIEdgeInsets.zero { 23 | return super.point(inside: point, with: event) 24 | } 25 | else { 26 | return self.bounds.inset(by: hitTestSlop).contains(point) 27 | } 28 | } 29 | 30 | var alignmentRectInsetsOverride: UIEdgeInsets? 31 | override var alignmentRectInsets: UIEdgeInsets { 32 | return alignmentRectInsetsOverride ?? super.alignmentRectInsets 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /View/BKDropDownCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BKDropDownCellTableViewCell.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2023/2/9. 6 | // Copyright © 2023 Fin. All rights reserved. 7 | // 8 | 9 | import DropDown 10 | import UIKit 11 | 12 | class BKDropDownCell: DropDownCell { 13 | 14 | @IBOutlet var selectBackgroundView: UIView! 15 | 16 | override func awakeFromNib() { 17 | super.awakeFromNib() 18 | self.backgroundColor = BKColor.white 19 | self.selectBackgroundView.layer.cornerRadius = 10 20 | self.selectBackgroundView.clipsToBounds = true 21 | } 22 | 23 | override func setSelected(_ selected: Bool, animated: Bool) { 24 | 25 | let executeSelection: () -> Void = { [weak self] in 26 | guard let `self` = self else { return } 27 | 28 | let selectedBackgroundColor = BKColor.grey.lighten5 29 | if selected { 30 | self.selectBackgroundView.backgroundColor = selectedBackgroundColor 31 | self.optionLabel.textColor = BKColor.grey.darken4 32 | } else { 33 | self.selectBackgroundView.backgroundColor = .clear 34 | self.optionLabel.textColor = BKColor.grey.darken3 35 | } 36 | } 37 | 38 | if animated { 39 | UIView.animate(withDuration: 0.3, animations: { 40 | executeSelection() 41 | }) 42 | } else { 43 | executeSelection() 44 | } 45 | 46 | accessibilityTraits = selected ? .selected : .none 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /View/BKLabel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BKLabel.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2020/5/29. 6 | // Copyright © 2020 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class BKLabel: UILabel { 12 | var hitTestSlop = UIEdgeInsets.zero 13 | 14 | override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { 15 | if hitTestSlop == UIEdgeInsets.zero { 16 | return super.point(inside: point, with: event) 17 | } 18 | else { 19 | return self.bounds.inset(by: hitTestSlop).contains(point) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /View/BaseTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BaseTableViewCell.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2020/11/20. 6 | // Copyright © 2020 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class BaseTableViewCell: UITableViewCell where T: ViewModel { 12 | var viewModel: T? 13 | func bindViewModel(model: T) { 14 | self.viewModel = model 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /View/DonateCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DonateCell.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 11/13/24. 6 | // Copyright © 2024 Fin. All rights reserved. 7 | // 8 | 9 | import SwiftyStoreKit 10 | import UIKit 11 | 12 | class DonateCell: UITableViewCell { 13 | var title: String? = nil { 14 | didSet { 15 | self.textLabel?.text = title 16 | } 17 | } 18 | 19 | var productId: String? = nil { 20 | didSet { 21 | guard let productId else { return } 22 | if let cachePriceStr = Settings["bark.price.\(productId)"] { 23 | self.detailTextLabel?.text = cachePriceStr 24 | return 25 | } 26 | // 查询价格 27 | SwiftyStoreKit.retrieveProductsInfo([productId]) { result in 28 | if let product = result.retrievedProducts.first, let price = product.localizedPrice { 29 | let priceStr = price + (product.localizedSubscriptionPeriod.isEmpty ? "" : " / \(product.localizedSubscriptionPeriod)") 30 | Settings["bark.price.\(productId)"] = priceStr 31 | self.detailTextLabel?.text = priceStr 32 | } 33 | } 34 | } 35 | } 36 | 37 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { 38 | super.init(style: .value1, reuseIdentifier: reuseIdentifier) 39 | self.selectionStyle = .none 40 | self.accessoryType = .disclosureIndicator 41 | self.backgroundColor = BKColor.background.secondary 42 | self.detailTextLabel?.textColor = BKColor.grey.darken2 43 | } 44 | 45 | @available(*, unavailable) 46 | required init?(coder aDecoder: NSCoder) { 47 | fatalError("init(coder:) has not been implemented") 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /View/GesturePassTextView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GesturePassTextView.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2023/7/26. 6 | // Copyright © 2023 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class GesturePassTextView: UITextView { 12 | var superCell: UITableViewCell? = nil 13 | override func touchesBegan(_ touches: Set, with event: UIEvent?) { 14 | if let cell = superCell { 15 | cell.touchesBegan(touches, with: event) 16 | return 17 | } 18 | super.touchesBegan(touches, with: event) 19 | } 20 | override func touchesMoved(_ touches: Set, with event: UIEvent?) { 21 | if let cell = superCell { 22 | cell.touchesMoved(touches, with: event) 23 | return 24 | } 25 | super.touchesMoved(touches, with: event) 26 | } 27 | override func touchesEnded(_ touches: Set, with event: UIEvent?) { 28 | if let cell = superCell { 29 | cell.touchesEnded(touches, with: event) 30 | return 31 | } 32 | super.touchesEnded(touches, with: event) 33 | } 34 | override func touchesCancelled(_ touches: Set, with event: UIEvent?) { 35 | if let cell = superCell { 36 | cell.touchesCancelled(touches, with: event) 37 | return 38 | } 39 | super.touchesCancelled(touches, with: event) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /View/GradientButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Gradient.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2023/2/10. 6 | // Copyright © 2023 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | typealias GradientPoints = (startPoint: CGPoint, endPoint: CGPoint) 12 | 13 | enum GradientOrientation { 14 | case topRightBottomLeft 15 | case topLeftBottomRight 16 | case horizontal 17 | case vertical 18 | 19 | var startPoint: CGPoint { 20 | return points.startPoint 21 | } 22 | 23 | var endPoint: CGPoint { 24 | return points.endPoint 25 | } 26 | 27 | var points: GradientPoints { 28 | switch self { 29 | case .topRightBottomLeft: 30 | return (CGPoint(x: 0.0, y: 1.0), CGPoint(x: 1.0, y: 0.0)) 31 | case .topLeftBottomRight: 32 | return (CGPoint(x: 0.0, y: 0.0), CGPoint(x: 1, y: 1)) 33 | case .horizontal: 34 | return (CGPoint(x: 0.0, y: 0.5), CGPoint(x: 1.0, y: 0.5)) 35 | case .vertical: 36 | return (CGPoint(x: 0.0, y: 0.0), CGPoint(x: 0.0, y: 1.0)) 37 | } 38 | } 39 | } 40 | 41 | class GradientButton: UIButton { 42 | lazy var gradient: CAGradientLayer = { 43 | let gradient = CAGradientLayer() 44 | return gradient 45 | }() 46 | 47 | func applyGradient(withColours colours: [UIColor], gradientOrientation orientation: GradientOrientation) { 48 | gradient.frame = self.bounds 49 | gradient.colors = colours.map { $0.cgColor } 50 | gradient.startPoint = orientation.startPoint 51 | gradient.endPoint = orientation.endPoint 52 | 53 | if gradient.superlayer == nil { 54 | self.layer.insertSublayer(gradient, at: 0) 55 | } 56 | } 57 | 58 | override func layoutSubviews() { 59 | super.layoutSubviews() 60 | gradient.frame = self.bounds 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /View/HUD.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HUD.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2023/3/6. 6 | // Copyright © 2023 Fin. All rights reserved. 7 | // 8 | 9 | import SVProgressHUD 10 | import UIKit 11 | class BarkProgressHUD: SVProgressHUD { 12 | override class func displayDuration(for string: String?) -> TimeInterval { 13 | return min(Double((string ?? "").utf8.count) * 0.06 + 0.5, 5.0) 14 | } 15 | } 16 | 17 | open class ProgressHUD: NSObject { 18 | open class func show() { 19 | BarkProgressHUD.show() 20 | } 21 | 22 | open class func showWithClearMask() { 23 | BarkProgressHUD.show() 24 | } 25 | 26 | open class func dismiss() { 27 | BarkProgressHUD.dismiss() 28 | } 29 | 30 | open class func showWithStatus(_ status: String!) { 31 | BarkProgressHUD.show(withStatus: status) 32 | } 33 | 34 | open class func success(_ status: String!) { 35 | BarkProgressHUD.showSuccess(withStatus: status) 36 | } 37 | 38 | open class func error(_ status: String!) { 39 | BarkProgressHUD.showError(withStatus: status) 40 | } 41 | 42 | open class func inform(_ status: String!) { 43 | BarkProgressHUD.showInfo(withStatus: status) 44 | } 45 | } 46 | 47 | public func HUDSuccess(_ status: String?) { 48 | ProgressHUD.success(status ?? "") 49 | } 50 | 51 | public func HUDError(_ status: String?) { 52 | ProgressHUD.error(status ?? "") 53 | } 54 | 55 | public func HUDInform(_ status: String?) { 56 | ProgressHUD.inform(status ?? "") 57 | } 58 | 59 | public func HUDShow() { 60 | ProgressHUD.show() 61 | } 62 | 63 | public func HUDShowWithStatus(_ status: String!) { 64 | ProgressHUD.showWithStatus(status) 65 | } 66 | 67 | public func HUDDismiss() { 68 | ProgressHUD.dismiss() 69 | } 70 | -------------------------------------------------------------------------------- /View/LabelCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LabelCell.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2020/5/29. 6 | // Copyright © 2020 Fin. All rights reserved. 7 | // 8 | 9 | import Material 10 | import UIKit 11 | 12 | class LabelCell: UITableViewCell { 13 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { 14 | super.init(style: style, reuseIdentifier: reuseIdentifier) 15 | self.selectionStyle = .none 16 | 17 | self.backgroundColor = BKColor.background.primary 18 | self.textLabel?.textColor = BKColor.grey.darken1 19 | self.textLabel?.fontSize = 12 20 | self.textLabel?.numberOfLines = 0 21 | } 22 | 23 | @available(*, unavailable) 24 | required init?(coder aDecoder: NSCoder) { 25 | fatalError("init(coder:) has not been implemented") 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /View/MessageList/MessageGroupHeaderView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MessageGroupHeaderView.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 12/23/24. 6 | // Copyright © 2024 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class MessageGroupHeaderView: UIView { 12 | private let groupNameLabel: UILabel = { 13 | let label = UILabel() 14 | label.font = UIFont.preferredFont(ofSize: 16, weight: .semibold) 15 | label.textColor = BKColor.grey.darken4 16 | return label 17 | }() 18 | 19 | private let showLessAndClearView: ShowLessAndClearView = { 20 | let view = ShowLessAndClearView() 21 | return view 22 | }() 23 | 24 | var groupName: String? { 25 | didSet { 26 | groupNameLabel.text = groupName 27 | } 28 | } 29 | 30 | var showLessAction: (() -> Void)? { 31 | didSet { 32 | showLessAndClearView.showLessAction = showLessAction 33 | } 34 | } 35 | 36 | var clearAction: (() -> Void)? { 37 | didSet { 38 | showLessAndClearView.clearAction = clearAction 39 | } 40 | } 41 | 42 | init() { 43 | super.init(frame: .zero) 44 | addSubview(groupNameLabel) 45 | addSubview(showLessAndClearView) 46 | 47 | groupNameLabel.snp.makeConstraints { make in 48 | make.left.equalTo(8) 49 | make.top.equalTo(10) 50 | make.bottom.equalTo(-10) 51 | } 52 | showLessAndClearView.snp.makeConstraints { make in 53 | make.right.equalToSuperview() 54 | make.centerY.equalTo(groupNameLabel) 55 | } 56 | 57 | self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tap))) 58 | } 59 | 60 | @available(*, unavailable) 61 | required init?(coder: NSCoder) { 62 | fatalError("init(coder:) has not been implemented") 63 | } 64 | 65 | @objc func tap() { 66 | showLessAction?() 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /View/MessageList/MessageGroupMoreView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MessageGroupMoreView.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 12/25/24. 6 | // Copyright © 2024 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class MessageGroupMoreView: UIView { 12 | private let moreLabel: UILabel = { 13 | let label = UILabel() 14 | label.textColor = BKColor.grey.darken3 15 | label.font = UIFont.preferredFont(ofSize: 12) 16 | return label 17 | }() 18 | 19 | let arrowImageView: UIImageView = { 20 | let imageView = UIImageView() 21 | imageView.image = UIImage(named: "keyboard_arrow_right_symbol")?.withRenderingMode(.alwaysTemplate) 22 | imageView.tintColor = BKColor.grey.darken2 23 | return imageView 24 | }() 25 | 26 | var count: Int = 0 { 27 | didSet { 28 | moreLabel.text = NSLocalizedString("viewAllMessages").format(count) 29 | } 30 | } 31 | 32 | init() { 33 | super.init(frame: CGRect.zero) 34 | self.backgroundColor = BKColor.grey.lighten5 35 | self.layer.cornerRadius = 28 / 2 36 | self.clipsToBounds = true 37 | 38 | self.addSubview(moreLabel) 39 | self.addSubview(arrowImageView) 40 | moreLabel.snp.makeConstraints { make in 41 | make.left.equalToSuperview().offset(8) 42 | make.height.equalTo(28).priority(.medium) 43 | make.top.bottom.equalToSuperview() 44 | } 45 | arrowImageView.snp.makeConstraints { make in 46 | make.right.equalToSuperview().offset(-6) 47 | make.centerY.equalToSuperview() 48 | make.left.equalTo(moreLabel.snp.right).offset(4) 49 | } 50 | } 51 | 52 | @available(*, unavailable) 53 | required init?(coder: NSCoder) { 54 | fatalError("init(coder:) has not been implemented") 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /View/MessageSettingFooter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MessageSettingFooter.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 11/14/24. 6 | // Copyright © 2024 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class MessageSettingFooter: UITextView, UITextViewDelegate { 12 | init() { 13 | super.init(frame: CGRect(x: 0, y: 0, width: 0, height: 80), textContainer: .none) 14 | self.backgroundColor = UIColor.clear 15 | self.isEditable = false 16 | self.delegate = self 17 | 18 | // 版本号 19 | let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "" 20 | // build号 21 | let buildVersion = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "" 22 | 23 | let attr = NSMutableAttributedString(string: "\(NSLocalizedString("version")) \(appVersion) (\(buildVersion))\n", attributes: [.font: UIFont.preferredFont(ofSize: 12), .foregroundColor: BKColor.grey.darken1]) 24 | attr.append(NSAttributedString(string: NSLocalizedString("privacyPolicy"), attributes: [.link: "privacyPolicy"])) 25 | attr.append(NSAttributedString(string: " · ")) 26 | attr.append(NSAttributedString(string: NSLocalizedString("userAgreement"), attributes: [.link: "userAgreement"])) 27 | attr.append(NSAttributedString(string: " · ")) 28 | attr.append(NSAttributedString(string: NSLocalizedString("restoreSubscription"), attributes: [.link: "restoreSubscription"])) 29 | 30 | let style = NSMutableParagraphStyle() 31 | style.lineSpacing = 6 32 | attr.addAttribute(.paragraphStyle, value: style, range: NSRange(location: 0, length: attr.length)) 33 | 34 | self.attributedText = attr 35 | self.linkTextAttributes = [.foregroundColor: BKColor.grey.darken1, .underlineStyle: NSUnderlineStyle.single.rawValue, .font: UIFont.preferredFont(ofSize: 12)] 36 | self.textAlignment = .center 37 | } 38 | 39 | @available(*, unavailable) 40 | required init?(coder: NSCoder) { 41 | fatalError("init(coder:) has not been implemented") 42 | } 43 | 44 | var openLinkHandler: ((String) -> Void)? 45 | func textView(_ textView: UITextView, shouldInteractWith url: URL, in characterRange: NSRange) -> Bool { 46 | self.openLinkHandler?(url.absoluteString) 47 | return false 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /View/MutableTextCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DeviceTokenCell.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2022/3/23. 6 | // Copyright © 2022 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class MutableTextCell: BaseTableViewCell { 12 | 13 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { 14 | super.init(style: UITableViewCell.CellStyle.value1, reuseIdentifier: reuseIdentifier) 15 | self.selectionStyle = .none 16 | self.accessoryType = .none 17 | self.backgroundColor = BKColor.background.secondary 18 | self.detailTextLabel?.textColor = BKColor.grey.darken2 19 | } 20 | 21 | @available(*, unavailable) 22 | required init?(coder aDecoder: NSCoder) { 23 | fatalError("init(coder:) has not been implemented") 24 | } 25 | 26 | override func bindViewModel(model: MutableTextCellViewModel) { 27 | super.bindViewModel(model: model) 28 | 29 | self.textLabel?.text = model.title 30 | model.text 31 | .drive(self.detailTextLabel!.rx.text) 32 | .disposed(by: rx.reuseBag) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /View/MutableTextCellViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DeviceTokenCellViewModel.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2022/3/23. 6 | // Copyright © 2022 Fin. All rights reserved. 7 | // 8 | 9 | import RxCocoa 10 | import UIKit 11 | class MutableTextCellViewModel: ViewModel { 12 | var title: String 13 | var text: Driver 14 | init(title: String, text: Driver) { 15 | self.title = title 16 | self.text = text 17 | super.init() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /View/ServerListTableViewCellViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ServerListTableViewCellViewModel.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2022/4/1. 6 | // Copyright © 2022 Fin. All rights reserved. 7 | // 8 | 9 | import RxRelay 10 | import UIKit 11 | 12 | class ServerListTableViewCellViewModel: ViewModel { 13 | let server: Server 14 | 15 | let name: BehaviorRelay 16 | let key: BehaviorRelay 17 | let state: BehaviorRelay 18 | 19 | init(server: Server) { 20 | self.server = server 21 | 22 | self.name = BehaviorRelay(value: { 23 | var serverName = URL(string: server.address)?.host ?? "Invalid Server" 24 | if let name = server.name, !name.isEmpty { 25 | serverName = name + "\n" + serverName 26 | } 27 | return serverName 28 | }()) 29 | self.key = BehaviorRelay(value: !server.key.isEmpty ? server.key : "none") 30 | self.state = BehaviorRelay(value: server.state == .ok) 31 | 32 | super.init() 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /View/SettingSectionHeader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SettingSectionHeader.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 11/13/24. 6 | // Copyright © 2024 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SettingSectionHeader: UIView { 12 | let titleLabel: UILabel = { 13 | let label = UILabel() 14 | label.textColor = BKColor.grey.darken1 15 | label.font = UIFont.preferredFont(ofSize: 12) 16 | label.numberOfLines = 0 17 | return label 18 | }() 19 | 20 | init() { 21 | super.init(frame: CGRect.zero) 22 | self.addSubview(titleLabel) 23 | titleLabel.snp.makeConstraints { make in 24 | make.top.equalTo(12) 25 | make.bottom.equalTo(-12) 26 | make.left.equalTo(13) 27 | make.right.equalTo(-13) 28 | } 29 | } 30 | 31 | @available(*, unavailable) 32 | required init?(coder: NSCoder) { 33 | fatalError("init(coder:) has not been implemented") 34 | } 35 | } 36 | 37 | class SettingSectionFooter: UIView { 38 | let titleLabel: UILabel = { 39 | let label = UILabel() 40 | label.textColor = BKColor.grey.darken1 41 | label.font = UIFont.preferredFont(ofSize: 12) 42 | label.numberOfLines = 0 43 | return label 44 | }() 45 | 46 | init() { 47 | super.init(frame: CGRect.zero) 48 | self.addSubview(titleLabel) 49 | titleLabel.snp.makeConstraints { make in 50 | make.top.equalTo(8) 51 | // make.bottom.equalTo(-6) 52 | make.left.equalTo(12) 53 | make.right.equalTo(-12) 54 | } 55 | } 56 | 57 | @available(*, unavailable) 58 | required init?(coder: NSCoder) { 59 | fatalError("init(coder:) has not been implemented") 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /View/SoundCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SoundCell.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2020/9/14. 6 | // Copyright © 2020 Fin. All rights reserved. 7 | // 8 | 9 | import AVKit 10 | import Material 11 | import UIKit 12 | 13 | class SoundCell: BaseTableViewCell { 14 | let copyButton = IconButton(image: UIImage(named: "baseline_file_copy_white_24pt"), tintColor: BKColor.grey.base) 15 | let nameLabel: UILabel = { 16 | let label = UILabel() 17 | label.fontSize = 14 18 | label.textColor = BKColor.grey.darken4 19 | return label 20 | }() 21 | 22 | let durationLabel: UILabel = { 23 | let label = UILabel() 24 | label.fontSize = 12 25 | label.textColor = BKColor.grey.darken1 26 | return label 27 | }() 28 | 29 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { 30 | super.init(style: style, reuseIdentifier: reuseIdentifier) 31 | self.selectionStyle = .none 32 | self.backgroundColor = BKColor.background.secondary 33 | self.contentView.addSubview(nameLabel) 34 | self.contentView.addSubview(durationLabel) 35 | self.contentView.addSubview(copyButton) 36 | 37 | nameLabel.snp.makeConstraints { make in 38 | make.left.top.equalToSuperview().offset(15) 39 | } 40 | durationLabel.snp.makeConstraints { make in 41 | make.left.equalTo(nameLabel) 42 | make.top.equalTo(nameLabel.snp.bottom).offset(5) 43 | make.bottom.equalToSuperview().offset(-15) 44 | } 45 | copyButton.snp.makeConstraints { make in 46 | make.right.equalToSuperview().offset(-15) 47 | make.centerY.equalToSuperview() 48 | make.width.height.equalTo(40) 49 | } 50 | } 51 | 52 | @available(*, unavailable) 53 | required init?(coder aDecoder: NSCoder) { 54 | fatalError("init(coder:) has not been implemented") 55 | } 56 | 57 | override func bindViewModel(model: SoundCellViewModel) { 58 | super.bindViewModel(model: model) 59 | 60 | model.name 61 | .bind(to: nameLabel.rx.text) 62 | .disposed(by: rx.reuseBag) 63 | model.duration 64 | .map { String(format: "%.2g second(s)", CMTimeGetSeconds($0)) } 65 | .bind(to: durationLabel.rx.text) 66 | .disposed(by: rx.reuseBag) 67 | 68 | copyButton.rx.tap 69 | .map { model.name.value } 70 | .bind(to: model.copyNameAction) 71 | .disposed(by: rx.reuseBag) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /View/SoundCellViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SoundCellViewModel.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2020/11/17. 6 | // Copyright © 2020 Fin. All rights reserved. 7 | // 8 | 9 | import AVKit 10 | import Foundation 11 | import RxCocoa 12 | import RxSwift 13 | 14 | class SoundCellViewModel: ViewModel { 15 | let name = BehaviorRelay(value: "") 16 | let duration = BehaviorRelay(value: .zero) 17 | 18 | let copyNameAction = PublishRelay() 19 | let playAction = PublishRelay() 20 | 21 | let model: AVURLAsset 22 | init(model: AVURLAsset) { 23 | self.model = model 24 | name.accept(model.url.deletingPathExtension().lastPathComponent) 25 | duration.accept(model.duration) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /View/SpacerCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SpacerCell.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2021/6/25. 6 | // Copyright © 2021 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SpacerCell: UITableViewCell { 12 | var height: CGFloat = 0 { 13 | didSet { 14 | self.contentView.snp.remakeConstraints { make in 15 | make.height.equalTo(height) 16 | } 17 | } 18 | } 19 | 20 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { 21 | super.init(style: style, reuseIdentifier: reuseIdentifier) 22 | self.backgroundColor = UIColor.clear 23 | self.selectionStyle = .none 24 | } 25 | 26 | @available(*, unavailable) 27 | required init?(coder aDecoder: NSCoder) { 28 | fatalError("init(coder:) has not been implemented") 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /View/TextCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextCell.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2021/6/25. 6 | // Copyright © 2021 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class DetailTextCell: UITableViewCell { 12 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { 13 | super.init(style: .value1, reuseIdentifier: reuseIdentifier) 14 | self.selectionStyle = .none 15 | self.accessoryType = .disclosureIndicator 16 | self.backgroundColor = BKColor.background.secondary 17 | } 18 | 19 | @available(*, unavailable) 20 | required init?(coder aDecoder: NSCoder) { 21 | fatalError("init(coder:) has not been implemented") 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /View/UINavigationItem+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UINavigationItem+Extension.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2020/9/23. 6 | // Copyright © 2020 Fin. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | // 如果第一个 item 是系统自带的 UIBarButtonItem ,则距离导航栏左右距离只有8 12 | // 自己定义的的则最少有16,太宽了 13 | // 所以先用 一个 fixedSpace UIBarButtonItem 先把距离给缩短点, 14 | // 然后用个 AlignmentRectInsetsOverridable 把自己的按钮往 左/右 挪动,减少距离 15 | // 用 HitTestSlopable 增加点击区域 16 | enum UINavigationItemPosition { 17 | case left 18 | case right 19 | } 20 | 21 | extension UINavigationItem { 22 | func setLeftBarButtonItem(item: UIBarButtonItem) { 23 | setBarButtonItems(items: [item], position: .left) 24 | } 25 | 26 | func setRightBarButtonItem(item: UIBarButtonItem) { 27 | setBarButtonItems(items: [item], position: .right) 28 | } 29 | 30 | func setBarButtonItems(items: [UIBarButtonItem], position: UINavigationItemPosition) { 31 | guard items.count > 0 else { 32 | self.leftBarButtonItems = nil 33 | return 34 | } 35 | var buttonItems = items 36 | if #available(iOS 11.0, *) { 37 | buttonItems.forEach { item in 38 | guard let view = item.customView else { return } 39 | item.customView?.translatesAutoresizingMaskIntoConstraints = false 40 | (item.customView as? HitTestSlopable)?.hitTestSlop = UIEdgeInsets(top: -10, left: -10, bottom: -10, right: -10) 41 | (item.customView as? AlignmentRectInsetsOverridable)?.alignmentRectInsetsOverride = UIEdgeInsets(top: 0, left: position == .left ? 8 : -8, bottom: 0, right: position == .left ? -8 : 8) 42 | item.customView?.snp.makeConstraints { make in 43 | make.width.equalTo(view.bounds.size.width > 24 ? view.bounds.width : 24) 44 | make.height.equalTo(view.bounds.size.height > 24 ? view.bounds.height : 24) 45 | } 46 | } 47 | buttonItems.insert(UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil), at: 0) 48 | } 49 | else { 50 | let spacer = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil) 51 | spacer.width = -8 52 | buttonItems.insert(spacer, at: 0) 53 | } 54 | if position == .left { 55 | self.leftBarButtonItems = buttonItems 56 | } 57 | else { 58 | self.rightBarButtonItems = buttonItems 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /View/iCloudStatusCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // iCloudStatusCell.swift 3 | // Bark 4 | // 5 | // Created by huangfeng on 2020/5/29. 6 | // Copyright © 2020 Fin. All rights reserved. 7 | // 8 | 9 | import CloudKit 10 | import UIKit 11 | 12 | class iCloudStatusCell: UITableViewCell { 13 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { 14 | super.init(style: .value1, reuseIdentifier: reuseIdentifier) 15 | self.selectionStyle = .none 16 | self.backgroundColor = BKColor.background.secondary 17 | self.textLabel?.text = NSLocalizedString("iCloudSatatus") 18 | self.detailTextLabel?.text = "" 19 | self.detailTextLabel?.textColor = BKColor.grey.darken2 20 | CKContainer.default().accountStatus { status, _ in 21 | dispatch_sync_safely_main_queue { 22 | switch status { 23 | case .available: 24 | self.detailTextLabel?.text = NSLocalizedString("available") 25 | case .noAccount, .restricted, .temporarilyUnavailable: 26 | self.detailTextLabel?.text = NSLocalizedString("restricted") 27 | case .couldNotDetermine: 28 | self.detailTextLabel?.text = NSLocalizedString("unknown") 29 | @unknown default: 30 | break 31 | } 32 | } 33 | } 34 | } 35 | 36 | @available(*, unavailable) 37 | required init?(coder aDecoder: NSCoder) { 38 | fatalError("init(coder:) has not been implemented") 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/docs/.nojekyll -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | bark.day.app -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | 2 | ### Bark 3 | - 免费、轻量!简单调用接口即可给自己的iPhone发送推送。 4 | - 依赖苹果APNs,及时、稳定、可靠 5 | - 不会消耗设备的电量, 基于系统推送服务与推送扩展,APP本体并不需要运行。 6 | - 隐私安全,可以通过一些方式确保包含作者本人在内的所有人都无法窃取你的隐私。
*点击详细了解如何保障[隐私安全](/privacy)* 7 | 8 | ### 源码 9 | - [Bark](https://github.com/Finb/Bark) 是完整开源的 iOS APP,用来接收自定义推送。 10 | - [bark-server](https://github.com/Finb/bark-server) 是完整开源的 Bark 服务后端,用来接收用户的推送请求并转发给苹果APNS。 11 | 12 | ### 反馈 13 | - [Bark 问题反馈群](https://t.me/joinchat/OsCbLzovUAE0YjY1) (注意点击入群验证) 14 | - [GitHub Issues](https://github.com/Finb/Bark/issues) 15 | 16 | ### 免费 17 | Bark **2018年7月**上线,至少会维持运营到 **2031年7月** 。*(说不出口“永久”这个词,后续还有需求再续吧)*
18 | APP在维持期间,不会有任何形式的收费功能与广告,各位彦祖放心使用。 19 | 20 | ### 赞助 21 | 目前接收 GitHub 赞助、App内内购赞助。非常感谢每一位赞助者!
22 | 赞助者:[https://github.com/sponsors/Finb](https://github.com/sponsors/Finb) 23 | 24 | ### 文档 25 | - **App** 26 | - [使用教程](/tutorial) 27 | - [推送加密](/encryption) 28 | - [常见问题](/faq) 29 | - **服务端** 30 | - [部署服务](/deploy) 31 | - [批量推送](/batch) 32 | - [编译代码](/build) 33 | - [推送证书](/cert) 34 | - [隐私安全](/privacy) -------------------------------------------------------------------------------- /docs/_coverpage.md: -------------------------------------------------------------------------------- 1 | ![logo](_media/Icon.png) 2 | 3 | # Bark 4 | 5 | > 一款注重隐私、安全可控的自定义通知推送工具。 6 | 7 | - 免费、简单、安全 8 | - 打开即用 9 | 10 | [GitHub](https://github.com/finb/bark) 11 | [Get Started](#bark) 12 | -------------------------------------------------------------------------------- /docs/_media/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/docs/_media/Icon.png -------------------------------------------------------------------------------- /docs/_media/environment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/docs/_media/environment.png -------------------------------------------------------------------------------- /docs/_media/example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/docs/_media/example.jpg -------------------------------------------------------------------------------- /docs/_media/shortcuts_cn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Finb/Bark/c1d9dfe7f663bfc31f5d01881220915b251c2002/docs/_media/shortcuts_cn.png -------------------------------------------------------------------------------- /docs/_navbar.md: -------------------------------------------------------------------------------- 1 | * Translations 2 | - [:cn: 简体中文](/) 3 | - [:uk: English](/en-us/) -------------------------------------------------------------------------------- /docs/_sidebar.md: -------------------------------------------------------------------------------- 1 | - [Bark](/#bark) 2 | - **App** 3 | - [使用教程](/tutorial) 4 | - [推送加密](/encryption) 5 | - [常见问题](/faq) 6 | - **服务端** 7 | - [部署服务](/deploy) 8 | - [批量推送](/batch) 9 | - [编译代码](/build) 10 | - [推送证书](/cert) 11 | - [隐私安全](/privacy) -------------------------------------------------------------------------------- /docs/batch.md: -------------------------------------------------------------------------------- 1 | 2 | ### 个人用户 3 | 批量推送仅支持Json请求,需 bark-server 更新至 v2.1.9。([https://api.day.app](https://api.day.app) 暂时不会更新至 v2.1.9, 目前还不支持批量推送)
4 | 用法: 5 | ```sh 6 | curl -X "POST" "https://api.day.app/push" \ 7 | -H 'Content-Type: application/json; charset=utf-8' \ 8 | -d $'{ 9 | "title": "Title", 10 | "body": "Body", 11 | "sound": "minuet", 12 | "group": "test", 13 | "device_keys": ["key1", "key2", ... ] 14 | }' 15 | ``` 16 | 17 | ### 中间服务 18 | 如果你的服务需要大批量且及时地向用户发送推送,建议自建服务端。可以提供 Url Scheme 方便用户一键更改服务器。 19 | 20 | Url Scheme 示例: 21 | ``` 22 | bark://addServer?address=https%3A%2F%2Fapi.day.app 23 | ``` 24 | bark-server 对配置要求很低,以下是美西 VPS 各配置下的 QPS 测试结果 : 25 | 26 | | Cores | Ram | Speed | 27 | | ----- | ----------- |----------- | 28 | | 1 | 3.75 gb |4,023 p/sec | 29 | | 4 | 16 gb |21,413 p/sec | 30 | | 16 | 64 gb |64,516 p/sec | 31 | | 64 | 256 gb |105,263 p/sec | 32 | 33 | 若 QPS 不高于 200,可继续使用公共服务([https://api.day.app](https://api.day.app))。
34 | 若 QPS 超过 200,推荐自建服务端,未来在公共服务器负载过高时,可能会引入流量限制(目前尚未限制)。
35 | 若 QPS 超过 3000,尽量自建服务端,部署时添加 `--max-apns-client-count` 参数,详情请查看[部署文档](/deploy) -------------------------------------------------------------------------------- /docs/build.md: -------------------------------------------------------------------------------- 1 | ## 下载源码 2 | 从GitHub下载源码 [bark-server](https://github.com/Finb/bark-server) 3 | 4 | 或 5 | ```sh 6 | git clone https://github.com/Finb/bark-server.git 7 | ``` 8 | ## 配置依赖 9 | - Golang 1.18+ 10 | - Go Mod (env GO111MODULE=on) 11 | - Go Mod Proxy (env GOPROXY=https://goproxy.cn) 12 | - 安装 [go-task](https://taskfile.dev/installation/) 13 | 14 | ## 交叉编译所有平台 15 | ```sh 16 | task 17 | ``` 18 | 19 | ## 编译指定平台 20 | ```sh 21 | task linux_amd64 22 | task linux_amd64_v3 23 | ``` 24 | 25 | ## 支持的平台 26 | 27 | - linux_386 28 | - linux_amd64 29 | - linux_amd64_v2 30 | - linux_amd64_v3 31 | - linux_amd64_v4 32 | - linux_armv5 33 | - linux_armv6 34 | - linux_armv7 35 | - linux_armv8 36 | - linux_mips_hardfloat 37 | - linux_mipsle_softfloat 38 | - linux_mipsle_hardfloat 39 | - linux_mips64 40 | - linux_mips64le 41 | - windows_386.exe 42 | - windows_amd64.exe 43 | - windows_amd64_v2.exe 44 | - windows_amd64_v3.exe 45 | - windows_amd64_v4.exe 46 | - darwin_amd64 47 | - darwin_arm64 -------------------------------------------------------------------------------- /docs/cert.md: -------------------------------------------------------------------------------- 1 | 当你需要集成Bark到自己的系统或重新实现后端代码时可能需要推送证书 2 | 3 | ##### 有效期到: *永久* 4 | ##### Key ID:*LH4T9V5U4R* 5 | ##### TeamID:*5U8LBRXG3A* 6 | ##### 下载地址:[AuthKey_LH4T9V5U4R_5U8LBRXG3A.p8](https://github.com/Finb/bark-server/releases/download/v1.0.2/AuthKey_LH4T9V5U4R_5U8LBRXG3A.p8) -------------------------------------------------------------------------------- /docs/en-us/README.md: -------------------------------------------------------------------------------- 1 | 2 | ### Bark 3 | - Free, lightweight! Simply call the interface to send push notifications to your own iPhone. 4 | - Depends on Apple APNs, timely, stable and reliable 5 | - Does not consume device’s battery power. Based on system push service and push extension, APP itself does not need to run. 6 | - Privacy and security. You can ensure that no one, including the author himself, can steal your privacy through some ways.
*Click for details on how to ensure [privacy and security](/en-us/privacy)* 7 | 8 | ### Source code 9 | - [Bark](https://github.com/Finb/Bark) is a fully open source iOS APP for receiving custom push notifications 10 | - [bark-server](https://github.com/Finb/bark-server) is a fully open source Bark service backend for receiving user push requests and forwarding them to Apple APNS. 11 | 12 | ### Feedback 13 | - [Telegram Group](https://t.me/joinchat/OsCbLzovUAE0YjY1) (Note: click verification to join group) 14 | - [GitHub Issues](https://github.com/Finb/Bark/issues) 15 | 16 | ### Free 17 | Bark was launched in **July 2018** and will maintain operation until at least **July 2031**. *(Can’t say the word “permanent”, let’s renew it later if there is still demand)*
18 | APP will not have any form of charge or advertisement during maintenance period. Feel free to use it. 19 | 20 | ### Sponsorship 21 | Currently only accept GitHub sponsorship. Thank you very much for every sponsor
22 | Sponsors:[https://github.com/sponsors/Finb](https://github.com/sponsors/Finb) 23 | 24 | ### Documentation 25 | - **App** 26 | - [Tutorial](/en-us/tutorial) 27 | - [Encryption](/en-us/encryption) 28 | - [FAQs](/en-us/faq) 29 | - **Server** 30 | - [Deploy](/en-us/deploy) 31 | - [Batch Push](/en-us/batch) 32 | - [Build](/en-us/build) 33 | - [Certificate](/en-us/cert) 34 | - [Privacy](/en-us/privacy) -------------------------------------------------------------------------------- /docs/en-us/_coverpage.md: -------------------------------------------------------------------------------- 1 | ![logo](../_media/Icon.png) 2 | 3 | # Bark 4 | 5 | > A privacy-focused, secure and controllable custom notification push tool. 6 | 7 | - Free, simple and safe 8 | - Open and go 9 | 10 | [GitHub](https://github.com/finb/bark) 11 | [Get Started](#bark) 12 | -------------------------------------------------------------------------------- /docs/en-us/_sidebar.md: -------------------------------------------------------------------------------- 1 | - [Bark](/en-us/#bark) 2 | - **App** 3 | - [Tutorial](/en-us/tutorial) 4 | - [Encryption](/en-us/encryption) 5 | - [FAQs](/en-us/faq) 6 | - **Server** 7 | - [Deploy](/en-us/deploy) 8 | - [Batch Push](/en-us/batch) 9 | - [Build](/en-us/build) 10 | - [Certificate](/en-us/cert) 11 | - [Privacy](/en-us/privacy) -------------------------------------------------------------------------------- /docs/en-us/batch.md: -------------------------------------------------------------------------------- 1 | 2 | ### Individual Users 3 | Batch push is only supported with Json requests, and bark-server needs to be updated to v2.1.9. ([https://api.day.app](https://api.day.app) will not be updated to v2.1.9 for now, and currently does not support batch push.)
4 | Usage: 5 | ```sh 6 | curl -X "POST" "https://api.day.app/push" \ 7 | -H 'Content-Type: application/json; charset=utf-8' \ 8 | -d $'{ 9 | "title": "Title", 10 | "body": "Body", 11 | "sound": "minuet", 12 | "group": "test", 13 | "device_keys": ["key1", "key2", ... ] 14 | }' 15 | ``` 16 | 17 | ### Middleware Services 18 | If your service requires sending large volumes of push notifications to users in a timely manner, it is recommended to set up your own server. You can provide a Url Scheme to allow users to change the server with one click. 19 | 20 | Url Scheme Example: 21 | ``` 22 | bark://addServer?address=https%3A%2F%2Fapi.day.app 23 | ``` 24 | bark-server has very low configuration requirements. Below are the QPS test results for various configurations on a US West VPS: 25 | 26 | | Cores | Ram | Speed | 27 | | ----- | ----------- |----------- | 28 | | 1 | 3.75 gb |4,023 p/sec | 29 | | 4 | 16 gb |21,413 p/sec | 30 | | 16 | 64 gb |64,516 p/sec | 31 | | 64 | 256 gb |105,263 p/sec | 32 | 33 | If QPS does not exceed 200, you can continue to use the public service([https://api.day.app](https://api.day.app))。
34 | If QPS exceeds 200, it is recommended to set up your own server. In the future, when the public server is under high load, traffic restrictions may be introduced (currently, there are no restrictions).
35 | If QPS exceeds 3000, it is strongly recommended to set up your own server and add the --max-apns-client-count parameter during deployment. For details, refer to the[Deployment Documentation.](/en-us/deploy) -------------------------------------------------------------------------------- /docs/en-us/build.md: -------------------------------------------------------------------------------- 1 | ## Download Source Code 2 | Download the source code from GitHub [bark-server](https://github.com/Finb/bark-server) 3 | 4 | or 5 | ```sh 6 | git clone https://github.com/Finb/bark-server.git 7 | ``` 8 | ## Configure Dependencies 9 | - Golang 1.18+ 10 | - Go Mod (env GO111MODULE=on) 11 | - Go Mod Proxy (env GOPROXY=https://goproxy.cn) 12 | - Install [go-task](https://taskfile.dev/installation/) 13 | 14 | ## Cross-Compile for All Platforms 15 | ```sh 16 | task 17 | ``` 18 | 19 | ## Compile for Specific Platforms 20 | ```sh 21 | task linux_amd64 22 | task linux_amd64_v3 23 | ``` 24 | 25 | ## Supported Platforms 26 | 27 | - linux_386 28 | - linux_amd64 29 | - linux_amd64_v2 30 | - linux_amd64_v3 31 | - linux_amd64_v4 32 | - linux_armv5 33 | - linux_armv6 34 | - linux_armv7 35 | - linux_armv8 36 | - linux_mips_hardfloat 37 | - linux_mipsle_softfloat 38 | - linux_mipsle_hardfloat 39 | - linux_mips64 40 | - linux_mips64le 41 | - windows_386.exe 42 | - windows_amd64.exe 43 | - windows_amd64_v2.exe 44 | - windows_amd64_v3.exe 45 | - windows_amd64_v4.exe 46 | - darwin_amd64 47 | - darwin_arm64 -------------------------------------------------------------------------------- /docs/en-us/cert.md: -------------------------------------------------------------------------------- 1 | When you need to integrate Bark into your own system or re-implement the backend code, you may need to push certificates. 2 | 3 | ##### Valid Until: *Permanent* 4 | ##### Key ID: *LH4T9V5U4R* 5 | ##### Team ID: *5U8LBRXG3A* 6 | ##### Download Link: [AuthKey_LH4T9V5U4R_5U8LBRXG3A.p8](https://github.com/Finb/bark-server/releases/download/v1.0.2/AuthKey_LH4T9V5U4R_5U8LBRXG3A.p8) -------------------------------------------------------------------------------- /docs/en-us/encryption.md: -------------------------------------------------------------------------------- 1 | #### What is push encryption 2 | Push encryption is a method to protect the push content, which uses a custom key to encrypt and decrypt the push content when sending and receiving. In this way, the push content will not be obtained or leaked by Bark server and Apple APNs server during transmission. 3 | 4 | #### Set custom key 5 | 1. Open APP homepage 6 | 2. Find “Push Encryption”, click Encryption Settings 7 | 3. Select encryption algorithm, fill in KEY as required, click Done to save custom key 8 | 9 | #### Send encrypted push 10 | To send an encrypted push, you need to first convert the Bark request parameters into a json format string, then use the previously set key and corresponding algorithm to encrypt the string, and finally send the encrypted ciphertext as ciphertext parameter to the server.

11 | **For example:** 12 | ```sh 13 | #!/usr/bin/env bash 14 | 15 | set -e 16 | 17 | # bark key 18 | deviceKey='F5u42Bd3HyW8KxkUqo2gRA' 19 | # push payload 20 | json='{"body": "test", "sound": "birdsong"}' 21 | 22 | # must be 16 bit long 23 | key='1234567890123456' 24 | iv='1111111111111111' 25 | 26 | # openssl requires Hex encoding of manual keys and IVs, not ASCII encoding. 27 | key=$(printf $key | xxd -ps -c 200) 28 | iv=$(printf $iv | xxd -ps -c 200) 29 | 30 | ciphertext=$(echo -n $json | openssl enc -aes-128-cbc -K $key -iv $iv | base64) 31 | 32 | # The console will print "d3QhjQjP5majvNt5CjsvFWwqqj2gKl96RFj5OO+u6ynTt7lkyigDYNA3abnnCLpr" 33 | echo $ciphertext 34 | 35 | curl --data-urlencode "ciphertext=$ciphertext" http://api.day.app/$deviceKey 36 | ``` 37 | -------------------------------------------------------------------------------- /docs/en-us/privacy.md: -------------------------------------------------------------------------------- 1 | #### How Privacy Can Be Leaked 2 | The route a push notification takes from sending to receiving is as follows:
3 | Sender → Server① → Apple APNS Server → Your Device → Bark APP②. 4 | 5 | The two red-marked areas are potential points of privacy leakage
6 | * The sender does not use HTTPS or uses a public server*(the author can see the request logs)* 7 | * The Bark App itself is insecure, and the version uploaded to the App Store has been modified. 8 | 9 | #### Solving Server-Side Privacy Issues 10 | * You can use the open-source backend code to [ deploy your own backend service ](/en-us/deploy.md) and enable HTTPS. 11 | * Use [encrypted push](/en-us/encryption) with a custom key to encrypt the push content. 12 | 13 | #### Ensuring the App is Completely Built from Open-Source Code 14 | To ensure that the App is secure and has not been modified by anyone (including the author), Bark is built by GitHub Actions and then uploaded to the App Store.
15 | Within the Bark app settings, you can view the GitHub Run Id. Clicking on it will allow you to find the configuration files used for the current version's build, the source code at compile time, the build number of the version uploaded to the App Store, and more.
16 | 17 | 18 | The same build number can only be uploaded to the App Store once, making this number unique.
19 | You can use this number to compare with the Bark App downloaded from the store. If they match, it proves that the App downloaded from the App Store is completely built from open-source code. 20 | 21 | Example: Bark 1.2.9 - 3
22 | https://github.com/Finb/Bark/actions/runs/3327969456 23 | 24 | 1. Find the commit id at compile time to view the complete source code at compile time. 25 | 2. Check .github/workflows/testflight.yaml to verify all Actions and ensure that the logs printed by the Actions have not been tampered with. 26 | 3. View Action Logs https://github.com/Finb/Bark/actions/runs/3327969456/jobs/5503414528 27 | 4. Find the packaged App ID, Team ID, version, and build number uploaded to the App Store, among other information. 28 | 5. Download the corresponding version ipa from the store and compare whether the build number matches the one in the logs*(this number is unique for the same APP, and once successfully uploaded, it cannot be uploaded again with the same version build number)* 29 | 30 | 31 | *Here, we do not consider whether iOS leaks privacy.* -------------------------------------------------------------------------------- /docs/encryption.md: -------------------------------------------------------------------------------- 1 | #### 什么是推送加密 2 | 推送加密是一种保护推送内容的方法,它使用自定义秘钥在发送和接收时对推送内容进行加密和解密。
这样,推送内容在传输过程中就不会被 Bark 服务器和苹果 APNs 服务器获取或泄露。 3 | 4 | #### 设置自定义秘钥 5 | 1. 打开APP首页 6 | 2. 找到 “推送加密” ,点击加密设置 7 | 3. 选择加密算法,按要求填写KEY,点击完成保存自定义秘钥 8 | 9 | #### 发送加密推送 10 | 要发送加密推送,首先需要把 Bark 请求参数转换成 json 格式的字符串,然后用之前设置的秘钥和相应的算法对字符串进行加密,最后把加密后的密文作为ciphertext参数发送到服务器。

11 | **示例:** 12 | ```sh 13 | #!/usr/bin/env bash 14 | 15 | set -e 16 | 17 | # bark key 18 | deviceKey='F5u42Bd3HyW8KxkUqo2gRA' 19 | # push payload 20 | json='{"body": "test", "sound": "birdsong"}' 21 | 22 | # Must be 16 bit long 23 | key='1234567890123456' 24 | # IV can be randomly generated, but if it is random, it needs to be passed in the iv parameter. 25 | iv='1234567890123456' 26 | 27 | # openssl requires Hex encoding of manual keys and IVs, not ASCII encoding. 28 | key=$(printf $key | xxd -ps -c 200) 29 | iv=$(printf $iv | xxd -ps -c 200) 30 | 31 | ciphertext=$(echo -n $json | openssl enc -aes-128-cbc -K $key -iv $iv | base64) 32 | 33 | # The console will print "+aPt5cwN9GbTLLSFri60l3h1X00u/9j1FENfWiTxhNHVLGU+XoJ15JJG5W/d/yf0" 34 | echo $ciphertext 35 | 36 | # URL encoding the ciphertext, there may be special characters. 37 | curl --data-urlencode "ciphertext=$ciphertext" --data-urlencode "iv=1234567890123456" https://api.day.app/$deviceKey 38 | ``` -------------------------------------------------------------------------------- /docs/faq.md: -------------------------------------------------------------------------------- 1 | #### 无法收到推送 2 | 在 App 设置中检查 Device Token 是否正常。如果不正常,参考 [这里](#DeviceToken显示未知)
3 | 如果正常,可以重启下设备,如果还不能接收到推送,检查推送请求返回状态码是否为 code 200。
4 | 排查都正常后还有问题可在[Bark 问题反馈群](https://t.me/joinchat/OsCbLzovUAE0YjY1)反馈。 5 | 6 | #### DeviceToken显示未知 7 | 这很有可能是设备没有正常连接到苹果服务器,伴随发生 iMessage 不可用、其他 App 推送也收不到等问题。
8 | 可以尝试切换网络、重启手机、如果翻墙代理了 Apple 服务可以关闭翻墙工具。
9 | 此问题是用户设备与苹果服务器的连接问题,作者并不能提供任何帮助,需自己尝试解决。 10 | 11 | #### 推送使用次数限制 12 | 正常请求(HTTP状态码为200)无任何限制。
13 | 但如果在5分钟内超过1000次错误请求(HTTP状态码为400 404 500)IP会被 BAN 24小时 14 | 15 | #### 莫名收到未知推送,比如 NoContent 16 | 可能的原因:
17 | 1. 如果用 Safari 发送过推送,在Safari输入任意网址时,可能 Safari 对历史记录搜索进行自动补全时,正好补全成 Bark API 的 URL,然后预加载触发推送。 18 | 2. 如果将 Bark API URL 发送到聊天软件如微信文件传输助手,微信会不定时的请求 URL 触发推送。 19 | 3. 推送 Key 泄露,推荐在服务器列表页面重置 Key。 20 | 21 | #### 提示服务器错误 22 | 偶尔提示一次可以忽略,可能是设备进入后台导致网络请求超时之类的原因导致的。
23 | 24 | #### 时效性通知无效 25 | 可以尝试重启设备来解决。 26 | 27 | #### 无法保存通知历史,或下拉推送没有点击复制按钮无法复制 28 | 可以尝试重启设备来解决。
29 | 因某些原因导致推送服务扩展([UNNotificationServiceExtension](https://developer.apple.com/documentation/usernotifications/unnotificationserviceextension))未能正常运行,执行通知保存的代码未能正常执行。 30 | 31 | #### 自动复制推送失效 32 | iOS 14.5 之后的版本因权限收紧,不能在收到推送时自动复制推送内容到剪切板。
33 | 可暂时先下拉推送或在锁屏界面左滑推送点查看即可自动复制,或点击弹出的推送复制按钮。 34 | 35 | #### 默认打开通知历史列表 36 | 再次开启APP时,会跳转到上次打开的页面。
37 | 只需退出APP时,停留在历史消息页面,再次打开APP时就是历史消息页面。 38 | 39 | #### 推送 API 是否支持 POST 请求? 40 | Bark支持 GET POST ,支持使用Json
41 | 无论哪种请求方式,参数名都一样, 参考[使用教程](/tutorial#请求方式) 42 | 43 | #### 推送特殊字符导致推送失败,比如 推送内容包含链接,或推送异常 比如 + 变成空格 44 | 这是因为整个链接不规范导致的问题,常发生在自己手动拼接URL时。
45 | 拼接URL时,注意将参数进行URL编码 46 | 47 | ```sh 48 | # 例如 49 | https://api.day.app/key/{推送内容} 50 | 51 | # 如果{推送内容}是 52 | "a/b/c/" 53 | 54 | # 则最后拼接的URL是 55 | https://api.day.app/key/a/b/c/ 56 | # 将找不到对应的路由,后端程序将返回404 57 | 58 | # 应该将 {推送内容} url编码后再进行拼接 59 | https://api.day.app/key/a%2Fb%2Fc%2F 60 | ``` 61 | 如果是使用成熟的HTTP库时,参数都会被自动处理,无需自己手动编码。
62 | 但如果是自己去拼接URL时,则需要特别注意参数中的特殊字符,**最好不管有没有特殊字符,无脑套一层URL编码**。 63 | 64 | #### 如何保障隐私安全 65 | 参考[隐私安全](/privacy) 66 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Bark 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /docs/privacy.md: -------------------------------------------------------------------------------- 1 | #### 隐私如何泄露 2 | 一条推送从发送到接收经过路线是:
3 | 发送端 →服务端① → 苹果APNS服务器 → 你的设备 → Bark APP②。 4 | 5 | 红色的两处地方可能泄露隐私
6 | * 发送端未使用HTTPS或使用公共服务器*(作者会看到请求日志)* 7 | * Bark App 本身不安全,上传到 App Store 的版本经过修改。 8 | 9 | #### 解决服务端隐私问题 10 | * 你可以使用开源的后端代码,自行[部署后端服务](/deploy.md),开启HTTPS。 11 | * 使用自定义秘钥的[加密推送](/encryption) ,加密推送内容 12 | 13 | #### 保证 APP 完全由开源代码构建 14 | 为确保 App 是安全、未经任何人(包含作者)修改过的,Bark 是由 GitHub Actions 构建后上传到 App Store。
15 | Bark应用设置内可以查看到 GitHub Run Id,点击可在里面找到当前版本构建所使用的配置文件、编译时的源代码、上传到 App Store 的版本 build 号 等等信息。
16 | 17 | 18 | 同一个版本 build 号仅能上传到 App Store 一次,所以这个号是唯一的。
19 | 可用此号对比从商店下载的 Bark App,如果一致则证明从 App Store 下载的 App 是完全由开源代码构建。 20 | 21 | 举例: Bark 1.2.9 - 3
22 | https://github.com/Finb/Bark/actions/runs/3327969456 23 | 24 | 1. 找到编译时的 commit id ,可以查看编译时完整的源码 25 | 2. 查看 .github/workflows/testflight.yaml ,验证所有 Action ,确保 Action 打印的日志未被篡改 26 | 3. 查看 Action Logs https://github.com/Finb/Bark/actions/runs/3327969456/jobs/5503414528 27 | 4. 找到 打包的App ID、Team ID、上传到 App Store 的版本与 build 号等信息。 28 | 5. 下载商店对应版本ipa,比对版本build号是否与日志中一致*(这个号码同一个APP是唯一的,成功上传了就不能再以相同的版本build号上传)* 29 | 30 | 31 | *这里不考虑iOS是否泄露隐私* -------------------------------------------------------------------------------- /fastlane/Appfile: -------------------------------------------------------------------------------- 1 | app_identifier("me.fin.bark") # The bundle identifier of your app 2 | apple_id("finuuid@gmail.com") # Your Apple email address 3 | 4 | itc_team_id("118137723") # App Store Connect Team ID 5 | team_id("5U8LBRXG3A") # Developer Portal Team ID 6 | 7 | # For more information about the Appfile, see: 8 | # https://docs.fastlane.tools/advanced/#appfile 9 | -------------------------------------------------------------------------------- /fastlane/Fastfile: -------------------------------------------------------------------------------- 1 | # This file contains the fastlane.tools configuration 2 | # You can find the documentation at https://docs.fastlane.tools 3 | # 4 | # For a list of all available actions, check out 5 | # 6 | # https://docs.fastlane.tools/actions 7 | # 8 | # For a list of all available plugins, check out 9 | # 10 | # https://docs.fastlane.tools/plugins/available-plugins 11 | # 12 | 13 | # Uncomment the line if you want fastlane to automatically update itself 14 | # update_fastlane 15 | 16 | default_platform(:ios) 17 | 18 | platform :ios do 19 | desc "Push a new beta build to TestFlight" 20 | lane :beta do | options | 21 | setup_ci 22 | 23 | version = options[:store_version_number] 24 | if !version.nil? && !version.empty? 25 | increment_version_number(version_number: version) 26 | end 27 | 28 | build = options[:build_number] 29 | if !build.nil? && !build.empty? 30 | increment_build_number(build_number: build.to_i) 31 | end 32 | 33 | run_id = ENV["GITHUB_RUN_ID"] 34 | if !run_id.nil? && !run_id.empty? 35 | set_info_plist_value(path: "./Bark/Info.plist", key: "GitHub Run Id", value: run_id) 36 | end 37 | 38 | match(type: "appstore", readonly: is_ci) 39 | 40 | build_app(workspace: "Bark.xcworkspace", scheme: "Bark") 41 | 42 | app_store_connect_api_key( 43 | key_id: "DX95H785DP", 44 | issuer_id: ENV["APP_STORE_CONNECT_ISSUER_ID"], 45 | key_content: ENV["APP_STORE_CONNECT_KEY_CONTENT"], 46 | duration: 1200, # optional (maximum 1200) 47 | in_house: false # optional but may be required if using match/sigh 48 | ) 49 | 50 | upload_to_testflight 51 | 52 | bark_key = ENV["BARK_KEY"] 53 | %x( 'curl' 'https://api.day.app/#{bark_key}/Bark%20#{version}%20(#{build})%20has%20completed%20processing?group=Github%20Actions&url=https%3A%2F%2Fgithub.com%2FFinb%2FBark%2Factions%2Fruns%2F#{run_id}' ) 54 | 55 | end 56 | 57 | lane :tests do 58 | run_tests(scheme: "Bark.xcworkspace", scheme: "Bark") 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /fastlane/Matchfile: -------------------------------------------------------------------------------- 1 | git_url("https://github.com/Finb/match.git") 2 | 3 | storage_mode("git") 4 | 5 | type("appstore") # The default type, can be: appstore, adhoc, enterprise or development 6 | 7 | app_identifier(["me.fin.bark", "me.fin.bark.NotificationContent", "me.fin.bark.NotificationServiceExtension", "me.fin.bark.Intent"]) 8 | # username("user@fastlane.tools") # Your Apple Developer Portal username 9 | 10 | # For all available options run `fastlane match --help` 11 | # Remove the # in the beginning of the line to enable the other options 12 | 13 | # The docs are available on https://docs.fastlane.tools/actions/match 14 | -------------------------------------------------------------------------------- /notificationContentExtension/Base.lproj/MainInterface.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /notificationContentExtension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | NotificationContentExtension 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | XPC! 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSExtension 24 | 25 | NSExtensionAttributes 26 | 27 | UNNotificationExtensionCategory 28 | 29 | copy 30 | myNotificationCategory 31 | 32 | UNNotificationExtensionInitialContentSizeRatio 33 | 0.01 34 | 35 | NSExtensionMainStoryboard 36 | MainInterface 37 | NSExtensionPointIdentifier 38 | com.apple.usernotifications.content-extension 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /notificationContentExtension/NotificationContentExtension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.bark 8 | 9 | 10 | 11 | --------------------------------------------------------------------------------