Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions LaunchNext.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 26.0;
MACOSX_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
Expand Down Expand Up @@ -330,7 +330,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 26.0;
MACOSX_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
Expand Down
52 changes: 44 additions & 8 deletions LaunchNext/Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,59 @@ extension Font {
}
}

// MARK: - Glass Effect Style

enum LiquidGlassStyle {
case regular
case clear
case identity
}

// MARK: - View Extensions for Glass Effect
extension View {
@ViewBuilder
func liquidGlass<S: Shape>(in shape: S, isEnabled: Bool = true) -> some View {
if #available(macOS 26.0, iOS 18.0, *) {
self.glassEffect(.regular, in: shape)
func liquidGlass<S: Shape>(_ style: LiquidGlassStyle = .regular, in shape: S, isEnabled: Bool = true) -> some View {
if #available(macOS 26.0, iOS 26.0, *) {
switch style {
case .regular:
self.glassEffect(.regular, in: shape)
case .clear:
self.glassEffect(.clear, in: shape)
case .identity:
self.glassEffect(.identity, in: shape)
}
} else {
self.background(.ultraThinMaterial, in: shape)
switch style {
case .regular:
self.background(.regularMaterial, in: shape)
case .clear:
self.background(.ultraThinMaterial, in: shape)
case .identity:
self
}
}
}

@ViewBuilder
func liquidGlass(isEnabled: Bool = true) -> some View {
if #available(macOS 26.0, iOS 18.0, *) {
self.glassEffect(.regular)
func liquidGlass(_ style: LiquidGlassStyle = .regular, isEnabled: Bool = true) -> some View {
if #available(macOS 26.0, iOS 26.0, *) {
switch style {
case .regular:
self.glassEffect(.regular)
case .clear:
self.glassEffect(.clear)
case .identity:
self.glassEffect(.identity)
}
} else {
self.background(.ultraThinMaterial)
switch style {
case .regular:
self.background(.regularMaterial)
case .clear:
self.background(.ultraThinMaterial)
case .identity:
self
}
}
}
}
Expand Down
135 changes: 132 additions & 3 deletions LaunchNext/SettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ struct SettingsView: View {
.background(.ultraThinMaterial)

Button {
appStore.stopAccessibilityPolling()
appStore.isSetting = false
} label: {
Image(systemName: "xmark")
Expand Down Expand Up @@ -499,7 +500,7 @@ private enum SettingsSection: String, CaseIterable, Identifiable {
ScrollView(showsIndicators: false) {
scrollContent(for: section)
}
.scrollDisabled(section == .about || section == .general)
.scrollDisabled(section == .about)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.scrollBounceBehavior(.basedOnSize)
}
Expand Down Expand Up @@ -2207,7 +2208,7 @@ private enum SettingsSection: String, CaseIterable, Identifiable {
.padding(.vertical, 10)

label
.glassEffect(.clear, in: Capsule())
.liquidGlass(.clear, in: Capsule())
.clipShape(Capsule())
.shadow(color: Color.black.opacity(shadowOpacity), radius: shadowRadius, x: 0, y: shadowOffsetY)
.scaleEffect(scale)
Expand Down Expand Up @@ -2360,7 +2361,7 @@ private enum SettingsSection: String, CaseIterable, Identifiable {
.frame(maxWidth: .infinity)
}
.buttonStyle(.plain)
.glassEffect(.regular, in: RoundedRectangle(cornerRadius: 20, style: .continuous))
.liquidGlass(in: RoundedRectangle(cornerRadius: 20, style: .continuous))
}

// MARK: - Inline Games
Expand Down Expand Up @@ -2753,6 +2754,72 @@ private enum SettingsSection: String, CaseIterable, Identifiable {
.frame(maxWidth: .infinity, alignment: .leading)
}

Divider()

HStack(alignment: .center, spacing: 24) {
VStack(alignment: .leading, spacing: 4) {
HStack {
Text(appStore.localized(.kioskModeTitle))
.font(.subheadline.weight(.semibold))
Spacer()
Toggle("", isOn: $appStore.kioskMode)
.labelsHidden()
.toggleStyle(.switch)
}
Text(appStore.localized(.kioskModeDescription))
.font(.footnote)
.foregroundStyle(.secondary)
}
.frame(maxWidth: .infinity, alignment: .leading)

VStack(alignment: .leading, spacing: 4) {
HStack {
Text(appStore.localized(.autoFullscreenTitle))
.font(.subheadline.weight(.semibold))
Spacer()
Toggle("", isOn: $appStore.autoFullscreen)
.labelsHidden()
.toggleStyle(.switch)
.onAppear {
appStore.startAccessibilityPolling()
}
.onDisappear {
appStore.stopAccessibilityPolling()
}
.onChange(of: appStore.autoFullscreen) { newValue in
if newValue && !appStore.isAccessibilityTrusted() {
appStore.autoFullscreen = false
appStore.promptAccessibilityPermission()
}
}
}
Text(appStore.localized(.autoFullscreenDescription))
.font(.footnote)
.foregroundStyle(.secondary)
}
.frame(maxWidth: .infinity, alignment: .leading)
}

Divider()

HStack(alignment: .center, spacing: 24) {
VStack(alignment: .leading, spacing: 4) {
HStack {
Text(appStore.localized(.showInDockTitle))
.font(.subheadline.weight(.semibold))
Spacer()
Toggle("", isOn: $appStore.showInDock)
.labelsHidden()
.toggleStyle(.switch)
}
Text(appStore.localized(.showInDockDescription))
.font(.footnote)
.foregroundStyle(.secondary)
}
.frame(maxWidth: .infinity, alignment: .leading)

Spacer().frame(maxWidth: .infinity)
}
}
.padding(12)
.frame(maxWidth: .infinity, alignment: .leading)
Expand Down Expand Up @@ -3661,6 +3728,32 @@ private enum SettingsSection: String, CaseIterable, Identifiable {
.pickerStyle(.segmented)
.labelsHidden()
}

if #available(macOS 26.0, iOS 26.0, *) {
let useGlass = appStore.launchpadBackgroundStyle == .glass
let shape = RoundedRectangle(cornerRadius: 14, style: .continuous)

ZStack {
Image("AboutBackground")
.resizable()
.interpolation(.high)
.aspectRatio(contentMode: .fill)

HStack(spacing: 16) {
glassPreviewCard(label: "Regular", icon: "app.fill", style: .regular, useGlass: useGlass, shape: shape)
glassPreviewCard(label: "Clear", icon: "app.fill", style: .clear, useGlass: useGlass, shape: shape)
glassPreviewCard(label: "Identity", icon: "app.fill", style: .identity, useGlass: useGlass, shape: shape)
}
.padding(20)
}
.frame(height: 140)
.clipShape(RoundedRectangle(cornerRadius: 16, style: .continuous))
.overlay(
RoundedRectangle(cornerRadius: 16, style: .continuous)
.stroke(Color.white.opacity(0.18), lineWidth: 1.4)
)
.allowsHitTesting(false)
}
}
}

Expand Down Expand Up @@ -4017,6 +4110,39 @@ private enum SettingsSection: String, CaseIterable, Identifiable {
.padding(.bottom, 20)
}

@ViewBuilder
private func glassPreviewCard(label: String, icon: String, style: LiquidGlassStyle, useGlass: Bool, shape: some Shape) -> some View {
let content = VStack(spacing: 8) {
Image(systemName: icon)
.font(.title)
Text(label)
.font(.subheadline.weight(.medium))
}
.foregroundStyle(.white)
.frame(maxWidth: .infinity)
.padding(.vertical, 18)

if useGlass, #available(macOS 26.0, iOS 26.0, *) {
switch style {
case .regular:
content.glassEffect(.regular, in: shape)
case .clear:
content.glassEffect(.clear, in: shape)
case .identity:
content.glassEffect(.identity, in: shape)
}
} else {
switch style {
case .regular:
content.background(.regularMaterial, in: shape)
case .clear:
content.background(.ultraThinMaterial, in: shape)
case .identity:
content
}
}
}

// MARK: - Export / Import Application Support Data
private func supportDirectoryURL() throws -> URL {
let fm = FileManager.default
Expand Down Expand Up @@ -4181,6 +4307,9 @@ private enum SettingsSection: String, CaseIterable, Identifiable {
keys.insert("isStartOnLogin")
keys.insert(AppStore.showQuickRefreshButtonKey)
keys.insert(AppStore.lockLayoutKey)
keys.insert("kioskMode")
keys.insert("autoFullscreen")
keys.insert("showInDock")
keys.insert(AppStore.uninstallToolAppPathKey)
}
if appearanceCheckbox.state == .on {
Expand Down
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Reads directly from the system Launchpad database:
## Installation

### Requirements
- macOS 26 (Tahoe) or later
- macOS 15 (Sequoia) or later
- Apple Silicon or Intel processor
- Xcode 26 (for building from source)

Expand All @@ -69,12 +69,17 @@ Reads directly from the system Launchpad database:
cd LaunchNext
```

2. **Open in Xcode**
2. **Build the updater**
```bash
swift build --package-path UpdaterScripts/SwiftUpdater --configuration release --arch arm64 --arch x86_64 --product SwiftUpdater
```

3. **Open in Xcode**
```bash
open LaunchNext.xcodeproj
```

3. **Build and run**
4. **Build and run**
- Select your target device
- Press `⌘+R` to build and run
- Or `⌘+B` to build only
Expand Down Expand Up @@ -132,7 +137,7 @@ xcodebuild -project LaunchNext.xcodeproj -scheme LaunchNext -configuration Relea
### Common Issues

**Q: App won't start?**
A: Ensure macOS 26.0+ and check system permissions.
A: Ensure macOS 15.0+ and check system permissions.

## Contributing

Expand Down
13 changes: 9 additions & 4 deletions i18n/README.cs.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Data aplikace jsou bezpečně uložena v:
## Instalace

### Požadavky
- macOS 26 (Tahoe) nebo novější
- macOS 15 (Sequoia) nebo novější
- Procesor Apple Silicon nebo Intel
- Xcode 26 (pro sestavení ze zdrojového kódu)

Expand All @@ -69,12 +69,17 @@ Data aplikace jsou bezpečně uložena v:
cd LaunchNext
```

2. **Otevřít v Xcode**
2. **Sestavit aktualizátor**
```bash
swift build --package-path UpdaterScripts/SwiftUpdater --configuration release --arch arm64 --arch x86_64 --product SwiftUpdater
```

3. **Otevřít v Xcode**
```bash
open LaunchNext.xcodeproj
```

3. **Sestavit a spustit**
4. **Sestavit a spustit**
- Vyberte vaše cílové zařízení
- Stiskněte `⌘+R` pro sestavení a spuštění
- Nebo `⌘+B` pouze pro sestavení
Expand Down Expand Up @@ -132,7 +137,7 @@ xcodebuild -project LaunchNext.xcodeproj -scheme LaunchNext -configuration Relea
### Běžné problémy

**Q: Aplikace se nespustí?**
A: Ujistěte se, že máte macOS 26.0+ a zkontrolujte systémová oprávnění.
A: Ujistěte se, že máte macOS 15.0+ a zkontrolujte systémová oprávnění.

## Přispívání

Expand Down
13 changes: 9 additions & 4 deletions i18n/README.de.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ Liest direkt aus der System-Launchpad-Datenbank:
## Installation

### Anforderungen
- macOS 26 (Tahoe) oder später
- macOS 15 (Sequoia) oder später
- Apple Silicon oder Intel-Prozessor
- Xcode 26 (für Build aus Quellcode)

Expand All @@ -112,12 +112,17 @@ Liest direkt aus der System-Launchpad-Datenbank:
cd LaunchNext/LaunchNext
```

2. **In Xcode öffnen**
2. **Updater bauen**
```bash
swift build --package-path UpdaterScripts/SwiftUpdater --configuration release --arch arm64 --arch x86_64 --product SwiftUpdater
```

3. **In Xcode öffnen**
```bash
open LaunchNext.xcodeproj
```

3. **Bauen und ausführen**
4. **Bauen und ausführen**
- Wählen Sie Ihr Zielgerät
- Drücken Sie `⌘+R` zum Bauen und Ausführen
- Oder `⌘+B` nur zum Bauen
Expand Down Expand Up @@ -170,7 +175,7 @@ xcodebuild -project LaunchNext.xcodeproj -scheme LaunchNext -configuration Relea
### Häufige Probleme

**F: App startet nicht?**
A: Stellen Sie macOS 26.0+ sicher und prüfen Sie Systemberechtigungen.
A: Stellen Sie macOS 15.0+ sicher und prüfen Sie Systemberechtigungen.

**F: Import-Button fehlt?**
A: Überprüfen Sie, dass SettingsView.swift die Import-Funktionalität enthält.
Expand Down
Loading