Skip to content

Commit 3d513d1

Browse files
committed
feat: improve Services tab UI with sections and header button
1 parent 6157bff commit 3d513d1

4 files changed

Lines changed: 80 additions & 39 deletions

File tree

Casks/vpn-bypass.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# Or if using local tap: brew install --cask --no-quarantine ./Casks/vpn-bypass.rb
44

55
cask "vpn-bypass" do
6-
version "2.7.2"
6+
version "2.8.0"
77
sha256 "8da2ba2e2073f8dbcd9d413658e995d244b52adc94559aecc31690448a9acf42"
88

99
url "https://github.com/GeiserX/VPN-Bypass/releases/download/v#{version}/VPN-Bypass-#{version}.dmg"

Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<key>CFBundlePackageType</key>
2424
<string>APPL</string>
2525
<key>CFBundleShortVersionString</key>
26-
<string>2.7.2</string><!-- VERSION -->
26+
<string>2.8.0</string><!-- VERSION -->
2727
<key>CFBundleVersion</key>
2828
<string>22</string>
2929
<key>LSMinimumSystemVersion</key>

Sources/VPNBypassCore/SettingsView.swift

Lines changed: 73 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,14 @@ struct ServicesTab: View {
506506
}
507507
}
508508

509+
private var customServices: [RouteManager.ServiceEntry] {
510+
filteredServices.filter { $0.isCustom }
511+
}
512+
513+
private var builtInServices: [RouteManager.ServiceEntry] {
514+
filteredServices.filter { !$0.isCustom }
515+
}
516+
509517
private var enabledCount: Int {
510518
routeManager.config.services.filter { $0.enabled }.count
511519
}
@@ -529,6 +537,18 @@ struct ServicesTab: View {
529537
Text("\(enabledCount)/\(routeManager.config.services.count) enabled")
530538
.font(.system(size: 11))
531539
.foregroundColor(Theme.textSecondary)
540+
541+
Button {
542+
editingService = nil
543+
showingCustomServiceEditor = true
544+
} label: {
545+
Image(systemName: "plus.circle.fill")
546+
.font(.system(size: 16))
547+
.foregroundColor(Theme.purpleLight)
548+
.frame(width: 24, height: 24)
549+
}
550+
.buttonStyle(.plain)
551+
.help("Create Custom Service")
532552
}
533553
}
534554

@@ -635,43 +655,55 @@ struct ServicesTab: View {
635655

636656
// Services list
637657
ScrollView {
638-
LazyVStack(spacing: 2) {
639-
ForEach(filteredServices) { service in
640-
ServiceRow(service: service, onEdit: service.isCustom ? {
641-
editingService = service
642-
showingCustomServiceEditor = true
643-
} : nil)
658+
VStack(spacing: 8) {
659+
// Custom Services section
660+
if !customServices.isEmpty {
661+
VStack(alignment: .leading, spacing: 4) {
662+
Text("CUSTOM SERVICES")
663+
.font(.system(size: 10, weight: .bold, design: .rounded))
664+
.foregroundColor(Theme.textSecondary)
665+
.padding(.horizontal, 12)
666+
.padding(.top, 8)
667+
668+
LazyVStack(spacing: 2) {
669+
ForEach(customServices) { service in
670+
ServiceRow(service: service, onEdit: {
671+
editingService = service
672+
showingCustomServiceEditor = true
673+
})
674+
}
675+
}
676+
}
677+
.padding(.bottom, 4)
678+
.background(
679+
RoundedRectangle(cornerRadius: 10)
680+
.fill(Theme.bgElevated)
681+
)
644682
}
645-
}
646-
}
647-
.background(
648-
RoundedRectangle(cornerRadius: 10)
649-
.fill(Theme.bgElevated)
650-
)
651683

652-
// Add Custom Service button
653-
Button {
654-
editingService = nil
655-
showingCustomServiceEditor = true
656-
} label: {
657-
HStack(spacing: 6) {
658-
Image(systemName: "plus.circle.fill")
659-
.font(.system(size: 13))
660-
Text("Create Custom Service")
661-
.font(.system(size: 12, weight: .medium))
684+
// Built-in Services section
685+
if !builtInServices.isEmpty {
686+
VStack(alignment: .leading, spacing: 4) {
687+
Text("BUILT-IN SERVICES")
688+
.font(.system(size: 10, weight: .bold, design: .rounded))
689+
.foregroundColor(Theme.textSecondary)
690+
.padding(.horizontal, 12)
691+
.padding(.top, 8)
692+
693+
LazyVStack(spacing: 2) {
694+
ForEach(builtInServices) { service in
695+
ServiceRow(service: service, onEdit: nil)
696+
}
697+
}
698+
}
699+
.padding(.bottom, 4)
700+
.background(
701+
RoundedRectangle(cornerRadius: 10)
702+
.fill(Theme.bgElevated)
703+
)
704+
}
662705
}
663-
.foregroundColor(Theme.purple)
664-
.padding(.horizontal, 12)
665-
.padding(.vertical, 8)
666-
.frame(maxWidth: .infinity)
667-
.background(Theme.purple.opacity(0.1))
668-
.cornerRadius(8)
669-
.overlay(
670-
RoundedRectangle(cornerRadius: 8)
671-
.stroke(Theme.purple.opacity(0.3), lineWidth: 1)
672-
)
673706
}
674-
.buttonStyle(.plain)
675707
}
676708
}
677709
.sheet(isPresented: $showingCustomServiceEditor) {
@@ -705,10 +737,10 @@ struct ServiceRow: View {
705737
if service.isCustom {
706738
Text("Custom")
707739
.font(.system(size: 9, weight: .bold))
708-
.foregroundColor(Theme.purple)
740+
.foregroundColor(Theme.purpleLight)
709741
.padding(.horizontal, 5)
710742
.padding(.vertical, 1)
711-
.background(Theme.purple.opacity(0.15))
743+
.background(Theme.purple.opacity(0.12))
712744
.cornerRadius(4)
713745
}
714746
}
@@ -720,25 +752,29 @@ struct ServiceRow: View {
720752

721753
Spacer()
722754

723-
// Edit button for custom services
724-
if service.isCustom && isHovered {
755+
// Edit/delete buttons for custom services
756+
if service.isCustom {
725757
Button {
726758
onEdit?()
727759
} label: {
728760
Image(systemName: "pencil")
729761
.font(.system(size: 11))
730762
.foregroundColor(Theme.purple)
763+
.frame(width: 24, height: 24)
731764
}
732765
.buttonStyle(.plain)
766+
.opacity(isHovered ? 1.0 : 0.4)
733767

734768
Button {
735769
routeManager.removeCustomService(service.id)
736770
} label: {
737771
Image(systemName: "trash")
738772
.font(.system(size: 11))
739773
.foregroundColor(Theme.error)
774+
.frame(width: 24, height: 24)
740775
}
741776
.buttonStyle(.plain)
777+
.opacity(isHovered ? 1.0 : 0.4)
742778
}
743779

744780
// Toggle

docs/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ All notable changes to VPN Bypass will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [2.8.0] - 2026-05-04
9+
10+
### Improved
11+
- **Services tab UI** — Added "+" button in the header for quick custom service creation. Services list is now split into "Custom Services" (top) and "Built-in Services" sections with clear headers. Custom badge contrast improved for readability. Edit/delete buttons for custom services are always visible (no longer hover-only). Removed the old full-width bottom button that was hidden by scroll.
12+
813
## [2.7.2] - 2026-05-04
914

1015
### Fixed

0 commit comments

Comments
 (0)