Skip to content

Commit 05fbe6f

Browse files
yaroslavyaroslav
authored andcommitted
Initial commit: Project setup
1 parent 54e8b75 commit 05fbe6f

File tree

25 files changed

+163
-74
lines changed

25 files changed

+163
-74
lines changed

.gitignore

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,17 @@ DerivedData/
1717
*.ipa
1818
*.dSYM.zip
1919
*.dSYM
20+
*.xcodeproj/project.xcworkspace/
21+
*.xcodeproj/xcuserdata/
22+
*.xcworkspace/xcuserdata/
2023

2124
# Swift Package Manager
2225
.build/
2326
Packages/
2427
Package.pins
2528
Package.resolved
2629
.swiftpm
30+
*.xcodeproj/project.swiftpm/
2731

2832
# CocoaPods
2933
Pods/
@@ -35,4 +39,8 @@ Carthage/Build/
3539
fastlane/report.xml
3640
fastlane/Preview.html
3741
fastlane/screenshots/**/*.png
38-
fastlane/test_output
42+
fastlane/test_output
43+
44+
# Другие временные файлы
45+
*.swp
46+
*~

NetPulse.xcodeproj/project.pbxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@
257257
GENERATE_INFOPLIST_FILE = YES;
258258
INFOPLIST_KEY_CFBundleDisplayName = NetPulse;
259259
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
260-
INFOPLIST_KEY_NSHumanReadableCopyright = "";
260+
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 ykreo. All rights reserved.\n\n";
261261
LD_RUNPATH_SEARCH_PATHS = (
262262
"$(inherited)",
263263
"@executable_path/../Frameworks",
@@ -286,7 +286,7 @@
286286
GENERATE_INFOPLIST_FILE = YES;
287287
INFOPLIST_KEY_CFBundleDisplayName = NetPulse;
288288
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
289-
INFOPLIST_KEY_NSHumanReadableCopyright = "";
289+
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 ykreo. All rights reserved.\n\n";
290290
LD_RUNPATH_SEARCH_PATHS = (
291291
"$(inherited)",
292292
"@executable_path/../Frameworks",

NetPulse/Application/AppDelegate.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// NetPulse/Application/AppDelegate.swift
2+
// Copyright © 2025 ykreo. All rights reserved.
23

34
import SwiftUI
45
import OSLog

NetPulse/Core/Logger+Extensions.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// NetPulse/Core/Logger+Extensions.swift
2+
// Copyright © 2025 ykreo. All rights reserved.
23

34
import Foundation
45
import OSLog

NetPulse/Core/Managers/NetworkManager.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// NetPulse/Core/Managers/NetworkManager.swift
2+
// Copyright © 2025 ykreo. All rights reserved.
23

34
import Foundation
45
import SwiftUI
@@ -248,7 +249,7 @@ class NetworkManager: ObservableObject {
248249

249250
func wolPC() {
250251
self.executeAndNotify(title: "Компьютер (WOL)", successMessage: "WOL-пакет для ПК отправлен.") {
251-
let command = "/usr/bin/etherwake -i br-lan \(self.settingsManager.settings.pcMAC)" // Команда может отличаться для разных прошивок роутеров
252+
let command = "\(self.settingsManager.settings.wolCommand) \(self.settingsManager.settings.pcMAC)"
252253
_ = try await self.ssh(user: self.settingsManager.settings.sshUserRouter, host: self.settingsManager.settings.routerIP, command: command)
253254
}
254255
}
@@ -300,6 +301,8 @@ class NetworkManager: ObservableObject {
300301

301302
private func executeAndNotify(title: String, successMessage: String, task: @escaping () async throws -> Void) {
302303
Task {
304+
self.isUpdating = true // <- Включаем индикатор
305+
defer { self.isUpdating = false } // <- Гарантированно выключаем в конце
303306
do {
304307
try await task()
305308
self.sendNotification(title: title, body: successMessage)
@@ -328,4 +331,4 @@ class NetworkManager: ObservableObject {
328331
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil)
329332
UNUserNotificationCenter.current().add(request)
330333
}
331-
}
334+
}

NetPulse/Core/Managers/SettingsManager.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// NetPulse/Core/Managers/SettingsManager.swift
2-
2+
// Copyright © 2025 ykreo. All rights reserved.
33
import Foundation
44
import SwiftUI
55
import UniformTypeIdentifiers

NetPulse/Features/About/AboutView.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// NetPulse/Features/About/AboutView.swift
2-
// Код отличный, оставляем как есть.
2+
// Copyright © 2025 ykreo. All rights reserved.
33
import SwiftUI
44

55
struct AboutView: View {
@@ -64,7 +64,7 @@ struct AboutView: View {
6464
.padding(.horizontal, 32)
6565

6666
HStack(spacing: 16) {
67-
Text("Автор: \(settingsManager.author)")
67+
Text("Copyright © 2025 \(settingsManager.author). All rights reserved.")
6868
.font(.body)
6969
.foregroundColor(.secondary)
7070

@@ -127,4 +127,4 @@ private struct FeatureRow: View {
127127
.fill(Color(NSColor.controlBackgroundColor))
128128
)
129129
}
130-
}
130+
}

NetPulse/Features/Menu/MenuView.swift

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// NetPulse/Features/Menu/MenuView.swift
2-
2+
// Copyright © 2025 ykreo. All rights reserved.
33
import SwiftUI
44

55
struct MenuView: View {
@@ -248,24 +248,35 @@ private struct ActionsView: View {
248248
}
249249

250250
private struct ActionButton: View {
251+
@EnvironmentObject var manager: NetworkManager
251252
let title: String
252253
let icon: String
253254
let action: () -> Void
254255
let isEnabled: Bool
255-
256+
256257
var body: some View {
257258
Button(action: action) {
258-
VStack(spacing: 6) {
259-
Image(systemName: icon)
260-
.font(.system(size: 16, weight: .medium))
261-
.foregroundColor(isEnabled ? .accentColor : .secondary)
262-
263-
Text(title)
264-
.font(.caption)
265-
.fontWeight(.medium)
266-
.foregroundColor(isEnabled ? .primary : .secondary)
267-
.multilineTextAlignment(.center)
268-
.lineLimit(2)
259+
// Используем ZStack, чтобы наложить ProgressView поверх контента
260+
ZStack {
261+
// Контент кнопки (иконка и текст)
262+
VStack(spacing: 6) {
263+
Image(systemName: icon)
264+
.font(.system(size: 16, weight: .medium))
265+
266+
Text(title)
267+
.font(.caption)
268+
.fontWeight(.medium)
269+
.multilineTextAlignment(.center)
270+
.lineLimit(2)
271+
}
272+
.foregroundColor(isEnabled ? .primary : .secondary)
273+
.opacity(manager.isUpdating ? 0 : 1) // Скрываем, когда идет загрузка
274+
275+
// Индикатор загрузки
276+
if manager.isUpdating {
277+
ProgressView()
278+
.controlSize(.small)
279+
}
269280
}
270281
.frame(maxWidth: .infinity)
271282
.frame(height: 56)
@@ -279,7 +290,7 @@ private struct ActionButton: View {
279290
)
280291
}
281292
.buttonStyle(.plain)
282-
.disabled(!isEnabled)
293+
.disabled(!isEnabled || manager.isUpdating)
283294
}
284295
}
285296

@@ -301,26 +312,28 @@ private struct FooterView: View {
301312

302313
Spacer()
303314

304-
// Кнопка "Выход"
305-
Button("Выход") {
306-
NSApplication.shared.terminate(nil)
307-
}
308-
.buttonStyle(.bordered)
309-
.controlSize(.small)
310-
311-
// Кнопка "Настройки"
312-
Button(action: onSettings) {
313-
HStack(spacing: 6) {
314-
Image(systemName: "gearshape.fill")
315-
.font(.caption)
316-
Text("Настройки")
317-
.font(.caption)
318-
.fontWeight(.medium)
315+
// Симметричные кнопки одинакового размера
316+
HStack(spacing: 8) {
317+
Button("Выход") {
318+
NSApplication.shared.terminate(nil)
319319
}
320-
.frame(height: 24)
320+
.buttonStyle(.bordered)
321+
.controlSize(.regular)
322+
.frame(minWidth: 80)
323+
324+
Button(action: onSettings) {
325+
HStack(spacing: 4) {
326+
Image(systemName: "gearshape.fill")
327+
.font(.caption)
328+
Text("Настройки")
329+
.font(.caption)
330+
.fontWeight(.medium)
331+
}
332+
}
333+
.buttonStyle(.borderedProminent)
334+
.controlSize(.regular)
335+
.frame(minWidth: 80)
321336
}
322-
.buttonStyle(.borderedProminent)
323-
.controlSize(.small)
324337
}
325338
}
326339
}
@@ -367,4 +380,4 @@ private struct UnconfiguredView: View {
367380
.padding(.horizontal, 16)
368381
.padding(.vertical, 20)
369382
}
370-
}
383+
}

NetPulse/Features/Settings/SettingsView.swift

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// NetPulse/Features/Settings/SettingsView.swift
2-
2+
// Copyright © 2025 ykreo. All rights reserved.
33
import SwiftUI
44
import ServiceManagement
55
import OSLog
@@ -242,13 +242,13 @@ private struct GeneralSettingsTab: View {
242242
localSettings = settingsManager.settings
243243
}
244244
.buttonStyle(.bordered)
245-
.controlSize(.small)
245+
.controlSize(.regular)
246246

247247
Button("Экспорт...") {
248248
settingsManager.exportSettings()
249249
}
250250
.buttonStyle(.bordered)
251-
.controlSize(.small)
251+
.controlSize(.regular)
252252
}
253253
}
254254

@@ -261,7 +261,7 @@ private struct GeneralSettingsTab: View {
261261
localSettings = settingsManager.settings
262262
}
263263
.buttonStyle(.bordered)
264-
.controlSize(.small)
264+
.controlSize(.regular)
265265
}
266266
}
267267
}
@@ -313,7 +313,7 @@ private struct NetworkSettingsTab: View {
313313
) {
314314
Button("Проверить SSH", action: onTestRouter)
315315
.buttonStyle(.bordered)
316-
.controlSize(.small)
316+
.controlSize(.regular)
317317
}
318318
}
319319
}
@@ -338,6 +338,14 @@ private struct NetworkSettingsTab: View {
338338
prompt: "00:1A:2B:3C:4D:5E",
339339
description: "MAC адрес сетевой карты для Wake-on-LAN"
340340
)
341+
ValidationField(
342+
title: "Команда WOL",
343+
text: $localSettings.wolCommand,
344+
focusedField: $focusedField,
345+
isValid: !localSettings.wolCommand.isEmpty, // Простая проверка на непустое значение
346+
prompt: "/usr/bin/etherwake -i br-lan",
347+
description: "Команда для отправки WOL-пакета через роутер"
348+
)
341349

342350
ValidationField(
343351
title: "Пользователь SSH",
@@ -354,7 +362,7 @@ private struct NetworkSettingsTab: View {
354362
) {
355363
Button("Проверить SSH", action: onTestPC)
356364
.buttonStyle(.bordered)
357-
.controlSize(.small)
365+
.controlSize(.regular)
358366
}
359367
}
360368
}
@@ -497,39 +505,30 @@ private struct ValidationField: View {
497505
private struct SshKeyPicker: View {
498506
@Binding var keyPath: String
499507
let isValid: Bool
500-
508+
@State private var showEditSheet = false
509+
501510
var body: some View {
502511
SettingsRow(
503512
title: "Путь к SSH ключу",
504-
description: "Приватный ключ для авторизации на устройствах без пароля"
513+
description: "Приватный ключ для авторизации на устройствах"
505514
) {
506515
HStack(spacing: 8) {
507516
Text((keyPath as NSString).abbreviatingWithTildeInPath)
508-
.font(.body)
509-
.foregroundColor(isValid ? .primary : .secondary)
510517
.lineLimit(1)
511518
.truncationMode(.middle)
512-
.frame(minWidth: 120, alignment: .leading)
513-
514-
Button("Выбрать...") {
515-
let panel = NSOpenPanel()
516-
panel.canChooseFiles = true
517-
panel.canChooseDirectories = false
518-
panel.allowsMultipleSelection = false
519-
panel.title = "Выберите SSH ключ"
520-
panel.message = "Выберите файл приватного ключа для SSH подключения"
521-
522-
if panel.runModal() == .OK, let url = panel.urls.first {
523-
keyPath = url.path
524-
}
525-
}
526-
.buttonStyle(.bordered)
527-
.controlSize(.small)
528-
519+
.padding(.horizontal, 8)
520+
.padding(.vertical, 4)
521+
.background(Color(NSColor.controlBackgroundColor), in: RoundedRectangle(cornerRadius: 6))
522+
523+
Button("Изменить...") { showEditSheet = true }
524+
.controlSize(.regular) // Используем новый размер
525+
529526
Image(systemName: isValid ? "checkmark.circle.fill" : "xmark.circle.fill")
530-
.font(.caption)
531527
.foregroundColor(isValid ? .green : .red)
532528
}
533529
}
530+
.sheet(isPresented: $showEditSheet) {
531+
SshKeyEditView(keyPath: $keyPath)
532+
}
534533
}
535-
}
534+
}

0 commit comments

Comments
 (0)