slovnicki / beamer

A routing package built on top of Router and Navigator's pages API, supporting arbitrary nested navigation, guards and more.
MIT License
591 stars 129 forks source link

iOS swipe-to-beam-back showing incorrect page #591

Open terekhovyes opened 1 year ago

terekhovyes commented 1 year ago

Describe the bug It looks like beamer ignores beamBackOnPop: true flag for iOS swipe-back transition and always shows "upward" page.

I use beamToNamed with beamBackOnPop: true flag on iOS to open pages. To go back I use standard iOS back-swipe gesture, which, you know, allows to see previous page where we are going to. The problem is instead of seeing correct "beam-back" page where I'm really going to - I see "pop" page where I would go if I didn't set beamBackOnPop flag. When swipe is finished - screen blinks and replaces "pop" page with correct "beam-back" page.

Beamer version: 1.5.3

Code to reproduce bug:

import 'package:beamer/beamer.dart';
import 'package:flutter/material.dart';

/// App

class TestApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerDelegate: beamerDelegate,
      routeInformationParser: BeamerParser(),
    );
  }
}

/// Beamer

final beamerDelegate = BeamerDelegate(locationBuilder: locationBuilder);

final locationBuilder = RoutesLocationBuilder(
  routes: {
    "/": (context, _, __) => BeamPage(
          key: ValueKey("home"),
          child: MovieScreen(
            tap: (id) => context.beamToNamed("/movie?id=$id"),
          ),
        ),
    "/movie": (context, state, _) {
      final id = int.parse(state.queryParameters["id"]!);
      return BeamPage(
        key: ValueKey("movie-$id"),
        child: MovieScreen(
          id: id,
          tap: (tappedId) => context.beamToNamed(
            "/movie?id=$tappedId",
            beamBackOnPop: true,
          ),
        ),
      );
    },
  },
);

/// Screen

typedef MovieCallback = void Function(int id);

class MovieScreen extends StatelessWidget {
  const MovieScreen({Key? key, this.id, required this.tap}) : super(key: key);

  final int? id;
  final MovieCallback tap;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(children: [
          Text(id == null ? "Home" : "Movie $id"),
          Expanded(
            child: ListView.builder(
              itemCount: 10,
              itemBuilder: (context, index) => TextButton(
                child: Text("Movie $index"),
                onPressed: () => tap(index),
              ),
            ),
          ),
        ]),
      ),
    );
  }
}

To Reproduce

  1. Start app to open "Home" page
  2. Click on "Movie 1"
  3. Click on "Movie 2"
  4. Slowly start to swipe from left edge to go back - you will see "Home" page is revealing below "Movie 2"
  5. Finish swipe - screen blinks and "Home" page turns into "Movie 1" page

Expected behavior On step 3 - I see "Movie 1" page which I'm going to by saying it to Beamer with "beamBackOnPop" flag

Screenshots Simulator Screen Shot - iPhone 14 - 2023-01-22 at 17 00 32

Smartphone:

Additional context My idea was to test how Beamer can handle situation when navigation graph have loops - I call it "infinite navigation case". I see that I can just build long url (like /movie1/movie2/movie10/movie5/movie7) - but don't know if RoutesLocationBuilder allows to do it. beamBackOnPop looked like solution for this situation - but I stuck with bug described above :)

Bagmet-Denis commented 1 year ago

did you find a solution?

terekhovyes commented 1 year ago

@Bagmet-Denis unfortunately, no! It was a little project, so "solved" the problem by switching to go-router. Much harder to make navigation code well structured and easy to understand. But didn't face issues like this.