@ -2043,7 +2043,7 @@
|
||||
repositoryURL = "https://github.com/intercom/intercom-ios";
|
||||
requirement = {
|
||||
kind = exactVersion;
|
||||
version = 11.1.2;
|
||||
version = 17.1.2;
|
||||
};
|
||||
};
|
||||
048F592A2790EAF800E0B494 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = {
|
||||
|
||||
@ -32,8 +32,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/nathantannar4/Engine",
|
||||
"state" : {
|
||||
"revision" : "0d2d5647921473be4aac40cb70ad13900f56ed2b",
|
||||
"version" : "1.8.1"
|
||||
"revision" : "391d0da0282f51327b5d2c0e5de64f75e59cbae7",
|
||||
"version" : "1.8.3"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -122,8 +122,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/intercom/intercom-ios",
|
||||
"state" : {
|
||||
"revision" : "3345d9e7599141d7c844981423a7e5409f2bfb81",
|
||||
"version" : "11.1.2"
|
||||
"revision" : "ad789a51b350dffe804dbf083430e0d6e91ac4af",
|
||||
"version" : "17.1.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -239,8 +239,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/nathantannar4/Transmission",
|
||||
"state" : {
|
||||
"revision" : "6b3e6b46f34d0d18715d27c46e0053f1eda1bcd1",
|
||||
"version" : "1.3.1"
|
||||
"revision" : "9cbf1f6fec330e25c615182f3de483b129576819",
|
||||
"version" : "1.3.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@ -71,9 +71,7 @@ var dependencies: [Package.Dependency] {
|
||||
.package(url: "https://github.com/google/GoogleSignIn-iOS", from: "6.2.2"),
|
||||
.package(url: "https://github.com/gonzalezreal/swift-markdown-ui", from: "2.0.0"),
|
||||
.package(url: "https://github.com/PostHog/posthog-ios.git", from: "2.0.0"),
|
||||
// .package(url: "https://github.com/nathantannar4/Engine", exact: "1.0.1"),
|
||||
// .package(url: "https://github.com/nathantannar4/Turbocharger", exact: "1.1.4"),
|
||||
.package(url: "https://github.com/nathantannar4/Transmission", exact: "1.3.1")
|
||||
.package(url: "https://github.com/nathantannar4/Transmission", exact: "1.3.2")
|
||||
]
|
||||
// Comment out following line for macOS build
|
||||
deps.append(.package(url: "https://github.com/PSPDFKit/PSPDFKit-SP", from: "13.7.0"))
|
||||
|
||||
@ -546,7 +546,6 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
if presentingItem.isPDF {
|
||||
PDFContainerView(item: presentingItem)
|
||||
} else {
|
||||
let too = print("$viewModel.linkIsActive", viewModel.linkIsActive)
|
||||
WebReaderContainerView(item: presentingItem)
|
||||
}
|
||||
} else {
|
||||
@ -804,9 +803,40 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
}
|
||||
}
|
||||
|
||||
@State private var isAnimating = false
|
||||
|
||||
var progress: some View {
|
||||
GeometryReader { geometry in
|
||||
VStack {
|
||||
Spacer()
|
||||
Rectangle()
|
||||
.fill(Color.yellow)
|
||||
.frame(height: 2)
|
||||
.offset(x: self.isAnimating ? geometry.size.width - 40 : 0)
|
||||
.frame(width: self.isAnimating ? geometry.size.width : 40)
|
||||
.animation(Animation.linear(duration: 2).repeatForever(autoreverses: true))
|
||||
Spacer()
|
||||
}
|
||||
.onAppear {
|
||||
self.isAnimating = true
|
||||
}
|
||||
.frame(height: 2)
|
||||
}
|
||||
.background(.clear)
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
Color.systemBackground.frame(height: 1)
|
||||
if viewModel.showLoadingBar == .simple {
|
||||
progress
|
||||
.frame(height: 2)
|
||||
.frame(maxWidth: .infinity)
|
||||
.listRowSeparator(.hidden, edges: .all)
|
||||
.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
|
||||
} else {
|
||||
Color.systemBackground.frame(height: 2)
|
||||
}
|
||||
ScrollViewReader { reader in
|
||||
List(selection: $selection) {
|
||||
Section(content: {
|
||||
@ -843,15 +873,7 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
}
|
||||
}
|
||||
|
||||
if viewModel.showLoadingBar == .redacted || viewModel.showLoadingBar == .simple {
|
||||
VStack {
|
||||
ProgressView()
|
||||
}
|
||||
.frame(minHeight: 400)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding()
|
||||
.listRowSeparator(.hidden, edges: .all)
|
||||
} else if viewModel.isEmptyingTrash {
|
||||
if viewModel.isEmptyingTrash {
|
||||
VStack {
|
||||
Text("Emptying trash")
|
||||
ProgressView()
|
||||
|
||||
@ -219,7 +219,7 @@ enum LoadingBarStyle {
|
||||
|
||||
func loadItems(dataService: DataService, isRefresh: Bool, forceRemote: Bool = false, loadingBarStyle: LoadingBarStyle? = nil) async {
|
||||
isLoading = true
|
||||
showLoadingBar = isRefresh ? loadingBarStyle ?? .redacted : .none
|
||||
showLoadingBar = .simple // isRefresh ? loadingBarStyle ?? .redacted : .none
|
||||
|
||||
if let filterState = filterState {
|
||||
await fetcher.loadItems(
|
||||
|
||||
@ -23,72 +23,18 @@
|
||||
var body: some View {
|
||||
Group {
|
||||
Form {
|
||||
if language.key == "en" {
|
||||
if viewModel.waitingForRealisticVoices {
|
||||
HStack {
|
||||
Text(LocalText.texttospeechBetaSignupInProcess)
|
||||
Spacer()
|
||||
ProgressView()
|
||||
if showLanguageChanger {
|
||||
Section("Language") {
|
||||
NavigationLink(destination: TextToSpeechLanguageView().navigationTitle("Language")) {
|
||||
Text(audioController.currentVoiceLanguage.name)
|
||||
}
|
||||
} else {
|
||||
Toggle("Use Ultra Realistic Voices", isOn: $viewModel.realisticVoicesToggle)
|
||||
.accentColor(Color.green)
|
||||
}
|
||||
|
||||
if !viewModel.waitingForRealisticVoices, !audioController.ultraRealisticFeatureKey.isEmpty {
|
||||
Text(LocalText.texttospeechBetaRealisticVoiceLimit)
|
||||
.multilineTextAlignment(.leading)
|
||||
} else if audioController.ultraRealisticFeatureRequested {
|
||||
Text(LocalText.texttospeechBetaRequestReceived)
|
||||
.multilineTextAlignment(.leading)
|
||||
} else {
|
||||
Text(LocalText.texttospeechBetaWaitlist)
|
||||
.multilineTextAlignment(.leading)
|
||||
}
|
||||
}
|
||||
|
||||
if viewModel.realisticVoicesToggle, !audioController.ultraRealisticFeatureKey.isEmpty {
|
||||
if showLanguageChanger {
|
||||
Section("Language") {
|
||||
NavigationLink(destination: TextToSpeechLanguageView().navigationTitle("Language")) {
|
||||
Text(audioController.currentVoiceLanguage.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
ultraRealisticVoices
|
||||
} else {
|
||||
if showLanguageChanger {
|
||||
Section("Language") {
|
||||
NavigationLink(destination: TextToSpeechLanguageView().navigationTitle("Language")) {
|
||||
Text(audioController.currentVoiceLanguage.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
standardVoices
|
||||
}
|
||||
standardVoices
|
||||
}
|
||||
}
|
||||
.navigationTitle("Choose a Voice")
|
||||
.onAppear {
|
||||
// swiftlint:disable:next line_length
|
||||
viewModel.realisticVoicesToggle = (audioController.useUltraRealisticVoices && !audioController.ultraRealisticFeatureKey.isEmpty)
|
||||
}
|
||||
.onChange(of: viewModel.realisticVoicesToggle) { value in
|
||||
if value, audioController.ultraRealisticFeatureKey.isEmpty {
|
||||
// User wants to sign up
|
||||
viewModel.waitingForRealisticVoices = true
|
||||
Task {
|
||||
await viewModel.requestUltraRealisticFeatureAccess(
|
||||
dataService: self.dataService,
|
||||
audioController: audioController
|
||||
)
|
||||
}
|
||||
} else if value, !audioController.ultraRealisticFeatureKey.isEmpty {
|
||||
audioController.useUltraRealisticVoices = true
|
||||
} else if !value {
|
||||
audioController.useUltraRealisticVoices = false
|
||||
}
|
||||
}.onReceive(NotificationCenter.default.publisher(for: Notification.Name("ScrollToTop"))) { _ in
|
||||
.onReceive(NotificationCenter.default.publisher(for: Notification.Name("ScrollToTop"))) { _ in
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,47 +15,8 @@
|
||||
|
||||
@MainActor final class TextToSpeechVoiceSelectionViewModel: ObservableObject {
|
||||
@Published var playbackSample: String?
|
||||
@Published var realisticVoicesToggle: Bool = false
|
||||
@Published var waitingForRealisticVoices: Bool = false
|
||||
|
||||
@Published var showSnackbar: Bool = false
|
||||
var snackbarMessage: String?
|
||||
|
||||
func requestUltraRealisticFeatureAccess(
|
||||
dataService: DataService,
|
||||
audioController: AudioController
|
||||
) async {
|
||||
do {
|
||||
let feature = try await dataService.optInFeature(name: "ultra-realistic-voice")
|
||||
DispatchQueue.main.async {
|
||||
if let feature = feature {
|
||||
audioController.useUltraRealisticVoices = true
|
||||
audioController.ultraRealisticFeatureRequested = true
|
||||
audioController.ultraRealisticFeatureKey = feature.granted ? feature.token : ""
|
||||
if feature.granted, !Voices.isUltraRealisticVoice(audioController.currentVoice) {
|
||||
// Attempt to set to an ultra voice
|
||||
if let voice = Voices.UltraPairs.first {
|
||||
audioController.currentVoice = voice.firstKey
|
||||
}
|
||||
}
|
||||
self.realisticVoicesToggle = true
|
||||
} else {
|
||||
audioController.useUltraRealisticVoices = false
|
||||
audioController.ultraRealisticFeatureKey = ""
|
||||
audioController.ultraRealisticFeatureRequested = false
|
||||
self.realisticVoicesToggle = false
|
||||
}
|
||||
self.waitingForRealisticVoices = false
|
||||
}
|
||||
} catch {
|
||||
print("ERROR OPTING INTO FEATURE", error)
|
||||
audioController.useUltraRealisticVoices = false
|
||||
realisticVoicesToggle = false
|
||||
waitingForRealisticVoices = false
|
||||
audioController.ultraRealisticFeatureRequested = false
|
||||
snackbarMessage = "Error signing up for beta. Please try again."
|
||||
showSnackbar = true
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -44,6 +44,7 @@ public final class Authenticator: ObservableObject {
|
||||
isLoggedIn = false
|
||||
}
|
||||
|
||||
@MainActor
|
||||
public func logout(dataService: DataService, isAccountDeletion: Bool = false) {
|
||||
dataService.resetLocalStorage()
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ public enum GoogleAuthResponse {
|
||||
}
|
||||
|
||||
extension Authenticator {
|
||||
@MainActor
|
||||
public func handleGoogleAuth(presentingVC: PlatformViewController?) async -> GoogleAuthResponse {
|
||||
let idToken = await withCheckedContinuation { continuation in
|
||||
googleSignIn(presenting: presentingVC) { continuation.resume(returning: $0) }
|
||||
|
||||
@ -50,6 +50,7 @@ public extension DataService {
|
||||
case let .error(errorCode: errorCode):
|
||||
if errorCode == .ineligible {
|
||||
continuation.resume(throwing: IneligibleError.message(messageText: "You are not eligible for this feature."))
|
||||
return
|
||||
}
|
||||
continuation.resume(throwing: BasicError.message(messageText: errorCode.rawValue))
|
||||
}
|
||||
|
||||
@ -82,7 +82,6 @@ public struct ViewerInternal {
|
||||
|
||||
do {
|
||||
try context.save()
|
||||
EventTracker.registerUser(userID: userID)
|
||||
logger.debug("Viewer saved succesfully")
|
||||
} catch {
|
||||
context.rollback()
|
||||
@ -90,5 +89,8 @@ public struct ViewerInternal {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
EventTracker.registerUser(userID: userID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import Foundation
|
||||
import PostHog
|
||||
#endif
|
||||
|
||||
@MainActor
|
||||
public enum EventTracker {
|
||||
#if os(iOS)
|
||||
public static var posthog: PHGPostHog? = {
|
||||
|
||||
@ -47,9 +47,11 @@ private let logger = Logger(subsystem: "app.omnivore", category: "app-delegate")
|
||||
Intercom.setApiKey(intercomKeys.apiKey, forAppId: intercomKeys.appID)
|
||||
|
||||
if let userId = UserDefaults.standard.string(forKey: Keys.userIdKey) {
|
||||
Intercom.registerUser(withUserId: userId)
|
||||
let userAttributes = ICMUserAttributes()
|
||||
userAttributes.userId = userId
|
||||
Intercom.loginUser(with: userAttributes)
|
||||
} else {
|
||||
Intercom.registerUnidentifiedUser()
|
||||
Intercom.loginUnidentifiedUser()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -29,10 +29,14 @@ struct MainApp: App {
|
||||
WindowGroup {
|
||||
RootView(
|
||||
intercomProvider: AppKeys.sharedInstance?.intercom != nil ? IntercomProvider(
|
||||
registerIntercomUser: { Intercom.registerUser(withUserId: $0) },
|
||||
registerIntercomUser: { userId in
|
||||
let userAttributes = ICMUserAttributes()
|
||||
userAttributes.userId = userId
|
||||
Intercom.loginUser(with: userAttributes)
|
||||
},
|
||||
setIntercomUserHash: { Intercom.setUserHash($0) },
|
||||
unregisterIntercomUser: Intercom.logout,
|
||||
showIntercomMessenger: Intercom.presentMessenger
|
||||
showIntercomMessenger: Intercom.present
|
||||
) : nil
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user