PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0
Showing posts with label swiftui. Show all posts
Showing posts with label swiftui. Show all posts

Monday, November 7, 2022

[FIXED] How to prevent Picker to fold into a submenu in SwiftUI macOS

 November 07, 2022     macos, menu, picker, swiftui     No comments   

Issue

I'm trying to combine Picker and some buttons inside Menu in macOS SwiftUI app. Unfortunately Picker is folding into submenu automatically and I'm struggle to find a solution. How to prevent Picker to fold, or maybe there is a better solution around?

Menu("Budgets") {
    Picker("Budgets", selection: $account) {
        Button("Personal") {}.tag(1)
        Button("Business") {}.tag(2)
    }.labelsHidden()
                
    Divider()
                
    Button("New Budget…") {}
    Button("Manage Budgets…") {}
}

Preview


Solution

You need inline picker style, like

 Picker("Budgets", selection: $account) {
      Button("Personal") {}.tag(1)
      Button("Business") {}.tag(2)
 }
 .labelsHidden()
 .pickerStyle(.inline)    // << here !!

enter image description here



Answered By - Asperi
Answer Checked By - Timothy Miller (PHPFixing Admin)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Monday, October 17, 2022

[FIXED] How to return to "View Parent" from ASWebAutheticationSession

 October 17, 2022     aswebauthenticationsession, macos, oauth, swift, swiftui     No comments   

Issue

How to return from the ASWebAutheticationSession completion handler back to the View?

Edit: Just for clearance this is not the original code in my project this is extremely shortened and is just for showcasing what I mean.

Here's an example of a code

struct SignInView: View {
    
    @EnvironmentObject var signedIn: UIState
    
    var body: some View {
        let AuthenticationSession = AuthSession()
        AuthenticationSession.webAuthSession.presentationContextProvider = AuthenticationSession
        AuthenticationSession.webAuthSession.prefersEphemeralWebBrowserSession = true
        AuthenticationSession.webAuthSession.start()
    }
}

class AuthSession: NSObject, ObservableObject, ASWebAuthenticationPresentationContextProviding {
    var webAuthSession = ASWebAuthenticationSession.init(
        url: AuthHandler.shared.signInURL()!,
        callbackURLScheme: "",
        completionHandler: { (callbackURL: URL?, error: Error?) in
            
            // check if any errors appeared
            
            // get code from authentication

            // Return to view to move on with code? (return code)
        })

    func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {

        return ASPresentationAnchor()
    }

}

So what I'm trying to do is call the sign In process and then get back to the view with the code from the authentication to move on with it.

Could somebody tell me how this may be possible? Thanks.


Solution

Not sure if I'm correctly understanding your question but it is normally done with publishers, commonly with the @Published wrapper, an example:

import SwiftUI
import Combine

struct ContentView: View {
    @ObservedObject var viewModel = ViewModel()
    
    var body: some View {
        VStack {
            Button {
                self.viewModel.signIn(user: "example", password: "example")
            }
            label: {
                Text("Sign in")
            }
            
            if self.viewModel.signedIn {
                Text("Successfully logged in")
            }
            else if let error = self.viewModel.signingError {
                Text("Error while logging in: \(error.localizedDescription)")
            }
        }
        .padding()
    }
}

class ViewModel: ObservableObject {
    @Published var signingStatus = SigningStatus.idle
    
    var signedIn: Bool {
        if case .success = self.signingStatus { return true }
        
        return false
    }
    
    var signingError: Error? {
        if case .failure(let error) = self.signingStatus { return error }
        
        return nil
    }
    
    func signIn(user: String, password: String) {
        self.dummyAsyncProcessWithCompletionHandler { [weak self] success in
            guard let self = self else { return }
            
            guard success else {
                self.updateSigning(.failure(CustomError(errorDescription: "Login failed")))
                return
            }
            
            self.updateSigning(.success)
        }
    }
    
    private func updateSigning(_ status: SigningStatus) {
        DispatchQueue.main.async {
            self.signingStatus = status
        }
    }
    
    private func dummyAsyncProcessWithCompletionHandler(completion: @escaping (Bool) -> ()) {
        Task {
            print("Signing in")

            try await Task.sleep(nanoseconds: 500_000_000)
            
            guard Int.random(in: 0..<9) % 2 == 0 else {
                print("Error")
                completion(false)
                return
            }
            
            print("Success")
            completion(true)
        }
    }
    
    enum SigningStatus {
        case idle
        case success
        case failure(Error)
    }
    
    struct CustomError: Error, LocalizedError {
        var errorDescription: String?
    }
}


Answered By - Marc Biosca
Answer Checked By - Pedro (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Friday, September 30, 2022

[FIXED] how do I construct a swiftui class annotated mainactor in preview

 September 30, 2022     concurrency, swiftui     No comments   

Issue

So - I have a class called settings, that I use all over the place - and particularly want other views to react when stuff is changed. I've annotated it with @MainActor - and when running the app, it all works fine.

however, in a preview I just try and create an instance:

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {        
        Group {
            ContentView( settings: Settings())
        }
    }
}

And suddenly, while the main program compiles and runs fine - the preview doesn't -

call to main actor-isolated initialiser 'init()' in a synchronous non isolated context.

Which I can get around with code like the following:

struct ContentView_Previews: PreviewProvider {
    
    var settings : Settings
    
    static func get_settings() -> Settings
    {
        var the_array : [Settings] =  []
        DispatchQueue.main.asyncAndWait( execute: DispatchWorkItem {
            the_array.append( Settings())
        })
        return the_array[0]
    }
    
    init()
    {
        self.settings = ContentView_Previews.get_settings()
    }
    
    static var previews: some View {        
        Group {
            ContentView( settings: Settings())
        }
    }
}

which is obviously ridiculous. I'm sure there's a better way - but don't know what it is - how can I do this in one or two lines, without having to make a helper function?

btw - THIS code crashes the preview provider every time:



struct ContentView_Previews: PreviewProvider {
        
    static func get_settings() -> Settings
    {
        var the_array : [Settings] =  []
        DispatchQueue.main.asyncAndWait( execute: DispatchWorkItem {
            the_array.append( Settings())
        })
        return the_array[0]
    }
  
    static var previews: some View {        
        Group {
            ContentView( settings: get_settings())
        }
    }
}

Solution

I was able to fix this issue by annotating the preview struct with @MainActor

@MainActor
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {        
        Group {
            ContentView( settings: Settings())
        }
    }
}


Answered By - Rob McMorran
Answer Checked By - Terry (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Thursday, September 29, 2022

[FIXED] How to change "MENU" button behaviour to not terminate App

 September 29, 2022     swiftui, tvos     No comments   

Issue

Just right at the start: I don't want to change the user experience from Apple's user experience guidelines, I actually want to bring it back to my App, so here's the problem:

The "MENU" button should go back one level in the navigation hierarchy and terminate the App if there is no level anymore.

My first navigation screen also has an initially hidden full screen view (e.g. a video player). From this first navigation screen the user can go to deeper levels. The "MENU" button has its correct standard behavior.

The deepest navigation level then shows the hidden full screen view. When the user presses "MENU", the navigation should go back to the last level, but instead it terminates the App.

How can I change the behavior of the "MENU" button just for this single view?


Solution

It is not difficult to implement this. Just make sure the initial Screen that is displayed to the User is not the root View.

I will put the stack here. Root View contains two views namely,

  1. VideoContainerView and

  2. MainContainerView.

VideoContainerView will have a UIViewController, which has menuHandler button listener. This VC displays anotherView on top of RootView on button press.

MainContainerView will have UIViewController, which doesn't have any menuHandler. MainContainerView is displayed on top of the VideoContainerView.

STACK

MainContainerView (Top)

VideoContainerView

RootViewController

RootView -> VideoContainerView (A View containing VideoScreenController) RootView -> MainContainerView (A View containing MainViewController)

RootView -> VideoContainerView -> VideoScreen (Initial Screen, make sure this is a View Controller displayed on top of that FirstView using ContainerView).

From the VideoScreenController, Menu button press will display the RootView's MainContainerView which was hidden till now on top of that VideoContainerView.

On Next Menu button press, the app will go to background, as the MainViewController doesn't handle any menu Button press.

Never listen to any MenuButton press on the RootView's topView.

One can easily control the preferred focus flow using,

override var preferredFocusEnvironments: [UIFocusEnvironment] {
   if topView.isHidden {
      return [VideoContainerView]
   } else {
      return [MainContainerView]
   }

}

Like wise, have preferredFocusEnvironments in every ViewController to handle the initial preferred Focus, so that system is aware which is currently focused.

The above code, helps the system to know, which view should be focused on launch or on every focus change.



Answered By - Senthil
Answer Checked By - Robin (PHPFixing Admin)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

[FIXED] How to make a SwiftUI list scrollable in tvOS

 September 29, 2022     listview, scroll, scrollview, swiftui, tvos     No comments   

Issue

I have a List with content and when I build to an Apple Tv I cannot scroll to the bottom of the List.

I tried the focusable on the List rows but I cannot seem to get the list to scroll. I also replaced the List with a ScrollView to no avail.

List(self.someData) { data in
     SomeListRow(data: data)
}
.shadow(radius: 5)
.focusable(true)

List(self.someData) { data in
     SomeListRow(data: data)
      .focusable(true)

}
.shadow(radius: 5)

Solution

SwiftUI on tvOS has a bug where if you set a shadow on something none of the components in it receive user input events such as focus. There's an easy workaround though, just set your shadow on the background layer.

.background(
    Color.white
        .shadow(radius: 5)
)


Answered By - Jeff
Answer Checked By - Cary Denson (PHPFixing Admin)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

[FIXED] How to add an additional platform to a SwiftUI project

 September 29, 2022     ios, swift, swiftui, tvos, watchos     No comments   

Issue

I've started with a SwiftUI project for iOS. Now I'd like to add tvOS and watchOS as additional target platforms. Of course all platforms should share the same models, APIs and some views. Some views will be different for each platform.

How can I add subprojects to my existing structure?


Solution

It is not necessary to create new sub-projects, just create new target for desired platform in you current project and add shared files to new platform target, as on demo below

demo



Answered By - Asperi
Answer Checked By - Marilyn (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

[FIXED] How can I scroll vertically in tvOS with SwiftUI?

 September 29, 2022     apple-tv, ios, swift, swiftui, tvos     No comments   

Issue

I don't know it's a SwiftUI specific problem but I can't scroll vertically in tvOS. It's just simple List that shows items.

var body: some View {
    List(items, id: \.self) { item in
         ItemView(item: item)
    }
}

There are 50+ items, but I can see about 10 of them.

I tried option + arrow keys, also tried with simulator's remote by holding option key. non of them worked. Is there anyone who encountered with it?

Thank you.


Solution

On tvOS List content should be active, like buttons, and then you can use Remote, or arrows on keyboard for simulator to scroll through

(tested with Xcode 11.4)

var body: some View {
    List(items, id: \.self) { item in
         Button(action: {}) {
           ItemView(item: item)
         }
    }
}


Answered By - Asperi
Answer Checked By - Robin (PHPFixing Admin)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Wednesday, September 28, 2022

[FIXED] How to use custom font in a tvOS project using SwiftUI?

 September 28, 2022     custom-font, fonts, swiftui, tvos     No comments   

Issue

I made an App for iOS and MacOS and I am now working on the tvOS version. The issue I am facing is that the custom font is not working when I use the following code for tvOS!

import SwiftUI

struct TestView: View {
    var body: some View {
      Text("R")
      .font(.custom("Arial Rounded MT Bold", size: 160))
      .bold()
      .shadow(color: Color.black, radius: 15, x: 15, y: 5)
      .foregroundColor(Color(red: 255 / 255.0, green: 194 / 255.0, blue: 58 / 255.0))
    }
}

struct TestView_Previews: PreviewProvider {
    static var previews: some View {
        TestView()
    }
}

The wrong result with the above code is the below letter:

Wrong Letter

The good letter that should be displayed by the above code should look like the one below:

Good letter I want to writte

What am I missing? Thanks


Solution

You are right that works for iOS & macOS but doesn't work for tvOS. Maybe because there are different built-in fonts available for iOS and tvOS? I don't have expertise in tvOS, so please don't assume I'm right. I'm guessing it from this available font list.

tvOS: Try something from this list, and I'm sure it'll work.

enter image description here

iOS:

enter image description here



Answered By - Harshil Patel
Answer Checked By - Mary Flores (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

[FIXED] How to detect a 'Click' gesture in SwiftUI tvOS

 September 28, 2022     swift, swiftui, tvos     No comments   

Issue

Using:

  • SwiftUI
  • Swift 5
  • tvOS
  • Xcode Version 11.2.1

I just want to detect a click gesture on the URLImage below

JFYI I am very new to Xcode, Swift and SwiftUI (less than 3 weeks).

URLImage(URL(string: channel.thumbnail)!,
                 delay: 0.25,
                 processors: [ Resize(size: CGSize(width:isFocused ?  300.0 : 225.0, height:isFocused ?  300.0 : 225.0), scale: UIScreen.main.scale) ],
                 content:  {
                    $0.image
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                        .clipped()
        })
            .frame(width: isFocused ?  300.0 : 250.0, height:isFocused ?  300.0 : 250.0)
            .clipShape(Circle())
            .overlay(
                Circle().stroke( isFocused ? Color.white : Color.black, lineWidth: 8))
            .shadow(radius:5)
            .focusable(true, onFocusChange:{ (isFocused) in
                withAnimation(.easeInOut(duration:0.3)){
                    self.isFocused = isFocused
                }
                if(isFocused){
                    self.manager.bannerChannel = self.channel
                    print(self.manager.bannerChannel)
                    self.manager.loadchannelEPG(id: self.channel.id)
                }
            })
            .padding(20)
    }
  • The only workaround I have found is wrapping it in a NavigationLink or a Button but then focusable on the button doesn't run.
  • I found out that focusable runs on a Button/NavigationLink if I add corner radius to it but then the default click action doesn't run
  • Also, TapGesture is not available in tvOS

Since Gestures are available maybe there is a way using gestures that I cannot figure out.

OR

If there is a way to tap into focusable on a button (although this is the less favoured alternative since this changes the look I want to achieve).


Solution

Edit: onTapGesture() is now available starting in tvOS 16

tvOS 16

struct ContentView: View {
    @FocusState var focused1
    @FocusState var focused2

    var body: some View {
        HStack {
            Text("Clickable 1")
                .foregroundColor(self.focused1 ? Color.red : Color.black)
                .focusable(true)
                .focused($focused1)
                .onTapGesture {
                    print("clicked 1")
                }
            Text("Clickable 2")
                .foregroundColor(self.focused2 ? Color.red : Color.black)
                .focusable(true)
                .focused($focused2)
                .onTapGesture {
                    print("clicked 2")
                }
        }
        
    }
}

Previous Answer for tvOS 15 and earlier

It is possible, but not for the faint of heart. I came up with a somewhat generic solution that may help you. I hope in the next swiftUI update Apple adds a better way to attach click events for tvOS and this code can be relegated to the trash bin where it belongs.

The high level explanation of how to do this is to make a UIView that captures the focus and click events, then make a UIViewRepresentable so swiftUI can use the view. Then the view is added to the layout in a ZStack so it's hidden, but you can receive focus and respond to click events as if the user was really interacting with your real swiftUI component.

First I need to make a UIView that captures the events.

class ClickableHackView: UIView {
    weak var delegate: ClickableHackDelegate?
    
    override init(frame: CGRect) {
        super.init(frame: frame)        
    }

    override func pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
        if event?.allPresses.map({ $0.type }).contains(.select) ?? false {
            delegate?.clicked()
        } else {
            superview?.pressesEnded(presses, with: event)
        }
    }

    override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
        delegate?.focus(focused: isFocused)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override var canBecomeFocused: Bool {
        return true
    }
}

The clickable delegate:

protocol ClickableHackDelegate: class {
    func focus(focused: Bool)
    func clicked()
}

Then make a swiftui extension for my view

struct ClickableHack: UIViewRepresentable {
    @Binding var focused: Bool
    let onClick: () -> Void
    
    func makeUIView(context: UIViewRepresentableContext<ClickableHack>) -> UIView {
        let clickableView = ClickableHackView()
        clickableView.delegate = context.coordinator
        return clickableView
    }
    
    func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<ClickableHack>) {
    }
    
    func makeCoordinator() -> Coordinator {
        return Coordinator(self)
    }
    
    class Coordinator: NSObject, ClickableHackDelegate {
        private let control: ClickableHack
        
        init(_ control: ClickableHack) {
            self.control = control
            super.init()
        }
        
        func focus(focused: Bool) {
            control.focused = focused
        }
        
        func clicked() {
            control.onClick()
        }
    }
}

Then I make a friendlier swiftui wrapper so I can pass in any kind of component I want to be focusable and clickable

struct Clickable<Content>: View where Content : View {
    let focused: Binding<Bool>
    let content: () -> Content
    let onClick: () -> Void
    
    @inlinable public init(focused: Binding<Bool>, onClick: @escaping () -> Void, @ViewBuilder content: @escaping () -> Content) {
        self.content = content
        self.focused = focused
        self.onClick = onClick
    }
    
    var body: some View {
        ZStack {
            ClickableHack(focused: focused, onClick: onClick)
            content()
        }
    }
}

Example usage:

struct ClickableTest: View {
    @State var focused1: Bool = false
    @State var focused2: Bool = false
    
    var body: some View {
        HStack {
            Clickable(focused: self.$focused1, onClick: {
                print("clicked 1")
            }) {
                Text("Clickable 1")
                    .foregroundColor(self.focused1 ? Color.red : Color.black)
            }
            Clickable(focused: self.$focused2, onClick: {
                print("clicked 2")
            }) {
                Text("Clickable 2")
                    .foregroundColor(self.focused2 ? Color.red : Color.black)
            }
        }
    }
}


Answered By - Jeff
Answer Checked By - Timothy Miller (PHPFixing Admin)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Monday, August 22, 2022

[FIXED] How to hide TextFields keyboard onTap by using FocusedValue key path?

 August 22, 2022     environment-variables, ios, swiftui     No comments   

Issue

I am trying to achieve hiding keyboard when .onTap anywhere in screen by using new .focused() methods which came with iOS15 (SwiftUI 3).

First declare my FocusedValueKey

struct FocusedTextField: FocusedValueKey {
    
    enum Field: Hashable {
        case firstName
        case lastName
        case emailAddress
    }
    
    typealias Value = FocusState<Field>.Binding
}

extension FocusedValues {
    var textField: FocusedTextField.Value? {
        get { self[FocusedTextField.self] }
        set { self[FocusedTextField.self] = newValue }
    }
}

then in MainApp, I put FocusState to pass nil to the path when I tapped anywhere in screen.

struct TextFieldTestApp: App {
    
    @FocusState private var state: FocusedTextField.Field?
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onTapGesture { state = nil }
                .focusedValue(\.textField, $state)
        }
    }
}

Then I create my ContentView

struct ContentView: View {

    @State private var firstName = ""
    @State private var lastName = ""
    @State private var emailAddress = ""

    // Error: Key path value type 'FocusedTextField.Value?' (aka 'Optional<FocusState<FocusedTextField.Field>.Binding>')
    // cannot be converted to contextual type 'Binding<Value>?'
    @FocusedBinding(\.textField) var focusedTextField 

    var body: some View {
        ZStack {
            Color.red
        VStack {
            Spacer()
            TextField("Enter your first name", text: $firstName)
                // Error: Type 'Hashable' has no member 'firstName'
                .focused($focusedTextField, equals: .firstName)
                .textContentType(.givenName)
                .submitLabel(.next)

            TextField("Enter your last name", text: $lastName)
                // Error: Type 'Hashable' has no member 'lastName'
                .focused(focusedTextField, equals: .lastName)
                .textContentType(.familyName)
                .submitLabel(.next)

            TextField("Enter your email address", text: $emailAddress)
                // Error: Type 'Hashable' has no member 'emailAddress'
                .focused(focusedTextField, equals: .emailAddress)
                .textContentType(.emailAddress)
                .submitLabel(.join)
            Spacer()
        }
    }
    }
}

I also tried it with environment variables but @FocusState PropertyWrapper causes problems again.


Solution

A FocusedValueKey is for changed value (ex. if you would want to pass entered text or state value), binding to focused state is not changed and does not fit concept (so signature is not matched).

As far as I can understand your goal it can be achieved by direct focused state injection into ContentView.

Here is an approach (w/o much refactoring of your code). Tested with Xcode 13 / iOS 15

demo

struct TextFieldTestApp: App {
    
    @FocusState private var state: FocusedTextField.Field?
    
    var body: some Scene {
        WindowGroup {
            ContentView(focusedTextField: $state)
                .onTapGesture { state = nil }
        }
    }
}

struct ContentView: View {

    @State private var firstName = ""
    @State private var lastName = ""
    @State private var emailAddress = ""

    var focusedTextField: FocusState<FocusedTextField.Field?>.Binding

    var body: some View {
        ZStack {
            Color.red
            VStack {
                Spacer()
                TextField("Enter your first name", text: $firstName)
                    .focused(focusedTextField, equals: .firstName)
                    .textContentType(.givenName)
                    .submitLabel(.next)

                TextField("Enter your last name", text: $lastName)
                    .focused(focusedTextField, equals: .lastName)
                    .textContentType(.familyName)
                    .submitLabel(.next)

                TextField("Enter your email address", text: $emailAddress)
                    .focused(focusedTextField, equals: .emailAddress)
                    .textContentType(.emailAddress)
                    .submitLabel(.join)
                Spacer()
            }
        }
    }
}

Update:

Here is an approach based on EnvironmentValues. Tested in same environment.

struct TextFieldTestApp: App {
    
    @FocusState private var state: FocusedTextField.Field?
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onTapGesture { state = nil }
                .environment(\.textField, $state)
        }
    }
}

struct FocusedTextField: EnvironmentKey {
    static var defaultValue: FocusState<Field?>.Binding? = nil

    enum Field: Hashable {
        case firstName
        case lastName
        case emailAddress
    }

    typealias Value = FocusState<Field?>.Binding?
}

extension EnvironmentValues {
    var textField: FocusedTextField.Value {
        get { self[FocusedTextField.self] }
        set { self[FocusedTextField.self] = newValue }
    }
}

struct ContentView: View {

    @State private var firstName = ""
    @State private var lastName = ""
    @State private var emailAddress = ""

    @Environment(\.textField) private var focusedTextField

    var body: some View {
        ZStack {
            Color.red
            VStack {
                Spacer()
                TextField("Enter your first name", text: $firstName)
                    .focused(focusedTextField!, equals: .firstName)                     
                    .textContentType(.givenName)
                    .submitLabel(.next)

                TextField("Enter your last name", text: $lastName)
                    .focused(focusedTextField!, equals: .lastName)
                    .textContentType(.familyName)
                    .submitLabel(.next)

                TextField("Enter your email address", text: $emailAddress)
                    .focused(focusedTextField!, equals: .emailAddress)
                    .textContentType(.emailAddress)
                    .submitLabel(.join)
                Spacer()
            }
        }
    }
}

Note: for demo simplicity environment value is force-unwrapped, but for real project it is better to check conditionally if value is present and add modifier if environment is not nil.



Answered By - Asperi
Answer Checked By - Terry (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Wednesday, August 10, 2022

[FIXED] How can a decimal number with a comma be converted in a decimal (Point) in SwiftUI?

 August 10, 2022     calculation, decimal, formatting, swiftui     No comments   

Issue

How can a textField were a comma is inserted be Formated so the inserted Decimal value example 10,05$ can be converted to a decimal(Point) 10.05$?

private static let Intrest = "Intrest"
private static let Repayment = "Repayment"



var loan: Double {
    let intrest = Double (Intrest)
    let repayment = Double (Repayment)

    let Loan = Intrest + Repayment

    return Loan
}



var body: some View {
     VStack{
        HStack{
           Text ("Repayment %")
           Spacer()
           TextField("2 %", text: $Repayment)
                .keyboardType(.decimalPad)
            }
      VStack{
         HStack{
            Text ("Loan / month")
            }
            TextField("2 %", text: $Loan)
                .keyboardType(.decimalPad)
            }
}

The problem only occurs because in many countries mostly comma is used which breaks the calculation.

Thanks


Solution

You need to make sure you convert your string into a double with point and not comma.

This one should help. Swift playground - How to convert a string with comma to a string with decimal



Answered By - Volker88
Answer Checked By - Clifford M. (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Friday, July 29, 2022

[FIXED] How to allow an image to extend beyond a Form {} in SwiftUI?

 July 29, 2022     forms, image, swiftui, xcode     No comments   

Issue

I'm looking to have an image extend above a form, as pictured in the first attached screenshot below. My code below accomplishes this when I run it on the Simulator using a iPod touch (7th Generation), but produces the second screenshot when I run it on iPhone 12 and iPhone 13. Any advice about how to ensure that the image extends beyond the limits of the form as intended on all devices?

struct ContentView: View {
    var body: some View {
        Form {
            Circle()
                .frame(width: 100, height: 100)
                .clipShape(Circle())
                .offset(y: -50)
                .padding(.bottom, -50)
        }
    }
}

enter image description here

enter image description here


Solution

Form uses different styles on different devices. A possible solution is to use instead List with explicit style for all devices.

Tested with Xcode 13.4 / iOS 15.5

demo

    List {
        Circle()
            .frame(width: 100, height: 100)
            .clipShape(Circle())
            .offset(y: -50)
            .padding(.bottom, -50)
    }
    .listStyle(.grouped)   // << here !!


Answered By - Asperi
Answer Checked By - David Marino (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

[FIXED] How to resize image in swift picker menu style

 July 29, 2022     image, picker, svg, swift, swiftui     No comments   

Issue

I want to use a image beside some text in my picker, but image is scaled up and I can't resize it with .resizable .frame and ... . How can i fix this problem? I use both svg and png format and neither of those don't working properly.

I using image from asset

here is the screen shot and its ok when I tapped on it

struct ContentView: View {
    @State var array = ["one", "two", "three", "four"]
    @State var selection: String = "one"
    var body: some View {
        HStack {
            Picker("Select",selection: $selection) {
                ForEach(array, id: \.self) { item in
                    HStack {
                        Text(item)
                            Image("BTC")
                                .resizable()
                                .clipped()
                    }
                   
                }
            }
            .pickerStyle(.menu)
            .padding(.trailing)
            
        }
        
    }
}

Solution

You can use Menu for this purpose:

struct ContentView: View {
    @State var array = ["one", "two", "three", "four"]
    @State var selection: String = "one"
    var body: some View {
        Menu(content: {
            Picker("Select",selection: $selection) {
                            ForEach(array, id: \.self) { item in
                                HStack {
                                    Text(item)
                                    Image("BTC")
                                }
                               
                            }
                        }
        }, label: {
            Text(selection)
        })
    }
}


Answered By - Kush Bhavsar
Answer Checked By - Mary Flores (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Wednesday, July 27, 2022

[FIXED] How to cut an image into 2 using SwiftUI

 July 27, 2022     crop, geometryreader, image, swiftui, uiimage     No comments   

Issue

I have an image like this enter image description here

I'd like to split it into 2 pieces across the center using SwiftUI. Leaving me with 2 separate images that I can access. However I can't figure out how to split the original into a top and bottom piece. The two pieces must line up to create the original image.

Top Image: enter image description here

Bottom Image: enter image description here

I've tried use a geometry reader to read the height and width and return an image with half the height, but the two images don't like up like this.

GeometryReader { geo in
    image
       .frame(width: geo.width, height: geo.height / 2, alignment: .center)
       .clipped()
}

Solution

Here a way of doing this: with using clipped() modifier.


enter image description here


struct ContentView: View {
    
    @State private var spacing: CGFloat = CGFloat()
    @State private var imageSize: CGSize = CGSize()
    
    var body: some View {
        
        let image = Image(systemName: "star")
            .resizable()
            .scaledToFit()
            .frame(width: 200, height: 200, alignment: .center)
            .background(Color.yellow)
            .cornerRadius(10.0)
            .background(GeometryReader { proxy in Color.clear.onAppear() { imageSize = proxy.size } })
        
        
        return ZStack {
            
            VStack(spacing: spacing) {
                
                image.frame(width: imageSize.width, height: imageSize.height/2, alignment: .top).clipped()
                
                image.frame(width: imageSize.width, height: imageSize.height/2, alignment: .bottom).clipped()
            }
            
            VStack { Spacer(); Slider(value: $spacing,in: 0.0...100.0) }
            
        }
        .padding()
        .compositingGroup()
        .shadow(radius: 10.0)
        
    }
}


Answered By - swiftPunk
Answer Checked By - Pedro (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Tuesday, July 26, 2022

[FIXED] How to center crop an image in SwiftUI

 July 26, 2022     center, crop, image, ios, swiftui     No comments   

Issue

I'm new to SwiftUI. I guess everyone is at this point. I've been an app developer for about 6 years now and I feel stupid asking this question on StackOverflow. But I looked everywhere. How do I center crop an image in an ImageView in SwiftUI?

I know there's an option to change the aspect ratio but I only see fit and fill. I just want the imageView to centerCrop(android term) the image. Does anybody know?


Solution

Android's ImageView.ScaleType documentation describes CENTER_CROP as:

CENTER_CROP

Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions (width and height) of the image will be equal to or larger than the corresponding dimension of the view (minus padding). The image is then centered in the view.

This is essentially what Aspect Fill Scaling (aka .scaledToFill()) does, except (surprisingly) Aspect Fill doesn't clip the parts that fall outside of the frame.

By making the image .resizable, and applying .scaledToFill(). the image will be scaled proportionally to fill its available frame leaving off the top and bottom or sides as necessary. .clipped() then removes the parts of the image outside of the frame.

Image("myImage")
    .resizable()
    .scaledToFill()
    .frame(width: 200, height: 200, alignment: .center)
    .clipped()

To make this more convenient, I created this extension of Image:

extension Image {
    func centerCropped() -> some View {
        GeometryReader { geo in
            self
            .resizable()
            .scaledToFill()
            .frame(width: geo.size.width, height: geo.size.height)
            .clipped()
        }
    }
}

To use the Image extension, just put it in a file in your project (a name like image-centercropped.swift will work nicely). Then just add .centerCropped() to any image you want to be center cropped.

Image("apolloimage").centerCropped()

It uses GeometryReader to figure out its frame so that it can crop the image correctly, which means you don't have to specify the frame to get proper clipping. You are free to size the image however you like using an explicit frame, or by just adding padding() and Spacer() to keep it nicely placed relative to other user interface items.

For example: If you want an image to fill the screen of the phone:

struct ContentView: View { 
    var body: some View {
        Image("apolloimage")
            .centerCropped()
            .edgesIgnoringSafeArea(.all)
    }
}

will nicely show the center of the image by scaling the image to show either the full height or the full width of the image and cropping the parts the hang over on the other dimension.


Demonstration:

Here's a demo that shows how the image is centered and cropped as the image grows. In this demo, the frame width is a constant 360 while the frame height varies from 50 to 700 as the slider advances to the right. At the beginning when the frame is short, the tops and bottoms of the image are cropped. As the frame exceeds the aspectRatio of the original image, the resulting image is centered but cropped on the left and right sides.

struct ContentView: View {
    
    @State private var frameheight: CGFloat = 50
    
    var body: some View {
        VStack(spacing: 20) {
            Spacer()
            Image("apolloimage")
                .resizable()
                .scaledToFill()
                .frame(width: 360, height: self.frameheight)
                .clipped()
            Spacer()
            Slider(value: self.$frameheight, in: 50...700)
                .padding(.horizontal, 20)
        }
    }
}

or an equivalent test using .centerCropped():

struct ContentView: View {
    
    @State private var frameheight: CGFloat = 50
    
    var body: some View {
        VStack(spacing: 20) {
            Spacer()
            Image("apolloimage")
                .centerCropped()
                .frame(width: 360, height: self.frameheight)
            Spacer()
            Slider(value: self.$frameheight, in: 50...700)
                .padding(.horizontal, 20)
        }
    }
}

Demo running on the simulator of .centerCropped scaling


Alternate Solution

Another way to make a center cropped image is to make the image an .overlay() of Color.clear. This allows Color.clear to establish the clipping bounds.

Color.clear
.overlay(
    Image("apolloimage")
    .resizable()
    .scaledToFill()
)
.clipped()

and the corresponding extension to Image looks like this:

extension Image {
    func centerCropped() -> some View {
        Color.clear
        .overlay(
            self
            .resizable()
            .scaledToFill()
        )
        .clipped()
    }
}


Answered By - vacawama
Answer Checked By - Mildred Charles (PHPFixing Admin)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Saturday, July 23, 2022

[FIXED] How to read and display a dictionary from JSON?

 July 23, 2022     json, swift, swiftui     No comments   

Issue

I am working on an app that fetches the data from JSON and displays it. However, I am stuck with an error saying Instance method 'appendInterpolation(_:formatter:)' requires that '[String : Int]' inherit from 'NSObject'

Here is my data structure:

struct Data: Codable {
    var message: String
    var data: Objects
}

struct Objects: Codable {
    var date: String
    var day: Int
    var resource: String
    var stats, increase: [String: Int]
}

Function to fetch the data:

func getData() {
    let urlString = "https://russianwarship.rip/api/v1/statistics/latest"
    let url = URL(string: urlString)
    
    URLSession.shared.dataTask(with: url!) { data, _, error in
        if let data = data {
            do {
                let decoder = JSONDecoder()
                let decodedData = try decoder.decode(Data.self, from: data)
                self.data = decodedData
            } catch {
                print("Hey there's an error: \(error.localizedDescription)")
            }
        }
    }.resume()
}

And a ContentView with the @State property to pass the placeholder data:

struct ContentView: View {

@State var data = Data(message: "", data: Objects(date: "123", day: 123, resource: "", stats: ["123" : 1], increase: ["123" : 1]))


var body: some View {
    VStack {
        Button("refresh") { getData() }
        Text("\(data.data.date)")
        
        Text("\(data.data.day)")
        
        Text(data.message) 
        
        Text("\(data.data.stats)") //error is here
        

Here is an example of JSON response

JSON Str

I wonder if the problem is in data structure, because both

Text("\(data.data.date)")            
Text("\(data.data.day)")

are working just fine. If there are any workarounds with this issue – please, I would highly appreciate your help!:)


Solution

stats is [String: Int], and so when you want to use it, you need to supply the key to get the value Int, the result is an optional that you must unwrap or supply a default value in Text

So use this:

 Text("\(data.data.stats["123"] ?? 0)")

And as mentioned in the comments, do not use Data for your struct name.

EDIT-1: there are two ways you can make the struct fields camelCase; one is using the CodingKeys as shown in ItemModel, or at the decoding stage, as shown in the getData() function. Note, I've also updated your models to make them easier to use.

struct DataModel: Codable {
    var message: String
    var data: ObjectModel
}

struct ObjectModel: Codable {
    var date: String
    var day: Int
    var resource: String
    var stats: ItemModel
    var increase: ItemModel
}

struct ItemModel: Codable {
    var personnelUnits: Int
    var tanks: Int
    var armouredFightingVehicles: Int
    // ...
    
    // manual CodingKeys
    //    enum CodingKeys: String, CodingKey {
    //        case tanks
    //        case personnelUnits = "personnel_units"
    //        case armouredFightingVehicles = "armoured_fighting_vehicles"
    //    }
}


struct ContentView: View {
    
    @State var dataModel = DataModel(message: "", data: ObjectModel(date: "123", day: 123, resource: "", stats: ItemModel(personnelUnits: 123, tanks: 456, armouredFightingVehicles: 789), increase: ItemModel(personnelUnits: 3, tanks: 4, armouredFightingVehicles: 5)))
    
    var body: some View {
        VStack {
            Button("get data from Server") { getData() }
            Text("\(dataModel.data.date)")
            Text("\(dataModel.data.day)")
            Text(dataModel.message)
            Text("\(dataModel.data.stats.armouredFightingVehicles)") // <-- here
        }
    }
    
func getData() {
    let urlString = "https://russianwarship.rip/api/v1/statistics/latest"
    if let url = URL(string: urlString) {
        URLSession.shared.dataTask(with: url) { data, _, error in
            if let data = data {
                do {
                    let decoder = JSONDecoder()
                    decoder.keyDecodingStrategy = .convertFromSnakeCase  // <-- here
                    dataModel = try decoder.decode(DataModel.self, from: data)
                } catch {
                    print("--> error: \(error)")
                }
            }
        }.resume()
    }
}
    
}


Answered By - workingdog support Ukraine
Answer Checked By - Pedro (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Monday, July 18, 2022

[FIXED] How to convert String to UTF-8 to Integer in Swift

 July 18, 2022     character, integer, swift, swiftui, utf-8     No comments   

Issue

I'm trying to take each character (individual number, letter, or symbol) from a string file name without the extension and put each one into an array index as an integer of the utf-8 code (i.e. if the file name is "A1" without the extension, I would want "A" as an int "41" in first index, and "1" as int "31" in second index)

Here is the code I have but I'm getting this error "No exact matches in call to instance method 'append'", my guess is because .utf8 still keeps it as a string type:

for i in allNoteFiles {
        var CharacterArray : [Int] = []
        
        for character in i {
            var utf8Character = String(character).utf8 
            CharacterArray.append(utf8Character)    //error is here
        }
....`//more code down here within the for in loop using CharacterArray indexes`

I'm sure the answer is probably simple, but I'm very new to Swift.

I've tried appending var number instead with:

var number = Int(utf8Character)

and

var number = (utf8Character).IntegerValue

but I get errors "No exact matches in call to initializer" and "Value of type 'String.UTF8View' has no member 'IntegerValue'"

Any help at all would be greatly appreciated. Thanks!


Solution

The reason

var utf8Character = String(character).utf8 
CharacterArray.append(utf8Character) 

doesn't work for you is because utf8Character is not a single integer, but a UTF8View: a lightweight way to iterate over the UTF-8 codepoints in a string. Every Character in a String can be made up of any number of UTF-8 bytes (individual integers) — while ASCII characters like "A" and "1" map to a single UTF-8 byte, the vast majority of characters do not: every UTF-8 code point maps to between 1 and 4 individual bytes. The Encoding section of UTF-8 on Wikipedia has a few very illustrative examples of how this works.

Now, assuming that you do want to split a string into individual UTF-8 bytes (either because you can guarantee your original string is ASCII-only, so the assumption that "character = byte" holds, or because you actually care about the bytes [though this is rarely the case]), there's a short and idiomatic solution to what you're looking for.

String.UTF8View is a Sequence of UInt8 values (individual bytes), and as such, you can use the Array initializer which takes a Sequence:

let characterArray: [UInt8] = Array(i.utf8)

If you need an array of Int values instead of UInt8, you can map the individual bytes ahead of time:

let characterArray: [UInt8] = Array(i.utf8.lazy.map { Int($0) })

(The .lazy avoids creating and storing an array of values in the middle of the operation.)

However, do note that if you aren't careful (e.g., your original string is not ASCII), you're bound to get very unexpected results from this operation, so keep that in mind.



Answered By - Itai Ferber
Answer Checked By - Willingham (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Saturday, July 16, 2022

[FIXED] How to login to Facebook on SwiftUI?

 July 16, 2022     facebook, facebook-login, ios, swift, swiftui     No comments   

Issue

There are not many resources explaining Facebook Login with SwiftUI. I'm not sure whether my code requires a ViewController or not because Facebook's LoginManager.login() contains a ViewController parameter - however this doesn't really translate to SwiftUI.

Regardless, I am trying to login the user to Facebook when they click on the Button below:

LoginView.swift

import Foundation
import SwiftUI
import FBSDKLoginKit

struct LoginView: View {
    @EnvironmentObject var auth: UserAuth
    var body: some View {
        ZStack {
            VStack {
                Image("launcher_logo").resizable()
                .scaledToFit()
                .frame(height: 100)
                    .padding(.top, 100)
                Spacer()
                Button(action: {
                    FBLogin()
                }) {
                    Text("Continue with Facebook")
                }.foregroundColor(Color.black)

when the Button is clicked, it initialises FBLogin below - which fires login() in its init():

Model:

class FBLogin: LoginManager {

    let loginButton = FBLoginButton()
    let token = AccessToken.current
    let permissions = ["user_birthday", "user_gender", "public_profile"]

    override init(){
        super.init()
        logIn(permissions: permissions, from: nil)
        print("fb init()")
    }

    override func logIn(permissions: [String], from fromViewController: UIViewController?, handler: LoginManagerLoginResultBlock? = nil) {
        // TODO
    }

}

However I'm not sure what to do from there. At the moment, only fb init() prints but I want to execute the login and listen to the login result.

Any idea?


Solution

Just create LoginManager instance inside ObservableObject and then customise login completion. You can easily use inside SwiftUI View. No need UIViewControllerRepresentable. Here is my sample.

struct ContentView: View {
    @ObservedObject var fbmanager = UserLoginManager()
    var body: some View {
        Button(action: {
            self.fbmanager.facebookLogin()
        }) {
            Text("Continue with Facebook")
        }
    }
}

class UserLoginManager: ObservableObject {
    let loginManager = LoginManager()
    func facebookLogin() {
        loginManager.logIn(permissions: [.publicProfile, .email], viewController: nil) { loginResult in
            switch loginResult {
            case .failed(let error):
                print(error)
            case .cancelled:
                print("User cancelled login.")
            case .success(let grantedPermissions, let declinedPermissions, let accessToken):
                print("Logged in! \(grantedPermissions) \(declinedPermissions) \(accessToken)")
                GraphRequest(graphPath: "me", parameters: ["fields": "id, name, first_name"]).start(completionHandler: { (connection, result, error) -> Void in
                    if (error == nil){
                        let fbDetails = result as! NSDictionary
                        print(fbDetails)
                    }
                })
            }
        }
    }
}


Answered By - Scotti
Answer Checked By - Terry (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Monday, July 11, 2022

[FIXED] How to make the message visible on the recipient's device instantly - SwiftUI and FirebaseFirestore

 July 11, 2022     chat, firebase, google-cloud-firestore, message, swiftui     No comments   

Issue

I make ChatApp by SwiftUI-FirebaseFirestore. I run 2 simulators at the same time and if user A sends a message to user B, I have to reload user B's interface to display. I want it to be automatic and show up immediately so what's the idea to do?


Solution

What you're looking for is called a snapshot listener. Effectively it's treated the same as with any other documents but it has a closure that allows you to respond to updated events on a particular document. It's general usage is this.

db.collection("cities").document("SF")
.addSnapshotListener { documentSnapshot, error in
  guard let document = documentSnapshot else {
    print("Error fetching document: \(error!)")
    return
  }
  guard let data = document.data() else {
    print("Document data was empty.")
    return
  }
  print("Current data: \(data)")
}

You should be able to look at the document snapshot to determine any changes in data, then respond to those changes. In your case you would reload the view.

https://firebase.google.com/docs/firestore/query-data/listen



Answered By - xTwisteDx
Answer Checked By - Mary Flores (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Friday, May 13, 2022

[FIXED] Why is my array is always nil, I'm try to add an item to the array in order to share a document

 May 13, 2022     append, arrays, swift, swiftui, xcode     No comments   

Issue

I'm try to share a PDF document which is display using Quick Look view.

I can correctly see the PDF loaded in the PDF view but I can't add the PDF path to the arrayItemToShare.

I have tried many things but can't find the reason why this code not adding anything!

arrayItemToShare?.append(report.pathFile!)

below the code of my report view.

struct listReport: View {
    @ObservedObject var dm : DataManager
    var report : UserReport
    
    @State var openQL = false
    @State var share = false
    
    @State var arrayItemToShare : [String]?
    var body: some View {

        Button(action: {
            
            openQL.toggle()
            
        }, label: {
            VStack(alignment: .center, spacing: 60){
                if report.urlFile != nil {
                    PDFThumbnailRepresented(urlDoc: report.urlFile!).padding()
                }
                Spacer()
                Text(report.id_report_show).foregroundColor(.primary).bold()
            }
        })
        .sheet(isPresented: $openQL, content: { // open sheet to preview PDF
            fakebar
            if report.pathFile != nil {
                QLView(filePath: report.pathFile!, isPresented: $openQL) // open Quick Look and preview the file pdf at path
                    .onAppear {
                    arrayItemToShare?.append(report.pathFile!) // why this not adding the value to the array
                    print("count \(arrayItemToShare!.count)") // here the crash because array is NIL
                }
            } else {
                Text("OPS!!.. unable to load pdf")
            }
        })
        .sheet(isPresented: $share) {
            ShareSheet(item: arrayItemToShare!)
        }
        
    }
    
    var fakebar: some View {
        ZStack {
            HStack {
                Button(action: {
                    if report.urlFile != nil {
                        openQL.toggle() // close preview pdf
                        
                        share.toggle() // open share sheet
                        
                    }
                }) {
                    Image(systemName: "square.and.arrow.up")
                        .foregroundColor(.white)
                        .padding(.horizontal)
                }

                Spacer()
                
                Image(systemName: "chevron.compact.down")
                    .font(.system(size: 60))
                    .aspectRatio(contentMode: .fit)
                    .foregroundColor(.white)
                
                Spacer()
                
                Button(action: {
                    openQL.toggle()
                }) {
                    Text("Close")
                        .fontWeight(.bold)
                        .foregroundColor(.white)
                        .padding(.horizontal)
                }
            }
        }
        .frame(height: 44)
        .background(Color("AMUColor").padding(.top, -44))
    }
    
}

I use this (listReport: View) inside a scrollView with a foreach loop, where everything work fine.


Solution

Here is a fix:

QLView(filePath: report.pathFile!, isPresented: $openQL) // open Quick Look and preview the file pdf at path
    .onAppear {
    if nil == arrayItemToShare {
       arrayItemToShare = [String]()       // << create if needed !!
    }
    arrayItemToShare?.append(report.pathFile!)
    print("count \(arrayItemToShare!.count)")
}


Answered By - Asperi
Answer Checked By - Terry (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Older Posts Home
View mobile version

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
All Comments
Atom
All Comments

Copyright © PHPFixing