diff --git a/ABS Client/ABS Client-macOS.entitlements b/ABS Client/ABS Client-macOS.entitlements new file mode 100644 index 0000000..38da9a9 --- /dev/null +++ b/ABS Client/ABS Client-macOS.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.network.client + + com.apple.security.files.user-selected.read-write + + + diff --git a/ABS Client/Audiobookshelf swift.xcodeproj/project.pbxproj b/ABS Client/Audiobookshelf swift.xcodeproj/project.pbxproj index 8c41f64..1a9ed49 100644 --- a/ABS Client/Audiobookshelf swift.xcodeproj/project.pbxproj +++ b/ABS Client/Audiobookshelf swift.xcodeproj/project.pbxproj @@ -254,22 +254,23 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + "CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "ABS Client-macOS.entitlements"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = PP34X97WS3; - ENABLE_APP_SANDBOX = NO; + "ENABLE_APP_SANDBOX[sdk=macosx*]" = YES; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_CFBundleDisplayName = "ABS Client"; - INFOPLIST_KEY_CFBundleName = "ABS Client"; - INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.books"; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; "GENERATE_INFOPLIST_FILE[sdk=iphoneos*]" = NO; "GENERATE_INFOPLIST_FILE[sdk=iphonesimulator*]" = NO; "INFOPLIST_FILE[sdk=iphoneos*]" = "Info-iOS.plist"; "INFOPLIST_FILE[sdk=iphonesimulator*]" = "Info-iOS.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "ABS Client"; + INFOPLIST_KEY_CFBundleName = "ABS Client"; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.books"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; IPHONEOS_DEPLOYMENT_TARGET = 17.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -283,6 +284,7 @@ "$(inherited)", "@executable_path/Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 26.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = "com.local.ABS-Client"; PRODUCT_NAME = "ABS Client"; @@ -296,7 +298,7 @@ SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; }; name = Debug; }; @@ -305,22 +307,23 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + "CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "ABS Client-macOS.entitlements"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = PP34X97WS3; - ENABLE_APP_SANDBOX = NO; + "ENABLE_APP_SANDBOX[sdk=macosx*]" = YES; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_CFBundleDisplayName = "ABS Client"; - INFOPLIST_KEY_CFBundleName = "ABS Client"; - INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.books"; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; "GENERATE_INFOPLIST_FILE[sdk=iphoneos*]" = NO; "GENERATE_INFOPLIST_FILE[sdk=iphonesimulator*]" = NO; "INFOPLIST_FILE[sdk=iphoneos*]" = "Info-iOS.plist"; "INFOPLIST_FILE[sdk=iphonesimulator*]" = "Info-iOS.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "ABS Client"; + INFOPLIST_KEY_CFBundleName = "ABS Client"; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.books"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; IPHONEOS_DEPLOYMENT_TARGET = 17.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -334,6 +337,7 @@ "$(inherited)", "@executable_path/Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 26.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = "com.local.ABS-Client"; PRODUCT_NAME = "ABS Client"; @@ -347,7 +351,7 @@ SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; }; name = Release; }; diff --git a/ABS Client/Audiobookshelf swift/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png b/ABS Client/Audiobookshelf swift/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png index 4f335a0..7e205d8 100644 Binary files a/ABS Client/Audiobookshelf swift/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png and b/ABS Client/Audiobookshelf swift/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png differ diff --git a/ABS Client/Audiobookshelf swift/Audiobookshelf_swiftApp.swift b/ABS Client/Audiobookshelf swift/Audiobookshelf_swiftApp.swift index 1981542..31d7728 100644 --- a/ABS Client/Audiobookshelf swift/Audiobookshelf_swiftApp.swift +++ b/ABS Client/Audiobookshelf swift/Audiobookshelf_swiftApp.swift @@ -35,13 +35,9 @@ struct Audiobookshelf_swiftApp: App { #if os(iOS) private func configureAudioSession() { - do { - let session = AVAudioSession.sharedInstance() - try session.setCategory(.playback, mode: .default, options: []) - try session.setActive(true) - } catch { - // non-fatal - } + // Nur die Kategorie registrieren — setActive(true) passiert erst in play(), + // damit beim App-Start keine laufende Fremd-Wiedergabe unterbrochen wird. + try? AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: []) } #endif } diff --git a/ABS Client/Audiobookshelf swift/Services/PlayerEngine.swift b/ABS Client/Audiobookshelf swift/Services/PlayerEngine.swift index 73e65dd..f636d90 100644 --- a/ABS Client/Audiobookshelf swift/Services/PlayerEngine.swift +++ b/ABS Client/Audiobookshelf swift/Services/PlayerEngine.swift @@ -11,6 +11,12 @@ import AppKit private typealias PlayerArtworkImage = NSImage #endif +enum SleepTimerMode: Equatable, Hashable { + case off + case minutes(Int) + case endOfBook +} + @Observable @MainActor final class PlayerEngine { @@ -21,6 +27,11 @@ final class PlayerEngine { var isReady: Bool = false var errorMessage: String? + var sleepTimer: SleepTimerMode = .off + /// Verbleibende Wallclock-Sekunden bis der Sleep-Timer auslöst (0 wenn off). + /// Pausiert mit der Wiedergabe; bei `.endOfBook` rate-skaliert aus der Restspielzeit. + var sleepRemainingSeconds: Double = 0 + private var player: AVQueuePlayer? private var trackDurations: [Double] = [] private var trackPlayerItems: [AVPlayerItem] = [] @@ -28,6 +39,7 @@ final class PlayerEngine { private var timeObserver: Any? private var endObservers: [NSObjectProtocol] = [] private var isSeeking: Bool = false + private var sleepTickTask: Task? var itemId: String? @@ -127,12 +139,16 @@ final class PlayerEngine { player?.play() player?.rate = rate isPlaying = true + if case .minutes = sleepTimer, sleepRemainingSeconds > 0, sleepTickTask == nil { + startSleepTickTask() + } updateNowPlayingInfo() } func pause() { player?.pause() isPlaying = false + cancelSleepTickTask() updateNowPlayingInfo() } @@ -143,6 +159,9 @@ final class PlayerEngine { func setRate(_ newRate: Float) { rate = newRate if isPlaying { player?.rate = newRate } + if case .endOfBook = sleepTimer { + sleepRemainingSeconds = wallclockRemainingUntilEndOfBook() + } updateNowPlayingInfo() } @@ -221,9 +240,13 @@ final class PlayerEngine { let wasPlaying = isPlaying isPlaying = player.timeControlStatus == .playing if wasPlaying != isPlaying { updateNowPlayingInfo() } + updateEndOfBookSleep() } func teardown() { + cancelSleepTickTask() + sleepTimer = .off + sleepRemainingSeconds = 0 if let token = timeObserver { player?.removeTimeObserver(token) } timeObserver = nil for obs in endObservers { NotificationCenter.default.removeObserver(obs) } @@ -248,6 +271,57 @@ final class PlayerEngine { clearNowPlayingInfo() } + // MARK: - Sleep timer + + func setSleepTimer(_ mode: SleepTimerMode) { + cancelSleepTickTask() + sleepTimer = mode + switch mode { + case .off: + sleepRemainingSeconds = 0 + case .minutes(let m): + sleepRemainingSeconds = Double(m * 60) + if isPlaying { startSleepTickTask() } + case .endOfBook: + sleepRemainingSeconds = wallclockRemainingUntilEndOfBook() + } + } + + private func startSleepTickTask() { + cancelSleepTickTask() + sleepTickTask = Task { @MainActor [weak self] in + while !Task.isCancelled { + try? await Task.sleep(nanoseconds: 500_000_000) + guard !Task.isCancelled, let self else { return } + self.sleepRemainingSeconds = max(0, self.sleepRemainingSeconds - 0.5) + if self.sleepRemainingSeconds <= 0 { + self.sleepTimer = .off + self.pause() + return + } + } + } + } + + private func cancelSleepTickTask() { + sleepTickTask?.cancel() + sleepTickTask = nil + } + + private func updateEndOfBookSleep() { + guard case .endOfBook = sleepTimer else { return } + sleepRemainingSeconds = wallclockRemainingUntilEndOfBook() + if sleepRemainingSeconds <= 0 { + sleepTimer = .off + } + } + + private func wallclockRemainingUntilEndOfBook() -> Double { + let playback = max(0, totalDuration - absoluteCurrentTime) + let r = max(0.1, Double(rate)) + return playback / r + } + // MARK: - Now-playing / remote commands private func configureRemoteCommandsIfNeeded() { diff --git a/ABS Client/Audiobookshelf swift/Views/LibraryGridView.swift b/ABS Client/Audiobookshelf swift/Views/LibraryGridView.swift index 9b714a0..6a52659 100644 --- a/ABS Client/Audiobookshelf swift/Views/LibraryGridView.swift +++ b/ABS Client/Audiobookshelf swift/Views/LibraryGridView.swift @@ -5,9 +5,22 @@ struct LibraryGridView: View { var onRefresh: (() async -> Void)? = nil var onSelect: (LibraryItem) -> Void + @AppStorage("libraryCoverSize") private var coverSize: Double = Self.defaultCoverSize + var body: some View { + #if os(macOS) + VStack(spacing: 0) { + zoomBar + gridContent + } + #else + gridContent + #endif + } + + private var gridContent: some View { ScrollView { - LazyVGrid(columns: gridColumns, spacing: 8) { + LazyVGrid(columns: gridColumns, spacing: gridSpacing) { ForEach(items) { item in LibraryItemCell(item: item) .onTapGesture { onSelect(item) } @@ -25,14 +38,59 @@ struct LibraryGridView: View { #endif } + #if os(macOS) + private var zoomBar: some View { + HStack(spacing: 8) { + Spacer() + Image(systemName: "rectangle.grid.3x2") + .font(.caption2) + .foregroundStyle(.secondary) + Slider(value: $coverSize, in: Self.minCoverSize...Self.maxCoverSize) + .frame(maxWidth: 220) + Image(systemName: "square") + .font(.caption2) + .foregroundStyle(.secondary) + } + .padding(.horizontal, 12) + .padding(.vertical, 4) + } + #endif + private var gridColumns: [GridItem] { + [GridItem(.adaptive(minimum: CGFloat(coverSize)), spacing: gridSpacing)] + } + + private var gridSpacing: CGFloat { #if os(iOS) - // 3 equal columns — compact spacing for full height utilization - [GridItem(.flexible(), spacing: 8), - GridItem(.flexible(), spacing: 8), - GridItem(.flexible())] + return 8 #else - [GridItem(.adaptive(minimum: 180), spacing: 20)] + return 20 + #endif + } + + // MARK: - Cover-Größen-Defaults (plattformabhängig) + + private static var defaultCoverSize: Double { + #if os(iOS) + return 110 + #else + return 180 + #endif + } + + private static var minCoverSize: Double { + #if os(iOS) + return 80 + #else + return 120 + #endif + } + + private static var maxCoverSize: Double { + #if os(iOS) + return 200 + #else + return 320 #endif } } diff --git a/ABS Client/Audiobookshelf swift/Views/LibraryItemCell.swift b/ABS Client/Audiobookshelf swift/Views/LibraryItemCell.swift index f9881dd..58cdbb6 100644 --- a/ABS Client/Audiobookshelf swift/Views/LibraryItemCell.swift +++ b/ABS Client/Audiobookshelf swift/Views/LibraryItemCell.swift @@ -45,17 +45,44 @@ struct LibraryItemCell: View { #if os(iOS) private var iOSCover: some View { - Color(.systemGray6) // neutral bg for PNG transparent areas - .frame(maxWidth: .infinity) // explicitly fill the column width + coverContainer(background: AnyShapeStyle(Color(.systemGray6))) + } + #endif + + #if os(macOS) + private var macosCover: some View { + coverContainer(background: AnyShapeStyle(.quaternary)) + } + #endif + + /// Quadratischer Cover-Container: füllt die Spaltenbreite, behält 1:1-Aspektverhältnis + /// und zeigt das Bild **ohne Verzerrung** (`.scaledToFit`). Nicht-quadratische Cover + /// bekommen Letterbox-/Pillarbox-Ränder im neutralen Hintergrund. + private func coverContainer(background: AnyShapeStyle) -> some View { + Rectangle() + .fill(background) + .frame(maxWidth: .infinity) .aspectRatio(1, contentMode: .fit) .overlay { if let url = app.client.coverURL(itemId: item.id) { - AsyncImage(url: url) { image in - image.resizable().scaledToFill() - } placeholder: { - ProgressView().tint(.accentColor) + AsyncImage(url: url) { phase in + switch phase { + case .success(let img): + img.resizable().scaledToFit() + case .empty: + ProgressView() + #if os(macOS) + .controlSize(.small) + #else + .tint(.accentColor) + #endif + case .failure: + Image(systemName: "book.closed") + .foregroundStyle(.secondary) + @unknown default: + EmptyView() + } } - .clipped() // clip image overflow before rounding } else { Image(systemName: "book.closed") .foregroundStyle(.secondary) @@ -63,34 +90,6 @@ struct LibraryItemCell: View { } .clipShape(RoundedRectangle(cornerRadius: 8)) } - #endif - - #if os(macOS) - private var macosCover: some View { - Group { - if let url = app.client.coverURL(itemId: item.id) { - AsyncImage(url: url) { phase in - switch phase { - case .empty: - Rectangle().fill(.quaternary) - .overlay(ProgressView().controlSize(.small)) - case .success(let img): - img.resizable().aspectRatio(contentMode: .fill) - case .failure: - Rectangle().fill(.quaternary) - .overlay(Image(systemName: "book.closed").foregroundStyle(.secondary)) - @unknown default: - Rectangle().fill(.quaternary) - } - } - } else { - Rectangle().fill(.quaternary) - } - } - .frame(width: 180, height: 180) - .clipShape(RoundedRectangle(cornerRadius: 8)) - } - #endif // MARK: - Download badge diff --git a/ABS Client/Audiobookshelf swift/Views/PlayerBar.swift b/ABS Client/Audiobookshelf swift/Views/PlayerBar.swift index f0c71d9..5619672 100644 --- a/ABS Client/Audiobookshelf swift/Views/PlayerBar.swift +++ b/ABS Client/Audiobookshelf swift/Views/PlayerBar.swift @@ -62,7 +62,7 @@ struct PlayerBar: View { } scrubber - HStack(spacing: 24) { + HStack(spacing: 20) { Button { app.skip(by: -Double(skipSeconds)) } label: { Image(systemName: skipBackImage).font(.system(size: 22)) } @@ -77,6 +77,8 @@ struct PlayerBar: View { Spacer() + sleepMenu + rateMenu Button { @@ -113,6 +115,8 @@ struct PlayerBar: View { rateMenu + sleepMenu + Spacer(minLength: 0) statusIndicator @@ -218,9 +222,73 @@ struct PlayerBar: View { .font(.caption2.monospacedDigit()) .foregroundStyle(.secondary) } + if app.player.sleepTimer != .off { + HStack(spacing: 4) { + Image(systemName: "moon.zzz.fill") + .font(.caption2) + Text("\(formatTime(app.player.sleepRemainingSeconds)) · endet \(formatWallTime(sleepEndsAt))") + .font(.caption2.monospacedDigit()) + } + .foregroundStyle(.tint) + .frame(maxWidth: .infinity, alignment: .center) + } } } + private var sleepMenu: some View { + Menu { + sleepOption(title: "Aus", mode: .off) + Divider() + sleepOption(title: "10 Minuten", mode: .minutes(10)) + sleepOption(title: "20 Minuten", mode: .minutes(20)) + sleepOption(title: "30 Minuten", mode: .minutes(30)) + sleepOption(title: "1 Stunde", mode: .minutes(60)) + sleepOption(title: endOfPlaybackLabel, mode: .endOfBook) + } label: { + Image(systemName: app.player.sleepTimer == .off ? "moon.zzz" : "moon.zzz.fill") + #if os(iOS) + .font(.system(size: 22)) + #else + .font(.system(size: 16)) + #endif + .foregroundStyle(app.player.sleepTimer == .off ? Color.secondary : Color.accentColor) + } + #if os(macOS) + .menuStyle(.borderlessButton) + .fixedSize() + #endif + .menuIndicator(.hidden) + .help("Sleep-Timer") + .disabled(!app.player.isReady) + } + + @ViewBuilder + private func sleepOption(title: String, mode: SleepTimerMode) -> some View { + Button { + app.player.setSleepTimer(mode) + } label: { + if app.player.sleepTimer == mode { + Label(title, systemImage: "checkmark") + } else { + Text(title) + } + } + } + + private var sleepEndsAt: Date { + Date().addingTimeInterval(app.player.sleepRemainingSeconds) + } + + private var endOfPlaybackLabel: String { + app.currentItem?.isPodcast == true + ? "Bis Ende der Folge" + : "Bis Ende des Hörbuchs" + } + + private func formatWallTime(_ date: Date) -> String { + date.formatted(.dateTime.hour().minute()) + } + private var rateMenu: some View { Menu { ForEach([0.75, 1.0, 1.25, 1.5, 1.75, 2.0], id: \.self) { r in diff --git a/ABS Client/Info-iOS.plist b/ABS Client/Info-iOS.plist index 0461174..abec678 100644 --- a/ABS Client/Info-iOS.plist +++ b/ABS Client/Info-iOS.plist @@ -40,11 +40,18 @@ UIColorName LaunchBackground - UISupportedInterfaceOrientations + UISupportedInterfaceOrientations~iphone UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + diff --git a/Exports/Mac/ABS Client.app/Contents/Info.plist b/Exports/Mac/ABS Client.app/Contents/Info.plist new file mode 100644 index 0000000..333bdb6 --- /dev/null +++ b/Exports/Mac/ABS Client.app/Contents/Info.plist @@ -0,0 +1,56 @@ + + + + + BuildMachineOSBuild + 25F71 + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ABS Client + CFBundleExecutable + ABS Client + CFBundleIconFile + AppIcon + CFBundleIconName + AppIcon + CFBundleIdentifier + com.local.ABS-Client + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ABS Client + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSupportedPlatforms + + MacOSX + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 25F70 + DTPlatformName + macosx + DTPlatformVersion + 26.5 + DTSDKBuild + 25F70 + DTSDKName + macosx26.5 + DTXcode + 2650 + DTXcodeBuild + 17F42 + LSApplicationCategoryType + public.app-category.books + LSMinimumSystemVersion + 26.0 + NSAccentColorName + AccentColor + + diff --git a/Exports/Mac/ABS Client.app/Contents/MacOS/ABS Client b/Exports/Mac/ABS Client.app/Contents/MacOS/ABS Client new file mode 100755 index 0000000..e074d25 Binary files /dev/null and b/Exports/Mac/ABS Client.app/Contents/MacOS/ABS Client differ diff --git a/Exports/Mac/ABS Client.app/Contents/PkgInfo b/Exports/Mac/ABS Client.app/Contents/PkgInfo new file mode 100644 index 0000000..bd04210 --- /dev/null +++ b/Exports/Mac/ABS Client.app/Contents/PkgInfo @@ -0,0 +1 @@ +APPL???? \ No newline at end of file diff --git a/Exports/Mac/ABS Client.app/Contents/Resources/AppIcon.icns b/Exports/Mac/ABS Client.app/Contents/Resources/AppIcon.icns new file mode 100644 index 0000000..3e9d861 Binary files /dev/null and b/Exports/Mac/ABS Client.app/Contents/Resources/AppIcon.icns differ diff --git a/Exports/Mac/ABS Client.app/Contents/Resources/Assets.car b/Exports/Mac/ABS Client.app/Contents/Resources/Assets.car new file mode 100644 index 0000000..00e8537 Binary files /dev/null and b/Exports/Mac/ABS Client.app/Contents/Resources/Assets.car differ diff --git a/Exports/Mac/ABS Client.app/Contents/_CodeSignature/CodeResources b/Exports/Mac/ABS Client.app/Contents/_CodeSignature/CodeResources new file mode 100644 index 0000000..c4003e9 --- /dev/null +++ b/Exports/Mac/ABS Client.app/Contents/_CodeSignature/CodeResources @@ -0,0 +1,139 @@ + + + + + files + + Resources/AppIcon.icns + + PIslMkIS+dR91jAoGiXhG5ZQxNw= + + Resources/Assets.car + + q6mmhkyHvvRXVcw9rIIm/MbqTqI= + + + files2 + + Resources/AppIcon.icns + + hash2 + + UmgGZpb6aN5Xnz7XswrsNpMxnVcQINgSUpIhHWS1GBM= + + + Resources/Assets.car + + hash2 + + lfMPkDEQ0MA2q3+uXr1255juM39IkgqKOiK8Kede+X0= + + + + rules + + ^Resources/ + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Resources/Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ + + nested + + weight + 10 + + ^.* + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^Resources/ + + weight + 20 + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Resources/Base\.lproj/ + + weight + 1010 + + ^[^/]+$ + + nested + + weight + 10 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/Exports/Mac/ABS-Client.dmg b/Exports/Mac/ABS-Client.dmg index a5b77b8..dc1f5a8 100644 Binary files a/Exports/Mac/ABS-Client.dmg and b/Exports/Mac/ABS-Client.dmg differ diff --git a/Exports/Mac/dmgmaker.sh b/Exports/Mac/dmgmaker.sh index 9ec663c..97e4aa7 100644 --- a/Exports/Mac/dmgmaker.sh +++ b/Exports/Mac/dmgmaker.sh @@ -1,9 +1,2 @@ -create-dmg \ - --volname "ABS-Client" \ - --window-size 600 400 \ - --icon-size 100 \ - --icon "ABS-Client.app" 150 200 \ - --app-drop-link 450 200 \ - ~/ABS-Client/Exports/Mac/ABS-Client.dmg \ - ABS Client.app -≈ +create-dmg --volname "ABS Client" --window-size 600 400 --icon-size 100 --icon "ABS Client.app" 150 200 --app-drop-link 450 200 ~/ABS-Client/Exports/Mac/ABS-Client.dmg 'ABS Client.app' +