FlutterFlow / flutterflow-issues

A community issue tracker for FlutterFlow.
98 stars 17 forks source link

Switch Widget Fails to Apply Initial Value Correctly #2851

Closed deepanchal closed 6 days ago

deepanchal commented 2 weeks ago

Has your issue been reported?

Current Behavior

When an initial value is provided to Switch widget, it is setting initial value to what the value was in flutterflow before setting an initial value var.

Expected Behavior

When an initial value is provided to Switch widget, it should set initial value correctly.

Steps to Reproduce

Please note: I am providing code from my existing project and I was able to replicate it by creating a simple flutterflow page with a Switch. The issue is in flutterflow code generation. Please see images below.

  1. Create a new page in flutterflow (e.g. BrokenSwitchBug)

  2. Add a new variable initialSwitchValue to Local Page State Variables with initial value of true image

  3. Add a Switch under Column and set the initial value to initialStateValue page state variable image

  4. Add an action from any main page to navigate to this page image

  5. Run the app and navigate to BrokenSwitchBug page.

  6. After navigating to the page, you should see that the switch is toggled on as it should be from initialSwitchValue var.

The switch value should be true, but it's false. This true/false value is coming from before we set a variable to set initial switch value image In this image, if you were to set "Switch Initial Value" to true, and then set it to use initialSwitchValue variable, then it will default to true. The flutterflow code generation used to be bool? switchValue; which would allow it to use value from initialSwitchValue var bc of this line _model.switchValue ??= _model.initialSwitchValue,, however, it no longer sets variable as null (bool switchValue = false;).

broken_switch_model.dart

import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/flutter_flow/flutter_flow_widgets.dart';
import 'broken_switch_bug_widget.dart' show BrokenSwitchBugWidget;
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';

class BrokenSwitchBugModel extends FlutterFlowModel<BrokenSwitchBugWidget> {
  ///  Local state fields for this page.

  bool initialSwitchValue = true;

  ///  State fields for stateful widgets in this page.

  final unfocusNode = FocusNode();
  // State field(s) for Switch widget.
  bool switchValue = false;

  @override
  void initState(BuildContext context) {}

  @override
  void dispose() {
    unfocusNode.dispose();
  }
}

broken_switch_widget.dart

import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/flutter_flow/flutter_flow_widgets.dart';
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
import 'broken_switch_bug_model.dart';
export 'broken_switch_bug_model.dart';

class BrokenSwitchBugWidget extends StatefulWidget {
  const BrokenSwitchBugWidget({super.key});

  @override
  State<BrokenSwitchBugWidget> createState() => _BrokenSwitchBugWidgetState();
}

class _BrokenSwitchBugWidgetState extends State<BrokenSwitchBugWidget> {
  late BrokenSwitchBugModel _model;

  final scaffoldKey = GlobalKey<ScaffoldState>();

  @override
  void initState() {
    super.initState();
    _model = createModel(context, () => BrokenSwitchBugModel());

    logFirebaseEvent('screen_view',
        parameters: {'screen_name': 'BrokenSwitchBug'});
    WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {}));
  }

  @override
  void dispose() {
    _model.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () => _model.unfocusNode.canRequestFocus
          ? FocusScope.of(context).requestFocus(_model.unfocusNode)
          : FocusScope.of(context).unfocus(),
      child: Scaffold(
        key: scaffoldKey,
        backgroundColor: FlutterFlowTheme.of(context).primaryBackground,
        appBar: AppBar(
          backgroundColor: FlutterFlowTheme.of(context).primary,
          automaticallyImplyLeading: false,
          title: Text(
            'Broken Switch Bug',
            style: FlutterFlowTheme.of(context).headlineMedium.override(
                  fontFamily: FlutterFlowTheme.of(context).headlineMediumFamily,
                  color: Colors.white,
                  fontSize: 22.0,
                  letterSpacing: 0.0,
                  useGoogleFonts: GoogleFonts.asMap().containsKey(
                      FlutterFlowTheme.of(context).headlineMediumFamily),
                ),
          ),
          actions: [],
          centerTitle: false,
          elevation: 2.0,
        ),
        body: SafeArea(
          top: true,
          child: Align(
            alignment: AlignmentDirectional(0.0, 0.0),
            child: Column(
              mainAxisSize: MainAxisSize.max,
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                Switch.adaptive(
                  value: _model.switchValue ??= _model.initialSwitchValue,
                  onChanged: (newValue) async {
                    setState(() => _model.switchValue = newValue!);
                  },
                  activeColor: FlutterFlowTheme.of(context).primary,
                  activeTrackColor: FlutterFlowTheme.of(context).accent1,
                  inactiveTrackColor: FlutterFlowTheme.of(context).alternate,
                  inactiveThumbColor:
                      FlutterFlowTheme.of(context).secondaryText,
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

This line in broken_switch_model was changed in flutterflow update from this morning.

before:

  // State field(s) for Switch widget.
  bool? switchValue;

after:

  // State field(s) for Switch widget.
  bool switchValue = false;

Reproducible from Blank

Bug Report Code (Required)

IT4kj8n18c5OoeFZ1s7pbcZWq2IXQ3ojTLJEtusbTUggfbL4EJk+d8ylXElpYMizaHNMemeZvHIfwvT5jdj2GMIqNRCaQao61qlUehPPbH2lVbqhC7jtPXRCJ/hbI2q51sGFvSZQHNd2W3Ak62eACujKYz6Cf9qOYwx5e6fDbOY=

Context

All of the switches in my project using initial values are broken

Visual documentation

I believe this bug was caused by a flutterflow update from this morning.

This diff shows that all switch values now have default value of true/false instead of null. image

And in the widget code, this line has no effect because model is already setting true/false value image

Additional Info

No response

Environment

- FlutterFlow version: 4.1.46+
- Platform: Android
- Browser name and version: Brave Browser 124.1.65.123
- Operating system and version affected:

General

Relative to the time the changes were made, data was lost within

When following my steps to reproduce, data loss happens

ignalauret commented 2 weeks ago

Hey @deepanchal thanks for your report. I can see a lot of detail that could help us fix really quick the bug, but I'm not seeing the steps to actually reproduce it and see the unexpected behaviour. Could you please give me some steps to reproduce this from a blank project so I can confirm the bug and send it to the technical team? Thanks!

deepanchal commented 2 weeks ago

Hii @ignalauret, here are the steps to reproduce the bug. Thanks!!

Steps to reproduce

  1. Create a new page in flutterflow (e.g. BrokenSwitchBug)

  2. Add a new variable initialSwitchValue to Local Page State Variables with initial value of true image

  3. Add a Switch under Column and set the initial value to initialStateValue page state variable image

  4. Add an action from any main page to navigate to this page image

  5. Run the app and navigate to BrokenSwitchBug page.

  6. After navigating to the page, you should see that the switch is toggled on as it should be from initialSwitchValue var.

The switch value should be true, but it's false. This true/false value is coming from before we set a variable to set initial switch value image In this image, if you were to set "Switch Initial Value" to true, and then set it to use initialSwitchValue variable, then it will default to true. The flutterflow code generation used to be bool? switchValue; which would allow it to use value from initialSwitchValue var bc of this line _model.switchValue ??= _model.initialSwitchValue,, however, it no longer sets variable as null (bool switchValue = false;).

mark-fran commented 2 weeks ago

I have the same issue. It looks like the Initial Value is not pulling the data from queries, but instead it is merely reflecting whether the initial value tickmark was ticked, and not based on the Initial Value query.

I tried using the Tickmark Widget and it correctly reflected the queried data. In the below screenshot, you can see that the Switch was set to True, while the Tick Box was set to False.

Screen Shot 2024-05-03 at 7 30 52 pm

rzambroni commented 2 weeks ago

Hi @deepanchal, thanks for the additional details, we replicated the issue you are describing and will send it to the team so they can take a look. We will update the status here when we have news.

Thanks for the report!

pollux-choh commented 2 weeks ago

image I have the same issue.

Hi @deepanchal, thanks for the additional details, we replicated the issue you are describing and will send it to the team so they can take a look. We will update the status here when we have news.

Thanks for the report!

tmgnr75 commented 2 weeks ago

Hey everyone,

I have the same issue and found the probable cause + workaround while they're working on a solution.

The cause seems to be the release of new widget SwitchTile (the documentation was updated 3 days ago).

I tried to use a SwitchTile widget instead of a Switch and the values are correctly initialized.

Hope it helps a few fellow builders ✌️

anoos1973 commented 2 weeks ago

I have the same issue

anoos1973 commented 2 weeks ago

I have the same issue. It looks like the Initial Value is not pulling the data from queries, but instead it is merely reflecting whether the initial value tickmark was ticked, and not based on the Initial Value query.

I tried using the Tickmark Widget and it correctly reflected the queried data. In the below screenshot, you can see that the Switch was set to True, while the Tick Box was set to False.

Screen Shot 2024-05-03 at 7 30 52 pm

EXACTLY

d6p2b commented 2 weeks ago

The issue is the use of the ??= operator to set the switch value. The model defaults switch values to true so using the null assignment operator will never do anything as the left hand side (model's switch value) is never null.

Here's a bit of Switch.adaptive code with the offending operator:

              Switch.adaptive(
                    value: _model.switchValue1 ??= _model.foobar == 1,
                    onChanged: (newValue) async {
                      setState(() => _model.switchValue1 = newValue!);
                    },
                    activeColor: FlutterFlowTheme.of(context).primary,
                    activeTrackColor: FlutterFlowTheme.of(context).accent1,
                    inactiveTrackColor: FlutterFlowTheme.of(context).alternate,
                    inactiveThumbColor:
                        FlutterFlowTheme.of(context).secondaryText,
                  ),

The fix would be to use a normal assignment operator not the if-null operator.

maxi069 commented 1 week ago

Mismo error! Lo solucione usando el Widget SwitchTile dejando solo el titulo. De todas formas estimo no pasara mucho para que solucionen!

htsnet commented 1 week ago

Same issue. I realized that only the visual was wrong. If my variable is OFF, the switch shows ON, but if I save, the value saved continues OFF. If I change to OFF and return to ON, then save, the value saved turns ON (correct).

switchIssue 2024 05 06

In this image, I am passing TRUE for the first block and FALSE to the second. Visually, both are TRUE.

request-tickets commented 1 week ago

Not sure but I think a possible cause for this is when it's querying from a backend data

htsnet commented 1 week ago

No, in this case, I passed the values (1 and 2) by parameters. And the same field (1 and 2) is used to text and switch.

mark-fran commented 1 week ago

@request-tickets @htsnet This has already been flagged as a confirmed bug.

mmearly commented 1 week ago

Hi all! Sorry for the delay here -- this fix was actually finished on Friday, but we had some issues with deployment. It should now be out to everyone and you should get the expected initialization behavior for both Switches and SwitchTiles. Thanks for your patience!

htsnet commented 1 week ago

@mmearly Thank you!

metalik commented 1 week ago

just download the latest Flutterflow Window Desktop and the problem still existing

The generated code is still using the ??= operator

Switch.adaptive( value: _model.mySwitchValue ??= widget.user!.mySwitchValue,

Thesergiolg99 commented 1 week ago

I can confirm the issue is still there on .49 FF build

mmearly commented 1 week ago

Hey @metalik and @Thesergiolg99, thanks for the feedback, I will investigate. Are you both on Windows desktop?

Quick note that the presence of the ??= operator doesn't necessarily indicate a problem -- it was the combination of this with the switch's boolean value in the model being non-nullable that resulted in the bug. The fixed version that it sounds like you don't have yet will still generate code with ??=.

d6p2b commented 1 week ago

I still see the problem with .49 on macOS. The generated model code is initializing the underlying bool to true (or false) and the widget is still using the ??= operator.

I think the ??= operator is absolutely the problem.

How will a switch ever be null? When it gets dropped into a scaffold the initial value is either on or off based on the Switch Properties.

mmearly commented 1 week ago

Hey all, it looks like what happened is that the fix that was emergency deployed on Monday didn't get included in Thursday's release, so the bug snuck back in. I don't have permissions to do deploys myself but I'm sending messages to the folks who do. Hopefully this should be fixed again soon!

mmearly commented 1 week ago

@d6p2b The traditional behavior with code generation for switches in FF is that their underlying bool is nullable (this bug was caused by something causing this bool to become non-nullable). It begins as null and if there is an initial value associated with the switch, instead of setting the value here (this is not trivial because this value can depend on other variables only scoped in the widget, not the model), we use the ??= operator in the widget to set the value of the switch because it lets us detect that the underlying bool is null, indicating the switch has not yet been initialized. This lets us easily tell when to overwrite the value in the bool (because it represents an uninitialized value) and when to keep it (because it does actually represent the state of the user's switch). Finally, in the widget, we are able to use the Switch's onChanged function to update the underlying boolean whenever the switch is toggled, and since a switch toggle can only be on or off, the boolean will not be null after this point.

The initial fix was just to get switch behavior back into this paradigm, but we've realized that this is a less-than-ideal way to be handling the initial values of switches, and so this section of code generation is being more drastically reworked. But the first priority is getting the current paradigm back to a working state.

mmearly commented 1 week ago

Reopening until redeploy

mmearly commented 6 days ago

Hi all, this has been redeployed on the backend, so functionality should have been restored! 🥳 Small caveat that we did not redeploy the front-end for this, so View Code will display the wrong thing until Thursday's release. But the correct code should be being generated (e.g., Download Code will give you the correct code now). Thanks again for your patience!

metalik commented 5 days ago

confirm that the issue is fixed, thanks