Redux рдХреЗ рд╕рд╛рде SwiftUI рдЗрдВрдЯрд░реИрдХреНрд╢рди

рдЫрд╡рд┐

рд╕рднреА рдХреЛ рдирдорд╕реНрдХрд╛рд░ред рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рд╣рдо Redux рдХреЗ рд╕рд╛рде рдорд┐рд▓рдХрд░ рд╕реНрд╡рд┐рдлреНрдЯрдпреВрдЖрдИ рдлреНрд░реЗрдорд╡рд░реНрдХ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░реЗрдВрдЧреЗ , рдпрд╣ рдмрдВрдбрд▓ рд╣рдореЗрдВ рдЬрд▓реНрджреА рдФрд░ рдЖрд╕рд╛рдиреА рд╕реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмрдирд╛рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред UIKit рдХреЗ рд╡рд┐рдкрд░реАрдд, рдПрдХ рдШреЛрд╖рдгрд╛ рд╢реИрд▓реА рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП SwiftUI рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ ред рдмрджрд▓реЗ рдореЗрдВ, Redux рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рд╕реНрдерд┐рддрд┐ рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рдиреЗ рдХрд╛ рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИред SwiftUI рдФрд░ Redux рдореЗрдВ

рд░рд╛рдЬреНрдп рдПрдХ рдореВрд▓рднреВрдд рдЕрд╡рдзрд╛рд░рдгрд╛ рд╣реИред рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдпрд╣ рди рдХреЗрд╡рд▓ рдПрдХ рдЪрд░реНрдЪрд╛ рд╣реИ, рдмрд▓реНрдХрд┐ рдПрдХ рдЗрдХрд╛рдИ рднреА рд╣реИ рдЬреЛ рдЙрдиреНрд╣реЗрдВ рдЬреЛрдбрд╝рддреА рд╣реИ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдПрдХ рд╕рд╛рде рдмрд╣реБрдд рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИред рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдореИрдВ рдпрд╣ рджрд┐рдЦрд╛рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реВрдВрдЧрд╛ рдХрд┐ рдЙрдкрд░реЛрдХреНрдд рдереАрд╕рд┐рд╕ рд╕рдЪ рд╣реИ, рддреЛ рдЪрд▓рд┐рдП рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ!

рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдХрд┐ рд╣рдо рдХреЛрдб рд▓рд┐рдЦрдиреЗ рдореЗрдВ рдЧреЛрддрд╛ рд▓рдЧрд╛рдПрдБ, рдЖрдЗрдП рдкрд╣рд▓реЗ рд╕рдордЭрддреЗ рд╣реИрдВ рдХрд┐ Redux рдХреНрдпрд╛ рд╣реИ рдФрд░ рдЗрд╕рдореЗрдВ рдХреНрдпрд╛ рд╢рд╛рдорд┐рд▓ рд╣реИред

Redux рдПрдХ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рд╕реНрдерд┐рддрд┐ рдХреЗ рдкреНрд░рдмрдВрдзрди рдХреЗ рд▓рд┐рдП рдПрдХ рдУрдкрди рд╕реЛрд░реНрд╕ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд╣реИред рдЬреНрдпрд╛рджрд╛рддрд░ рдЕрдХреНрд╕рд░ рдЧреНрд░рд╛рд╣рдХ рдкрдХреНрд╖ рдХреЛ рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдпрд╛ рдХреЛрдгреАрдп рдХреЗ рд╕рд╛рде рд╕рдВрдпреЛрдЬрди рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд╕рдВрджрд░реНрдн рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рднрдВрдбрд╛рд░рдг рдбреЗрдЯрд╛ рдХреЗ рд╣рд╕реНрддрд╛рдВрддрд░рдг рдХреЛ рд╕рд░рд▓ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХрдИ рдЙрдкрдХрд░рдг рд╢рд╛рдорд┐рд▓ рд╣реИрдВред рдирд┐рд░реНрдорд╛рддрд╛: рдбреЗрдирд┐рдпрд▓ рдЕрдмреНрд░рд╛рдореЛрд╡ рдФрд░ рдПрдВрдбреНрд░рдпреВ рдХреНрд▓рд╛рд░реНрдХред

рдореЗрд░реЗ рд▓рд┐рдП, Redux рд╕рд┐рд░реНрдл рдПрдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдирд╣реАрдВ рд╣реИ, рдпрд╣ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдХреБрдЫ рдФрд░ рд╣реИ, рдореИрдВ рдЗрд╕реЗ рдЙрди рд╡рд╛рд╕реНрддреБ рдирд┐рд░реНрдгрдпреЛрдВ рдХреЗ рд▓рд┐рдП рд╡рд┐рд╢реЗрд╖рддрд╛ рджреЗрддрд╛ рд╣реВрдВ рдЬрд┐рди рдкрд░ рдЖрд╡реЗрджрди рдЖрдзрд╛рд░рд┐рдд рд╣реИред рдореБрдЦреНрдп рд░реВрдк рд╕реЗ рдЗрд╕рдХреА рдпреВрдирд┐рдбрд╛рдпрд░реЗрдХреНрд╢рдирд▓ рдбреЗрдЯрд╛ рд╕реНрдЯреНрд░реАрдо рдХреЗ рдХрд╛рд░рдгред

рдмрд╣реБрдЖрдпрд╛рдореА рдпрд╛ рдЕрдкреНрд░рддреНрдпрдХреНрд╖ рдкреНрд░рд╡рд╛рд╣


рдпрд╣ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдбреЗрдЯрд╛ рдкреНрд░рд╡рд╛рд╣ рд╕реЗ рдореЗрд░рд╛ рдХреНрдпрд╛ рдорддрд▓рдм рд╣реИ, рдореИрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЙрджрд╛рд╣рд░рдг рджреВрдВрдЧрд╛ред VIPER рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рдПрдХ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЙрдбреНрдпреВрд▓ рдХреЗ рдмреАрдЪ рдПрдХ рдмрд╣реБрдЖрдпрд╛рдореА рдбреЗрдЯрд╛ рд╕реНрдЯреНрд░реАрдо рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИ:

рдЫрд╡рд┐

Redux, рдмрджрд▓реЗ рдореЗрдВ, рдПрдХ рдпреВрдирд┐рдбрд╛рдпрд░реЗрдХреНрд╢рдирд▓ рдбреЗрдЯрд╛ рд╕реНрдЯреНрд░реАрдо рд╣реИ рдФрд░ рдЗрд╕рдХреЗ рдШрдЯрдХ рдШрдЯрдХреЛрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рд╡реНрдпрд╛рдЦреНрдпрд╛ рдХрд░рдирд╛ рд╕рдмрд╕реЗ рдЖрд╕рд╛рди рд╣реИред

рдЫрд╡рд┐

рдЖрдЗрдП рдкреНрд░рддреНрдпреЗрдХ Redux рдШрдЯрдХ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рдмрд╛рдд рдХрд░рддреЗ рд╣реИрдВред

рд░рд╛рдЬреНрдп рд╕рддреНрдп рдХрд╛ рдПрдХрдорд╛рддреНрд░ рд╕реНрд░реЛрдд рд╣реИ рдЬрд┐рд╕рдореЗрдВ рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдХреЗ рд▓рд┐рдП рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рдЬрд╛рдирдХрд╛рд░реА рд╢рд╛рдорд┐рд▓ рд╣реИред

рдХрд╛рд░реНрд░рд╡рд╛рдИ рд░рд╛рдЬреНрдп рдмрджрд▓рдиреЗ рдХрд╛ рдЗрд░рд╛рджрд╛ рд╣реИред рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдпрд╣ рдПрдХ рдРрд╕реА рд╕реВрдЪрдирд╛ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдирдИ рдЬрд╛рдирдХрд╛рд░реА рд╢рд╛рдорд┐рд▓ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдо рд╡рд░реНрддрдорд╛рди рд╕реНрдерд┐рддрд┐ рдореЗрдВ рдЬреЛрдбрд╝рдирд╛ рдпрд╛ рдмрджрд▓рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред

рдХрдо рдХрд░рдиреЗрдПрдХ рдлрд╝рдВрдХреНрд╢рди рд╣реИ рдЬреЛ рдХрд╛рд░реНрд░рд╡рд╛рдИ рдФрд░ рд╡рд░реНрддрдорд╛рди рд╕реНрдерд┐рддрд┐ рдХреЛ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рд░реВрдк рдореЗрдВ рд▓реЗрддрд╛ рд╣реИ рдФрд░ рдПрдХ рдирдпрд╛ рд░рд╛рдЬреНрдп рджреЗрддрд╛ рд╣реИред рдпрд╣ рдЗрд╕реЗ рдмрдирд╛рдиреЗ рдХрд╛ рдПрдХрдорд╛рддреНрд░ рддрд░реАрдХрд╛ рд╣реИред рдпрд╣ рднреА рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рд╣реИ рдХрд┐ рдпрд╣ рд╕реБрд╡рд┐рдзрд╛ рд╕рд╛рдл рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдПред

рд╕реНрдЯреЛрд░ рдПрдХ рдРрд╕реА рд╡рд╕реНрддреБ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рд╕реНрдЯреЗрдЯ рд╣реЛрддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рдЕрдкрдбреЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рдЙрдкрдХрд░рдг рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред

рдореЗрд░рд╛ рдорд╛рдирдирд╛ тАЛтАЛрд╣реИ рдХрд┐ рд╕рд┐рджреНрдзрд╛рдВрдд рдкрд░реНрдпрд╛рдкреНрдд рд╣реИ, рдЪрд▓реЛ рдЕрднреНрдпрд╛рд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдЧреЗ рдмрдврд╝реЗрдВред

Redux рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди


рдПрдХ рдЙрдкрдХрд░рдг рдХреЛ рдЬрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдмрд╕реЗ рдЖрд╕рд╛рди рддрд░реАрдХреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рд╢реБрд░реВ рдХрд░рдирд╛ рд╣реИ, рдЬреИрд╕рд╛ рдХрд┐ рдореЗрд░реЗ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рд╢рд┐рдХреНрд╖рдХ рдиреЗ рдХрд╣рд╛, рдпрджрд┐ рдЖрдк рдПрдХ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рднрд╛рд╖рд╛ рд╕реАрдЦрдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рдЙрд╕ рдкрд░ рдПрдХ рдЖрд╡реЗрджрди рд▓рд┐рдЦреЗрдВред рддреЛ рдЪрд▓реЛ рдПрдХ рдЫреЛрдЯрд╛ рд╕рд╛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмрдирд╛рдПрдВ, рдЗрд╕реЗ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдбрд╛рдпрд░реА рд╣реЛрдиреЗ рджреЗрдВ, рдЗрд╕рдореЗрдВ рдХреЗрд╡рд▓ рдЪрд╛рд░ рд╡рд┐рдХрд▓реНрдк рд╣реЛрдВрдЧреЗ, рдкрд╣рд▓рд╛ рд╣реИ рд╡рд░реНрдХрдЖрдЙрдЯ рдХреА рд╕реВрдЪреА рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдирд╛, рджреВрд╕рд░рд╛ рд╣реИ рдПрдХ рдкреВрд░рд╛ рд╡рд░реНрдХрдЖрдЙрдЯ рдЬреЛрдбрд╝рдирд╛, рддреАрд╕рд░рд╛ рд╣реИ рдбрд┐рд▓реАрдЯ рдХрд░рдирд╛ рдФрд░ рдЪреМрдерд╛ рд╣реИ рд╡рд░реНрдХрдЖрдЙрдЯ рдХреЛ рд╕реЙрд░реНрдЯ рдХрд░рдирд╛ред рд╕реБрдВрджрд░ рд╕рд░рд▓ рдЕрдиреБрдкреНрд░рдпреЛрдЧ, рд▓реЗрдХрд┐рди рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ рд╣рдореЗрдВ Redux рдФрд░ SwiftUI рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реЛрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛ред

Xcode рдореЗрдВ рдПрдХ рд╕рд╛рдл рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдмрдирд╛рдПрдВ, рдЗрд╕реЗ WorkoutsDiary рдирд╛рдо рджреЗрдВ, рдФрд░ рд╕рдмрд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдмрд╛рдд, рдпреВрдЬрд░ рдЗрдВрдЯрд░рдлреЗрд╕ рдХреЗ рд▓рд┐рдП SwiftUI рдХрд╛ рдЪрдпрди рдХрд░реЗрдВ, рдХреНрдпреЛрдВрдХрд┐ рд╣рдо рдЕрдкрдиреЗ рдпреВрдЬрд░ рдЗрдВрдЯрд░рдлреЗрд╕ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП SwiftUI рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред

рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдмрдирд╛рдиреЗ рдХреЗ рдмрд╛рджред рдПрдХ рд╡рд░реНрдХрдЖрдЙрдЯ рд╕рдВрд░рдЪрдирд╛ рдмрдирд╛рдПрдВ рдЬреЛ рд╣рдорд╛рд░реЗ рджреНрд╡рд╛рд░рд╛ рдкреВрд░реА рдХреА рдЧрдИ рдХрд╕рд░рдд рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реЛрдЧреАред

import Foundation

struct Workout: Identifiable {
    let id: UUID = .init()
    let name: String
    let distance: String
    let date: Date
    let complexity: Complexity
}

рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдЗрд╕ рд╕рдВрд░рдЪрдирд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рднреА рдкрд╛рдЧрд▓ рдирд╣реАрдВ рд╣реИ, рдкрд╣рдЪрд╛рди рдпреЛрдЧреНрдп рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХрд╛ рдкрд╛рд▓рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдИрдбреА рдлрд╝реАрд▓реНрдб рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдФрд░ рдЬрдЯрд┐рд▓рддрд╛ рдХреНрд╖реЗрддреНрд░ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкрд░рд┐рднрд╛рд╖рд╛ рдХреЗ рд╕рд╛рде рдмрд╕ рдПрдХ рдПрдирдо рд╣реИ:

enum Complexity: Int {
    case low
    case medium
    case high
}

рдЕрдм рдЬрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ Redux рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╕рдм рдХреБрдЫ рд╣реИ, рддреЛ рдЖрдЗрдП рдПрдХ рд░рд╛рдЬреНрдп рдмрдирд╛рдХрд░ рд╢реБрд░реБрдЖрдд рдХрд░реЗрдВред

struct AppState {
    var workouts: [Workout]
    var sortType: SortType?
}

рд░рд╛рдЬреНрдп рдПрдХ рд╕рд░рд▓ рд╕рдВрд░рдЪрдирд╛ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рджреЛ рдлрд╝реАрд▓реНрдб рд╢рд╛рдорд┐рд▓ рд╣реИрдВ: рд╡рд░реНрдХрдЖрдЙрдЯ рдФрд░ рд╕реЙрд░реНрдЯ рдЯрд╛рдЗрдк ред рдкрд╣рд▓рд╛ рд╡рд░реНрдХрдЖрдЙрдЯреНрд╕ рдХреА рдПрдХ рд╕реВрдЪреА рд╣реИ, рдФрд░ рджреВрд╕рд░рд╛ рдПрдХ рд╡реИрдХрд▓реНрдкрд┐рдХ рдХреНрд╖реЗрддреНрд░ рд╣реИ рдЬреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рд╕реВрдЪреА рдХреЛ рдХреИрд╕реЗ рд╕реЙрд░реНрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред

SortType рдПрдХ рдЧрдгрдирд╛ рд╣реИ рдЬрд┐рд╕реЗ рдирд┐рдореНрдирд╛рдиреБрд╕рд╛рд░ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ:

enum SortType {
    case distance
    case complexity
}

рд╕рд╛рджрдЧреА рдХреЗ рд▓рд┐рдП, рд╣рдо рджреВрд░реА рдФрд░ рдХреНрд░рдо рдЕрд╡рд░реЛрд╣реА рдореЗрдВ рдХрдард┐рдирд╛рдИ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдЫрд╛рдБрдЯ рд▓реЗрдВрдЧреЗ, рдЕрд░реНрдерд╛рддреН, рд╣рдорд╛рд░реЗ рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдХреА рдЬрдЯрд┐рд▓рддрд╛ рдЬрд┐рддрдиреА рдЕрдзрд┐рдХ рд╣реЛрдЧреА, рдЙрддрдиреА рд╣реА рдпрд╣ рд╣рдорд╛рд░реА рд╕реВрдЪреА рдореЗрдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рд╣реЛрдЧреАред рдпрд╣ рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рд╣реИ рдХрд┐ рд╕реЙрд░реНрдЯ рдЯрд╛рдЗрдк рдПрдХ рд╡реИрдХрд▓реНрдкрд┐рдХ рдкреНрд░рдХрд╛рд░ рд╣реИ рдФрд░ рдпрд╣ рд╢реВрдиреНрдп рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рд╕реВрдЪреА рдХреЛ рдлрд┐рд▓рд╣рд╛рд▓ рд╕реЙрд░реНрдЯ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред

рд╣рдо рдЕрдкрдиреЗ рдШрдЯрдХреЛрдВ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ рдЬрд╛рд░реА рд░рдЦреЗрдВрдЧреЗред рдПрдХреНрд╢рди рдмрдирд╛рддреЗ рд╣реИрдВ

enum Action {
    case addWorkout(_ workout: Workout)
    case removeWorkout(at: IndexSet)
    case sort(by: SortType)
}

рдЬреИрд╕рд╛ рдХрд┐ рд╣рдо рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдПрдХреНрд╢рди рддреАрди рдорд╛рдорд▓реЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдЬреНрдЮрд╛рди рд╣реИ рдЬреЛ рд╣рдореЗрдВ рд╣рдорд╛рд░реЗ рд░рд╛рдЬреНрдп рдореЗрдВ рд╣реЗрд░рдлреЗрд░ рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рджреЗрддрд╛ рд╣реИ ред

  • addWorkout (_ рд╡рд░реНрдХрдЖрдЙрдЯ: рд╡рд░реНрдХрдЖрдЙрдЯ) рдмрд╕ рдПрдХ рд╡рд░реНрдХрдЖрдЙрдЯ рдЬреЛрдбрд╝рддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рдПрдХ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд░реВрдк рдореЗрдВ рдкрд╛рд╕ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
  • removeWorkout (at: IndexSet) рдЖрдЗрдЯрдо рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдЗрдВрдбреЗрдХреНрд╕ рдкрд░ рдирд┐рдХрд╛рд▓рддрд╛ рд╣реИред
  • рд╕реЙрд░реНрдЯ (рджреНрд╡рд╛рд░рд╛: SortType) рдкреНрд░рд╢рд┐рдХреНрд╖рдг рд╕реВрдЪреА рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╕реЙрд░реНрдЯ рдкреНрд░рдХрд╛рд░ рджреНрд╡рд╛рд░рд╛ рд╕реЙрд░реНрдЯ рдХрд░рддрд╛ рд╣реИред

рдЪрд▓реЛ рд╕рдмрд╕реЗ рдЬрдЯрд┐рд▓ рдШрдЯрдХреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдмрдирд╛рддреЗ рд╣реИрдВ, рдпрд╣ Reducer рд╣реИ :

func reducer(state: AppState, action: Action) -> AppState {
    var state = state
    
    switch action {
    case .addWorkout(let workout):
        state.workouts.append(workout)
        
    case .removeWorkout(let indexSet):
        state.workouts.remove(atOffsets: indexSet)
    
    case .sort(let type):
        switch type {
        case .distance:
            state.workouts.sort { $0.distance > $1.distance }
            state.sortType = .distance
        case .complexity:
            state.workouts.sort { $0.complexity.rawValue > $1.complexity.rawValue }
            state.sortType = .complexity
        }
    }
    return state
}


рд╣рдордиреЗ рдЬреЛ рдлрд╝рдВрдХреНрд╢рди рд▓рд┐рдЦрд╛ рд╣реИ рд╡рд╣ рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИ рдФрд░ рдирд┐рдореНрдирд╛рдиреБрд╕рд╛рд░ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ:

  1. рдЗрд╕рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд░реНрддрдорд╛рди рд╕реНрдерд┐рддрд┐ рдХреА рдкреНрд░рддрд┐рд▓рд┐рдкрд┐ рдмрдирд╛рддрд╛ рд╣реИред
  2. рдХрд╛рд░реНрд░рд╡рд╛рдИ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ , рд╣рдо рдЕрдкрдиреА рдХреЙрдкреА рдХреА рдЧрдИ рд╕реНрдерд┐рддрд┐ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рддреЗ рд╣реИрдВ ред
  3. рдЕрджреНрдпрддрди рд╕реНрдерд┐рддрд┐ рд╡рд╛рдкрд╕ рдХрд░реЗрдВ

рдпрд╣ рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рд╣реИ рдХрд┐ рдЙрдкрд░реЛрдХреНрдд рдлрд╝рдВрдХреНрд╢рди рдПрдХ рд╢реБрджреНрдз рдлрд╝рдВрдХреНрд╢рди рд╣реИ, рдФрд░ рдпрд╣реА рд╡рд╣ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдо рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рдереЗ! рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЛ "рд╢реБрджреНрдз" рдорд╛рдирд╛ рдЬрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рджреЛ рд╢рд░реНрддреЛрдВ рдХреЛ рдкреВрд░рд╛ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП:

  • рд╣рд░ рдмрд╛рд░, рдлрд╝рдВрдХреНрд╢рди рд╕рдорд╛рди рдкрд░рд┐рдгрд╛рдо рджреЗрддрд╛ рд╣реИ рдЬрдм рдЗрд╕реЗ рдЙрд╕реА рдбреЗрдЯрд╛ рд╕реЗрдЯ рдХреЗ рд╕рд╛рде рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред
  • рдЗрд╕рдХреЗ рдХреЛрдИ рджреБрд╖реНрдкреНрд░рднрд╛рд╡ рдирд╣реАрдВ рд╣реИрдВред

рдЕрдВрддрд┐рдо рдЕрдиреБрдкрд▓рдмреНрдз Redux рддрддреНрд╡ рд╕реНрдЯреЛрд░ рд╣реИ , рддреЛ рдЖрдЗрдП рдЗрд╕реЗ рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдХреЗ рд▓рд┐рдП рд▓рд╛рдЧреВ рдХрд░реЗрдВред

final class Store: ObservableObject {
     @Published private(set) var state: AppState
     
     init(state: AppState = .init(workouts: [Workout]())) {
         self.state = state
     }
     
     public func dispatch(action: Action) {
         state = reducer(state: state, action: action)
     }
 }

рд╕реНрдЯреЛрд░ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдореЗрдВ, рд╣рдо рдСрдмреНрдЬрд░реНрд╡реЗрдмрд▓ рдСрдмрдЬреЗрдХреНрдЯ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреЗ рд╕рднреА рд▓рд╛рднреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ , рдЬреЛ рд╣рдореЗрдВ рдмрд╣реБрдд рд╕рд╛рд░реЗ рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЛрдб рд▓рд┐рдЦрдиреЗ рдпрд╛ рддреАрд╕рд░реЗ рдкрдХреНрд╖ рдХреЗ рдврд╛рдВрдЪреЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╕реЗ рдмрд╛рд╣рд░ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рд░рд╛рдЬреНрдп рд╕рдВрдкрддреНрддрд┐ рдХреЗрд╡рд▓ рдкрдврд╝реА рдЬрд╛рддреА рд╣реИ рдФрд░ @ рдкреНрд░реЙрдкрд░реНрдЯреА рдХреЗ рд░реИрдкрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреА рд╣реИ , рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рдЬрдм рднреА рдЗрд╕реЗ рдмрджрд▓рд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ SwiftUI рдХреЛ рд╕реВрдЪрдирд╛рдПрдВ рдкреНрд░рд╛рдкреНрдд рд╣реЛрдВрдЧреАред рдЗрдирд┐рдЯ рд╡рд┐рдзрд┐ рдПрдХ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдЕрд╡рд╕реНрдерд╛ рдХреЛ рд╡рд░реНрдХрдЖрдЙрдЯ рддрддреНрд╡реЛрдВ рдХреЗ рдЦрд╛рд▓реА рд╕рд░рдгреА рдХреЗ рд░реВрдк рдореЗрдВ рджрд┐рдП рдЧрдП рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдорд╛рди рдХреЗ рд╕рд╛рде рдПрдХ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд░реВрдк рдореЗрдВ рд▓реЗрддреА рд╣реИред рдкреНрд░реЗрд╖рдг рдлрд╝рдВрдХреНрд╢рди рд░рд╛рдЬреНрдп рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рдиреЗ рдХрд╛ рдПрдХрдорд╛рддреНрд░ рддрд░реАрдХрд╛ рд╣реИ: рдпрд╣ рд╡рд░реНрддрдорд╛рди рд╕реНрдерд┐рддрд┐ рдХреЛ рдирдП рдирд┐рд░реНрдорд╛рддрд╛ рд╕реЗ рдмрджрд▓ рджреЗрддрд╛ рд╣реИ, рдЬреЛ рдХрд┐ рд░реЗрдбреНрдпреВрд╕рд░ рдлрд╝рдВрдХреНрд╢рди рджреНрд╡рд╛рд░рд╛ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ ,рдХрд╛рд░реНрд░рд╡рд╛рдИ , рдЬрд┐рд╕реЗ рдПрдХ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд░реВрдк рдореЗрдВ рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рдЕрдм рдЬрдм рд╣рдордиреЗ Redux рдХреЗ рд╕рднреА рдШрдЯрдХреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░ рджрд┐рдпрд╛ рд╣реИ, рддреЛ рд╣рдо рдЕрдкрдиреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд▓рд┐рдП рдПрдХ рдпреВрдЬрд░ рдЗрдВрдЯрд░рдлреЗрд╕ рдмрдирд╛рдирд╛ рд╢реБрд░реВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

рдЖрд╡реЗрджрди рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди


рд╣рдорд╛рд░реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛рдлреА рд╕рд░рд▓ рд╣реЛрдЧрд╛ред рдФрд░ рдЗрд╕рдореЗрдВ рджреЛ рдЫреЛрдЯреЗ рд╕реНрдХреНрд░реАрди рд╢рд╛рдорд┐рд▓ рд╣реЛрдВрдЧреЗред рдкрд╣рд▓реА рдФрд░ рдореБрдЦреНрдп рд╕реНрдХреНрд░реАрди рдПрдХ рд╕реНрдХреНрд░реАрди рд╣реИ рдЬреЛ рд╡рд░реНрдХрдЖрдЙрдЯ рдХреА рд╕реВрдЪреА рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗрдЧреАред рджреВрд╕рд░реА рд╕реНрдХреНрд░реАрди рдРрдб рд╡рд░реНрдХрдЖрдЙрдЯ рд╕реНрдХреНрд░реАрди рд╣реИред рд╕рд╛рде рд╣реА, рдкреНрд░рддреНрдпреЗрдХ рддрддреНрд╡ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рд░рдВрдЧ рдореЗрдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рд░рдВрдЧ рдХрд╕рд░рдд рдХреА рдЬрдЯрд┐рд▓рддрд╛ рдХреЛ рджрд░реНрд╢рд╛рдПрдЧрд╛ред рд▓рд╛рд▓ рдХреЛрд╢рд┐рдХрд╛рдПрдВ рдХрд╕рд░рдд рдХреА рдЙрдЪреНрдЪрддрдо рдХрдард┐рдирд╛рдИ рдХрд╛ рд╕рдВрдХреЗрдд рджреЗрддреА рд╣реИрдВ, рдирд╛рд░рдВрдЧреА рдФрд╕рдд рдХрдард┐рдирд╛рдИ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИ рдФрд░ рд╣рд░реЗ рд░рдВрдЧ рдХреА рд╕рдмрд╕реЗ рдЖрд╕рд╛рди рдХрд╕рд░рдд рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИред

рд╣рдо Apple рд╕реЗ рдПрдХ рдирдИ рд░реВрдкрд░реЗрдЦрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд░реЗрдВрдЧреЗ рдЬрд┐рд╕реЗ SwiftUI рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред SwiftUI рд╣рдорд╛рд░реЗ рдкрд░рд┐рдЪрд┐рдд UIKit рдХреЛ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрддрд╛ рд╣реИред SwiftUI рдореМрд▓рд┐рдХ рд░реВрдк рд╕реЗ UIKit рд╕реЗ рдЕрд▓рдЧ рд╣реИ, рдореБрдЦреНрдп рд░реВрдк рд╕реЗ рдпрд╣ рдпреВрдЖрдИ рддрддреНрд╡реЛрдВ рдХреЛ рдХреЛрдб рдХреЗ рд╕рд╛рде рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдШреЛрд╖рдгрд╛рддреНрдордХ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╣реИред рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рдореИрдВ рд╕реНрд╡рд┐рдлреНрдЯрдпреВрдЖрдИ рдХреА рд╕рднреА рдкреЗрдЪреАрджрдЧрд┐рдпреЛрдВ рдореЗрдВ рддрд▓реНрд▓реАрди рдирд╣реАрдВ рдХрд░реВрдВрдЧрд╛ рдФрд░ рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рд╕реНрд╡рд┐рдлреНрдЯрдпреВрдЖрдИ рдХреЗ рд╕рд╛рде рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЕрдиреБрднрд╡ рд╣реИред рдпрджрд┐ рдЖрдкрдХреЛ SwiftUI рдХрд╛ рдЬреНрдЮрд╛рди рдирд╣реАрдВ рд╣реИ, рддреЛ рдореИрдВ рдЖрдкрдХреЛ Apple рд╕реЗ рдкреНрд░рд▓реЗрдЦрди рдкрд░ рдзреНрдпрд╛рди рджреЗрдиреЗ рдХреА рд╕рд▓рд╛рд╣ рджреЗрддрд╛ рд╣реВрдВ, рдЕрд░реНрдерд╛рддреН, рдЪрд░рдг-рджрд░-рдЪрд░рдг рдЬреЛрдбрд╝ рдФрд░ рдкрд░рд┐рдгрд╛рдо рдХреЗ рд╕рдВрд╡рд╛рджрд╛рддреНрдордХ рдкреНрд░рджрд░реНрд╢рди рдХреЗ рд╕рд╛рде рдЙрдирдХреЗ рдХрдИ рд╕рдВрдкреВрд░реНрдг рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ рджреЗрдЦреЗрдВред рдЙрджрд╛рд╣рд░рдг рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдХреЗ рд▓рд┐рдВрдХ рднреА рд╣реИрдВред рдпреЗ рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ рдЖрдкрдХреЛ SwiftUI рдХреА рдШреЛрд╖рд┐рдд рджреБрдирд┐рдпрд╛ рдореЗрдВ рдЬрд▓реНрджреА рд╕реЗ рдЧреЛрддрд╛ рд▓рдЧрд╛рдиреЗ рджреЗрдВрдЧреЗред

рдпрд╣ рднреА рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рд╣реИ рдХрд┐ SwiftUI рдЕрднреА рддрдХ рдЙрддреНрдкрд╛рджрди рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рдирд╣реАрдВ рд╣реИ, рдпрд╣ рдмрд╣реБрдд рдЫреЛрдЯрд╛ рд╣реИ рдФрд░ рдЗрд╕ рддрд░рд╣ рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдПрдХ рд╡рд░реНрд╖ рд╕реЗ рдЕрдзрд┐рдХ рд╕рдордп рдмреАрдд рдЬрд╛рдПрдЧрд╛ред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдпрд╣ рдордд рднреВрд▓реЛ рдХрд┐ рдпрд╣ рдХреЗрд╡рд▓ iOS 13.0+ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдпрд╣ рднреА рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рд╣реИ рдХрд┐ SwiftUI рд╕рднреА Apple рдкреНрд▓реЗрдЯрдлрд╛рд░реНрдореЛрдВ рдкрд░ рдХрд╛рдо рдХрд░реЗрдЧреА, рдЬреЛ рдХрд┐ UIKit рдкрд░ рдПрдХ рдмрдбрд╝рд╛ рд▓рд╛рдн рд╣реИ!

рдЖрдЗрдП рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдХреА рдореБрдЦреНрдп рд╕реНрдХреНрд░реАрди рд╕реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╢реБрд░реВ рдХрд░реЗрдВред рдлрд╝рд╛рдЗрд▓ рдкрд░ рдЬрд╛рдПрдВ ContentView.swift рд╡рд░реНрддрдорд╛рди рдХреЛрдб рдХреЛ рдЗрд╕рдореЗрдВ рдмрджрд▓реЗрдВред

struct ContentView: View {
    @EnvironmentObject var store: Store
    @State private var isAddingMode: Bool = false
    
    var body: some View {
        NavigationView {
            WorkoutListView()
                .navigationBarTitle("Workouts diary", displayMode: .inline)
                .navigationBarItems(
                    leading: AddButton(isAddingMode: self.$isAddingMode),
                    trailing: TrailingView()
                )
        }
        .sheet(isPresented: $isAddingMode) {
            AddWorkoutView(isAddingMode: self.$isAddingMode)
                .environmentObject(self.store)
        }
    }
}

рд╕рд╛рдордЧреНрд░реА рджреГрд╢реНрдп SwiftUI рдореЗрдВ рдПрдХ рдорд╛рдирдХ рджреГрд╢реНрдп рд╣реИред рд╕рдмрд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣рд┐рд╕реНрд╕рд╛ - рдореЗрд░реЗ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╕реЗ - рдХреЛрдб рдХреА рдкрдВрдХреНрддрд┐ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рд╕реНрдЯреЛрд░ рдЪрд░ рд╢рд╛рдорд┐рд▓ рд╣реИред рд╣рдо @EnvironmentObject рдмрдирд╛рдПрдВрдЧреЗред рдпрд╣ рд╣рдореЗрдВ рдЬрд╣рд╛рдБ рдЖрд╡рд╢реНрдпрдХ рд╣реИ, рд╕реНрдЯреЛрд░ рд╕реЗ рдбреЗрдЯрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛, рдФрд░ рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдпрд╣ рдбреЗрдЯрд╛ рдмрджрд▓рдиреЗ рдкрд░ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рд╣рдорд╛рд░реЗ рд╡рд┐рдЪрд╛рд░реЛрдВ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░реЗрдЧрд╛ред рдпрд╣ рд╣рдорд╛рд░реЗ рд╕реНрдЯреЛрд░ рдХреЗ рд▓рд┐рдП рд╕рд┐рдВрдЧрд▓рдЯрди рдХреА рддрд░рд╣ рдХреБрдЫ рд╣реИред

@EnvironmentObject var store: Store

рдпрд╣ рдХреЛрдб рдХреА рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкрдВрдХреНрддрд┐ рдХреЛ рднреА рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рд╣реИ:

@State private var isAddingMode: Bool = false

рд░рд╛рдЬреНрдпрдПрдХ рдЖрд╡рд░рдг рд╣реИ рдЬрд┐рд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рд╣рдо рдПрдХ рджреГрд╢реНрдп рдХреА рд╕реНрдерд┐рддрд┐ рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред SwiftUI рдЗрд╕реЗ рд╡реНрдпреВ рд╕реНрдЯреНрд░рдХреНрдЪрд░ рдХреЗ рдмрд╛рд╣рд░ рдПрдХ рд╡рд┐рд╢реЗрд╖ рдЖрдВрддрд░рд┐рдХ рдореЗрдореЛрд░реА рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░реЗрдЧрд╛ред рдХреЗрд╡рд▓ рдПрдХ рдЬреБрдбрд╝рд╛ рд╣реБрдЖ рджреГрд╢реНрдп рд╣реА рдЗрд╕реЗ рдПрдХреНрд╕реЗрд╕ рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдПрдХ рдмрд╛рд░ рд╕рдВрдкрддреНрддрд┐ рдХрд╛ рдореВрд▓реНрдпрд░рд╛рдЬреНрдп рдкрд░рд┐рд╡рд░реНрддрди, SwiftUI рд░рд╛рдЬреНрдп рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЗ рд▓рд┐рдП рдЦрд╛рддреЗ рдХреЛ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдкреБрди: рдмрдирд╛рддрд╛ рд╣реИред

рдЫрд╡рд┐

рдлрд┐рд░ рд╣рдо SceneDelegate.swift рдлрд╛рдЗрд▓ рдореЗрдВ рдЬрд╛рдПрдВрдЧреЗ рдФрд░ рдХреЛрдб рдХреЛ рд╡рд┐рдзрд┐ рдореЗрдВ рдЬреЛрдбрд╝ рджреЗрдВрдЧреЗ:

func scene(
        _ scene: UIScene,
        willConnectTo session: UISceneSession,
        options connectionOptions: UIScene.ConnectionOptions
    ) {
        let contentView = ContentView().environmentObject(Store())
        
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: contentView)
            self.window = window
            window.makeKeyAndVisible()
        }
    }

рдЙрд╕реА рддрд░рд╣, рдХрд┐рд╕реА рднреА @EnvironmentObject рдХреЛ рдкреВрд░реЗ рдЖрд╡реЗрджрди рдореЗрдВ рдХрд┐рд╕реА рднреА рдмрдЪреНрдЪреЗ рдХреЗ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХреЗ рд▓рд┐рдП рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рдпрд╣ рд╕рдм рдкрд░реНрдпрд╛рд╡рд░рдг рдХреЗ рд▓рд┐рдП рд╕рдВрднрд╡ рд╣реИред IsAddingMode рдЪрд░ рдЪрд┐рд╣реНрдирд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИрд░рд╛рдЬреНрдпрдФрд░ рдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдорд╛рдзреНрдпрдорд┐рдХ рджреГрд╢реНрдп рдкреНрд░рджрд░реНрд╢рд┐рдд рд╣реЛрддрд╛ рд╣реИ рдпрд╛ рдирд╣реАрдВред рджреБрдХрд╛рди рдЪрд░ рд╣реИ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рджреНрд╡рд╛рд░рд╛ рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рдорд┐рд▓реА WorkoutListView , рдФрд░ рд╣рдо рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдкрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреА рдЬрд░реВрд░рдд рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рд╣рдо рдХреЗ рд▓рд┐рдП рдРрд╕рд╛ рдХрд░рдиреЗ рдХреА рдЬрд░реВрд░рдд AddWorkoutView рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдПрдХ рдЪрд╛рджрд░ рд╣реИ рдХрд┐ рдПрдХ рдмрдЪреНрдЪреЗ рдХреЛ рдирд╣реАрдВ рд╣реИ рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рд╕реНрддреБрдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, contentView ред

рдЕрдм рдПрдХ WorkoutListView рдмрдирд╛рдПрдВ рдЬреЛ рд╡реНрдпреВ рд╕реЗ рдЗрдирд╣реЗрд░рд┐рдЯ рдХрд░реЗрдЧрд╛ред WorkoutListView рдирд╛рдордХ рдПрдХ рдирдИ рд╕реНрд╡рд┐рдлреНрдЯ рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдБ ред

struct WorkoutListView: View {
    @EnvironmentObject var store: Store
    
    var body: some View {
        List {
            ForEach(store.state.workouts) {
                WorkoutView(workout: $0)
            }
            .onDelete {
                self.store.dispatch(action: .removeWorkout(at: $0))
            }
            .listRowInsets(EdgeInsets())
        }
    }
}

рджреЗрдЦреЗрдВ, рдЬреЛ рд╡рд░реНрдХрдЖрдЙрдЯ рдХреА рд╕реВрдЪреА рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрдВрдЯреЗрдирд░ рд╕реВрдЪреА рддрддреНрд╡ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред OnDelete рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдПрдХ рдХрд╕рд░рдд рдХреЛ рд╣рдЯрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рд░рд┐рдореВрд╡рдЖрдЙрдЯ рдХрд╛рд░реНрд░рд╡рд╛рдИ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ , рдЬреЛ рд╕реНрдЯреЛрд░ рджреНрд╡рд╛рд░рд╛ рдкреНрд░рджрд╛рди рдХрд┐рдП рдЧрдП рдкреНрд░реЗрд╖рдг рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ ред рд╕реВрдЪреА рдореЗрдВ рд╡рд░реНрдХрдЖрдЙрдЯ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╡рд░реНрдХрдЖрдЙрдЯ рд╡реНрдпреВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рдПрдХ рдЕрдиреНрдп рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдБ WorkoutView.swift рдЬреЛ рд╕реВрдЪреА рдореЗрдВ рд╣рдорд╛рд░реЗ рдЖрдЗрдЯрдо рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реЛрдЧреАред

struct WorkoutView: View {
    let workout: Workout
    
    private var backgroundColor: Color {
        switch workout.complexity {
        case .low:
            return .green
        case .medium:
            return .orange
        case .high:
            return .red
        }
    }
    
    var body: some View {
        HStack {
            VStack(alignment: .leading) {
                Text(workout.name)
                Text("Distance:" + workout.distance + "km")
                    .font(.subheadline)
            }
            Spacer()
            VStack(alignment: .leading) {
                Text(simpleFormat(workout.date))
            }
        }
        .padding()
        .background(backgroundColor)
    }
}

private extension WorkoutView {
    func simpleFormat(_ date: Date) -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "dd MMM yyyy"
        dateFormatter.locale = .init(identifier: "en_GB")
        return dateFormatter.string(from: date)
    }
}

рдпрд╣ рджреГрд╢реНрдп рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рдПрдХ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд░реВрдк рдореЗрдВ рд▓реЗрддрд╛ рд╣реИ рдФрд░ рдЗрд╕рдХреЗ рдЧреБрдгреЛрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред

рд╕реВрдЪреА рдореЗрдВ рдПрдХ рдирдпрд╛ рдЖрдЗрдЯрдо рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ AddWorkoutView рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП isAddingMode рдкреИрд░рд╛рдореАрдЯрд░ рдХреЛ рд╕рд╣реА рдкрд░ рдмрджрд▓рдирд╛ рд╣реЛрдЧрд╛ ред рдпрд╣ рдЬрд┐рдореНрдореЗрджрд╛рд░реА AddButton рдХреЗ рд╕рд╛рде рд╣реИ ред

struct AddButton: View {
    @Binding var isAddingMode: Bool
    
    var body: some View {
        Button(action: { self.isAddingMode = true }) {
            Image(systemName: "plus")
        }
    }
}

AddButton рднреА рдПрдХ рдЕрд▓рдЧ рдлрд╛рдЗрд▓ рдореЗрдВ рдбрд╛рд▓рдиреЗ рд▓рд╛рдпрдХ рд╣реИред

рдпрд╣ рджреГрд╢реНрдп рдПрдХ рд╕рд░рд▓ рдмрдЯрди рд╣реИ рдХрд┐ рдореБрдЦреНрдп рд░реВрдк рд╕реЗ рдирд┐рдХрд╛рд▓рд╛ рдЧрдпрд╛ рд╣реИ рд╣реИ contentView рдмреЗрд╣рддрд░ рд╕рдВрд░рдЪрдирд╛ рдФрд░ рдХреЛрдб рдЕрд▓рдЧ рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдПред

рдПрдХ рдирдИ рдХрд╕рд░рдд рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рджреГрд╢реНрдп рдмрдирд╛рдПрдВред рдПрдХ рдирдпрд╛ AddWorkoutView.swift рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдБ :

struct AddWorkoutView: View {
    @EnvironmentObject private var store: Store
    
    @State private var nameText: String = ""
    @State private var distanceText: String = ""
    @State private var complexityField: Complexity = .medium
    @State private var dateField: Date = Date()
    @Binding var isAddingMode: Bool
    
    var body: some View {
        NavigationView {
            Form {
                TextField("Name", text: $nameText)
                TextField("Distance", text: $distanceText)
                Picker(selection: $complexityField, label: Text("Complexity")) {
                    Text("Low").tag(Complexity.low)
                    Text("Medium").tag(Complexity.medium)
                    Text("High").tag(Complexity.high)
                }
                DatePicker(selection: $dateField, displayedComponents: .date) {
                    Text("Date")
                }
            }
            .navigationBarTitle("Workout Details", displayMode: .inline)
            .navigationBarItems(
                leading: Button(action: { self.isAddingMode = false }) {
                    Text("Cancel")
                },
                trailing: Button(action: {
                    let workout = Workout(
                        name: self.nameText,
                        distance: self.distanceText,
                        date: self.dateField,
                        complexity: self.complexityField
                    )
                    self.store.dispatch(action: .addWorkout(workout))
                    self.isAddingMode = false
                }) {
                    Text("Save")
                }
                .disabled(nameText.isEmpty)
            )
        }
    }
}

рдпрд╣ рдПрдХ рдХрд╛рдлреА рдмрдбрд╝рд╛ рдирд┐рдпрдВрддреНрд░рдХ рд╣реИ, рдЬреЛ рдЕрдиреНрдп рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рдХреА рддрд░рд╣, рд╕реНрдЯреЛрд░ рдЪрд░ рднреА рд╢рд╛рдорд┐рд▓ рд╣реИред рдЗрд╕рдореЗрдВ рд╡реИрд░рд┐рдПрдмрд▓ nameText, DistanceText, complexityField рдФрд░ isAddingMode рднреА рд╢рд╛рдорд┐рд▓ рд╣реИрдВ ред TextField, Picker, DatePicker рдХреЛ рд▓рд┐рдВрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд╣рд▓реЗ рддреАрди рдЪрд░ рдЖрд╡рд╢реНрдпрдХ рд╣реИрдВ , рдЬрд┐рдиреНрд╣реЗрдВ рдЗрд╕ рд╕реНрдХреНрд░реАрди рдкрд░ рджреЗрдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдиреЗрд╡рд┐рдЧреЗрд╢рди рдмрд╛рд░ рдореЗрдВ рджреЛ рддрддреНрд╡ рд╣реИрдВред рдкрд╣рд▓рд╛ рдмрдЯрди рдПрдХ рдмрдЯрди рд╣реИ рдЬреЛ рдирдИ рдХрд╕рд░рдд рдХреЛ рдЬреЛрдбрд╝реЗ рдмрд┐рдирд╛ рд╕реНрдХреНрд░реАрди рдХреЛ рдмрдВрдж рдХрд░ рджреЗрддрд╛ рд╣реИ, рдФрд░ рдЕрдВрддрд┐рдо рд╕реВрдЪреА рдореЗрдВ рдПрдХ рдирдпрд╛ рд╡рд░реНрдХрдЖрдЙрдЯ рдЬреЛрдбрд╝рддрд╛ рд╣реИ, рдЬреЛ рдХрд┐ рдРрдбрд╡рд░реНрдХ рд╡рд░реНрдХ рднреЗрдЬрдХрд░ рд╣рд╛рд╕рд┐рд▓ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣ рдХреНрд░рд┐рдпрд╛ рдирдП рд╡рд░реНрдХрдЖрдЙрдЯ рд╕реНрдХреНрд░реАрди рдХреЛ рднреА рдмрдВрдж рдХрд░ рджреЗрддреА рд╣реИред

рдЫрд╡рд┐

рдкрд┐рдЫрд▓реЗ рдирд╣реАрдВ рдмрд▓реНрдХрд┐ рдХрдо рд╕реЗ рдХрдо TrailingView рд╣реИ ред

struct TrailingView: View {
    @EnvironmentObject var store: Store
    
    var body: some View {
        HStack(alignment: .center, spacing: 30) {
            Button(action: {
                switch self.store.state.sortType {
                case .distance:
                    self.store.dispatch(action: .sort(by: .distance))
                default:
                    self.store.dispatch(action: .sort(by: .complexity))
                }
            }) {
                Image(systemName: "arrow.up.arrow.down")
            }
            EditButton()
        }
    }
}

рдЗрд╕ рджреГрд╢реНрдп рдореЗрдВ рджреЛ рдмрдЯрди рд╣реЛрддреЗ рд╣реИрдВ рдЬреЛ рд╡рд░реНрдХрдЖрдЙрдЯ рд╕реВрдЪреА рдХреЛ рд╕реЙрд░реНрдЯ рдХрд░рдиреЗ рдФрд░ рд╣рдорд╛рд░реА рд╡рд░реНрдХрдЖрдЙрдЯ рд╕реВрдЪреА рдХреЗ рд╕рдВрдкрд╛рджрди рдореЛрдб рдХреЛ рд╕рдХреНрд░рд┐рдп рдпрд╛ рдирд┐рд╖реНрдХреНрд░рд┐рдп рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реЛрддреЗ рд╣реИрдВред рдЫрдВрдЯрдиреА рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЛ рдкреНрд░реЗрд╖рдг рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рд╣рдо рд╕реНрдЯреЛрд░ рд╕рдВрдкрддреНрддрд┐ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХреЙрд▓ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

рдЫрд╡рд┐

рдкрд░рд┐рдгрд╛рдо


рдЖрд╡реЗрджрди рддреИрдпрд╛рд░ рд╣реИ рдФрд░ рдЙрдореНрдореАрдж рдХреЗ рдореБрддрд╛рдмрд┐рдХ рдХрд╛рдо рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред рдЖрдЗрдП рдЗрд╕реЗ рд╕рдВрдХрд▓рд┐рдд рдХрд░рдиреЗ рдФрд░ рдЪрд▓рд╛рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВред

рдЬрд╛рдБрдЪ - рдкрд░рд┐рдгрд╛рдо


Redux рдФрд░ SwiftUI рдПрдХ рд╕рд╛рде рдмрд╣реБрдд рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВред рдЗрди рдЙрдкрдХрд░рдгреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд▓рд┐рдЦреЗ рдЧрдП рдХреЛрдб рдХреЛ рд╕рдордЭрдирд╛ рдЖрд╕рд╛рди рд╣реИ рдФрд░ рдЗрд╕реЗ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕ рд╕рдорд╛рдзрд╛рди рдХрд╛ рдПрдХ рдФрд░ рдЕрдЪреНрдЫрд╛ рдкрд╣рд▓реВ рдЗрд╕рдХреА рдЙрддреНрдХреГрд╖реНрдЯ рдХреЛрдб рдкрд░реАрдХреНрд╖рдгрд╢реАрд▓рддрд╛ рд╣реИред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдпрд╣ рд╕рдорд╛рдзрд╛рди рдХрдорд┐рдпреЛрдВ рдХреЗ рдмрд┐рдирд╛ рдирд╣реАрдВ рд╣реИ, рдЙрдирдореЗрдВ рд╕реЗ рдПрдХ рдмрдбрд╝реА рдорд╛рддреНрд░рд╛ рдореЗрдВ рдореЗрдореЛрд░реА рд╣реИ рдЬрд┐рд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рджреНрд╡рд╛рд░рд╛ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдЬрдм рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рд╕реНрдерд┐рддрд┐ рдмрд╣реБрдд рдЬрдЯрд┐рд▓ рд╣реЛрддреА рд╣реИ, рдФрд░ рдХреБрдЫ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдкрд░рд┐рджреГрд╢реНрдпреЛрдВ рдореЗрдВ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХрд╛ рдкреНрд░рджрд░реНрд╢рди рдЖрджрд░реНрд╢ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдПрдХ рдирдпрд╛ рд░рд╛рдЬреНрдп рдмрдирд╛рддреЗ рд╕рдордп рд╕рднреА рд╕реНрд╡рд┐рдлреНрдЯрдпреВрдЖрдИ рдореЗрдВ рдЕрдкрдбреЗрдЯ рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред рдЗрди рдХрдорд┐рдпреЛрдВ рдХрд╛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдФрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреА рдмрд╛рддрдЪреАрдд рдХреА рдЧреБрдгрд╡рддреНрддрд╛ рдкрд░ рдмрдбрд╝рд╛ рдкреНрд░рднрд╛рд╡ рдкрдбрд╝ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдЧрд░ рд╣рдо рдЙрдиреНрд╣реЗрдВ рдпрд╛рдж рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдЙрдЪрд┐рдд рддрд░реАрдХреЗ рд╕реЗ рд░рд╛рдЬреНрдп рддреИрдпрд╛рд░ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдирдХрд╛рд░рд╛рддреНрдордХ рдкреНрд░рднрд╛рд╡ рдХреЛ рдЖрд╕рд╛рдиреА рд╕реЗ рдХрдо рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдпрд╛ рдмрдЪрд╛ рднреА рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдЖрдк рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рд╕реНрд░реЛрдд рдХреЛрдб рдХреЛ рдбрд╛рдЙрдирд▓реЛрдб рдпрд╛ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВредрдпрд╣рд╛рдБ ред

рдореБрдЭреЗ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдЖрдкрдХреЛ рдпрд╣ рд▓реЗрдЦ рдкрд╕рдВрдж рдЖрдпрд╛ рд╣реЛрдЧрд╛ рдФрд░ рдЖрдкрдиреЗ рдЕрдкрдиреЗ рд▓рд┐рдП рдХреБрдЫ рдирдпрд╛ рд╕реАрдЦрд╛ рд╣реЛрдЧрд╛, рдЬрд▓реНрдж рд╣реА рдорд┐рд▓рддреЗ рд╣реИрдВред рдЖрдЧреЗ рдпрд╣ рдФрд░ рднреА рджрд┐рд▓рдЪрд╕реНрдк рд╣реЛрдЧрд╛ред

All Articles