Lagrange [work/v1.10]

Mobile: Fixed swipe navigation and scroll position issues

=> 2fa228e2ddc7151f99a9d039190ad5dc5ad785c1

diff --git a/src/app.c b/src/app.c
index ed56d5b1..5f5791bf 100644
--- a/src/app.c
+++ b/src/app.c
@@ -171,6 +171,7 @@ struct Impl_App {
     unsigned int idleSleepDelayMs;
 #endif
     iAtomicInt   pendingRefresh;
+    iBool        disableRefresh;
     iBool        isLoadingPrefs;
     iStringList *launchCommands;
     iBool        isFinishedLaunching;
@@ -1067,6 +1068,10 @@ static void dumpRequestFinished_App_(void *obj, iGmRequest *req) {
     unlock_Mutex(dumpMutex_);
 }
 
+void disableRefresh_App(iBool dis) {
+    app_.disableRefresh = dis;
+}
+
 static void init_App_(iApp *d, int argc, char **argv) {
     iBool doDump = iFalse;
 #if defined (iPlatformAndroid)
@@ -1081,6 +1086,7 @@ static void init_App_(iApp *d, int argc, char **argv) {
 #endif
     d->isDarkSystemTheme = iTrue; /* will be updated by system later on, if supported */
     d->isSuspended = iFalse;
+    d->disableRefresh = iFalse;
     d->tempFilesPendingDeletion = new_StringSet();
     d->recentlyClosedTabUrls = new_StringList();
     d->overrideDataPath = NULL;
@@ -2252,6 +2258,9 @@ static int run_App_(iApp *d) {
 
 void refresh_App(void) {
     iApp *d = &app_;
+    if (d->disableRefresh) {
+        return;
+    }
 #if defined (LAGRANGE_ENABLE_IDLE_SLEEP)
     if (d->warmupFrames == 0 && d->isIdling) {
         return;
@@ -4077,7 +4086,8 @@ iBool handleCommand_App(const char *cmd) {
         setUrlAndSource_DocumentWidget(page,
                                        collectNewCStr_String(""),
                                        collectNewCStr_String("text/gemini"),
-                                       utf8_String(src));
+                                       utf8_String(src),
+                                       0);
         return iTrue;
     }
     else if (equal_Command(cmd, "zoom.set")) {
@@ -4623,7 +4633,8 @@ iBool handleCommand_App(const char *cmd) {
             expTab,
             collect_String(format_Date(&now, "file:Lagrange User Data %Y-%m-%d %H%M%S.zip")),
             collectNewCStr_String("application/zip"),
-            data_Buffer(zip));
+            data_Buffer(zip),
+            0);
         iRelease(zip);
         delete_Export(export);
 #if defined (iPlatformAppleMobile) || defined (iPlatformAndroidMobile)
diff --git a/src/app.h b/src/app.h
index 48411791..7db9cf6e 100644
--- a/src/app.h
+++ b/src/app.h
@@ -89,6 +89,7 @@ void        refresh_App                 (void);
 iBool       isRefreshPending_App        (void);
 iBool       isFinishedLaunching_App     (void);
 uint32_t    elapsedSinceLastTicker_App  (void); /* milliseconds */
+void        disableRefresh_App          (iBool);
 
 iBool               isLandscape_App     (void);
 iLocalDef iBool     isPortrait_App      (void) { return !isLandscape_App(); }
diff --git a/src/ui/certlistwidget.c b/src/ui/certlistwidget.c
index a97b7f15..f3bac75a 100644
--- a/src/ui/certlistwidget.c
+++ b/src/ui/certlistwidget.c
@@ -231,7 +231,8 @@ static iBool processEvent_CertListWidget_(iCertListWidget *d, const SDL_Event *e
                     expTab,
                     collectNewFormat_String("file:%s.pem", cstr_String(name_GmIdentity(ident))),
                     collectNewCStr_String("text/plain"),
-                    utf8_String(pem));
+                    utf8_String(pem),
+                    0);
             }
             return iTrue;
         }
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 1be0b35c..6067e24f 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -538,11 +538,11 @@ static iChar linkOrdinalChar_DocumentWidget_(const iDocumentWidget *d, size_t or
 /*----------------------------------------------------------------------------------------------*/
 
 void init_DocumentView(iDocumentView *d) {
-    d->owner            = NULL;
-    d->doc              = new_GmDocument();
-    d->invalidRuns      = new_PtrSet();
-    d->drawBufs         = new_DrawBufs();
-    d->pageMargin       = 5;
+    d->owner         = NULL;
+    d->doc           = new_GmDocument();
+    d->invalidRuns   = new_PtrSet();
+    d->drawBufs      = new_DrawBufs();
+    d->pageMargin    = 5;
     d->hoverPre      = NULL;
     d->hoverAltPre   = NULL;
     d->hoverLink     = NULL;
@@ -728,15 +728,6 @@ static const iGmRun *lastVisibleLink_DocumentView_(const iDocumentView *d) {
     return NULL;
 }
 
-static float normScrollPos_DocumentView_(const iDocumentView *d) {
-    const int docSize = pageHeight_DocumentView_(d);
-    if (docSize) {
-        float pos = pos_SmoothScroll(&d->scrollY) / (float) docSize;
-        return iMax(pos, 0.0f);
-    }
-    return 0;
-}
-
 static int scrollMax_DocumentView_(const iDocumentView *d) {
     const iWidget *w = constAs_Widget(d->owner);
     int sm = pageHeight_DocumentView_(d) +
@@ -745,6 +736,15 @@ static int scrollMax_DocumentView_(const iDocumentView *d) {
     return sm;
 }
 
+static float normScrollPos_DocumentView_(const iDocumentView *d) {
+    const int height = pageHeight_DocumentView_(d);
+    if (height > 0) {
+        float pos = pos_SmoothScroll(&d->scrollY) / (float) height;
+        return iMax(pos, 0.0f);
+    }
+    return 0;
+}
+
 static void invalidateLink_DocumentView_(iDocumentView *d, iGmLinkId id) {
     /* A link has multiple runs associated with it. */
     iConstForEach(PtrArray, i, &d->visibleLinks) {
@@ -949,9 +949,11 @@ static void updateVisible_DocumentView_(iDocumentView *d) {
     updateHover_DocumentView_(d, mouseCoord_Window(get_Window(), 0));
     updateSideOpacity_DocumentView_(d, iTrue);
     animateMedia_DocumentWidget_(d->owner);
-    /* Remember scroll positions of recently visited pages. */ {
+    /* Remember scroll positions of recently visited pages. */
+    if (~d->owner->flags & animationPlaceholder_DocumentWidgetFlag) {
+        iAssert(~d->owner->widget.flags & destroyPending_WidgetFlag);
         iRecentUrl *recent = mostRecentUrl_History(d->owner->mod.history);
-        if (recent && docSize && d->owner->state == ready_RequestState &&
+        if (recent && size_GmDocument(d->doc).y > 0 && d->owner->state == ready_RequestState &&
             equal_String(&recent->url, d->owner->mod.url)) {
             recent->normScrollY = normScrollPos_DocumentView_(d);
         }
@@ -3933,6 +3935,10 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) {
        
        2022-03-16: Yeah, something did break, again. "swipeout" is not found if the tab bar
        is moved to the bottom, when swiping back.
+
+       2023-02-03: There is a visual glitch because a refresh occurs during the switchover
+       of the document and its swipe placeholder. Solution is to forcibly prevent refresh from
+       occuring during the switch operation.
     */
     iWidget *w = as_Widget(d);
     if (!prefs_App()->edgeSwipe &&
@@ -3997,9 +4003,11 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) {
                         updateBanner_DocumentWidget_(swipeIn);
                     }
                     else {
-                        setUrlAndSource_DocumentWidget(swipeIn, &recent->url,
+                        setUrlAndSource_DocumentWidget(swipeIn,
+                                                       &recent->url,
                                                        collectNewCStr_String("text/gemini"),
-                                                       collect_Block(new_Block(0)));
+                                                       collect_Block(new_Block(0)),
+                                                       recent->normScrollY);
                     }
                     unlock_History(d->mod.history);
                 }
@@ -4038,7 +4046,8 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) {
                     setUrlAndSource_DocumentWidget(d,
                                                    collectNewCStr_String("about:blank"),
                                                    collectNewCStr_String("text/gemini"),
-                                                   collect_Block(new_Block(0)));
+                                                   collect_Block(new_Block(0)),
+                                                   0);
                 }
                 if (flags_Widget(w) & dragged_WidgetFlag) {
                     setVisualOffset_Widget(w, width_Widget(w) +
@@ -4075,13 +4084,21 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) {
         iAssert(~d->flags & animationPlaceholder_DocumentWidgetFlag);
         setFlags_Widget(w, dragged_WidgetFlag, iFalse);
         setVisualOffset_Widget(w, 0, 250, easeOut_AnimFlag | softer_AnimFlag);
+        stopWidgetMomentum_Touch(w);
         return iTrue;
     }
     if (equal_Command(cmd, "edgeswipe.ended") && argLabel_Command(cmd, "side") == 1) {
+        if (!argLabel_Command(cmd, "abort") && flags_Widget(w) & dragged_WidgetFlag) {
+            /* Hacky fix for animation glitches during swipe navigation, where the widgets get
+               refreshed in between the switch from swipeout/in and the real DocumentWidget.
+               GET RID OF THIS when the swipe animation is implemented in a more elegant way
+               (using DocumentViews). */
+            disableRefresh_App(iTrue);
+        }
         iWidget *swipeParent = swipeParent_DocumentWidget_(d);
         iDocumentWidget *swipeIn = findChild_Widget(swipeParent, "swipein");
         d->swipeSpeed = argLabel_Command(cmd, "speed") / gap_UI;
-        /* "swipe.back" will soon follow. The `d` document will do the actual back navigation,
+        /* "swipe.back" may soon follow. The `d` document will do the actual back navigation,
             switching immediately to a cached page. However, if one is not available, we'll need
             to show a blank page for a while. */
         if (swipeIn) {
@@ -4098,11 +4115,13 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) {
                 setUrlAndSource_DocumentWidget(d,
                                                swipeIn->mod.url,
                                                collectNewCStr_String("text/gemini"),
-                                               collect_Block(new_Block(0)));
+                                               collect_Block(new_Block(0)),
+                                               0);
                 as_Widget(swipeIn)->offsetRef = NULL;
             }
             destroy_Widget(as_Widget(swipeIn));
         }
+        stopWidgetMomentum_Touch(w);
     }
     if (equal_Command(cmd, "swipe.back")) {
         iWidget *swipeParent = swipeParent_DocumentWidget_(d);
@@ -4112,6 +4131,7 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) {
             if (target) {
                 destroy_Widget(as_Widget(target)); /* didn't need it after all */
             }
+            disableRefresh_App(iFalse);
             return iTrue;
         }
         setupSwipeOverlay_DocumentWidget_(d, as_Widget(target));
@@ -5084,8 +5104,11 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
     }
     else if (equal_Command(cmd, "document.setmediatype") && document_App() == d) {
         if (!isRequestOngoing_DocumentWidget(d)) {
-            setUrlAndSource_DocumentWidget(d, d->mod.url, string_Command(cmd, "mime"),
-                                           &d->sourceContent);
+            setUrlAndSource_DocumentWidget(d,
+                                           d->mod.url,
+                                           string_Command(cmd, "mime"),
+                                           &d->sourceContent,
+                                           normScrollPos_DocumentView_(&d->view));
         }
         return iTrue;
     }
@@ -6546,6 +6569,10 @@ void deserializeState_DocumentWidget(iDocumentWidget *d, iStream *ins) {
 void setUrlFlags_DocumentWidget(iDocumentWidget *d, const iString *url, int setUrlFlags,
                                 const iBlock *setIdent) {
     iAssert(~d->flags & animationPlaceholder_DocumentWidgetFlag);
+    /* Hacky fix for animation glitches during swipe navigation, where the widgets get refreshed
+       in between the switch from swipeout/in and the real DocumentWidget. GET RID OF THIS when
+       the swipe animation is implemented in a more elegant way (using DocumentViews). */
+    disableRefresh_App(iFalse);
     const iBool allowCache     = (setUrlFlags & useCachedContentIfAvailable_DocumentWidgetSetUrlFlag) != 0;
     const iBool allowCachedDoc = (setUrlFlags & disallowCachedDocument_DocumentWidgetSetUrlFlag) == 0;
     iChangeFlags(d->flags, preventInlining_DocumentWidgetFlag,
@@ -6569,7 +6596,7 @@ void setUrlFlags_DocumentWidget(iDocumentWidget *d, const iString *url, int setU
 }
 
 void setUrlAndSource_DocumentWidget(iDocumentWidget *d, const iString *url, const iString *mime,
-                                    const iBlock *source) {
+                                    const iBlock *source, float normScrollY) {
     setLinkNumberMode_DocumentWidget_(d, iFalse);
     d->flags |= preventInlining_DocumentWidgetFlag;
     setUrl_DocumentWidget_(d, url);
@@ -6579,7 +6606,7 @@ void setUrlAndSource_DocumentWidget(iDocumentWidget *d, const iString *url, cons
     initCurrent_Time(&resp->when);
     set_String(&resp->meta, mime);
     set_Block(&resp->body, source);
-    updateFromCachedResponse_DocumentWidget_(d, 0, resp, NULL);
+    updateFromCachedResponse_DocumentWidget_(d, normScrollY, resp, NULL);
     updateBanner_DocumentWidget_(d);
     delete_GmResponse(resp);
 }
diff --git a/src/ui/documentwidget.h b/src/ui/documentwidget.h
index d734fda4..8071c759 100644
--- a/src/ui/documentwidget.h
+++ b/src/ui/documentwidget.h
@@ -67,7 +67,8 @@ void    setIdentity_DocumentWidget      (iDocumentWidget *, const iBlock *setIde
 void    setUrl_DocumentWidget           (iDocumentWidget *, const iString *url);
 void    setUrlFlags_DocumentWidget      (iDocumentWidget *, const iString *url, int setUrlFlags,
                                          const iBlock *setIdent);
-void    setUrlAndSource_DocumentWidget  (iDocumentWidget *, const iString *url, const iString *mime, const iBlock *source);
+void    setUrlAndSource_DocumentWidget  (iDocumentWidget *, const iString *url, const iString *mime,
+                                         const iBlock *source, float normScrollY);
 void    setInitialScroll_DocumentWidget (iDocumentWidget *, float normScrollY); /* set after content received */
 void    setRedirectCount_DocumentWidget (iDocumentWidget *, int count);
 void    setSource_DocumentWidget        (iDocumentWidget *, const iString *sourceText);
diff --git a/src/ui/widget.c b/src/ui/widget.c
index 4e5c43c3..f2caddec 100644
--- a/src/ui/widget.c
+++ b/src/ui/widget.c
@@ -147,8 +147,10 @@ static void visualOffsetAnimation_Widget_(void *ptr) {
     iWidget *d = ptr;
     postRefresh_App();
     d->root->didAnimateVisualOffsets = iTrue;
-//    printf("'%s' visoffanim: fin:%d val:%f\n", cstr_String(&d->id),
-//           isFinished_Anim(&d->visualOffset), value_Anim(&d->visualOffset)); fflush(stdout);
+#if 0
+    printf("'%s' visoffanim: fin:%d val:%f\n", cstr_String(&d->id),
+           isFinished_Anim(&d->visualOffset), value_Anim(&d->visualOffset)); fflush(stdout);
+#endif
     if (!isFinished_Anim(&d->visualOffset)) {
         addTickerRoot_App(visualOffsetAnimation_Widget_, d->root, ptr);
     }
Proxy Information
Original URL
gemini://git.skyjake.fi/lagrange/work%2Fv1.10/cdiff/2fa228e2ddc7151f99a9d039190ad5dc5ad785c1
Status Code
Success (20)
Meta
text/gemini; charset=utf-8
Capsule Response Time
92.306344 milliseconds
Gemini-to-HTML Time
0.811179 milliseconds

This content has been proxied by September (3851b).