deakjahn / flutter_dropzone

A drag-and-drop Flutter plugin (Web). Only web and only from outside into Flutter.
https://pub.dev/packages/flutter_dropzone
85 stars 36 forks source link

Rendering issue on Firefox with Dropzone + Flutter 3.19.0 + GoRouter #77

Closed koichia closed 3 months ago

koichia commented 5 months ago

Hello,

I'm encountering an issue on Firefox (version 123.0, the latest version at the time of testing) with Dropzone after upgrading Flutter version to 3.19.0 (before this, I was on 3.16.9 and it was working without any issues). This does not happen with Chrome or Edge. I'm not sure if the issue is with Dropzone but since in my app problem disappears when I remove Dropzone so I thought I'd report the issue here first.

The issue is that when I use Dropzone + Flutter 3.19.0 + GoRouter (NavigationRail) I get some exceptions and also the rendering becomes incorrect.

I have created this simple UI to replicate the issue (Navigation rails on the left, main contents on the right). Screenshot 2024-02-19 205329

What happens is that on Firefox, when I hover around the left navigation icons, the icons becomes larger and appears broken. Screenshot 2024-02-19 205256

and then I get series of exceptions. For example:

The issue disappears when I remove Dropzone. Screenshot 2024-02-19 215617

This is the minimum code to reproduce this issue: main.dart.zip

import 'package:flutter/material.dart';
import 'package:flutter_dropzone/flutter_dropzone.dart';
import 'package:go_router/go_router.dart';

class MyNavigationRail extends StatelessWidget {
  const MyNavigationRail({super.key, required this.navigationShell});

  final StatefulNavigationShell navigationShell;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Row(
        children: [
          SafeArea(
            child: NavigationRail(
              extended: true,
              labelType: NavigationRailLabelType.none,
              selectedIndex: navigationShell.currentIndex,
              onDestinationSelected: (int index) {
                navigationShell.goBranch(
                  index,
                  initialLocation: (index == navigationShell.currentIndex),
                );
              },
              destinations: const [
                NavigationRailDestination(
                  label: Text('Main'),
                  icon: Icon(Icons.folder_outlined),
                  selectedIcon: Icon(Icons.folder),
                ),
                NavigationRailDestination(
                  label: Text('Sub'),
                  icon: Icon(Icons.inventory_2_outlined),
                  selectedIcon: Icon(Icons.inventory_2),
                ),
              ],
            ),
          ),
          Expanded(
            child: navigationShell,
          ),
        ],
      ),
    );
  }
}

void main(List<String> args) {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  MyApp({super.key});

  final _goRouter = GoRouter(
    navigatorKey: GlobalKey<NavigatorState>(),
    routes: [
      StatefulShellRoute.indexedStack(
        builder: (context, state, navigationShell) {
          return MyNavigationRail(
            navigationShell: navigationShell,
          );
        },
        branches: [
          StatefulShellBranch(
            navigatorKey: GlobalKey<NavigatorState>(),
            routes: [
              GoRoute(
                path: '/',
                pageBuilder: (context, state) => NoTransitionPage(
                  key: state.pageKey,
                  child: const MainPage(),
                ),
              ),
            ],
          ),
          StatefulShellBranch(
            navigatorKey: GlobalKey<NavigatorState>(),
            routes: [
              GoRoute(
                path: '/sub',
                pageBuilder: (context, state) => NoTransitionPage(
                  key: state.pageKey,
                  child: const SubPage(),
                ),
              ),
            ],
          ),
        ],
      ),
    ],
  );

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      debugShowCheckedModeBanner: false,
      scaffoldMessengerKey: GlobalKey<ScaffoldMessengerState>(),
      routerConfig: _goRouter,
    );
  }
}

class MainPage extends StatelessWidget {
  const MainPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          DropzoneView(
            operation: DragOperation.copy,
            onCreated: (ctrl) => debugPrint('Zone created'),
            onLoaded: () => debugPrint('Zone loaded'),
            onError: (ev) => debugPrint('Error: $ev'),
            onHover: () => debugPrint('Zone hovered'),
            onDrop: (ev) => debugPrint('Drop: $ev'),
            onDropMultiple: (ev) => debugPrint('Drop multiple: $ev'),
            onLeave: () => debugPrint('Zone left'),
          ),
          const Center(child: Text('Main')),
        ],
      ),
    );
  }
}

class SubPage extends StatelessWidget {
  const SubPage({super.key});

  @override
  Widget build(BuildContext context) {
    return const Scaffold(body: Center(child: Text('Sub')));
  }
}

Please let me know if I should report this to the Flutter team first. Thank you!

deakjahn commented 5 months ago

The problem is that I use neither GoRouter nor Firefox. :-) But considering that this plugin does nothing more than adds a <DIV> to the HTML with a couple of drag-drop handlers attached, I'm not sure how it could cause this effect. Actually, you are allowed to add an onHover handler as well but it's up to you to decide what happens, there's nothing on the JavaScript side but a callback (as I can see, you added nothing, all it's there is a debug print).

At first, you should try the original example, without GoRouter in Firefox to see if that works all right.

koichia commented 5 months ago

Thank you for the reply. Yes If I don't use GoRouter the it works as expected in Firefox. In my app I have a fair amount of packages loaded and the code I shared above is the minimum code I came up with that could reproduce the issue.

Since Dropzone and GoRouter did not change when Flutter 3.19.0 came out, the issue may well be somewhere in Flutter. Since I was in a bit of rush, I decided to use an alternative, super_drag_and_drop, which did not cause any rendering issues with Firefox. So for the time being I'll be using that one, but eventually it'll be great if I could go back to using Dropzone again since super_drag_and_drop is a bit overkill for my use case.

Oleh-Sv commented 4 months ago

I was able to reproduce with app without go_router. It happened after flutter 3.19 and only in firefox

koichia commented 4 months ago

Okay that's great!

deakjahn commented 4 months ago

@Oleh-Sv Than could you just zip up a minimal sample for testing?

koichia commented 3 months ago

Hi,

I happened to find a simpler code to reproduce the issue in Firefox while I was working on something else. This time it doesn't even involve Dropzone, but just a single HtmlElementView. Since this happens without Dropzone, I should report it to the Flutter team instead.

import 'dart:ui_web' as ui_web;
import 'package:flutter/material.dart';
import 'package:web/web.dart' as web;

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

class HtmlElementViewExampleApp extends StatelessWidget {
  const HtmlElementViewExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: MainApp(),
    );
  }
}

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

  @override
  State<MainApp> createState() => _MainAppState();
}

class _MainAppState extends State<MainApp> {
  int _selectedIndex = 0;

  @override
  void initState() {
    super.initState();

    ui_web.platformViewRegistry.registerViewFactory(
      'test-html-view',
      (int viewId) {
        final divElement = web.HTMLDivElement();
        divElement.style.width = '100%';
        divElement.style.height = '100%';
        divElement.style.backgroundColor = '#ffff00';
        divElement.style.textAlign = 'center';
        divElement.text = 'Text from DIV';
        return divElement;
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          mainAxisSize: MainAxisSize.min,
          children: [
            Text(
              'Navigation Index: $_selectedIndex',
              style: const TextStyle(
                fontSize: 30,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(
              width: 100,
              height: 20,
              child: HtmlElementView(viewType: 'test-html-view'),
            ),
          ],
        ),
      ),
      bottomNavigationBar: BottomNavigationBar(
        selectedItemColor: Colors.orange,
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.business),
            label: 'Business',
          ),
        ],
        currentIndex: _selectedIndex,
        onTap: (index) => setState(() {
          _selectedIndex = index;
        }),
      ),
    );
  }
}

Firefox HtmlElementView issue Flutter 3 19

koichia commented 3 months ago

Looks like the issue is already reported to Flutter. Like these:

Hopefully the fix is coming soon.

koichia commented 3 months ago

The Flutter version 3.19.6 is out and I confirmed that it works on Firefox now 🙌

deakjahn commented 3 months ago

Nice. Thank you.