Fork me on GitHub
#matrix
<
2023-06-05
>
Benjamin C04:06:40

I think I'm missing something:

(defn button [title action]
  (fx/gesture-detector
   {:onTap (fx/as-dart-callback [] (action))}
   (fx/center
    (m/Text title .style (m/TextStyle .fontSize 18 .fontWeight m/FontWeight.w800)))))

(defn make-app []
  (let [title "Why Hello"]
    (fx/material-app
     {:title title}
     (fx/scaffold
      {:appBar (fx/app-bar {:title (fx/text title)})}
      {:name :scaffo
       :step (cI 1)}
      (fx/center
       (fx/column
        (fx/text (str "current step: " (mget (fasc :scaffo) :step)))
        (fx/elevated-button {:onPressed (dfn [] (with-cc :test (mset! (fasc :scaffo) :step 2)))}
                            (fx/text "Change to next step"))
        (fx/elevated-button {:onPressed (dfn [] (with-cc :test (mset! (fasc :scaffo) :step 1)))}
                            (fx/text (str "Change to first step")))
        (case (mget (fasc :scaffo) :step)
          1 (fx/column (fx/text "hi -- ")
                       (button "you'd think this would change" (fn [] (mx/dp :button-1))))
          2 (fx/column (fx/text "howdy -- ")
                       (button "but does it?" (fn [] (mx/dp :button-2)))))))))))
The regular text (IE. "hi -- " and "howdy -- ") Changes with the :step prop, as I would expect. Yet somehow the (button ,,,,) call does not?

👀 2
Benjamin C05:06:14

Hmm, works fine without the fx/guesture-detector .

kennytilton12:06:52

Gonna fire this up now....

kennytilton12:06:42

Confirmed the issue. Oh, btw, it should not matter (it's a NOP), but we only need to wrap state change in with-cc in watches, when a state change is already underway. So the gesture-detector :onTap is fine. But I have those commented out in the elevated button onPresses and the problem is unchanged. I will leave them commented out while I explore, just to KISS. I suspect I may be missing a setState. Deep-diving...

kennytilton13:06:08

Confirm it works without the gesture-detector -- good clue! Just realizing how strange is the behavior -- the text hi/howdy proves we are changing columns! Btw, eliminating the "but does it?" button altogether works in the sense that "you'd think" disappears. Good one! Wondering if we are looking at two issues... :thinking_face:

kennytilton13:06:41

OK, the second column runs as expected, and as we can see from the text being pulled in. I have to crash, but methinks Flutter thinks the two GDs (gesture detectors) are the same, for some value of "same". More after a quick crash.

Benjamin C15:06:35

Sounds likely! Some bits in this thread are perhaps relevant: https://clojurians.slack.com/archives/C03A6GE8D32/p1675818632237609

Benjamin C16:06:20

Hmm, maybe it has something to do with GuestureDetector being a StatelessWidget ?

Benjamin C16:06:05

Since we're not dealing with a stateful widget, maybe we need to call markNeedsBuild directly?

kennytilton16:06:58

Thx, I have been getting ready to explore which widgets were stateless and which not. I think I have experimented enough with widget juggling, I'll see where I can work markNeedsBuild into things.

Benjamin C16:06:56

Ooh, wait, this might be a very simple fix, this deftag looks suspicious...

Benjamin C16:06:09

(deftag tiltontec.flutter-mx.factory/k1-child-stateful gesture-detector m/GestureDetector)

Benjamin C16:06:44

@U0PUGPSFR Aha, that's the culprit! swapped with k1-child-stateless and now it works like a charm :)

👏 2
kennytilton16:06:32

Great catch, and the Flutter doc confirms I got that wrong. Now I have to cheak Ink, because a center/ink/text is also broken, no GD at all.

Benjamin C16:06:29

Not sure about Ink itself, but InkWell is stateless, so probably same for Ink? I wish flutter gave us a simpler way to find out :P

Benjamin C16:06:38

Oh, yeah, InkWell is indeed stateful, (in accordence with the deftag), so something else must be at play.

kennytilton16:06:43

Ink seems to be either. No inheritance (I scroll waaayyyyyyyy down to an inheritance list) and see neither Stateful nor Stateless.

Benjamin C16:06:23

Oh you're right, I got my pages mixed up for a sec.

kennytilton16:06:28

ISTR Text is the same.

Benjamin C16:06:57

Hmm, (deftag tiltontec.flutter-mx.factory/k1-child-stateless ink m/Ink) work?

kennytilton16:06:26

With text I covered all the bases:

(deftagleaf tiltontec.flutter-mx.factory/konly-param1-stateless text m/Text)
(deftagleaf tiltontec.flutter-mx.factory/konly-param1-stateful text! m/Text)

kennytilton16:06:03

And ISTR that was necessitated by sth not updating.

Benjamin C17:06:22

The Joy of Clojure Flutter :P

Benjamin C17:06:15

Maybe taking a more direct approach of markNeedsBuild instead of setState might work around the flutter dance?

Benjamin C17:06:44

Would need some extra guards in the mx internals, I'd guess, but might be a universal solution.

Benjamin C17:06:26

(I really have little context to work with here, this is just me stabbing in the dark)

kennytilton17:06:51

So far I have found Flutter and Dart to be a PITA to get to work, but eventually sort it out in a way that makes sense. Then I get to look at mobile, desktop, and Web. 🙂 And f/mx can hide the nuisance. With other tools, the pain never ends, we just soldier on grumbling. Are you able to toggle back and forth OK. What if you hit the first button twice, then hit the second? I am seeing:

The following assertion was thrown while handling a gesture:
md-awaken> incoming md-state not= :nascent, it is:md-quiesced
re mNB vs setState, I felt ss might be more "within the system". But mnb is part of the API, and perhaps better than agonizing over stateful/stateless. I mean, after learning a bit more about native Flutter -- they go steful when they need to maintain the custom state f/mx handles at the CLJ level. Why does f/mx ever have to go there? :thinking_face:

2
🔥 2
Benjamin C17:06:47

> Are you able to toggle back and forth OK. What if you hit the first button twice, then hit the second? Hmm, yes this works without incident on my end. Granted I've patched state-set awhile ago because my bluetooth callbacks were trying to set state while things were still building. Not sure if that why or not, but just in case it's relevant. :

(defn state-set
  ([^State state]
   (state-set state nil))
  ([^State state me]
   (if (.-mounted state)
     (do (dpx :setting-state state (minfo me))
         (try (.setState state (fn [] (do)))
              (catch Exception e
                (Future.delayed Duration.zero
                                (fn [] (if (.-mounted state)) (.setState state (fn [] (do))))))
              #_ (finally (Future.delayed Duration.zero
                                (fn [] (if (.-mounted state)) (.setState state (fn [] (do))))))))
     #_(dp :NOT_SETTING_STATE_NOT_MOUNTED state (cty/minfo me)))))

kennytilton18:06:10

Ah, I had jazzed things up a little:

(button (str "but does it?" (* 10 (mget (fasc :scaffo) :step)))
  (fn [] (mx/dp :button-2)))
I better see what's going on. :male-detective:

kennytilton21:06:01

Not able to recreate. Meanwhile, I broke the x03-physics-sim example which expects the GD to have state. Hopefully just need to work in that "nearest state" utility:

(cF (when-let [st (fx/my-state)]
      (m/AnimationController .vsync st)))

2
kennytilton23:06:08

So I changed the physics sim to search up to the nearest state, after making GD stateless, and got an error saying it was not a TickerProvider. WTF? A code search and I discover that, in desperation a year ago, I had splatted this line on exactly one factory variant, k1-child-stateful:

^:mixin m/SingleTickerProviderStateMixin ;; todo make optional
Love the comment. When I made GD k1-child-stateless, it lost the TickerProvider. The next state up was not a k1-child-stateful. Boom. I love this game!

😅 2
kennytilton23:06:08
replied to a thread:I think I'm missing something: (defn button [title action] (fx/gesture-detector {:onTap (fx/as-dart-callback [] (action))} (fx/center (m/Text title .style (m/TextStyle .fontSize 18 .fontWeight m/FontWeight.w800))))) (defn make-app [] (let [title "Why Hello"] (fx/material-app {:title title} (fx/scaffold {:appBar (fx/app-bar {:title (fx/text title)})} {:name :scaffo :step (cI 1)} (fx/center (fx/column (fx/text (str "current step: " (mget (fasc :scaffo) :step))) (fx/elevated-button {:onPressed (dfn [] (with-cc :test (mset! (fasc :scaffo) :step 2)))} (fx/text "Change to next step")) (fx/elevated-button {:onPressed (dfn [] (with-cc :test (mset! (fasc :scaffo) :step 1)))} (fx/text (str "Change to first step"))) (case (mget (fasc :scaffo) :step) 1 (fx/column (fx/text "hi -- ") (button "you'd think this would change" (fn [] (mx/dp :button-1)))) 2 (fx/column (fx/text "howdy -- ") (button "but does it?" (fn [] (mx/dp :button-2))))))))))) The regular text (IE. "hi -- " and "howdy -- ") Changes with the `:step` prop, as I would expect. Yet somehow the `(button ,,,,)` call does not?

So I changed the physics sim to search up to the nearest state, after making GD stateless, and got an error saying it was not a TickerProvider. WTF? A code search and I discover that, in desperation a year ago, I had splatted this line on exactly one factory variant, k1-child-stateful:

^:mixin m/SingleTickerProviderStateMixin ;; todo make optional
Love the comment. When I made GD k1-child-stateless, it lost the TickerProvider. The next state up was not a k1-child-stateful. Boom. I love this game!

😅 2