You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

351 lines
13 KiB

import SwiftUI
import AVFoundation
import Photos
struct AppPermissionsView: View {
@EnvironmentObject private var languageManager: LanguageManager
@State private var cameraPermissionStatus: AVAuthorizationStatus = .notDetermined
@State private var photoPermissionStatus: PHAuthorizationStatus = .notDetermined
var body: some View {
NavigationView {
ZStack {
//
LinearGradient(
gradient: Gradient(colors: [
Color(.systemBackground),
Color(.systemGray6).opacity(0.2)
]),
startPoint: .top,
endPoint: .bottom
)
.ignoresSafeArea()
ScrollView {
VStack(spacing: 24) {
//
VStack(spacing: 16) {
ZStack {
Circle()
.fill(
LinearGradient(
gradient: Gradient(colors: [
Color.blue.opacity(0.1),
Color.blue.opacity(0.05)
]),
startPoint: .topLeading,
endPoint: .bottomTrailing
)
)
.frame(width: 80, height: 80)
Image(systemName: "lock.shield")
.font(.system(size: 36, weight: .light))
.foregroundColor(.blue)
}
Text("app_permissions".localized)
.font(.system(size: 28, weight: .bold, design: .rounded))
.foregroundColor(.primary)
.id(languageManager.refreshTrigger)
}
.padding(.top, 20)
//
VStack(alignment: .leading, spacing: 16) {
HStack {
Image(systemName: "info.circle")
.font(.system(size: 20, weight: .medium))
.foregroundColor(.blue)
.frame(width: 32)
Text("permissions_info".localized)
.font(.system(size: 18, weight: .semibold))
Spacer()
}
Text("permissions_description".localized)
.font(.system(size: 14))
.foregroundColor(.secondary)
.lineLimit(nil)
}
.padding(20)
.background(
RoundedRectangle(cornerRadius: 16)
.fill(Color(.systemBackground))
.shadow(color: .black.opacity(0.05), radius: 8, x: 0, y: 2)
)
.padding(.horizontal, 20)
//
PermissionCard(
icon: "camera.fill",
iconColor: .blue,
title: "camera_permission".localized,
description: "camera_permission_description".localized,
status: cameraPermissionStatus.displayText,
statusColor: cameraPermissionStatus.statusColor,
action: {
requestCameraPermission()
},
actionTitle: cameraPermissionStatus.actionTitle
)
//
PermissionCard(
icon: "photo.fill",
iconColor: .green,
title: "photo_permission".localized,
description: "photo_permission_description".localized,
status: photoPermissionStatus.displayText,
statusColor: photoPermissionStatus.statusColor,
action: {
requestPhotoPermission()
},
actionTitle: photoPermissionStatus.actionTitle
)
//
VStack(alignment: .leading, spacing: 16) {
HStack {
Image(systemName: "gearshape.fill")
.font(.system(size: 20, weight: .medium))
.foregroundColor(.orange)
.frame(width: 32)
Text("system_settings".localized)
.font(.system(size: 18, weight: .semibold))
Spacer()
}
Text("system_settings_description".localized)
.font(.system(size: 14))
.foregroundColor(.secondary)
.lineLimit(nil)
Button(action: {
openSystemSettings()
}) {
HStack {
Image(systemName: "arrow.up.right.square")
.font(.system(size: 16, weight: .medium))
Text("open_system_settings".localized)
.font(.system(size: 16, weight: .medium))
}
.foregroundColor(.white)
.padding(.horizontal, 20)
.padding(.vertical, 12)
.background(
RoundedRectangle(cornerRadius: 8)
.fill(Color.blue)
)
}
}
.padding(20)
.background(
RoundedRectangle(cornerRadius: 16)
.fill(Color(.systemBackground))
.shadow(color: .black.opacity(0.05), radius: 8, x: 0, y: 2)
)
.padding(.horizontal, 20)
Spacer(minLength: 30)
}
}
}
.navigationTitle("App Permissions")
.navigationBarTitleDisplayMode(.inline)
.onAppear {
checkPermissions()
}
}
}
// MARK: -
private func checkPermissions() {
cameraPermissionStatus = AVCaptureDevice.authorizationStatus(for: .video)
photoPermissionStatus = PHPhotoLibrary.authorizationStatus()
}
// MARK: -
private func requestCameraPermission() {
AVCaptureDevice.requestAccess(for: .video) { granted in
DispatchQueue.main.async {
self.cameraPermissionStatus = granted ? .authorized : .denied
}
}
}
// MARK: -
private func requestPhotoPermission() {
PHPhotoLibrary.requestAuthorization { status in
DispatchQueue.main.async {
self.photoPermissionStatus = status
}
}
}
// MARK: -
private func openSystemSettings() {
if let settingsUrl = URL(string: UIApplication.openSettingsURLString) {
UIApplication.shared.open(settingsUrl)
}
}
}
// MARK: -
struct PermissionCard: View {
let icon: String
let iconColor: Color
let title: String
let description: String
let status: String
let statusColor: Color
let action: () -> Void
let actionTitle: String
var body: some View {
VStack(alignment: .leading, spacing: 16) {
HStack {
Image(systemName: icon)
.font(.system(size: 20, weight: .medium))
.foregroundColor(iconColor)
.frame(width: 32)
VStack(alignment: .leading, spacing: 4) {
Text(title)
.font(.system(size: 18, weight: .semibold))
Text(description)
.font(.system(size: 14))
.foregroundColor(.secondary)
}
Spacer()
}
HStack {
Text(status)
.font(.system(size: 14, weight: .medium))
.foregroundColor(statusColor)
Spacer()
Button(action: action) {
Text(actionTitle)
.font(.system(size: 14, weight: .medium))
.foregroundColor(.white)
.padding(.horizontal, 16)
.padding(.vertical, 8)
.background(
RoundedRectangle(cornerRadius: 6)
.fill(statusColor)
)
}
}
}
.padding(20)
.background(
RoundedRectangle(cornerRadius: 16)
.fill(Color(.systemBackground))
.shadow(color: .black.opacity(0.05), radius: 8, x: 0, y: 2)
)
.padding(.horizontal, 20)
}
}
// MARK: -
extension AVAuthorizationStatus {
var displayText: String {
switch self {
case .notDetermined:
return "not_determined".localized
case .restricted:
return "restricted".localized
case .denied:
return "denied".localized
case .authorized:
return "authorized".localized
@unknown default:
return "unknown".localized
}
}
var statusColor: Color {
switch self {
case .notDetermined:
return .orange
case .restricted, .denied:
return .red
case .authorized:
return .green
@unknown default:
return .gray
}
}
var actionTitle: String {
switch self {
case .notDetermined:
return "request_permission".localized
case .restricted, .denied:
return "open_settings".localized
case .authorized:
return "permission_granted".localized
@unknown default:
return "unknown".localized
}
}
}
extension PHAuthorizationStatus {
var displayText: String {
switch self {
case .notDetermined:
return "not_determined".localized
case .restricted:
return "restricted".localized
case .denied:
return "denied".localized
case .authorized:
return "authorized".localized
case .limited:
return "limited".localized
@unknown default:
return "unknown".localized
}
}
var statusColor: Color {
switch self {
case .notDetermined:
return .orange
case .restricted, .denied:
return .red
case .authorized, .limited:
return .green
@unknown default:
return .gray
}
}
var actionTitle: String {
switch self {
case .notDetermined:
return "request_permission".localized
case .restricted, .denied:
return "open_settings".localized
case .authorized, .limited:
return "permission_granted".localized
@unknown default:
return "unknown".localized
}
}
}
#Preview {
AppPermissionsView()
.environmentObject(LanguageManager.shared)
}