Skip to content

Commit

Permalink
Merge pull request #1221 from TortugaPower/watch-remoteplay
Browse files Browse the repository at this point in the history
Add support for stand alone playback for the watch app
  • Loading branch information
GianniCarlo authored Dec 10, 2024
2 parents 5fe537b + 2412d5a commit 158284e
Show file tree
Hide file tree
Showing 101 changed files with 3,826 additions and 293 deletions.
148 changes: 138 additions & 10 deletions BookPlayer.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion BookPlayer/Base.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
"ok_button" = "OK";
"siri_alert_description" = "Siri Shortcuts are available on iOS 12 and above";
"support_bookplayer_title" = "Support BookPlayer";
"support_bookplayer_description" = "Get BookPlayer Pro to support future development and get extra themes, app icons and cloud sync";
"support_bookplayer_description" = "Support future development and get extra themes, app icons, cloud sync and stand-alone playback on the Apple Watch";
"learn_more_title" = "LEARN MORE";
"settings_appearance_title" = "Appearance";
"settings_theme_title" = "Theme";
Expand Down Expand Up @@ -321,3 +321,4 @@ We're working hard on providing a seamless experience, if possible, please conta
"more_title" = "More";
"repeat_turn_on_title" = "Turn on Repeat for this book";
"repeat_turn_off_title" = "Turn off Repeat for this book";
"benefits_watchapp_description" = "Stream or download your books and listen on the go without your phone.";
10 changes: 6 additions & 4 deletions BookPlayer/Player/PlayerLoaderService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
// Copyright © 2024 Tortuga Power. All rights reserved.
//

import BookPlayerKit
#if os(watchOS)
import BookPlayerWatchKit
#else
import BookPlayerKit
#endif
import Foundation

final class PlayerLoaderService: @unchecked Sendable {
Expand Down Expand Up @@ -68,9 +72,7 @@ final class PlayerLoaderService: @unchecked Sendable {
playerManager.load(item, autoplay: autoplay)

if recordAsLastBook {
await MainActor.run {
libraryService.setLibraryLastBook(with: item.relativePath)
}
libraryService.setLibraryLastBook(with: item.relativePath)
}
}
}
6 changes: 5 additions & 1 deletion BookPlayer/Player/PlayerManagerProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
// Copyright © 2024 Tortuga Power. All rights reserved.
//

import BookPlayerKit
#if os(watchOS)
import BookPlayerWatchKit
#else
import BookPlayerKit
#endif
import Combine
import Foundation

Expand Down
19 changes: 13 additions & 6 deletions BookPlayer/Player/SleepTimer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@
// Copyright © 2018 Florian Pichler.
//

import BookPlayerKit
import Combine
import Foundation
import IntentsUI
import UIKit

#if os(watchOS)
import BookPlayerWatchKit
#else
import BookPlayerKit
import IntentsUI
#endif

/// Available sleep timer states
enum SleepTimerState: Equatable {
case off
Expand Down Expand Up @@ -53,7 +58,7 @@ final class SleepTimer {
600.0,
900.0,
1800.0,
3600.0
3600.0,
]

/// Publisher when the countdown timer reaches the defined threshold
Expand Down Expand Up @@ -88,8 +93,10 @@ final class SleepTimer {
let intent = SleepTimerIntent()
intent.option = option

let interaction = INInteraction(intent: intent, response: nil)
interaction.donate(completion: nil)
#if os(iOS)
let interaction = INInteraction(intent: intent, response: nil)
interaction.donate(completion: nil)
#endif
}

/// Periodic function used for the `countdown` case of ``SleepTimerState``
Expand All @@ -116,7 +123,7 @@ final class SleepTimer {
}

// MARK: Public methods

public func setTimer(_ newState: SleepTimerState) {
/// Always cancel any ongoing timer
reset()
Expand Down
6 changes: 5 additions & 1 deletion BookPlayer/Player/SpeedService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
// Copyright © 2021 Tortuga Power. All rights reserved.
//

import BookPlayerKit
#if os(watchOS)
import BookPlayerWatchKit
#else
import BookPlayerKit
#endif
import Combine
import Foundation

Expand Down
21 changes: 16 additions & 5 deletions BookPlayer/Player/WidgetReloadService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@
//

import Foundation
import BookPlayerKit
import WidgetKit

#if os(watchOS)
import BookPlayerWatchKit
#else
import BookPlayerKit
#endif

protocol WidgetReloadServiceProtocol {
/// Reload all the registered widgets
func reloadAllWidgets()
Expand All @@ -31,15 +36,19 @@ class WidgetReloadService: WidgetReloadServiceProtocol {
$0.cancel()
})
referenceWorkItems = [:]
WidgetCenter.shared.reloadAllTimelines()
if #available(watchOS 9.0, *) {
WidgetCenter.shared.reloadAllTimelines()
}
}

func reloadWidget(_ type: Constants.Widgets) {
let referenceWorkItem = referenceWorkItems[type]

referenceWorkItem?.cancel()

WidgetCenter.shared.reloadTimelines(ofKind: type.rawValue)
if #available(watchOS 9.0, *) {
WidgetCenter.shared.reloadTimelines(ofKind: type.rawValue)
}
}

func scheduleWidgetReload(of type: Constants.Widgets) {
Expand All @@ -48,9 +57,11 @@ class WidgetReloadService: WidgetReloadServiceProtocol {
referenceWorkItem?.cancel()

let workItem = DispatchWorkItem {
WidgetCenter.shared.reloadTimelines(ofKind: type.rawValue)
if #available(watchOS 9.0, *) {
WidgetCenter.shared.reloadTimelines(ofKind: type.rawValue)
}
}

referenceWorkItems[type] = workItem

DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(5), execute: workItem)
Expand Down
34 changes: 23 additions & 11 deletions BookPlayer/Profile/Login Screen/LoginViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ class LoginViewController: UIViewController {
return stackView
}()

private lazy var watchAppBenefitStackView: UIStackView = {
let stackView = LoginBenefitView(
title: "Apple Watch (Beta)",
description: "benefits_watchapp_description".localized,
systemName: "applewatch.radiowaves.left.and.right",
imageAlpha: 0.5
)
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()

private lazy var cosmeticBenefitStackView: UIStackView = {
let stackView = LoginBenefitView(
title: "benefits_themesicons_title".localized,
Expand Down Expand Up @@ -66,7 +77,6 @@ class LoginViewController: UIViewController {
disclaimers: [
"benefits_disclaimer_account_description".localized,
"benefits_disclaimer_subscription_description".localized,
"benefits_disclaimer_watch_description".localized
]
)
stackView.translatesAutoresizingMaskIntoConstraints = false
Expand Down Expand Up @@ -115,8 +125,8 @@ class LoginViewController: UIViewController {
view.addSubview(scrollView)
scrollView.addSubview(contentView)
contentView.addSubview(cloudBenefitStackView)
contentView.addSubview(watchAppBenefitStackView)
contentView.addSubview(cosmeticBenefitStackView)
contentView.addSubview(supportBenefitStackView)
contentView.addSubview(disclaimerStackView)
}

Expand Down Expand Up @@ -145,19 +155,21 @@ class LoginViewController: UIViewController {
cloudBenefitStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: Spacing.M),
cloudBenefitStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
cloudBenefitStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -Spacing.M),
cosmeticBenefitStackView.topAnchor.constraint(equalTo: cloudBenefitStackView.bottomAnchor, constant: 30),
cosmeticBenefitStackView.leadingAnchor.constraint(equalTo: cloudBenefitStackView.leadingAnchor),
cosmeticBenefitStackView.trailingAnchor.constraint(equalTo: cloudBenefitStackView.trailingAnchor),
supportBenefitStackView.topAnchor.constraint(equalTo: cosmeticBenefitStackView.bottomAnchor, constant: 30),
supportBenefitStackView.leadingAnchor.constraint(equalTo: cosmeticBenefitStackView.leadingAnchor),
supportBenefitStackView.trailingAnchor.constraint(equalTo: cosmeticBenefitStackView.trailingAnchor),
watchAppBenefitStackView.topAnchor.constraint(equalTo: cloudBenefitStackView.bottomAnchor, constant: 30),
watchAppBenefitStackView.leadingAnchor.constraint(equalTo: cloudBenefitStackView.leadingAnchor),
watchAppBenefitStackView.trailingAnchor.constraint(equalTo: cloudBenefitStackView.trailingAnchor),

cosmeticBenefitStackView.topAnchor.constraint(equalTo: watchAppBenefitStackView.bottomAnchor, constant: 30),
cosmeticBenefitStackView.leadingAnchor.constraint(equalTo: watchAppBenefitStackView.leadingAnchor),
cosmeticBenefitStackView.trailingAnchor.constraint(equalTo: watchAppBenefitStackView.trailingAnchor),

// setup disclaimer
disclaimerStackView.topAnchor.constraint(
greaterThanOrEqualTo: supportBenefitStackView.bottomAnchor,
greaterThanOrEqualTo: cosmeticBenefitStackView.bottomAnchor,
constant: 45
),
disclaimerStackView.leadingAnchor.constraint(equalTo: supportBenefitStackView.leadingAnchor, constant: Spacing.M),
disclaimerStackView.trailingAnchor.constraint(equalTo: supportBenefitStackView.trailingAnchor),
disclaimerStackView.leadingAnchor.constraint(equalTo: cosmeticBenefitStackView.leadingAnchor, constant: Spacing.M),
disclaimerStackView.trailingAnchor.constraint(equalTo: cosmeticBenefitStackView.trailingAnchor),
disclaimerStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -Spacing.L),
])
}
Expand Down
6 changes: 5 additions & 1 deletion BookPlayer/Services/UserActivityManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
// Copyright © 2018 Tortuga Power. All rights reserved.
//

import BookPlayerKit
#if os(watchOS)
import BookPlayerWatchKit
#else
import BookPlayerKit
#endif
import Foundation
import Intents

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
Expand All @@ -21,27 +21,24 @@
<rect key="frame" x="0.0" y="0.0" width="391" height="149"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" alpha="0.5" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icloud.and.arrow.up.fill" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="q8b-g4-bTO">
<rect key="frame" x="16" y="48.5" width="70" height="50"/>
<imageView userInteractionEnabled="NO" alpha="0.5" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="applewatch.radiowaves.left.and.right" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="q8b-g4-bTO">
<rect key="frame" x="16" y="68" width="70" height="50"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="a71-tI-vwv"/>
<constraint firstAttribute="width" constant="70" id="zuh-0P-o2j"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Support BookPlayer" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rpT-kz-YBF" customClass="LocalizableLabel" customModule="BookPlayer" customModuleProvider="target">
<rect key="frame" x="102" y="24" width="265" height="21"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="BookPlayer Pro" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rpT-kz-YBF">
<rect key="frame" x="102" y="44" width="265" height="21"/>
<constraints>
<constraint firstAttribute="height" constant="21" id="7qM-If-ztF"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.13728347420692444" green="0.13718283176422119" blue="0.14117720723152161" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
<nil key="highlightedColor"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="localizedKey" value="support_bookplayer_title"/>
</userDefinedRuntimeAttributes>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Get BookPlayer Pro to support future development and get extra themes, app icons and cloud sync" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" minimumScaleFactor="0.80000000000000004" translatesAutoresizingMaskIntoConstraints="NO" id="FWO-08-PTC" customClass="LocalizableLabel" customModule="BookPlayer" customModuleProvider="target">
<rect key="frame" x="102" y="48" width="265" height="47"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Support future development and get extra themes, app icons, cloud sync and stand-alone playback on the Apple Watch" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" minimumScaleFactor="0.80000000000000004" translatesAutoresizingMaskIntoConstraints="NO" id="FWO-08-PTC" customClass="LocalizableLabel" customModule="BookPlayer" customModuleProvider="target">
<rect key="frame" x="102" y="68" width="265" height="27"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<color key="textColor" red="0.60795658826828003" green="0.61154496669769287" blue="0.6235319972038269" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
<nil key="highlightedColor"/>
Expand Down Expand Up @@ -91,6 +88,6 @@
</view>
</objects>
<resources>
<image name="icloud.and.arrow.up.fill" catalog="system" width="128" height="108"/>
<image name="applewatch.radiowaves.left.and.right" catalog="system" width="128" height="87"/>
</resources>
</document>
Loading

0 comments on commit 158284e

Please sign in to comment.