Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CIS-371] LLC for macOS #1132

Merged
merged 16 commits into from
Jun 3, 2021
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions .github/workflows/macos-checks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: macOS checks

on:
push:
branches:
- main
pull_request:
branches:
- main
release:
types:
- created

env:
HOMEBREW_NO_INSTALL_CLEANUP=1: 1 # Disable cleanup for homebrew, we don't need it on CI
DEVELOPER_DIR: /Applications/Xcode_12.4.app/Contents/Developer # Use Xcode 12.4

jobs:
build-and-test-release-macos:
name: Run Tests macOS (Release)
runs-on: macos-latest
steps:
- name: Install Bot SSH Key
uses: webfactory/ssh-agent@v0.4.1
with:
ssh-private-key: ${{ secrets.BOT_SSH_PRIVATE_KEY }}
- uses: actions/checkout@v1
- name: Cache RubyGems
uses: actions/cache@v2
id: rubygem-cache
with:
path: vendor/bundle
key: ${{ runner.os }}-gem-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: ${{ runner.os }}-gem-
- name: Cache Mint
uses: actions/cache@v2
id: mint-cache
with:
path: /usr/local/lib/mint
key: ${{ runner.os }}-mint-${{ hashFiles('./Mintfile') }}
restore-keys: ${{ runner.os }}-mint-
- name: Run bootstrap.sh
run: ./bootstrap.sh
- name: Run Tests (Release)
env:
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
run: bundle exec fastlane test_release_macos

build-and-test-debug-macos:
name: Run Tests macOS (Debug)
runs-on: macos-latest
steps:
- name: Install Bot SSH Key
uses: webfactory/ssh-agent@v0.4.1
with:
ssh-private-key: ${{ secrets.BOT_SSH_PRIVATE_KEY }}
- uses: actions/checkout@v1
- name: Cache RubyGems
uses: actions/cache@v2
id: rubygem-cache
with:
path: vendor/bundle
key: ${{ runner.os }}-gem-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: ${{ runner.os }}-gem-
- name: Cache Mint
uses: actions/cache@v2
id: mint-cache
with:
path: /usr/local/lib/mint
key: ${{ runner.os }}-mint-${{ hashFiles('./Mintfile') }}
restore-keys: ${{ runner.os }}-mint-
- name: Run bootstrap.sh
run: ./bootstrap.sh
- name: Run Tests (Release)
env:
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
run: bundle exec fastlane test_debug_macos
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Add `areTypingEventsEnabled`, `areReactionsEnabled`, `areRepliesEnabled`, `areReadEventsEnabled`, `areUploadsEnabled` to `ChatChannelListController` [#1085](https://github.com/GetStream/stream-chat-swift/pull/1085)
- Add `ImageCDN` protocol to improve work with image cache and thumbnails [#1111](https://github.com/GetStream/stream-chat-swift/pull/1111)
- Add missing APIs `open` of `ComposerVC`. Including the delegate implementations and showing the suggestions as a child view controller. [#1140](https://github.com/GetStream/stream-chat-swift/pull/1140)
- Add possibility to build the StreamChat framework on macOS
[#1132](https://github.com/GetStream/stream-chat-swift/pull/1132)
dmigach marked this conversation as resolved.
Show resolved Hide resolved

### 🐞 Fixed
- Fix background color of message list in dark mode [#1109](https://github.com/GetStream/stream-chat-swift/pull/1109)
Expand Down
1 change: 1 addition & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ var streamChatSourcesExcluded: [String] { [
"Database/DTOs/DeviceDTO_Tests.swift",
"Database/DatabaseContainer_Tests.swift",
"Config/TokenProvider_Tests.swift",
"WebSocketClient/BackgroundTaskScheduler_Tests.swift",
"WebSocketClient/WebSocketClient_Mock.swift",
"WebSocketClient/EventMiddlewares/ChannelTruncatedEventMiddleware_Tests.swift",
"WebSocketClient/EventMiddlewares/MemberEventMiddleware_Tests.swift",
Expand Down
13 changes: 8 additions & 5 deletions Sources/StreamChat/APIClient/APIClient_Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ extension URLSessionConfiguration {
// simply compares the pointers.
@available(iOS, deprecated: 12.0, message: "Remove this workaround when dropping iOS 12 support.")
func isTestEqual(to otherConfiguration: URLSessionConfiguration) -> Bool {
identifier == otherConfiguration.identifier
let commonEquatability = identifier == otherConfiguration.identifier
&& requestCachePolicy == otherConfiguration.requestCachePolicy
&& timeoutIntervalForRequest == otherConfiguration.timeoutIntervalForRequest
&& timeoutIntervalForResource == otherConfiguration.timeoutIntervalForResource
Expand All @@ -333,16 +333,19 @@ extension URLSessionConfiguration {
&& urlCredentialStorage == otherConfiguration.urlCredentialStorage
&& urlCache == otherConfiguration.urlCache
&& shouldUseExtendedBackgroundIdleMode == otherConfiguration.shouldUseExtendedBackgroundIdleMode
// && protocolClasses == otherConfiguration.protocolClasses
&& multipathServiceType == otherConfiguration.multipathServiceType
&& waitsForConnectivity == otherConfiguration.waitsForConnectivity
&& isDiscretionary == otherConfiguration.isDiscretionary
&& sharedContainerIdentifier == otherConfiguration.sharedContainerIdentifier
&& sessionSendsLaunchEvents == otherConfiguration.sessionSendsLaunchEvents
// && connectionProxyDictionary == otherConfiguration.connectionProxyDictionary
&& waitsForConnectivity == otherConfiguration.waitsForConnectivity
&& isDiscretionary == otherConfiguration.isDiscretionary
&& sharedContainerIdentifier == otherConfiguration.sharedContainerIdentifier

#if os(iOS)
return commonEquatability
&& multipathServiceType == otherConfiguration.multipathServiceType
&& sessionSendsLaunchEvents == otherConfiguration.sessionSendsLaunchEvents
#endif
dmigach marked this conversation as resolved.
Show resolved Hide resolved

return commonEquatability
}
}
5 changes: 5 additions & 0 deletions Sources/StreamChat/Config/ChatClientConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,13 @@ public struct ChatClientConfig {

/// The folder `ChatClient` uses to store its local cache files.
public var localStorageFolderURL: URL? = {
#if os(macOS)
let urls = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
return urls.first.map { $0.appendingPathComponent("io.getstream.StreamChat") }
#else
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return urls.first
#endif
}()

/// The datacenter `ChatClient` uses for connecting.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//

import Combine
import UIKit
import Foundation

@available(iOS 13, *)
extension _ChatChannelController {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//

import Combine
import UIKit
import Foundation

@available(iOS 13, *)
extension _ChatChannelListController {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//

import Combine
import UIKit
import Foundation

@available(iOS 13, *)
extension _ChatChannelWatcherListController {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//

import Combine
import UIKit
import Foundation

@available(iOS 13, *)
extension _ChatConnectionController {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//

import Combine
import UIKit
import Foundation

@available(iOS 13, *)
extension _CurrentChatUserController {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,17 @@ final class ListChange_Tests: XCTestCase {

func test_fieldChange() {
let insertedItem: MemberPayload<NoExtraData> = .dummy()
let insertedAt = IndexPath(row: 1, section: 1)
let insertedAt = IndexPath(item: 1, section: 1)

let updatedItem: MemberPayload<NoExtraData> = .dummy()
let updatedAt = IndexPath(row: 2, section: 3)
let updatedAt = IndexPath(item: 2, section: 3)

let removedItem: MemberPayload<NoExtraData> = .dummy()
let removedAt = IndexPath(row: 3, section: 4)
let removedAt = IndexPath(item: 3, section: 4)

let movedItem: MemberPayload<NoExtraData> = .dummy()
let movedFrom = IndexPath(row: 5, section: 6)
let movedTo = IndexPath(row: 7, section: 8)
let movedFrom = IndexPath(item: 5, section: 6)
let movedTo = IndexPath(item: 7, section: 8)

let path = \MemberPayload<NoExtraData>.user.id

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//

import Combine
import UIKit
import Foundation

@available(iOS 13, *)
extension _ChatChannelMemberController {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//

import Combine
import UIKit
import Foundation

@available(iOS 13, *)
extension _ChatChannelMemberListController {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//

import Combine
import UIKit
import Foundation

@available(iOS 13, *)
extension _ChatMessageController {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//

import Combine
import UIKit
import Foundation

@available(iOS 13, *)
extension _ChatUserController {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//

import Combine
import UIKit
import Foundation

@available(iOS 13, *)
extension _ChatUserListController {
Expand Down
2 changes: 1 addition & 1 deletion Sources/StreamChat/Utils/SystemEnvironment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Copyright © 2021 Stream.io Inc. All rights reserved.
//

import UIKit
import Foundation

enum SystemEnvironment {
static let systemName = UIDevice.current.systemName + UIDevice.current.systemVersion
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//
// Copyright © 2021 Stream.io Inc. All rights reserved.
//

import Foundation

/// Object responsible for platform specific handling of background tasks
protocol BackgroundTaskScheduler {
/// It's your responsibility to finish previously running task.
///
/// Returns: `false` if system forbid background task, `true` otherwise
func beginTask(expirationHandler: (() -> Void)?) -> Bool
func endTask()
func startListeningForAppStateUpdates(
onEnteringBackground: @escaping () -> Void,
onEnteringForeground: @escaping () -> Void
)
}

#if os(iOS)
import UIKit

class IOSBackgroundTaskScheduler: BackgroundTaskScheduler {
private lazy var app: UIApplication? = {
// We can't use `UIApplication.shared` directly because there's no way to convince the compiler
// this code is accessible only for non-extension executables.
UIApplication.value(forKeyPath: "sharedApplication") as? UIApplication
}()

/// The identifier of the currently running background task. `nil` if no background task is running.
private var activeBackgroundTask: UIBackgroundTaskIdentifier?

func beginTask(expirationHandler: (() -> Void)?) -> Bool {
activeBackgroundTask = app?.beginBackgroundTask { [weak self] in
expirationHandler?()
self?.endTask()
}
return activeBackgroundTask != .invalid
}

func endTask() {
if let activeTask = activeBackgroundTask {
app?.endBackgroundTask(activeTask)
activeBackgroundTask = nil
}
}

private var onEnteringBackground: () -> Void = {}
private var onEnteringForeground: () -> Void = {}

func startListeningForAppStateUpdates(
onEnteringBackground: @escaping () -> Void,
onEnteringForeground: @escaping () -> Void
) {
self.onEnteringForeground = onEnteringForeground
self.onEnteringBackground = onEnteringBackground

NotificationCenter.default.addObserver(
self,
selector: #selector(handleAppDidEnterBackground),
name: UIApplication.didEnterBackgroundNotification,
object: nil
)

NotificationCenter.default.addObserver(
self,
selector: #selector(handleAppDidBecomeActive),
name: UIApplication.didBecomeActiveNotification,
object: nil
)
}

@objc private func handleAppDidEnterBackground() {
onEnteringBackground()
}

@objc private func handleAppDidBecomeActive() {
onEnteringForeground()
}
}

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// Copyright © 2021 Stream.io Inc. All rights reserved.
//

@testable import StreamChat
import XCTest

#if os(iOS)
class IOSBackgroundTaskScheduler_Tests: XCTestCase {
func test_notifications_foreground() {
// Arrange: Subscribe for app notifications
let scheduler = IOSBackgroundTaskScheduler()
var calledBackground = false
var calledForeground = false
scheduler.startListeningForAppStateUpdates(
onEnteringBackground: { calledBackground = true },
onEnteringForeground: { calledForeground = true }
)

// Act: Send notification
NotificationCenter.default.post(name: UIApplication.didBecomeActiveNotification, object: nil)

// Assert: Only intended closure is called
XCTAssertTrue(calledForeground)
XCTAssertFalse(calledBackground)
}

func test_notifications_background() {
// Arrange: Subscribe for app notifications
let scheduler = IOSBackgroundTaskScheduler()
var calledBackground = false
var calledForeground = false
scheduler.startListeningForAppStateUpdates(
onEnteringBackground: { calledBackground = true },
onEnteringForeground: { calledForeground = true }
)

// Act: Send notification
NotificationCenter.default.post(name: UIApplication.didEnterBackgroundNotification, object: nil)

// Assert: Only intended closure is called
XCTAssertFalse(calledForeground)
XCTAssertTrue(calledBackground)
}
}
#endif
Loading