Merge pull request #1160 from omnivore-app/feature/text-to-speech-reader-shortcut

Text to Speech Reader Shortcut
This commit is contained in:
Jackson Harper 2022-09-02 13:21:47 +08:00 committed by GitHub
commit 7cba83d13e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 93 additions and 4 deletions

View file

@ -18,6 +18,7 @@ public struct MiniPlayer: View {
@State var expanded = false
@State var offset: CGFloat = 0
@State var showVoiceSheet = false
@Namespace private var animation
let minExpandedHeight = UIScreen.main.bounds.height / 3
@ -40,9 +41,9 @@ public struct MiniPlayer: View {
action: {
switch audioSession.state {
case .playing:
audioSession.pause()
_ = audioSession.pause()
case .paused:
audioSession.unpause()
_ = audioSession.unpause()
default:
break
}
@ -102,6 +103,15 @@ public struct MiniPlayer: View {
)
}
func viewArticle() {
if let item = audioSession.item {
NSNotification.pushReaderItem(objectID: item.objectID)
withAnimation(.easeIn(duration: 0.1)) {
expanded = false
}
}
}
// swiftlint:disable:next function_body_length
func playerContent(_ item: LinkedItem) -> some View {
GeometryReader { geom in
@ -153,7 +163,6 @@ public struct MiniPlayer: View {
playPauseButtonItem
.frame(width: 28, height: 28)
.matchedGeometryEffect(id: "PlayPauseButton", in: animation)
stopButton
.frame(width: 28, height: 28)
@ -170,6 +179,9 @@ public struct MiniPlayer: View {
.foregroundColor(.appGrayTextContrast)
.frame(maxWidth: .infinity, alignment: expanded ? .center : .leading)
.matchedGeometryEffect(id: "ArticleTitle", in: animation)
.onTapGesture {
viewArticle()
}
HStack {
Spacer()
@ -235,6 +247,22 @@ public struct MiniPlayer: View {
}
HStack {
Menu {
Button("1.0×", action: {})
Button("1.2×", action: {})
Button("1.5×", action: {})
Button("1.7×", action: {})
Button("2.0×", action: {})
} label: {
VStack {
Text("1.0×")
.font(.appCallout)
.lineLimit(0)
}
.contentShape(Rectangle())
}
.padding(8)
Button(
action: { self.audioSession.skipBackwards(seconds: 30) },
label: {
@ -246,7 +274,6 @@ public struct MiniPlayer: View {
playPauseButtonItem
.frame(width: 64, height: 64)
.padding(32)
.matchedGeometryEffect(id: "PlayPauseButton", in: animation)
Button(
action: { self.audioSession.skipForward(seconds: 30) },
@ -255,6 +282,19 @@ public struct MiniPlayer: View {
.font(.appTitleTwo)
}
)
Menu {
Button("View Article", action: { viewArticle() })
Button("Change Voice", action: { showVoiceSheet = true })
} label: {
VStack {
Image(systemName: "ellipsis")
.font(.appCallout)
.frame(width: 20, height: 20)
}
.contentShape(Rectangle())
}
.padding(8)
}
}
}
@ -266,6 +306,8 @@ public struct MiniPlayer: View {
)
.onTapGesture {
withAnimation(.easeIn(duration: 0.08)) { expanded = true }
}.sheet(isPresented: $showVoiceSheet) {
changeVoiceView
}
}
}
@ -287,6 +329,29 @@ public struct MiniPlayer: View {
}
}
var changeVoiceView: some View {
NavigationView {
VStack {
List {
ForEach(["Jenny", "Guy"], id: \.self) { name in
Button(action: {}) {
Text(name)
}
.buttonStyle(PlainButtonStyle())
}
}
.padding(.top, 32)
.listStyle(.plain)
Spacer()
}
.navigationBarTitle("Change Voice")
.navigationBarTitleDisplayMode(.inline)
.navigationBarItems(leading: Button(action: { self.showVoiceSheet = false }) {
Image(systemName: "chevron.backward")
})
}
}
func onDragChanged(value: DragGesture.Value) {
if value.translation.height > 0, expanded {
offset = value.translation.height

View file

@ -1,3 +1,4 @@
import CoreData
import Models
import Services
import SwiftUI
@ -112,6 +113,11 @@ import Views
viewModel.pushFeedItem(item: linkedItem)
viewModel.selectedLinkItem = linkedItem.objectID
}
.onReceive(NSNotification.pushReaderItemPublisher) { notification in
if let objectID = notification.userInfo?["objectID"] as? NSManagedObjectID {
viewModel.handleReaderItemNotification(objectID: objectID)
}
}
.onOpenURL { url in
withoutAnimation {
viewModel.linkRequest = nil

View file

@ -34,6 +34,10 @@ import Views
from: Date(timeIntervalSinceReferenceDate: 0)
)
func handleReaderItemNotification(objectID: NSManagedObjectID) {
selectedLinkItem = objectID
}
var cursor: String?
// These are used to make sure we handle search result

View file

@ -1,8 +1,10 @@
import CoreData
import Foundation
import Models
public extension NSNotification {
static let PushJSONArticle = Notification.Name("PushJSONArticle")
static let PushReaderItem = Notification.Name("PushReaderItem")
static let OperationSuccess = Notification.Name("OperationSuccess")
static let OperationFailure = Notification.Name("OperationFailure")
static let ReaderSettingsChanged = Notification.Name("ReaderSettingsChanged")
@ -11,6 +13,10 @@ public extension NSNotification {
NotificationCenter.default.publisher(for: PushJSONArticle)
}
static var pushReaderItemPublisher: NotificationCenter.Publisher {
NotificationCenter.default.publisher(for: PushReaderItem)
}
static var operationSuccessPublisher: NotificationCenter.Publisher {
NotificationCenter.default.publisher(for: OperationSuccess)
}
@ -38,6 +44,14 @@ public extension NSNotification {
)
}
static func pushReaderItem(objectID: NSManagedObjectID) {
NotificationCenter.default.post(
name: NSNotification.PushReaderItem,
object: nil,
userInfo: ["objectID": objectID]
)
}
static func operationSuccess(message: String) {
NotificationCenter.default.post(name: NSNotification.OperationSuccess, object: nil, userInfo: ["message": message])
}