Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Manually opening Backdrop #131

Closed
pishguy opened this issue Sep 4, 2023 · 9 comments
Closed

Manually opening Backdrop #131

pishguy opened this issue Sep 4, 2023 · 9 comments

Comments

@pishguy
Copy link

pishguy commented Sep 4, 2023

how can i Manually opening Backdrop to show frontLayer without using like sample code action such as:

backLayer: BackdropNavigationBackLayer(
  items: [
    ListTile(title: Text("Widget 1")),
    ListTile(title: Text("Widget 2")),
  ],
  onTap: (int position) => {setState(() => _currentIndex = position)},
),

this is my code and i get Null check operator used on a null value error on this line of code Backdrop.of(context).fling() :

return BackdropScaffold(
  backgroundColor: Colors.white,
  revealBackLayerAtStart: true,
  backLayer: Center(
    child: GestureDetector(
      onTap: () {
        Backdrop.of(context).fling();
      },
      child: Container(
        width: 200,
        height: 100,
        color: Colors.black12,
        child: Text("Back Layer"),
      ),
    ),
  ),
  frontLayer: Center(child: Text("Widget 1")),
);
@WieFel
Copy link
Collaborator

WieFel commented Sep 4, 2023

Hi @pishguy, thanks for opening the issue.
Please check this section of the readme, where we describe that you can't directly access the Backdrop.of(context) within the same widget context, in which you create the BackdropScaffold.

You

  1. either need to put the use of Backdrop.of(context) into a separate widget (i.e. create a new StatelessWidget and put the GestureDetector stuff into it), or
  2. you wrap your GestureDetector (in this case) in a Builder widget. Like that you have a "new" context, from which you can access Backdrop.of(context)

@WieFel WieFel closed this as completed Sep 4, 2023
@pishguy
Copy link
Author

pishguy commented Sep 23, 2023

@WieFel hi again :)

could you help me whats the correct context in this code? i want to close Backdrop manually:

using Builder context:

return ValueListenableBuilder<bool>(
  valueListenable: wm.bottomSheetVisibility,
  builder: (_, bool visibility, __) {
    return Builder(
      builder: (context) {
        return WillPopScope(
          onWillPop: () async {
            if (visibility) {
              wm.onChangeBottomSheetVisibility(context: context, visibility: false);
              return Future.value(false);
            }
            wm.onChangeBottomSheetVisibility(context: context, visibility: true);
            return Future.value(true);
          },
          child: BackdropScaffold(
            revealBackLayerAtStart: true,
            frontLayerActiveFactor: .9,
            resizeToAvoidBottomInset: false,
            onBackLayerConcealed: () {
              wm.bottomSheetVisibility.value = true;
            },
            onBackLayerRevealed: () {
              wm.bottomSheetVisibility.value = false;
            },

onChangeBottomSheetVisibility method:

  void onChangeBottomSheetVisibility({
    required BuildContext context,
    required bool visibility,
  }) {
    bottomSheetVisibility.value = visibility;
    Backdrop.of(context).fling();
  }

using ValueListenableBuilder context:

return ValueListenableBuilder<bool>(
  valueListenable: wm.bottomSheetVisibility,
  builder: (context, bool visibility, __) {
    return WillPopScope(
      onWillPop: () async {
        if (visibility) {
          wm.onChangeBottomSheetVisibility(context: context, visibility: false);
          return Future.value(false);
        }
        wm.onChangeBottomSheetVisibility(context: context, visibility: true);
        return Future.value(true);
      },
      child: BackdropScaffold(

using the widget context:

builder: (_, bool visibility, __) {
  return WillPopScope(
    onWillPop: () async {
      if (visibility) {
        wm.onChangeBottomSheetVisibility(visibility: false);
        return Future.value(false);
      }
      wm.onChangeBottomSheetVisibility(visibility: true);
      return Future.value(true);
    },

onChangeBottomSheetVisibility method:

void onChangeBottomSheetVisibility({required bool visibility}) {
    bottomSheetVisibility.value = visibility;
    Backdrop.of(context).fling();
  }

i'm opening frontLayer by clicking on subHeader widget, thanks so much

@WieFel
Copy link
Collaborator

WieFel commented Sep 23, 2023

I think the problem here is that the context that you pass to Backdrop.of(context).fling(); in all cases is not the correct one. They are ALL from "above" (outside) the BackdropScaffold. But what you need is a context from ONE LEVEL BELOW the BackdropScaffold.

So, having the ValueListenableBuilder inside the BackdropScaffold (e.g. in the body, if possible) would solve the problem in my opinion. Then, you wouldn't even need an additional Builder, but using the context of the ValueListenableBuilder would be enough.

@pishguy
Copy link
Author

pishguy commented Sep 23, 2023

@WieFel if i put ValueListenableBuilder inside BackdropScaffold how can i close frontLayer manually with WillPopScope?

my widget has a default context and i tested that before.

is this your meant?

@override
Widget build(ILocationScreenWidgetModel wm) {
  return ValueListenableBuilder<bool>(
    valueListenable: wm.bottomSheetVisibility,
    builder: (context, bool visibility, __) {
      return WillPopScope(
        onWillPop: () async {
          if (visibility) {
            wm.bottomSheetVisibility.value = false;
            Backdrop.of(context).fling();
            return Future.value(false);
          }
          wm.bottomSheetVisibility.value = true;
          return Future.value(true);
        },
        child: BackdropScaffold(
          ...
          onBackLayerConcealed: () {
            wm.bottomSheetVisibility.value = true;
          },
          onBackLayerRevealed: () {
            wm.bottomSheetVisibility.value = false;
          },

problem is closing the frontLayer inside WillPopScope widget not inside of subHeader

return ValueListenableBuilder<bool>(
  valueListenable: wm.bottomSheetVisibility,
  builder: (_, bool visibility, __) {
    return Builder(
      builder: (context) {
        return WillPopScope(
          onWillPop: () async {
            if (visibility) {
              wm.bottomSheetVisibility.value = false;
              Backdrop.of(context).fling();
              return Future.value(false);
            }
            wm.bottomSheetVisibility.value = true;
            return Future.value(true);
          },
          child: BackdropScaffold(
            //...
            subHeader: BackdropSubHeader(
              leading: Builder(
                builder: (context) {
                  return IconButton(
                    onPressed: () => Backdrop.of(context).fling(),
                    icon: const Icon(Icons.close_rounded),
                  );
                },
              ),

@WieFel
Copy link
Collaborator

WieFel commented Sep 24, 2023

Could you briefly explain again what you are trying to achieve?
I am a bit confused... Could you maybe provide a simpler example of what your use case is?

as far as I understand, you have the following:

  1. you have a BackdropScaffold with an initially "open" front layer (?)
  2. you want to close the front layer (conceal the back layer) on some event

is that correct?

@pishguy
Copy link
Author

pishguy commented Sep 24, 2023

@WieFel

In the default state, the frontLayer widget is hidden, and when I click a button, its state changes to visible. The first fundamental issue was that when I pressed the back button on the phone, I expected to be able to return the frontLayer widget to the hidden state, which was not happening.

The second issue is that when the frontLayer widget is in the hidden state, I should be able to return to the previous screen by clicking the back button.

These two states were not implementable outside of the library, so I modified the library itself to address these issues.

please check this pull request: #135

@WieFel
Copy link
Collaborator

WieFel commented Sep 24, 2023

I created a small example app for you, which does the following:

  1. There is a home page, which redirects to a page which has a BackdropScaffold
  2. The front layer is "hidden" at start. It can be shown with a button placed on the back layer.
  3. When pressing the back button, or pressing the back arrow in the app bar, it is possible to navigate back to the home page.
import 'package:backdrop/backdrop.dart';
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Backdrop Demo',
      home: Scaffold(
        appBar: AppBar(
          title: const Text("My App"),
        ),
        body: Center(
          // Builder necessary here to be able to use Navigator.push (as we are in the same widget as
          // our MaterialApp)
          child: Builder(builder: (context) {
            return ElevatedButton(
              child: const Text("Open Backdrop Page"),
              onPressed: () => Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => const MyCustomPage(),
                ),
              ),
            );
          }),
        ),
      ),
    );
  }
}

class MyCustomPage extends StatelessWidget {
  const MyCustomPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BackdropScaffold(
      appBar: AppBar(
        title: const Text("Backdrop Example"),
      ),
      concealBacklayerOnBackButton: false,
      revealBackLayerAtStart: true,
      backLayerBackgroundColor: Colors.grey.shade300,
      backLayer: Center(
        // Builder necessary here to be able to call Backdrop.of(context), as we are inside the same
        // widget as our BackdropScaffold
        child: Builder(
          builder: (context) {
            return ElevatedButton(
              onPressed: () => Backdrop.of(context).concealBackLayer(),
              child: const Text("Conceal Back Layer"),
            );
          },
        ),
      ),
      subHeader: const BackdropSubHeader(
        title: Text("Sub Header"),
      ),
      frontLayer: const Center(
        child: Text("Front Layer"),
      ),
    );
  }
}

In my opinion, it should not be necessary to make any change to the library for this.
Hope this helps...

@pishguy
Copy link
Author

pishguy commented Sep 25, 2023

@WieFel i checked your code, thanks

closing frontLayer doesn't work every where such as my project, i tires to use Builder but it couldn't resolve py problem

@WieFel
Copy link
Collaborator

WieFel commented Sep 25, 2023

Yes, but you need to put it in the correct place. As I said, it needs to be BELOW the BackdropScaffold in the widget tree. Otherwise, Backdrop.of(context) won't find anything...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants