@@ -15,13 +15,112 @@ class NoteEditViewController: UIViewController {
1515 private var presenter
1616
1717 private var cancellableSet : Set < AnyCancellable > = [ ]
18+
19+ @IBOutlet private var closeBarItem : UIBarButtonItem !
20+ @IBOutlet private var saveBarItem : UIBarButtonItem !
21+ @IBOutlet private weak var textView : UITextView !
1822
1923 override func viewDidLoad( ) {
2024 super. viewDidLoad ( )
21-
25+ navigationController? . presentationController? . delegate = self
26+
27+ presenter. configure (
28+ showAlertHandler: { [ weak self] title, message in
29+ let alert = UIAlertController ( title: title, message: message, preferredStyle: . alert)
30+ alert. addAction ( . init( title: " OK " , style: . default, handler: nil ) )
31+ self ? . present ( alert, animated: true , completion: nil )
32+ }
33+ )
34+
35+ textView. textContainer. lineFragmentPadding = 0
36+ updateTextViewInsets ( keyboardHeight: 0 )
37+
38+ textView. text = presenter. contentText
39+ textView. delegate = self
40+
2241 presenter. titlePublisher. sink { [ weak self] in
2342 self ? . navigationItem. title = $0
2443 } . store ( in: & cancellableSet)
44+
45+ presenter. editStatePublisher. sink { [ weak self] in
46+ self ? . updateForEditState ( $0)
47+ } . store ( in: & cancellableSet)
48+
49+ NotificationCenter . default
50+ . publisher ( for: UIResponder . keyboardWillChangeFrameNotification)
51+ . sink { [ weak self] notification in
52+ guard let self = self ,
53+ let keyboardValue = notification. userInfo ? [ UIResponder . keyboardFrameEndUserInfoKey] as? NSValue else { return }
54+ let keyboardScreenEndFrame = keyboardValue. cgRectValue
55+ let keyboardViewEndFrame = self . view. convert ( keyboardScreenEndFrame, from: self . view. window)
56+ let keyboardHeight = keyboardViewEndFrame. height - self . view. safeAreaInsets. bottom
57+ self . updateTextViewInsets ( keyboardHeight: keyboardHeight)
58+ self . scrollToCursorTextView ( )
59+ } . store ( in: & cancellableSet)
60+
61+ NotificationCenter . default
62+ . publisher ( for: UIResponder . keyboardWillHideNotification)
63+ . sink { [ weak self] _ in
64+ self ? . updateTextViewInsets ( keyboardHeight: 0 )
65+ } . store ( in: & cancellableSet)
66+ }
67+
68+ // MARK: Actions
69+ @IBAction private func close( ) {
70+ dismiss ( animated: true , completion: nil )
71+ }
72+
73+ @IBAction private func save( ) {
74+ presenter. save ( completion: nil )
75+ }
76+
77+ private func confirmClose( ) {
78+ let alert = UIAlertController ( title: " Save changes? " , message: nil , preferredStyle: . actionSheet)
79+ alert. addAction ( . init( title: " Cancel " , style: . cancel, handler: nil ) )
80+ alert. addAction ( . init( title: " Save " , style: . default, handler: { [ weak self] _ in
81+ self ? . presenter. save ( completion: { success in
82+ if success {
83+ self ? . close ( )
84+ }
85+ } )
86+ } ) )
87+ alert. addAction ( . init( title: " Not save " , style: . destructive, handler: { [ weak self] _ in
88+ self ? . close ( )
89+ } ) )
90+
91+ present ( alert, animated: true , completion: nil )
92+ }
93+
94+ // MARK: - Private
95+ private func updateForEditState( _ state: NoteEditViewModel . EditState ) {
96+ closeBarItem? . title = state == . saved ? " Done " : " Cancel "
97+ saveBarItem? . title = ( state == . new || state == . newInvalid) ? " Add " : " Save "
98+
99+ let canSaved = state == . new || state == . changed
100+ saveBarItem? . isEnabled = canSaved
101+ isModalInPresentation = canSaved
102+ }
103+
104+ private func updateTextViewInsets( keyboardHeight: CGFloat ) {
105+ let padding : CGFloat = 16
106+ textView. contentInset = . init( top: padding, left: padding, bottom: padding + keyboardHeight, right: padding)
107+ textView. scrollIndicatorInsets = . init( top: 0 , left: 0 , bottom: keyboardHeight, right: 0 )
25108 }
26109
110+ private func scrollToCursorTextView( ) {
111+ let selectedRange = textView. selectedRange
112+ textView. scrollRangeToVisible ( selectedRange)
113+ }
114+ }
115+
116+ extension NoteEditViewController : UITextViewDelegate {
117+ func textViewDidChange( _ textView: UITextView ) {
118+ presenter. contentText = textView. text ?? " "
119+ }
120+ }
121+
122+ extension NoteEditViewController : UIAdaptivePresentationControllerDelegate {
123+ func presentationControllerDidAttemptToDismiss( _ presentationController: UIPresentationController ) {
124+ confirmClose ( )
125+ }
27126}
0 commit comments