diff --git a/ios/App/App.xcodeproj/project.pbxproj b/ios/App/App.xcodeproj/project.pbxproj index 525df168..de0917d3 100644 --- a/ios/App/App.xcodeproj/project.pbxproj +++ b/ios/App/App.xcodeproj/project.pbxproj @@ -59,10 +59,22 @@ E9D5507328AC218300C746DD /* DaoExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9D5507228AC218300C746DD /* DaoExtensions.swift */; }; E9D5507528AEF93100C746DD /* PlayerSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9D5507428AEF93100C746DD /* PlayerSettings.swift */; }; E9DFCBFB28C28F4A00B36356 /* AudioPlayerSleepTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9DFCBFA28C28F4A00B36356 /* AudioPlayerSleepTimer.swift */; }; + E9E8814A28DA644F00D750C1 /* PlayerTimeUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E8814928DA644F00D750C1 /* PlayerTimeUtils.swift */; }; + E9E8814D28DA6B9000D750C1 /* PlayerTimeUtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E8814C28DA6B9000D750C1 /* PlayerTimeUtilsTests.swift */; }; E9E985F828B02D9400957F23 /* PlayerProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E985F728B02D9400957F23 /* PlayerProgress.swift */; }; E9FA07E328C82848005520B0 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9FA07E228C82848005520B0 /* Logger.swift */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + E9E8813E28DA5DE500D750C1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 504EC2FC1FED79650016851F /* Project object */; + proxyType = 1; + remoteGlobalIDString = 504EC3031FED79650016851F; + remoteInfo = Audiobookshelf; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXFileReference section */ 2FAD9762203C412B000D30F8 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = config.xml; sourceTree = ""; }; 3A200C1427D64D7E00CBF02E /* AudioPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayer.swift; sourceTree = ""; }; @@ -122,6 +134,9 @@ E9D5507228AC218300C746DD /* DaoExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DaoExtensions.swift; sourceTree = ""; }; E9D5507428AEF93100C746DD /* PlayerSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerSettings.swift; sourceTree = ""; }; E9DFCBFA28C28F4A00B36356 /* AudioPlayerSleepTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayerSleepTimer.swift; sourceTree = ""; }; + E9E8813A28DA5DE500D750C1 /* AudiobookshelfUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AudiobookshelfUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + E9E8814928DA644F00D750C1 /* PlayerTimeUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerTimeUtils.swift; sourceTree = ""; }; + E9E8814C28DA6B9000D750C1 /* PlayerTimeUtilsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerTimeUtilsTests.swift; sourceTree = ""; }; E9E985F728B02D9400957F23 /* PlayerProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerProgress.swift; sourceTree = ""; }; E9FA07E228C82848005520B0 /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = ""; }; FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.debug.xcconfig"; sourceTree = ""; }; @@ -136,6 +151,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + E9E8813728DA5DE500D750C1 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -150,6 +172,7 @@ 3ABF6190280432610070250E /* player */ = { isa = PBXGroup; children = ( + E9E8814828DA641B00D750C1 /* util */, 3A200C1427D64D7E00CBF02E /* AudioPlayer.swift */, E9DFCBFA28C28F4A00B36356 /* AudioPlayerSleepTimer.swift */, 3ABF618E2804325C0070250E /* PlayerHandler.swift */, @@ -220,6 +243,7 @@ children = ( 3AC8248B27F2316900529205 /* Shared */, 504EC3061FED79650016851F /* App */, + E9E8813B28DA5DE500D750C1 /* AudiobookshelfUnitTests */, 504EC3051FED79650016851F /* Products */, 7F8756D8B27F46E3366F6CEA /* Pods */, 27E2DDA53C4D2A4D1A88CE4A /* Frameworks */, @@ -230,6 +254,7 @@ isa = PBXGroup; children = ( 504EC3041FED79650016851F /* Audiobookshelf.app */, + E9E8813A28DA5DE500D750C1 /* AudiobookshelfUnitTests.xctest */, ); name = Products; sourceTree = ""; @@ -302,6 +327,46 @@ path = download; sourceTree = ""; }; + E9E8813B28DA5DE500D750C1 /* AudiobookshelfUnitTests */ = { + isa = PBXGroup; + children = ( + E9E8814328DA5E5900D750C1 /* Shared */, + ); + path = AudiobookshelfUnitTests; + sourceTree = ""; + }; + E9E8814328DA5E5900D750C1 /* Shared */ = { + isa = PBXGroup; + children = ( + E9E8814428DA5E6000D750C1 /* player */, + ); + path = Shared; + sourceTree = ""; + }; + E9E8814428DA5E6000D750C1 /* player */ = { + isa = PBXGroup; + children = ( + E9E8814B28DA6B6B00D750C1 /* util */, + ); + path = player; + sourceTree = ""; + }; + E9E8814828DA641B00D750C1 /* util */ = { + isa = PBXGroup; + children = ( + E9E8814928DA644F00D750C1 /* PlayerTimeUtils.swift */, + ); + path = util; + sourceTree = ""; + }; + E9E8814B28DA6B6B00D750C1 /* util */ = { + isa = PBXGroup; + children = ( + E9E8814C28DA6B9000D750C1 /* PlayerTimeUtilsTests.swift */, + ); + path = util; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -324,13 +389,31 @@ productReference = 504EC3041FED79650016851F /* Audiobookshelf.app */; productType = "com.apple.product-type.application"; }; + E9E8813928DA5DE500D750C1 /* AudiobookshelfUnitTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = E9E8814228DA5DE500D750C1 /* Build configuration list for PBXNativeTarget "AudiobookshelfUnitTests" */; + buildPhases = ( + E9E8813628DA5DE500D750C1 /* Sources */, + E9E8813728DA5DE500D750C1 /* Frameworks */, + E9E8813828DA5DE500D750C1 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + E9E8813F28DA5DE500D750C1 /* PBXTargetDependency */, + ); + name = AudiobookshelfUnitTests; + productName = AudiobookshelfUnitTests; + productReference = E9E8813A28DA5DE500D750C1 /* AudiobookshelfUnitTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 504EC2FC1FED79650016851F /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 920; + LastSwiftUpdateCheck = 1400; LastUpgradeCheck = 1330; TargetAttributes = { 504EC3031FED79650016851F = { @@ -338,6 +421,11 @@ LastSwiftMigration = 1240; ProvisioningStyle = Automatic; }; + E9E8813928DA5DE500D750C1 = { + CreatedOnToolsVersion = 14.0; + ProvisioningStyle = Automatic; + TestTargetID = 504EC3031FED79650016851F; + }; }; }; buildConfigurationList = 504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */; @@ -354,6 +442,7 @@ projectRoot = ""; targets = ( 504EC3031FED79650016851F /* Audiobookshelf */, + E9E8813928DA5DE500D750C1 /* AudiobookshelfUnitTests */, ); }; /* End PBXProject section */ @@ -372,6 +461,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + E9E8813828DA5DE500D750C1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -460,13 +556,30 @@ 3AF1970C2806E2590096F747 /* ApiClient.swift in Sources */, 4D66B954282EE87C008272D4 /* AbsDownloader.swift in Sources */, E9D5505628AC1BFA00C746DD /* FileMetadata.swift in Sources */, + E9E8814A28DA644F00D750C1 /* PlayerTimeUtils.swift in Sources */, 3AB34055280832720039308B /* PlayerEvents.swift in Sources */, E9D5506C28AC1E2100C746DD /* LocalMediaProgress.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; + E9E8813628DA5DE500D750C1 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E9E8814D28DA6B9000D750C1 /* PlayerTimeUtilsTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + E9E8813F28DA5DE500D750C1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 504EC3031FED79650016851F /* Audiobookshelf */; + targetProxy = E9E8813E28DA5DE500D750C1 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ 504EC30B1FED79650016851F /* Main.storyboard */ = { isa = PBXVariantGroup; @@ -646,6 +759,49 @@ }; name = Release; }; + E9E8814028DA5DE500D750C1 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.audiobookshelf.AudiobookshelfUnitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Audiobookshelf.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Audiobookshelf"; + }; + name = Debug; + }; + E9E8814128DA5DE500D750C1 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MARKETING_VERSION = 1.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.audiobookshelf.AudiobookshelfUnitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Audiobookshelf.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Audiobookshelf"; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -667,6 +823,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + E9E8814228DA5DE500D750C1 /* Build configuration list for PBXNativeTarget "AudiobookshelfUnitTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E9E8814028DA5DE500D750C1 /* Debug */, + E9E8814128DA5DE500D750C1 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = 504EC2FC1FED79650016851F /* Project object */; diff --git a/ios/App/App.xcodeproj/xcshareddata/xcschemes/App.xcscheme b/ios/App/App.xcodeproj/xcshareddata/xcschemes/App.xcscheme index c99f0ab6..600c22aa 100644 --- a/ios/App/App.xcodeproj/xcshareddata/xcschemes/App.xcscheme +++ b/ios/App/App.xcodeproj/xcshareddata/xcschemes/App.xcscheme @@ -28,6 +28,17 @@ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> + + + + TimeInterval { + let sinceLastPlayed = timeSinceLastPlayed(lastPlayedMs) + let timeToSeekBack = timeToSeekBackForSinceLastPlayed(sinceLastPlayed) + return currentTime.advanced(by: -timeToSeekBack) + } + + static internal func timeSinceLastPlayed(_ lastPlayedMs: Double?) -> TimeInterval? { + guard let lastPlayedMs = lastPlayedMs else { return nil } + let lastPlayed = Date(timeIntervalSince1970: lastPlayedMs / 1000) + return lastPlayed.timeIntervalSinceNow + } + + static internal func timeToSeekBackForSinceLastPlayed(_ sinceLastPlayed: TimeInterval?) -> TimeInterval { + if let sinceLastPlayed = sinceLastPlayed { + if sinceLastPlayed < 6 { + return 2 + } else if sinceLastPlayed < 12 { + return 10 + } else if sinceLastPlayed < 30 { + return 15 + } else if sinceLastPlayed < 180 { + return 20 + } else if sinceLastPlayed < 3600 { + return 25 + } else { + return 29 + } + } else { + return 5 + } + } + +}