diff --git a/AutoCat2.xcodeproj/project.pbxproj b/AutoCat2.xcodeproj/project.pbxproj index 9458998..5fb9815 100644 --- a/AutoCat2.xcodeproj/project.pbxproj +++ b/AutoCat2.xcodeproj/project.pbxproj @@ -36,6 +36,9 @@ 7A68399A269612EA00B2188A /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A683998269612EA00B2188A /* Response.swift */; }; 7ACD05D72695C08A00557667 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ACD05D62695C08A00557667 /* Constants.swift */; }; 7ACD05D82695C08A00557667 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ACD05D62695C08A00557667 /* Constants.swift */; }; + 7AEFAEED26985A3400ED2C85 /* ACProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AEFAEEC26985A3400ED2C85 /* ACProgressView.swift */; }; + 7AEFAEEE26985A3400ED2C85 /* ACProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AEFAEEC26985A3400ED2C85 /* ACProgressView.swift */; }; + 7AF552D92696E5C100578083 /* ApiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF552D82696E5C100578083 /* ApiTests.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -107,6 +110,8 @@ 7A40D6012694FF5D009B0BC4 /* Api.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Api.swift; sourceTree = ""; }; 7A683998269612EA00B2188A /* Response.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Response.swift; sourceTree = ""; }; 7ACD05D62695C08A00557667 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; + 7AEFAEEC26985A3400ED2C85 /* ACProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ACProgressView.swift; sourceTree = ""; }; + 7AF552D82696E5C100578083 /* ApiTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiTests.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -234,6 +239,7 @@ isa = PBXGroup; children = ( 7A40D5E826938BEC009B0BC4 /* AuthView.swift */, + 7AEFAEEC26985A3400ED2C85 /* ACProgressView.swift */, ); path = Views; sourceTree = ""; @@ -250,6 +256,7 @@ isa = PBXGroup; children = ( 7A40D5F52693A63A009B0BC4 /* SettingsTests.swift */, + 7AF552D82696E5C100578083 /* ApiTests.swift */, ); path = AutoCat2Tests; sourceTree = ""; @@ -464,6 +471,7 @@ 7A40D5E926938BEC009B0BC4 /* AuthView.swift in Sources */, 7ACD05D72695C08A00557667 /* Constants.swift in Sources */, 7A40D5E326924B09009B0BC4 /* Settings.swift in Sources */, + 7AEFAEED26985A3400ED2C85 /* ACProgressView.swift in Sources */, 7A40D5A02691C6D8009B0BC4 /* AutoCat2App.swift in Sources */, 7A683999269612EA00B2188A /* Response.swift in Sources */, 7A40D5A42691C6D8009B0BC4 /* Persistence.swift in Sources */, @@ -483,6 +491,7 @@ 7A40D5EA26938BEC009B0BC4 /* AuthView.swift in Sources */, 7ACD05D82695C08A00557667 /* Constants.swift in Sources */, 7A40D5A12691C6D8009B0BC4 /* AutoCat2App.swift in Sources */, + 7AEFAEEE26985A3400ED2C85 /* ACProgressView.swift in Sources */, 7A40D5A52691C6D8009B0BC4 /* Persistence.swift in Sources */, 7A68399A269612EA00B2188A /* Response.swift in Sources */, 7A40D5E526924B0C009B0BC4 /* User.swift in Sources */, @@ -515,6 +524,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 7AF552D92696E5C100578083 /* ApiTests.swift in Sources */, 7A40D5F62693A63A009B0BC4 /* SettingsTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/AutoCat2.xcodeproj/xcuserdata/selim.xcuserdatad/xcschemes/xcschememanagement.plist b/AutoCat2.xcodeproj/xcuserdata/selim.xcuserdatad/xcschemes/xcschememanagement.plist index 6d7bf61..65d954e 100644 --- a/AutoCat2.xcodeproj/xcuserdata/selim.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/AutoCat2.xcodeproj/xcuserdata/selim.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ AutoCat2 (iOS).xcscheme_^#shared#^_ orderHint - 0 + 1 AutoCat2 (macOS).xcscheme_^#shared#^_ orderHint - 1 + 0 AutoCatCore.xcscheme_^#shared#^_ diff --git a/AutoCat2Tests/ApiTests.swift b/AutoCat2Tests/ApiTests.swift new file mode 100644 index 0000000..75cd001 --- /dev/null +++ b/AutoCat2Tests/ApiTests.swift @@ -0,0 +1,29 @@ +import XCTest +import AutoCat2 + +class ApiTests: XCTestCase { + + private var api: Api! + + override func setUpWithError() throws { + let sessionConfig = URLSessionConfiguration.default + let session = URLSession(configuration: sessionConfig) + self.api = Api(session: session) + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testLogin() async throws { + let user = try await self.api.login() + } + +// func testPerformanceExample() throws { +// // This is an example of a performance test case. +// self.measure { +// // Put the code you want to measure the time of here. +// } +// } + +} diff --git a/Shared/Views/ACProgressView.swift b/Shared/Views/ACProgressView.swift new file mode 100644 index 0000000..2eed1cc --- /dev/null +++ b/Shared/Views/ACProgressView.swift @@ -0,0 +1,68 @@ +import SwiftUI + +struct ACProgressView: View { + @State var isDeterminate: Bool = false + @State var progress: CGFloat = 0 + @State var text: String? = nil + @State var isAnimating: Bool = false + + var body: some View { + ZStack(alignment: .center) { + Color.black.opacity(0.4) + VStack { + VStack(spacing: 24) { + if self.isDeterminate { + ZStack { + Circle() + .stroke(Color.secondary.opacity(0.2), style: StrokeStyle(lineWidth: 4)) + .frame(width: 100, height: 100) + Circle() + .trim(from: 0, to: self.progress) + .stroke(Color.blue, style: StrokeStyle(lineWidth: 4)) + .rotationEffect(.degrees(-90)) + .frame(width: 100, height: 100) + Text("\(Int(self.progress*100)) %") + } + } else { + let gradient = AngularGradient( + gradient: Gradient(colors: [Color.blue, Color.blue.opacity(0.01)]), + center: .center, + startAngle: .degrees(360), + endAngle: .degrees(0)) + Circle() + .stroke(gradient, style: StrokeStyle(lineWidth: 4)) + .rotationEffect(Angle(degrees: self.isAnimating ? 360 : 0)) + .onAppear { + withAnimation(.linear(duration: 1).repeatForever(autoreverses: false)) { + self.isAnimating = true + } + } + .onDisappear(perform: { + self.isAnimating = false + }) + .frame(width: 100, height: 100) + } + + if let msg = self.text { + Text(msg) + } + } + .padding(28) + } + //.frame(width: 160, height: 160) + .background(.regularMaterial) + .cornerRadius(20) + } + .edgesIgnoringSafeArea(.all) + } +} + +struct ACProgressView_Previews: PreviewProvider { + static var previews: some View { + Group { + ACProgressView() + ACProgressView(isDeterminate: true, progress: 0.3, text: "Loading...") + .preferredColorScheme(.dark) + } + } +} diff --git a/Shared/Views/AuthView.swift b/Shared/Views/AuthView.swift index 86045a6..0594e3c 100644 --- a/Shared/Views/AuthView.swift +++ b/Shared/Views/AuthView.swift @@ -5,22 +5,30 @@ struct AuthView: View { @State var login: String @State var password: String + @State var showProgress: Bool = false var body: some View { - VStack(alignment: .center, spacing: 16) { - Spacer() - TextField("Login", text: $login) - SecureField("Password", text: $password) - Button("Login") { - async { - try await self.viewModel.login(user: self.login, password: self.password) + ZStack { + VStack(alignment: .center, spacing: 16) { + Spacer() + TextField("Login", text: $login) + SecureField("Password", text: $password) + Button("Login") { + self.showProgress = true + async { + try await self.viewModel.login(user: self.login, password: self.password) + } } + Spacer() + } + .buttonStyle(.bordered) + .textFieldStyle(.roundedBorder) + .padding(20) + + if self.showProgress { + ACProgressView() } - Spacer() } - .buttonStyle(.bordered) - .textFieldStyle(.roundedBorder) - .padding(20) } }